YiiFramework Константы статусов в моделях

Vano

Новичок
Этот вопрос точно тупой)) но вы поймете о чем я. Заведено в моделях делать удобства для разных статусов.

Вот к примеру значит, в таблице базы данных есть 2 поля в которых записываем: 1 - видимость на сайте(1/0) и 2 - статус активен не активен(1/0), а в моделе для удобства делаем человекопонятные константы: const VISIBLE = 1; const INVISIBLE = 0; const ACTIVE = 1; const INACTIVE = 0; Эта полезняшка дает мне или кому-то еще, кто будет читать код, не запутаться. Значит, $users = Users::find()-> ... тут понятно нужно еще и Scopes(кстате как это перевести на наш язык?) использовать ... -where->('status = '.Users::VISIBLE)->all(), вот это одна из полезняшек.

Но помню, эти константы давали еще полезняшек. Если добавить какую-то функцию, которая по константе будет возвращать текстовое представление этого статуса(или еще что-то другое).

Подскажите, что это за функция и как она упрощает код? В интернете искал - не могу найти, но точно помню где-то видел. Или как делаете вы?
 
Последнее редактирование:

Adelf

Administrator
Команда форума
Это уже старье.
Если уж хочется код читаемым делать, то пусть будет так: -where->visible()->notActive()->all()
Типа того.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
а как он именованные условия из query builder вызовет в yii1? китаец завещал учиться кодить с учетом его ошибок
 

Adelf

Administrator
Команда форума
Оу. Я подумал это общий топик. А тут про Yii. Тогда наверно никак :)
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
может, и как-то, но я не смог понять вопрос
 

Adelf

Administrator
Команда форума
Сам вопрос неинтересен.
Подозреваю, что ТС имеет ввиду элементарщину типа такой:
PHP:
class User{
......
public function GetVisibleText() {
return $this->status == User::VISIBLE ? 'visible' : 'hidden';
}
}
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
наблюдатель или компоновщик? :) красиво
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
Вурдалак, а можно поподробнее? Какой контракт у repository->specify, и какой интерфейс реализует $spec? Как-то так? Меня там supports($className) очень сильно смущает.
 

WMix

герр M:)ller
Партнер клуба
я уже представляю себе класс SpecificationExpression, со всей логикой or, and, скобками и удобным интерфейсом для создания правильной характеристики, использующую набор обьектов, каждый из которых описывает буквально каждую ТаблицаПолеЗначение сущность, декларированых как отдельно описаный класс. :D
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
fixxxer, с интерфейсом $spec, конечно, из-за отсутствия generics придётся идти на какой-то компромисс. И я хз как тут можно лучше :) Дублировать OrSpecification, AndSpecification и т.д. под каждый тип выглядит очень жестко. Но если допустить автогенерацию кода:
PHP:
interface UserRepository
{
    function findAll();
    function findSatisfying(UserSpecification $spec);
}

/**
 * This class is auto-generated
 */
abstract class UserSpecification
{
    // Composite specification with or(), and(), not(), etc.

    abstract public function isSatisfiedBy(User $user);
    abstract public function getCriteria();
}

/**
 * This class is auto-generated
 */
final class OrUserSpecification extends UserSpecification
{
    public function __construct(UserSpecification $left, UserSpecification $right)
    {
        // ...
    }

    public function isSatisfiedBy(User $user)
    {
        return $this->left->isSatisfying($user) || $this->right->isSatisfying($user);
    }

    public function getCriteria()
    {
        return Criteria::expr()->or(
            $this->left->getCriteria(),
            $this->right->getCriteria()
        );
    }
}

final class VisibleUserSpecification extends UserSpecification
{
    public function isSatisfiedBy(User $user)
    {
        return $user->getStatus() === UserStatus::VISIBLE;
    }

    public function getCriteria()
    {
        return Criteria::expr()->eq('status', UserStatus::VISIBLE);
    }
}

final class DoctrineUserRepository implements UserRepository
{
    public function findSatisfying(UserSpecification $spec)
    {
        return $this->repository->matching($spec->getCriteria());
    }
}

