Управление записями
===================

Под управлением записями подразумевается отображение их списка в административном
разделе с возможностью просматривать записи с любым статусом, редактировать и
удалять их. Этот функционал реализуется в действиях `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/ru/form.model), которую мы будем использовать для
сбора критериев поиска, указанных пользователем. Далее мы присваиваем
данные, введённые пользователем, модели. И, наконец, мы выводим отображение
`admin`, используя модель.

Ниже приведён код отображения `admin`:

~~~
[php]
<?php
$this->breadcrumbs=array(
	'Manage Posts',
);
?>
<h1>Manage Posts</h1>

<?php $this->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/ru/topics.security).


Удаление записей
----------------

В data grid `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), можно использовать каскадное
> удаление комментариев в случае удаления записи. В этом случае нет необходимости
> удалять комментарии в коде.