Модель Post
, згенерована за допомогою Gii
, потребує наступних змін:
rules()
: задає правила валідації атрибутів моделі;relations()
: задає звʼязки з іншими обʼєктами.Інформація: Модель складається із набору атрибутів, кожен з яких асоціюється з відповідним полем у таблиці БД. Атрибути можуть бути описані явно як змінні класу, або використовуватися без будь-якого опису.
rules()
¶У першу чергу необхідно визначити правила валідації, які дозволять переконатися в тому,
що дані, введені користувачем, коректні до їх збереження в БД.
Наприклад, атрибут status
моделі Post
повинен бути цілим числом, рівним 1, 2 або 3.
Консоль Gii
генерує правила валідації для кожної моделі.
При цьому використовується структура БД,
тому деякі правила можуть виявитися неточними.
Грунтуючись на аналізі вимог, змінимо метод rules ()
наступним чином:
public function rules()
{
return array(
array('title, content, status', 'required'),
array('title', 'length', 'max'=>128),
array('status', 'in', 'range'=>array(1,2,3)),
array('tags', 'match', 'pattern'=>'/^[\w\s,]+$/',
'message'=>'У тегах можна використовувати лише літери.'),
array('tags', 'normalizeTags'),
array('title, status', 'safe', 'on'=>'search'),
);
}
У коді вище ми визначили, що атрибути title
, content
і status
є обовʼязковими для заповнення. Довжина title
не повинна перевищувати 128 символів.
Значення status
може бути 1 (чернетка), 2 (опубліковано) або 3 (в архіві).
В tags
можуть міститися тільки букви, коми та пробіли.
Теги, що вводяться користувачем, додатково нормалізуються за допомогою normalizeTags
.
Це робиться для того, щоб теги були унікальними і правильно розділялися комами.
Останнє правило використовується пошуком і буде описано пізніше.
Валідатори, такі як required
, length
, in
та match
є стандартними валідаторами Yii.
Валідатор normalizeTags
використовує визначений метод у класі Post
.
За додатковою інформацією про те, як описувати правила валідації ви можете звернутися до повного керівництва.
public function normalizeTags($attribute,$params)
{
$this->tags=Tag::array2string(array_unique(Tag::string2array($this->tags)));
}
де array2string
та string2array
- нові методи,
які ми повинні визначити у класі моделі Tag
:
public static function string2array($tags)
{
return preg_split('/\s*,\s*/',trim($tags),-1,PREG_SPLIT_NO_EMPTY);
}
public static function array2string($tags)
{
return implode(', ',$tags);
}
Правила, описані у методі rules()
, викликаються по черзі при виклиці методів моделі
validate() або save().
Примітка: Важливо памʼятати, що атрибути, описувані у
rules()
повинні вводитися користувачем. Інші атрибути моделіPost
, такі якid
абоcreate_time
, що заповнюються у коді або безпосередньо у БД, не повинні бути присутніми вrules()
. Детальніше це описано у розділі Безпечне присвоювання значень атрибутів.
Після того, як ми зробили описані зміни, ми можемо зайти на сторінку створення запису і перевірити, що нові правила валідації працюють.
relations()
¶Далі вкажемо у методі relations()
звʼязані із записом обʼєкти. Після цього ми
зможемо використовувати реляційну ActiveRecord (RAR)
для отримання звʼязаних із записом даних, таких як інформацію про автора та коментарі. Складні SQL запити з JOIN в цьому випадку не потрібні.
Визначимо метод relations()
:
public function relations()
{
return array(
'author' => array(self::BELONGS_TO, 'User', 'author_id'),
'comments' => array(self::HAS_MANY, 'Comment', 'post_id',
'condition'=>'comments.status='.Comment::STATUS_APPROVED,
'order'=>'comments.create_time DESC'),
'commentCount' => array(self::STAT, 'Comment', 'post_id',
'condition'=>'status='.Comment::STATUS_APPROVED),
);
}
Також, у класі моделі Comment
ми описуємо дві константи, які використовуються у наведеному вище методі:
class Comment extends CActiveRecord
{
const STATUS_PENDING=1;
const STATUS_APPROVED=2;
......
}
Звʼязки, описані у методі relations ()
, означають наступне:
User
), звʼязок із яким встановлюється на основі поля
запису author_id
;Comment
), звʼязок із якими встановлюється на основі поля коментаря post_id
. Коментарі сортуються за часом їх створення;commentCount
є особливим, оскільки повертає результат агрегації, тобто число коментарів запису.Задавши описані вище звʼязки, ми можемо отримати інформацію про автора та коментарі до запису наступним чином:
$author=$post->author;
echo $author->username;
$comments=$post->comments;
foreach($comments as $comment)
echo $comment->content;
Більш докладно використання та визначення звʼязків описано у повному керівництві.
url
¶Кожному запису відповідає унікальний URL.
Замість повсюдного виклику CWebApplication::createUrl для формування цього URL,
ми можемо додати властивість url
моделі Post
і повторно використовувати
код для генерації URL. Пізніше ми опишемо, як отримати гарні URL.
Використання властивості моделі дозволить реалізувати це максимально зручно.
Для того, щоб додати властивість url
, ми додаємо геттер у клас Post
:
class Post extends CActiveRecord
{
public function getUrl()
{
return Yii::app()->createUrl('post/view', array(
'id'=>$this->id,
'title'=>$this->title,
));
}
}
На додаток до ID запису, в URL через GET-параметр ми виводимо заголовок. Робиться це головним чином для оптимізації під пошукові алгоритми (SEO). Детальніше це буде описано в розділі «людинозрозумілі URL».
Так як CComponent є предком класу Post
, геттер getUrl()
дозволяє нам
писати код на зразок $post->url
. При зверненні до $post->url
буде викликаний
геттер і ми отримаємо результат його виконання.
Більш докладно це описано у повному керівництві.
Так як статус запису зберігається у БД у вигляді числа, нам необхідно отримати його текстове представлення для відображення користувачам. Для великих систем така вимога є досить типовою.
Для зберігання звʼязків між цілими числами і їх текстовим поданням, необхідним
іншим обʼєктам даних, ми використовуємо таблицю tbl_lookup
. Для більш зручного
отримання текстових даних змінимо модель Lookup
наступним чином:
class Lookup extends CActiveRecord
{
…
private static $_items=array();
public static function items($type)
{
if(!isset(self::$_items[$type]))
self::loadItems($type);
return self::$_items[$type];
}
public static function item($type,$code)
{
if(!isset(self::$_items[$type]))
self::loadItems($type);
return isset(self::$_items[$type][$code]) ? self::$_items[$type][$code] : false;
}
private static function loadItems($type)
{
self::$_items[$type]=array();
$models=self::model()->findAll(array(
'condition'=>'type=:type',
'params'=>array(':type'=>$type),
'order'=>'position',
));
foreach($models as $model)
self::$_items[$type][$model->code]=$model->name;
}
}
Ми додали два статичних методи: Lookup::items()
та Lookup::item()
.
Перший повертає список рядків для заданого типу даних, другий - конкретний
рядок для заданого типу даних і значення.
У базі даних блогу є два типи даних: PostStatus
та CommentStatus
.
Перший містить можливі статуси запису, другий - статуси коментаря.
Для того, щоб зробити код більш читабельним ми описуємо константи, відповідні цілочисловим значенням статусу. Ці константи необхідно використовувати у коді замість відповідних їм цілих значень.
class Post extends CActiveRecord
{
const STATUS_DRAFT=1;
const STATUS_PUBLISHED=2;
const STATUS_ARCHIVED=3;
......
}
Отже, для отримання списку всіх можливих статусів запису (масиву рядків
із ключами, рівними відповідним їм значенням), ми можемо скористатися кодом
Lookup::items('PostStatus')
. А для отримання конкретного рядка - кодом
Lookup::item('PostStatus', Post::STATUS_PUBLISHED)
.
Found a typo or you think this page needs improvement?
Edit it on github !
Signup or Login in order to comment.