final class CustomNonSqlUserRepository implements UserRepository
{
    public function findSatisfying(UserSpecification $spec)
    {
        return $this->customNonSqlDb->findMatching(
            $this->customNonSqlQueryMaker->build($spec->getCriteria())
        );
    }
}
Внутри там да, используется Visitor для генерации SQL из Criteria.

UserRepository::specify() же навеян http://besnikgeek.blogspot.ru/2010/08/specification-pattern-versus-query.html просто для отделения критериев типа orderBy, limit, offset от user specific критериев, потому что иметь спецификации типа OrderByUserSpecification, LimitUserSpecification для меня очень странно.

Но это так, полёт фантазии. :)
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
PHP:
final class OnlineUserSpecification extends UserSpecification
{
    private $clock;
    private $onlineInterval;

    public function __construct(Clock $clock, $onlineInterval = 60)
    {
        $this->clock = $clock;
        $this->onlineInterval = DateInterval::createFromDateString(
            sprintf('%d seconds', $onlineInterval)
        );
    }

    public function isSatisfiedBy(User $user)
    {
        return $user->getLastVisitedAt() >= $this->clock->now()->sub($this->onlineInterval);
    }

    public function getCriteria()
    {
        return Criteria::expr()->gte(
            'lastVisitedAt',
            $this->clock->now()->sub($this->onlineInterval)
        );
    }
}
PHP:
$onlineUsers = $this->userRepository->findSatisfying(
    $this->onlineUserSpec->and($this->visibleUserSpec)
);
 
Последнее редактирование:

WMix

герр M:)ller
Партнер клуба
Вурдалак, сидел прокручивал в голове, полюбому прикольно нагенерить, но никак не соображу как в
$this->userRepository->specify($spec) впихнуть только пользовательские характеристики
тоесть abstract class UserSpecification это прикольно, но это повторение кода на каждую табличку.

PHP:
interface IExpr{
    public function fetch();
}

class Record implements IExpr{

    protected $table;
    protected $field;
    protected $value;
    protected $op;

    public static function eq($value){
        $obj = new static();
        $obj->op = '=';
        $obj->value = $value;
        return $obj;
    }
    public function fetch(){
        return sprintf(
            '`%s`.`%s` %s "%s"',
            $this->table,
            $this->field,
            $this->op,
            $this->value
        );
    }
}

abstract class Expr implements IExpr{

    const _AND = ' and ';
    const _OR = ' or ';

    private $ex;
    protected $op;

    public function add( IExpr $s ){
        $this->ex[] = $s;
        return $this;
    }

    public function fetch(){
        $out = array();
        if( count($this->ex) ){
            foreach($this->ex as $spec){
                $out[] = $spec->fetch();
            }
            return '('.implode( $this->op, $out ).')';
        }
    }

    public static function create(){
        return new static();
    }
}
// пусть будут or и and для сокращения
class OrExpr extends Expr{
    protected $op = self::_OR;
}
class AndExpr extends Expr{
    protected $op = self::_AND;
}

// и даже наследование меня не смущает, просто чтоб сократить код
class UserRecord extends Record{
    protected $table = 'user';
}

class VisibleUserRecord extends UserRecord{
    protected $field = 'is_visible';
}
class ActiveUserRecord extends UserRecord{
    protected $field = 'is_active';
}
class NickUserRecord extends UserRecord{
    protected $field = 'nick';
}

// сорь тут тестил поразному поле содержит нечто другое чем ее имя
$visibleNotActiveOrAdminSpec =  AndExpr::create()
    ->add( NickUserRecord::eq('admin') )
    ->add(
        OrExpr::create()
            ->add( ActiveUserRecord::eq(1) )
            ->add( VisibleUserRecord::eq(0) )
    );

// как тут заставить сообщать только пользовательские характеристики?
// тип этого поля IExpr
echo $visibleNotActiveOrAdminSpec->fetch();
 

Вурдалак

Продвинутый новичок
Здесь нет никаких таблиц, полей, записей. Если ты отталкиваешься от базы, то тебе нужен какой-нибудь Eloquent.

abstract class UserSpecification это прикольно, но это повторение кода
В этом и смысл автогенерации кода. За неимением generics, нужно либо автогенерировать, либо таскать $className, как уже давали ссылку. Со сгенерированным кодом хотя бы проблем с автокомплитом не будет.
 
Сверху