Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
qiang.xue
committed
Sep 6, 2009
1 parent
e40edb3
commit 7a84347
Showing
48 changed files
with
2,113 additions
and
599 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
Доработка модели Comment | ||
======================== | ||
|
||
Также, как и в модели `Post`, в модели `Comment` нам необходимо поправить методы | ||
`rules()`, `relations()` и `safeAttributes()`. Кроме того, нужно задать свои | ||
подписи некоторым полям в методе `attributeLabels()`. | ||
|
||
|
||
Изменение метода `rules()` | ||
-------------------------- | ||
|
||
Начнём с уточнения правил валидации, сгенерированных при помощи `yiic`. | ||
Для комментариев будем использовать следующие правила: | ||
|
||
~~~ | ||
[php] | ||
public function rules() | ||
{ | ||
return array( | ||
array('author,email,content', 'required'), | ||
array('author,email,url','length','max'=>128), | ||
array('email','email'), | ||
array('url','url'), | ||
array('verifyCode', 'captcha', 'on'=>'insert', | ||
'allowEmpty'=>!Yii::app()->user->isGuest), | ||
); | ||
} | ||
~~~ | ||
|
||
Здесь мы указываем, что атрибуты `author`, `email` и `content` обязательны. | ||
Длина `author`, `email` и `url` не может превышать 128 символов. Атрибут `email` | ||
должен содержать корректный email-адрес. `url` должен содержать корректный URL. | ||
Атрибут `verifyCode` должен проверяться как код [CAPTCHA](http://ru.wikipedia.org/wiki/Captcha). | ||
|
||
Здесь `verifyCode` используется для хранения кода подтверждения, введённого | ||
пользователем для того, чтобы оставить комментарий. Так как в таблице `Comment` | ||
поля `verifyCode` нет, нам надо явно описать его как public свойство класса. | ||
Для его валидации используется специальный валидатор `captcha`, которому | ||
соответствует класс [CCaptchaValidator]. Более того, валидация будет проводиться | ||
только при добавлении нового комментария(см. параметр `on`). Для аутентифицированных | ||
пользователей валидация не требуется(см. параметра `allowEmpty`). | ||
|
||
|
||
Изменение метода `safeAttributes()` | ||
----------------------------------- | ||
|
||
Далее изменим метод `safeAttributes()`. Укажем атрибуты, которые могут быть | ||
назначены пакетно. | ||
|
||
~~~ | ||
[php] | ||
public function safeAttributes() | ||
{ | ||
return array('author', 'email', 'url', 'content', 'verifyCode'); | ||
} | ||
~~~ | ||
|
||
Приведённый выше код также показывает, что форма комментирования будет состоять | ||
из нескольких полей: автор, почта, URL, текст и код подтверждения. | ||
|
||
|
||
Изменение метода `relations()` | ||
------------------------------ | ||
|
||
При разработке портлета «последние комментарии» нам необходимо получить список | ||
последних комментариев с информации о записях, связанных с ними. Поэтому мы | ||
добавляем информацию об отношении в метод `relations()`: | ||
|
||
~~~ | ||
[php] | ||
public function relations() | ||
{ | ||
return array( | ||
'post'=>array(self::BELONGS_TO, 'Post', 'postId', | ||
'joinType'=>'INNER JOIN'), | ||
); | ||
} | ||
~~~ | ||
|
||
Стоит отметить, что тип join для отношения `post` — `INNER JOIN`. Сделано это | ||
так как комментарий должен относиться к записи. | ||
|
||
|
||
Изменение метода `attributeLabels()` | ||
------------------------------------ | ||
|
||
Изменим метод `attributeLabels()`. Зададим свои подписи атрибутам. Метод возвращает | ||
массив пар имя атрибута-подпись. При вызове [CHtml::activeLabel()], сначала | ||
будет проверено, существует ли своя подпись. Если подпись не задана — будет | ||
сгенерирована подпись по умолчанию. | ||
|
||
~~~ | ||
[php] | ||
public function attributeLabels() | ||
{ | ||
return array( | ||
'author'=>'Имя', | ||
'url'=>'Сайт', | ||
'content'=>'Комментарий', | ||
'verifyCode'=>'Код подтверждения', | ||
); | ||
} | ||
~~~ | ||
|
||
> Tip|Подсказка: Подпись по умолчанию генерируется на основе имени атрибута. | ||
Сначала имя разбивается на слова учитывая camelCase. Затем каждый символ каждого | ||
слова переводится в верхний регистр. К примеру, атрибуту с именем `verifyCode` | ||
будет присвоена подпись `Verify Code`. | ||
|
||
|
||
Изменение процесса сохранения | ||
----------------------------- | ||
|
||
Так как мы хотим обновлять количество комментариев для каждой записи при удалении | ||
или публикации нового комментария, нам необходимо изменять соответствующее поле | ||
записи. Для этого переопределим методы `afterSave()` и `afterDelete()` модели | ||
`Comment`. Также переопределим метод `beforeValidate()`. Это позволит нам | ||
конвертировать текст из формата Markdown в HTML и выставлять время создания | ||
комментария. | ||
|
||
~~~ | ||
[php] | ||
protected function beforeValidate($on) | ||
{ | ||
$parser=new CMarkdownParser; | ||
$this->contentDisplay=$parser->safeTransform($this->content); | ||
if($this->isNewRecord) | ||
$this->createTime=time(); | ||
return true; | ||
} | ||
|
||
protected function afterSave() | ||
{ | ||
if($this->isNewRecord && $this->status==Comment::STATUS_APPROVED) | ||
Post::model()->updateCounters(array('commentCount'=>1), "id={$this->postId}"); | ||
} | ||
|
||
protected function afterDelete() | ||
{ | ||
if($this->status==Comment::STATUS_APPROVED) | ||
Post::model()->updateCounters(array('commentCount'=>-1), "id={$this->postId}"); | ||
} | ||
~~~ | ||
|
||
|
||
<div class="revision">$Id: comment.model.txt 814 2009-03-10 18:00:11Z qiang.xue $</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
Управление записями | ||
=================== | ||
|
||
Под управлением записями подразумевается отображение их списка в административном | ||
разделе и их удаление. Этот функционал реализуется в действиях `admin` и `delete` | ||
соответственно. Код, сгенерированный при помощи `yiic` почти не нуждается в | ||
изменениях. Ниже мы объясним, как реализованы эти действия. | ||
|
||
|
||
Отображение записей в виде таблицы | ||
---------------------------------- | ||
|
||
Действие `admin` выводит все записи (включая неопубликованные) в виде таблицы, | ||
разбитой на несколько страниц и поддерживающей сортировку по нескольким колонкам. | ||
Далее приведён метод `actionAdmin()` контроллера `PostController`: | ||
|
||
~~~ | ||
[php] | ||
public function actionAdmin() | ||
{ | ||
$criteria=new CDbCriteria; | ||
|
||
$pages=new CPagination(Post::model()->count()); | ||
$pages->applyLimit($criteria); | ||
|
||
$sort=new CSort('Post'); | ||
$sort->defaultOrder='status ASC, createTime DESC'; | ||
$sort->applyOrder($criteria); | ||
|
||
$posts=Post::model()->findAll($criteria); | ||
|
||
$this->render('admin',array( | ||
'posts'=>$posts, | ||
'pages'=>$pages, | ||
'sort'=>$sort, | ||
)); | ||
} | ||
~~~ | ||
|
||
Данный код очень похож на используемый в `actionList()`. Главное отличие в том, | ||
что мы используем объект [CSort] для представления информации о сортировке | ||
(т.е. какие колонки и в каком порядке сортировать). [CSort] используется | ||
отображением `admin` для создания ссылок в заголовке таблицы. Щелчок по такой | ||
ссылке вызывает перезагрузку страницы с сортировкой данных по данной колонке. | ||
|
||
Ниже приведён код отображения `admin`: | ||
|
||
~~~ | ||
[php] | ||
<h2>Manage Posts</h2> | ||
|
||
<table class="dataGrid"> | ||
<tr> | ||
<th><?php echo $sort->link('status'); ?></th> | ||
<th><?php echo $sort->link('title'); ?></th> | ||
<th><?php echo $sort->link('createTime'); ?></th> | ||
<th><?php echo $sort->link('updateTime'); ?></th> | ||
</tr> | ||
<?php foreach($posts as $n=>$post): ?> | ||
<tr class="<?php echo $n%2?'even':'odd';?>"> | ||
<td><?php echo CHtml::encode($post->statusText); ?></td> | ||
<td><?php echo CHtml::link(CHtml::encode($post->title), | ||
array('show','id'=>$post->id)); ?></td> | ||
<td><?php echo date('F j, Y',$post->createTime); ?></td> | ||
<td><?php echo date('F j, Y',$post->updateTime); ?></td> | ||
</tr> | ||
<?php endforeach; ?> | ||
</table> | ||
|
||
<br/> | ||
<?php $this->widget('CLinkPager',array('pages'=>$pages)); ?> | ||
~~~ | ||
|
||
Понять код довольно просто. Мы делаем цикл по всем записям и каждую отображаем | ||
в строке таблицы. В заголовке мы используем [CSort] для создания ссылок для | ||
сортировки. В самом конце мы подключаем виджет [CLinkPager], который отображает | ||
при необходимости постраничную разбивку. | ||
|
||
> Tip|Подсказка: При выводе текста мы используем [CHtml::encode()] для | ||
кодирования сущностей HTML. Это позволяет избежать атак через [межсайтовый | ||
скриптинг](/doc/guide/ru/topics.security). | ||
|
||
|
||
Удаление записей | ||
---------------- | ||
|
||
При выводе записи с использованием действия `show` мы показываем ссылку | ||
`удалить`(`delete`) если текущий пользователь является владельцем системы. | ||
При нажатии на ссылку запись будет удалена. Так как удаление записи вызывает | ||
изменение данных, логично использовать для этого метод POST, поэтому для генерации | ||
кнопки `удалить` мы воспользуемся следующим кодом: | ||
|
||
~~~ | ||
[php] | ||
<?php echo CHtml::linkButton('Delete',array( | ||
'submit'=>array('post/delete','id'=>$post->id), | ||
'confirm'=>"Вы уверены, что хотите удалить запись?", | ||
)); ?> | ||
~~~ | ||
|
||
Метод [CHtml::linkButton()] генерирует ссылку, нажатие на которую вызывает отправку | ||
методом POST формы, в которой она располагается. Здесь мы указываем, что форма | ||
должна быть отправлена по URL, сгенерированному в соответствии с | ||
`array('post/delete','id'=>$post->id)`. В нашем приложении это будет | ||
`/blog/index.php?r=post/delete&id=1`. То есть действие `delete` контроллера | ||
`PostController`. Также мы указываем, что при нажатии должен быть показан диалог | ||
подтверждения. Это даёт пользователю шанс отказаться от удаления записи. | ||
|
||
Код действия `delete` говорит сам за себя, поэтому приведём его как есть: | ||
|
||
~~~ | ||
[php] | ||
public function actionDelete() | ||
{ | ||
if(Yii::app()->request->isPostRequest) | ||
{ | ||
// we only allow deletion via POST request | ||
$this->loadPost()->delete(); | ||
$this->redirect(array('list')); | ||
} | ||
else | ||
throw new CHttpException(400,'Плохой запрос какой-то…'); | ||
} | ||
~~~ | ||
|
||
|
||
<div class="revision">$Id: post.admin.txt 1050 2009-05-22 20:06:18Z qiang.xue $</div> |
Oops, something went wrong.