Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Yii обмен навыком: модели (окончание)

Anna | 29.05.2014 | нет комментариев
Область ответственности модели и ее место в плане

Модели предуготовлены только для оперирования данными (поиск, сохранение, удаление), а также связанными статическими файлами, так как они тоже неотделимая часть конструкции данных (фотография, видеоролик). Безусловно что при удалении записи, связанные с ней медиафайлы обязаны удаляться, для этого комфортно применять beforeDelete() либо afterDelete().
Несложную бизнес-логику дозволено реализовать в модели, для трудной — отменнее применять сервисную прослойку (Service Layer) так вы избавите модель от массы зависимостей и не будете раздувать из нее священный объект.
В моделях не обязаны возникать:

  • HTML-верстка, CSS, javascript
  • Суперглобальные массивы ($_GET, …)
  • Всеобщии переменные
  • Проверка прав доступа (данный момент, допустимо, спорный, практика показывает что контроль доступа к операции необходимо проводить в контроллере)
  • Текстовые строки не обернутые в Yii::t()

Модели обязаны иметь как дозволено поменьше зависимостей от других компонентов, так мы сумеем сделать ее переносимой, и применять в других планах. При этом компоненты от которых модель зависит обязаны устанавливаться сеттерами (скажем User::setEmailComponent(‘email’)). Назначать компоненты дозволено и в User::init() но при этом непременно сделать проверку на его присутствие. Если компонент — побочный и недостижим — модель обязана трудиться без шума, впрочем если компонент первоочередной, то на стадии инициализации следует выкинуть прерывание.
Эти несложные правила дозволят поддерживать ваш код командой программистов, и довольно эластично расширять функционал.

Проверка состояния ранга

Традиционно проверку делают в различных местах, как в контроллерах так и в представлениях и проверка Зачастую выглядит так:

// примитивный вариант
if($model->status == 1){ ... }

// больше продвинутый вариант
if($model->getStatus() === Model::STATUS_ACTIVE){ ... }

// ужасный вариант
if($model->status !== 1 && $model->status !== 2 && $model->status !== 4){ ... }  //да-да-да бывает и такое

Впрочем если сделать способ isActive() тот, что делает эту проверку, то код станет больше контролируемым, исключительно в условиях Зачастую меняющегося ТЗ. Также изредка пригодным окажется создание способа, в котором описана проверка на вероятность перехода в иное состояние ранг. Скажем: если запись имеет ранг — «Спам», то перевести ее в ранг «Энергична» невозможно, впрочем ее дозволено перевести в ранг «На проверку». Всю эту логику желанно размещать также в моделях. (Это может быть пригодно при построении workflow систем)

Применение флаговых полей

Для экономии размера таблицы (числа колонок) и для того Дабы иметь больше эластичный функционал растяжения модели применяют поля с битовыми флагами.
Такие поля как правило представлены в базе типом integer (но необязательно) и способны поместить достаточно огромное число флагов. Флаговые поля я теснее затронул в предыдущей статье. Сейчас покажу фактическое использование. (Подробно битовые маски описаны в этой статье).
Пример: Есть модель пользователя в которой для пользователя дозволено назначить несколько одновременных флагов — «наилучший автор», «подтвержден телефон», «подтвержден email», «оставил запрос на пост модератора»

Фрагмент модели

    public $flags = 0;

    const FLAG_CONFIRM_EMAIL    = 1; // 00000001
    const FLAG_CONFIRM_PHONE    = 2; // 00000010
    const FLAG_BEST_AUTHOR      = 4; // 00000100
    const FLAG_BECOME_MODERATOR = 8; // 00001000

    /**
     * Устанавливает флаг
     * @param integer $flag
     * @return \User
     */
    public function setFlag($flag)
    {
         $this->flag  = intval($flag);
         return $this;
    }

    /**
     * Снимает флаг
     * @param integer $flag
     * @return \User
     */
    public function unsetFlag($flag)
    {
         $this->flag -= intval($flag);
         return $this;
    }

    /**
     * Проверяет присутствие флага
     * @param integer $flag
     * @return boolean
     */
    public function hasFlag($flag)
    {     
         return ($this->flags & intval($flag));
    }

    /**
     * Возвращает человеческие наименования флагов
     * @return array
     */
    public function getFlagsLabels(){
        return array(
            self::FLAG_CONFIRM_EMAIL    => Yii::t('User',"Email подтвержден"),
            self::FLAG_CONFIRM_PHONE    => Yii::t('User',"Телефон подтвержден"),
            self::FLAG_BEST_AUTHOR      => Yii::t('User',"Наилучший автор"),
            self::FLAG_BECOME_MODERATOR => Yii::t('User',"Заявка на пост модератора"),
        );
    }

    /**
     * Применяется для выборки по флагам
     * @param integer $flag
     * @return \User
     */
    public function withFlags($flag=0)
    {
        $this->getDbCriteria()->mergeWith(array(
            'order'=>'flags & :flag',
            'params' => array(':flag' => $flag),
        ));
        return $this;
    }
    

В запросе MySQL проверка примет вид:

    SELECT * FROM `User` WHERE STATUS & 6

В примере сделана именованная группа условий это дозволит изготавливать поиск как показано ниже:

    User::model()->withFlags(User::FLAG_CONFIRM_EMAIL)->findAll();
Реляционные связи

Реляционные связи отлично описаны в официальной документации.
На практике появляются такие нюансы.

  • Если реляционная связь построена верно с применением FK то все должно трудиться Отчетливо, так как целостность данных обеспечена БД.
  • Если реляционная связь построена только средствами YII ( и нет вероятности применять FK), в этом случае не следует применять прямой доступ к переменной обозначающей связь, взамен этого следует применять CActiveRecord::getRelated().
  • Проверку правильности связей (положительные ID) нужно контролировать при валидации и в beforeSave() обработчике.
  • Удаление связанных данных нужно реализовать в beforeDelete() обработчике.
Представления для признаков

В коде моделей изредка встречается HTML-код — ему там не место. Если есть надобность вывести HTML-форматированный вид признака для этого следует применять либо виджет либо сделать хелпер для модели (класс со статическими способами). примеры показаны ниже.

Пример хелпера

class UserHelper{

     /**
      * Возвращает гиперссылку на профиль пользователя
      * @return string
      */
     public static function getProfileLink(User $model, $htmlOptions = array())
     {
          return CHtml::link($model->getUserName(),$model->getProfileUrl(),$htmlOptions);
     }

}

Пример виджета

class UserAvatar extends CWidget
{
public $emptyPhotoUrl = “/static/images/no-photo.png”;
public $model;
public $htmlOptions;

public function run(){
$avatar = $this->emptyPhotoUrl;
if($model->hasAvatar())
{
$avatar = $model->getAvatarUrl();
}
echo CHtml::image($avatar,$model->getUserName(),$this->htmlOptions);
}
}

Виджет и хелпер комфортно применять в представлениях, хелпер комфортен при применении внутри виджета CGridView.

Журналирование моделей

Для отладки моделей, исключительно для отлова трудновоспроизводимой ошибки изредка благотворно иметь вероятность узнать хронологию событий.
Для этого в модель дозволено добавить способы журналирования, и на все операции изготавливаемые с данными вести журнал (лог-файл). Реализация этой несложной механики может быть всякий, впрочем благотворно припомнить про компонент CLogRoute и настроить один из маршрутов для своей модели, лог дозволено вести как в базу (осмотрительно, снижает продуктивность) так и в примитивные файлы. Также в лог пригодно писать данные пользователя от имени которого совершается операция, это упростит разбор полетов.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB