リレーション : Post BELONGS_TO Author
次のような関係の二つのモデルがあるとします。
// 投稿者
class Author extends CActiveRecord {
...
}
// 記事
class Post extends CActiveRecord {
...
function relations() {
return array(
'author'=>array(self::BELONGS_TO, 'Author', 'id_author'),
);
}
...
}
記事をグリッドで一覧表示するときには、投稿者名をコラムに表示して、投稿者名でソートしたり、検索したり出来るようにしたいと思うでしょう。そういう機能を提供する(私の考えでは)最善の方法を以下に述べます。
検索用の属性を追加する
最初に Post モデルに検索文字列を格納する新しい属性を追加します。検索文字列の格納は外部キーのカラムを使っても出来ますが、私としては、外部キーのカラムの意味をオーバーロードしない方が良いと思います。というのは、検索のシナリオでは、外部キーの ID ではなく文字列を格納するからです。この新しい属性は 'search' のシナリオで 'safe' であると宣言しなければいけません。
class Post extends CActiveRecord {
public $author_search;
...
public function rules() {
return array(
...
array('xxx,yyy,author_search', 'safe', 'on'=>'search'),
);
}
}
検索の実装
次にクエリ基準を組むときにこの属性を使います。具体的には、標準の実装ですべてのモデルに search() という関数が提供されていますので、その関数を修正します。このとき、Post モデルと関連する Author を一緒に取得したいので、クエリ基準の 'with' 属性を設定します。こうすると JOIN を使った単一のデータベース・クエリを実行してデータが取得されます。(こうしない場合は、関連する Author のモデルはレイジー・ローディングによって取得されることになります。その場合は、実行されるデータベース・クエリの数が 1+N 個になります。)
$criteria = new CDbCriteria;
$criteria->with = array('author');
...
$criteria->compare('author.username', $this->author_search, true);
...
ソートの実装
投稿者名によるソートを実現するためには、ちょっとトリッキーですが、search 関数から返す CActiveDataProvider に細工をほどこします。
return new CActiveDataProvider('Post', array(
'criteria'=>$criteria,
'sort'=>array(
'attributes'=>array(
'author_search'=>array(
'asc'=>'author.username',
'desc'=>'author.username DESC',
),
'*',
),
),
));
sort 設定の 'attributes' セクションによって、デフォルトのソート方法をオーバーロードすることが出来ます。上記の設定は、ユーザが 'author_search' フィールドでのソートを指定した場合に、どういう ORDER 句を生成すべきかを指定するものです。最後の '*' は、このモデルの他のフィールドは標準的な ORDER 句を生成すべき事を指定しています。他のフィールドも同じ方法でデフォルトのソート方法をオーバーロードすることが出来ます。(例えば、ユーザが last_name でのソートを指定した場合に、last_name と first_name の両方を ORDER 句に含めるようにすることが出来ます。)
CGridView での使用
以上でグリッドを使用する準備は完了しました。
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'title',
'post_time',
array('name'=>'author_search', 'value'=>'$data->author->username'),
array(
'class'=>'CButtonColumn',
),
),
));
これで、author_id の外部キーではなく投稿者名によるソートが可能になり、投稿者名の部分一致による検索が可能になりました。
注記
上記は Searching and sorting by related model in CGridView の翻訳です。