記事の作成と修正
================

`Post` モデルの準備ができたら、`PostController` のためのアクションとビューを手直しします。このセクションでは、最初に CRUD 操作のアクセス制御をカスタマイズします。次に `create` と `update` の操作を実装しているコードを修正します。


アクセス制御のカスタマイズ
--------------------------

最初にやりたいのは、[アクセス制御](http://www.yiiframework.com/doc/guide/ja/topics.auth#sec-5) のカスタマイズです。`gii` が生成したコードは私達の要求に合っていません。

`/wwwroot/blog/protected/controllers/PostController.php` ファイルを開いて、`accessRules()` メソッドを以下のように修正します。

~~~
[php]
public function accessRules()
{
	return array(
		array('allow',  // 全てのユーザに 'index' と 'view' のアクションを許可
			'actions'=>array('index', 'view'),
			'users'=>array('*'),
		),
		array('allow', // 認証されたユーザに全てのアクションを許可
			'users'=>array('@'),
		),
		array('deny',  // 全てのユーザのアクセスを拒否
			'users'=>array('*'),
		),
	);
}
~~~

上記のルールでは、すべてのユーザが `index` と `view` アクションにアクセス可能です。認証済みユーザは、`admin` アクションを含め、すべてのアクションにアクセス可能です。これ以外のシナリオではアクセスが拒否されます。ここで気をつけて欲しいのは、これらのルールはここに書き並べた順番で評価されるということです。そのときの状況に最初に一致したルールによって、アクセスの可否が決まります。例えば、ユーザがシステムオーナで記事作成ページを訪れようとした場合、2番目のルールが一致して、ユーザにアクセス権が与えられます。


`create` 操作と `update` 操作のカスタマイズ
----------------------------------------

`create` 操作と `update` 操作はよく似ています。両方とも、ユーザの入力を得るために HTML フォームを表示し、入力を検証し、データベースに保存します。大きな違いは、`update` 操作ではデータベースの既存のデータをあらかじめフォームにセットするという点です。このため `gii` は部分的なビュー(partial view)として `/wwwroot/blog/protected/views/post/_form.php` を生成し、これを `create` と `update` の両方のビューに埋め込んで HTML フォームを表示します。

最初に `_form.php` ファイルを修正して、HTML フォームで集める入力値をユーザに入力させたい `title`, `content`, `tags`, `status` だけにします。はじめの3つの属性には通常のテキスト入力欄を使います。`status` にはドロップダウンリストを使います。ドロップダウンリストの選択肢は、記事のステータスを表す文字列です。

~~~
[php]
<?php echo $form->dropDownList($model,'status',Lookup::items('PostStatus')); ?>
~~~

上の例では、記事が取り得るステータスの一覧を取得するために、`Lookup::items('PostStatus')` を呼んでいます。

次に `Post` クラスを修正し、記事がデータベースに保存される前にいくつかの属性 (`create_time` や `author_id`) が自動的にセットされるようにします。以下のように `beforeSave()` メソッドをオーバーライドします。

~~~
[php]
protected function beforeSave()
{
	if(parent::beforeSave())
	{
		if($this->isNewRecord)
		{
			$this->create_time=$this->update_time=time();
			$this->author_id=Yii::app()->user->id;
		}
		else
			$this->update_time=time();
		return true;
	}
	else
		return false;
}
~~~

記事を保存するときに、タグの出現頻度の変化を反映するために `tbl_tag` テーブルを更新する必要があります。この処理は `afterSave()` メソッドに書けばできます。この `afterSave()` メソッドは、データベースへの記事の保存が成功した後に、Yii から自動的に呼ばれます。

~~~
[php]
protected function afterSave()
{
	parent::afterSave();
	Tag::model()->updateFrequency($this->_oldTags, $this->tags);
}

private $_oldTags;

protected function afterFind()
{
	parent::afterFind();
	$this->_oldTags=$this->tags;
}
~~~

実装においては、ユーザが既存の記事を更新するときにタグを変更したかどうか判定したいので、変更前のタグが何であったかを知る必要があります。このため、`afterFind()` メソッドを書いて、`_oldTags` 変数に古いタグを保持するようにしました。この `afterFind()` メソッドは、AR レコードにデータベースから取得したデータが投入されたときに、Yii から自動的に呼ばれます。

ここでは `Tag::updateFrequency()` メソッドについて詳しく説明しません。興味のある方は `/wwwroot/yii/demos/blog/protected/models/Tag.php` を参照してください。


<div class="revision">$Id$</div>