LoginSignup
2
4

More than 5 years have passed since last update.

CGridView で関連モデルによって検索とソートをする

Last updated at Posted at 2012-12-02

リレーション : Post BELONGS_TO Author

次のような関係の二つのモデルがあるとします。

Author.php
// 投稿者
class Author extends CActiveRecord {
    ...
}
Post.php
// 記事
class Post extends CActiveRecord {
    ...
    function relations() {
        return array(
            'author'=>array(self::BELONGS_TO, 'Author', 'id_author'),
        );
    }
    ...
}

記事をグリッドで一覧表示するときには、投稿者名をコラムに表示して、投稿者名でソートしたり、検索したり出来るようにしたいと思うでしょう。そういう機能を提供する(私の考えでは)最善の方法を以下に述べます。

検索用の属性を追加する

最初に Post モデルに検索文字列を格納する新しい属性を追加します。検索文字列の格納は外部キーのカラムを使っても出来ますが、私としては、外部キーのカラムの意味をオーバーロードしない方が良いと思います。というのは、検索のシナリオでは、外部キーの ID ではなく文字列を格納するからです。この新しい属性は 'search' のシナリオで 'safe' であると宣言しなければいけません。

Post.php
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 個になります。)

Post.php
    $criteria = new CDbCriteria;
    $criteria->with = array('author');
    ...
    $criteria->compare('author.username', $this->author_search, true);
    ...

ソートの実装

投稿者名によるソートを実現するためには、ちょっとトリッキーですが、search 関数から返す CActiveDataProvider に細工をほどこします。

Post.php
    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 での使用

以上でグリッドを使用する準備は完了しました。

view.php
$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 の翻訳です。

2
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4