После того, как мы закончили с моделью Post
, займёмся контроллером
PostController
и его отображениями. В данном разделе мы настроим правила
доступа операций CRUD. Затем изменим код, отвечающий за создание
(create
) и
обновление
(update
). В завершение мы реализуем предварительный просмотр для
обеих операций.
Первое, что мы запланировали — настройка
прав доступа. Код,
сгенерированный при помощи yiic
нам не подойдёт.
Необходимо изменить метод accessRules()
в файле
/wwwroot/blog/protected/controllers/PostController.php
следующим образом:
public function accessRules()
{
return array(
array('allow', // все пользователи могут использовать действия 'list' и 'show'
'actions'=>array('list', 'show'),
'users'=>array('*'),
),
array('allow', // аутентифицированные пользователи могут всё
'users'=>array('@'),
),
array('deny', // все остальные не могут ничего
'users'=>array('*'),
),
);
}
Описанные выше правила разрешают всем пользователям выполнять действия
list
и show
. Аутентифицированным — любые действия, включая admin
.
Всем остальным пользователям запрещено всё. Стоит отметить, что правила
применяются в порядке их описания. Первое сработавшее правило определяет,
давать доступ или не давать. К примеру, если текущий пользователь является
владельцем системы и пытается зайти на страницу создания записи, будет применено
второе правило и доступ будет разрешён.
create
и update
¶Операции create
и update
довольно похожи. В обоих случаях требуется
вывести HTML форму для сбора данных, вводимых пользователем. Также требуется
валидация и сохранение данных в БД. Главное отличие в том, что при update
форма будет заполняться данными о редактируемой записи. По этой причине yiic
генерирует вложенное отображение /wwwroot/blog/protected/views/post/_form.php
,
которое включается как в отображение create
, так и отображение update
для
вывода HTML формы.
Для начала изменим файл _form.php
таким образом, чтобы форма собирала только
нужные нам данные: title
, content
и status
. Для первых двух атрибутов мы
используем текстовые поля. Для status
— выпадающий список с всеми возможными
состояниями записи:
echo CHtml::activeDropDownList($post,'status',Post::model()->statusOptions);
Подсказка: Для получения состояний можно вместо
Post::model()->statusOptions
использоватьPost::model()->getStatusOptions()
. Это возможно так какPost
является компонентом, что даёт нам возможность использовать свойства, определённые как методы (геттеры).
Далее изменим класс Post
таким образом, чтобы он автоматически выставлял
некоторые атрибуты (такие, как createTime
и authorId
) непосредственно перед
сохранением записи в БД. Перекроем метод beforeValidate()
:
protected function beforeValidate($on)
{
$parser=new CMarkdownParser;
$this->contentDisplay=$parser->safeTransform($this->content);
if($this->isNewRecord)
{
$this->createTime=$this->updateTime=time();
$this->authorId=Yii::app()->user->id;
}
else
$this->updateTime=time();
return true;
}
В данном методе мы используем CMarkdownParser для того, чтобы конвертировать
текст в формате Markdown в HTML
и сохранить результат в contentDisplay
. Сделано это для того, чтобы
не конвертировать текст каждый раз при отображении записи. Если запись новая,
мы выставляем время создания(createTime
) и автора(authorId
). Иначе мы
выставляем время обновления(updateTime
) как текущее время. Стоит отметить, что
данный метод вызывается автоматически при вызове методов модели validate()
или save()
.
Так как мы хотим сохранить теги записи в таблицу Tag
, нам понадобится добавить
в класс Post
метод, который будет вызываться автоматически после сохранения
записи:
protected function afterSave()
{
if(!$this->isNewRecord)
$this->dbConnection->createCommand(
'DELETE FROM PostTag WHERE postId='.$this->id)->execute();
foreach($this->getTagArray() as $name)
{
if(($tag=Tag::model()->findByAttributes(array('name'=>$name)))===null)
{
$tag=new Tag(array('name'=>$name));
$tag->save();
}
$this->dbConnection->createCommand(
"INSERT INTO PostTag (postId, tagId) VALUES ({$this->id},{$tag->id})")->execute();
}
}
public function getTagArray()
{
// break tag string into a set of tags
return array_unique(
preg_split('/\s*,\s*/',trim($this->tags),-1,PREG_SPLIT_NO_EMPTY)
);
}
Сначала удаляем все записи, связанные с данной из таблицы PostTag
. Затем
вставляем новые теги в таблицу Tag
и добавляем соответствующую запись в PostTag
.
Логика в данном случае немного сложная, поэтому вместо использования
ActiveRecord, мы пишем выражения SQL и выполняем
их напрямую через соединение с БД.
Подсказка: Хорошим тоном является отделение бизнес-логики, такой как
beforeValidate()
иafterSave()
, описанные выше и размещение её в моделях, а не в контроллерах.
Кроме изменений, описанных выше, нам необходимо добавить возможность предварительного просмотра, которая позволит нам оценить запись до её сохранения в БД.
Для того, чтобы добавить кнопку «предварительный просмотр» и само отображение
записи, изменим представление _form.php
. Просмотр отображается только при
нажатии кнопки и если не произошло ошибок валидации.
echo CHtml::submitButton('Предварительный просмотр',array('name'=>'previewPost')); ...... if(isset($_POST['previewPost']) && !$post->hasErrors()): ...отображаем предварительный просмотр модели $post... endif;
Добавим в методы actionCreate()
и actionUpdate()
контроллера PostController
обработку
запроса на предварительный просмотр. Ниже приведён код actionCreate()
, который
очень похож на то, что необходимо сделать и в actionUpdate()
:
public function actionCreate()
{
$post=new Post;
if(isset($_POST['Post']))
{
$post->attributes=$_POST['Post'];
if(isset($_POST['previewPost']))
$post->validate();
else if(isset($_POST['submitPost']) && $post->save())
$this->redirect(array('show','id'=>$post->id));
}
$this->render('create',array('post'=>$post));
}
При нажатии на кнопку «предварительный просмотр» мы вызываем $post->validate()
для выполнения валидации введённых данных. Если же нажали на кнопку
«сохранить»(submit) — пробуем сохранить запись при помощи $post->save()
,
который также выполняет валидацию данных. Если сохранение прошло успешно,
(не возникли ошибки валидации и данные сохранились в БД без ошибки) —
перенаправляем пользователя на страницу только что созданной записи.
Signup or Login in order to comment.