Модель Post
, сгенерированная при помощи yiic
, нуждается в следующих изменениях:
rules()
: задаёт правила валидации атрибутов модели;relations()
: задаёт отношения с связанными объектами;safeAttributes()
: определяет, какие атрибуты могут быть назначены
пакетно (в основном используется при передаче пользовательского ввода в модель);Информация: Модель состоит из набора атрибутов, каждый из которых ассоциируется с соответствующим полем в таблице БД. Атрибуты могут быть описаны явно как переменные класса, либо использоваться без какого-либо описания.
rules()
¶В первую очередь необходимо определить правила валидации, которые позволят
убедится в том, что данные, полученные от пользователя корректны до их вставки в БД.
К примеру, атрибут status
модели Post
должен быть целым числом, равным 0, 1 или 2.
Консоль yiic
генерирует правила валидации для каждой модели. При этом
используется структура БД, поэтому некоторые правила могу оказаться неточными.
Основываясь на анализе требований, изменим метод rules()
следующим образом:
public function rules()
{
return array(
array('title, content, status', 'required'),
array('title', 'length', 'max'=>128),
array('status', 'in', 'range'=>array(0, 1, 2)),
array('tags', 'match', 'pattern'=>'/^[\w\s,]+$/',
'message'=>'В тегах можно использовать только буквы.'),
);
}
В коде выше мы определили, что атрибуты title
, content
и status
являются
обязательными для заполнения. Длина title
не должна превышать 128 символов.
Значение status
может быть 0 (черновик), 1 (опубликовано) или 2 (в архиве).
В tags
могут содержаться только буквы, запятые и пробелы. Все остальные
атрибуты (id
, createTime
и т.д.) не будут валидироваться т.к. их значения
пользователь не задаёт.
После того, как мы сделали описанные изменения, мы можем зайти на страницу создания записи и проверить, что новые правила валидации работают.
Информация: Правила валидации используются при вызове методов модели validate() или save(). За более подробной информацией о правилах валидации обратитесь к полному руководству.
safeAttributes()
¶Перейдём к изменению метода safeAttributes()
. Нам необходимо указать, какие
атрибуты могут быть назначены пакетно. При передаче пользовательского ввода
модели мы часто используем пакетное назначение для того, чтобы упростить код:
$post->attributes=$_POST['Post'];
Без использования данной возможности нам бы пришлось написать:
$post->title=$_POST['Post']['title'];
$post->content=$_POST['Post']['content'];
// и т.д.
Несмотря на то, что пакетное назначение удобно, существует потенциальная опасность,
если злоумышленник передаст значение, которое не должно было сохраняться или
должно было изменяться исключительно разработчиком. К примеру, id
записи,
которую мы обновляем, не должен изменяться.
Для того, чтобы этого не допустить, мы должны разрешить пакетное назначение
только атрибутам title
, content
, status
и tags
. Для этого необходимо
реализовать метод safeAttributes()
следующим образом:
public function safeAttributes()
{
return array('title', 'content', 'status', 'tags');
}
Подсказка: Самый простой способ узнать, какие атрибуты должны быть перечислены в safeAttributes — ознакомиться с HTML-формой, которая используется для ввода данных. Те атрибуты, которые присутствуют в форме, могут считаться безопасными. Так как эти атрибуты заполняются пользователем, чаще всего для них определены правила валидации.
relations()
¶Далее укажем в методе relations()
связанные с записью объекты. После этого мы
сможем использовать реляционную ActiveRecord (RAR)
для получения связанных с записью данных, таких как информацию об авторе и
комментарии. Сложные SQL запросы с JOIN в этом случае не потребуются.
Определим метод relations()
:
public function relations()
{
return array(
'author'=>array(self::BELONGS_TO, 'User', 'authorId'),
'comments'=>array(self::HAS_MANY, 'Comment', 'postId',
'order'=>'??.createTime'),
'tagFilter'=>array(self::MANY_MANY, 'Tag', 'PostTag(postId, tagId)',
'together'=>true,
'joinType'=>'INNER JOIN',
'condition'=>'??.name=:tag'),
);
}
Выше описано следующее:
User
), связь с которым устанавливается на основе
поля записи authorId
;Comment
), связь с которыми
устанавливается на основе поля комменария postId
. Комментарии сортируются по
времени их создания.Отношение tagFilter
немного сложнее. Оно используется для явного пересечения
таблицы Post
с таблицей Tag
и выбора только строк с определённым тегом. Мы
покажем, как использовать это отношение, когда будем реализовывать отображение
записей.
Задав описанные выше отношения, мы можем получить информацию об авторе и комментариях к записи следующим образом:
$author=$post->author;
echo $author->username;
$comments=$post->comments;
foreach($comments as $comment)
echo $comment->content;
Более подробно использование и определение отношений описано в полном руководстве.
Так как статус записи хранится в БД в виде числа, нам необходимо получить его
текстовое представление для отображения пользователям. Для этого дополним
модель Post
:
class Post extends CActiveRecord
{
const STATUS_DRAFT=0;
const STATUS_PUBLISHED=1;
const STATUS_ARCHIVED=2;
......
public function getStatusOptions()
{
return array(
self::STATUS_DRAFT=>'Черновик',
self::STATUS_PUBLISHED=>'Опубликовано',
self::STATUS_ARCHIVED=>'В архиве',
);
}
public function getStatusText()
{
$options=$this->statusOptions;
return isset($options[$this->status]) ? $options[$this->status]
: "unknown ({$this->status})";
}
}
В приведённом коде мы определили константы класса для представления возможных
значений статуса. Эти константы используются для улучшения читаемости кода.
Был определён метод getStatusOptions()
, возвращающий соответствия
числовых значений статуса и его текстовых представлений. Также мы реализовали
метод getStatusText()
, который возвращает текстовое представление статуса
текущей записи.
Signup or Login in order to comment.