Управління записами
===================
Під управлінням записами мається на увазі відображення їх списку у адміністративному
розділі з можливістю переглядати записи з будь-яким статусом, редагувати та
видаляти їх. Ця функціональність реалізується у діях `admin` та `delete`
відповідно. Код, згенерований за допомогою `Gii`, майже не потребує
змін. Нижче ми пояснимо, як реалізовані ці дії.
Відображення записів у вигляді таблиці
--------------------------------------
Дія `admin` виводить записи із всіма статусами у вигляді таблиці,
розбитої на кілька сторінок, яка підтримує сортування по декільком колонкам.
Далі наведено метод `actionAdmin()` контролера `PostController`:
~~~
[php]
public function actionAdmin()
{
$model=new Post('search');
if(isset($_GET['Post']))
$model->attributes=$_GET['Post'];
$this->render('admin',array(
'model'=>$model,
));
}
~~~
Даний код повністю згенеровано `Gii`.
Спочатку створюється модель `Post` із сценарієм `search`
[scenario](/doc/guide/uk/form.model), який ми будемо використовувати для
збору критеріїв пошуку, вказаних користувачем.
Далі ми присвоюємо дані, введені користувачем, моделі.
І, нарешті, ми виводимо відображення `admin`, використовуючи модель.
Нижче приведений код відображення `admin`:
~~~
[php]
breadcrumbs=array(
'Manage Posts',
);
?>
Manage Posts
widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
array(
'name'=>'title',
'type'=>'raw',
'value'=>'CHtml::link(CHtml::encode($data->title), $data->url)'
),
array(
'name'=>'status',
'value'=>'Lookup::item("PostStatus",$data->status)',
'filter'=>Lookup::items('PostStatus'),
),
array(
'name'=>'create_time',
'type'=>'datetime',
'filter'=>false,
),
array(
'class'=>'CButtonColumn',
),
),
)); ?>
~~~
Для виведення записів ми використовуємо компонент [CGridView], який
розбиває дані на сторінки і дозволяє сортувати їх по стовпцях.
Наша зміна стосується, головним чином, відображення кожного стовпця.
Наприклад, для стовпця `title` ми вказуємо, що він повинен містити
посилання на перегляд запису. Вираз `$data->url` повертає значення
властивості `url`, яке ми визначаємо у класі `Post`.
> Tip|Підказка: При виведенні тексту ми використовуємо [CHtml::encode()] для
кодування сутностей HTML. Це дозволяє уникнути атак через [міжсайтовий
скриптинг](/doc/guide/uk/topics.security).
Видалення записів
-----------------
У таблиці данних `admin` у кожному рядку є кнопка «Видалити», яка
видаляє відповідний запис. Дія `delete` виглядає наступним чином:
~~~
[php]
public function actionDelete()
{
if(Yii::app()->request->isPostRequest)
{
// we only allow deletion via POST request
$this->loadModel()->delete();
if(!isset($_GET['ajax']))
$this->redirect(array('index'));
}
else
throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');
}
~~~
Наведений вище код повністю згенеровано `Gii`.
Зупинимося докладніше на перевірці `$_GET['ajax']`.
У віджеті [CGridView] сортування, розбивка на сторінки
та видалення за замовчуванням реалізовані з використанням AJAX.
Тобто при виконанні перерахованих дій сторінка перезавантажуватися не буде.
Віджет може працювати і без AJAX (якщо властивість `ajaxUpdate` виставлено у
`false` або відключений JavaScript). У дії `delete` при AJAX запиті перенаправлення
проводитися не повинно.
Видалення запису повинно викликати видалення всіх коментарів до неї.
До того ж, ми повинні оновити теги у таблиці `tbl_tag`.
Обидва завдання можуть бути виконані у методі `afterDelete` моделі `Post`:
~~~
[php]
protected function afterDelete()
{
parent::afterDelete();
Comment::model()->deleteAll('post_id='.$this->id);
Tag::model()->updateFrequency($this->tags, '');
}
~~~
Код, наведений вище не складний: спочатку видаляються всі коментарі, чий
`post_id` дорівнює ID запису, що видаляється. Далі оновлюється таблиця `tbl_tag`.
> Tip|Підказка: Ми видаляємо коментарі запису, що видаляється, у коді, так як SQLite
не підтримує обмеження по зовнішньому ключу. У СУБД, які дані обмеження
підтримують (наприклад, MySQL або PostgreSQL), можна використовувати каскадне
видалення коментарів у разі видалення запису. У цьому випадку немає необхідності
видаляти коментарі у коді.