Skip to content

Commit

Permalink
merge from yiidoc.
Browse files Browse the repository at this point in the history
  • Loading branch information
qiang.xue committed Sep 6, 2009
1 parent e40edb3 commit 7a84347
Show file tree
Hide file tree
Showing 48 changed files with 2,113 additions and 599 deletions.
6 changes: 3 additions & 3 deletions docs/blog/ja/prototype.auth.txt
Expand Up @@ -42,11 +42,11 @@ class UserIdentity extends CUserIdentity
}
~~~

`authenticate()` メソッドにおいて、 `User` クラスを用いて `User` テーブルの行を参照しています。`User` テーブルの `username` 列は特定のユーザ名(大文字小文字の区別なし)と同一です。`User` クラスは前のセクションで `yiic` ツールによって作られたものであることを思い出してください。`User` クラスは [CActiveRecord] を継承しているため、 [ActiveRecord 機能](http://www.yiiframework.com/doc/guide/database.ar)を、オブジェクト指向に(OOP)のっとったやり方で `User` テーブルにアクセスすることができます。
`authenticate()` メソッドにおいて、 `User` クラスを用いて `User` テーブルの行を参照しています。`User` テーブルの `username` 列は特定のユーザ名(大文字小文字の区別なし)と同一です。`User` クラスは前のセクションで `yiic` ツールによって作られたものであることを思い出してください。`User` クラスは [CActiveRecord] を継承しているため、 [ActiveRecord 機能](http://www.yiiframework.com/doc/guide/database.ar)を、オブジェクト指向(OOP)にのっとったやり方で `User` テーブルにアクセスすることができます。

`UserIdentity` クラスでは、`getId()` メソッドをオーバーライドして、`User` テーブルから見つかったユーザの `id` を返すようにしています。元の実装では、代わりにユーザ名を返すようになっていました。`username` と `id` プロパティはともにユーザセッションに保存され、コードのどこからでも `Yii::app()->user` でアクセスすることが可能です。

> Tip|ヒント: `UserIdentity` クラスにおいて、対応するクラスファイルを読み込むことなく [CUserIdentity] を参照しています。 これは [CUserIdentity] が Yii framework のコアクラスであるためです。Yii は任意のコアクラスが最初に参照されたときに、自動的のそのクラスファイルを読み込みます。`User` クラスでも同じことが行われています。 なぜなら、 `User` クラスファイルが、`/wwwroot/blog/protected/models` ディレクトリ以下にあり、アプリケーション初期構成の書きコードで PHP の `include_path` に追加されているからです。
> Tip|ヒント: `UserIdentity` クラスにおいて、対応するクラスファイルを読み込むことなく [CUserIdentity] を参照しています。 これは [CUserIdentity] が Yii framework のコアクラスであるためです。Yii は任意のコアクラスが最初に参照されたときに、自動的のそのクラスファイルを読み込みます。`User` クラスでも同じことが行われています。 なぜなら、 `User` クラスファイルが、`/wwwroot/blog/protected/models` ディレクトリ以下にあり、アプリケーション初期構成の下記コードで PHP の `include_path` に追加されているからです。
>
> ~~~
> [php]
Expand Down Expand Up @@ -81,4 +81,4 @@ switch($identity->errorCode)

修正後の `UserIdentity` クラスを確認するため、ブラウザで URL `http://www.example.com/blog/index.php` にアクセスし、 `User` テーブルのユーザ名とパスワードでログインしてみてください。 [ブログデモ](http://www.yiiframework.com/demos/blog/) で提供されるデータベースを利用した場合、ユーザー名 `demo` 、パスワード `demo` でアクセスできるはずです。このブログシステムにはユーザ管理機能はありません。そのため、ユーザーはウェブインターフェースで、自身のアカウントを変更したり、新しいアカウントを作成出来ません。ユーザ管理機能はブログアプリケーションの将来の機能拡張として検討されるでしょう。

<div class="revision">$Id: prototype.auth.txt 702 2009-02-18 19:29:48Z qiang.xue $</div>
<div class="revision">$Id: prototype.auth.txt 702 2009-02-18 19:29:48Z qiang.xue $</div>
4 changes: 2 additions & 2 deletions docs/blog/ja/prototype.summary.txt
Expand Up @@ -11,10 +11,10 @@
6. 記事とコメントの CRUD 基本操作ができるようコードを実装しました
7. 認証メソッドを変更し、 `User` テーブルに対してチェックするように変更しました

新しいプロジェクトでは、多くの場合、この最初の参るストーン 1 から 4 の手順をこなすことになるでしょう。
新しいプロジェクトでは、多くの場合、この最初のマイルストーン 1 から 4 の手順をこなすことになるでしょう。

`yiic` ツールによって生成されたコードは、データベーステーブルのための完全な CRUD 操作機能を実装しますが、実際に利用する際にはしばしば、変更する必要があります。この理由から、次の2つのマイルストーンでは、初期の要求を満たすように、投稿とコメントについて発生する CRUD コードをカスタマイズします。

一般的には、最初に[モデル](http://www.yiiframework.com/doc/guide/basics.model)クラスファイルで、適切な[バリデーション](http://www.yiiframework.com/doc/guide/form.model#declaring-validation-rules)ルールを加え、[リレーションオブジェクト](http://www.yiiframework.com/doc/guide/database.arr#declaring-relationship)を宣言する変更を行います。その後、それぞれの CRUD 操作のために[コントローラアクション](http://www.yiiframework.com/doc/guide/basics.controller)と[ビュー](http://www.yiiframework.com/doc/guide/basics.view)コードを変更します。

<div class="revision">$Id: prototype.summary.txt 683 2009-02-16 05:20:17Z qiang.xue $</div>
<div class="revision">$Id: prototype.summary.txt 683 2009-02-16 05:20:17Z qiang.xue $</div>
4 changes: 2 additions & 2 deletions docs/blog/pl/comment.admin.txt
Expand Up @@ -78,7 +78,7 @@ public function actionList()
$criteria=new CDbCriteria;
$criteria->condition='Comment.status='.Comment::STATUS_PENDING;

$pages=new CPagination(Comment::model()->count());
$pages=new CPagination(Comment::model()->count($criteria));
$pages->pageSize=self::PAGE_SIZE;
$pages->applyLimit($criteria);

Expand Down Expand Up @@ -110,4 +110,4 @@ Zaleca się aby żądania GET nie modyfikowały danych na serwerze. W przeciwnym
możemy mieć do czynienia z niebezpieczeństwem, że użytkownik nieumyślnie może zmienić
dane po stronie serwera parokrotnie jeśli będzie odświeżał stronę kilka razy.

<div class="revision">$Id: comment.admin.txt 1050 2009-05-22 20:06:18Z qiang.xue $</div>
<div class="revision">$Id: comment.admin.txt 1335 2009-08-15 20:34:36Z qiang.xue $</div>
146 changes: 146 additions & 0 deletions docs/blog/ru/comment.model.txt
@@ -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>
127 changes: 127 additions & 0 deletions docs/blog/ru/post.admin.txt
@@ -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>

0 comments on commit 7a84347

Please sign in to comment.