Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

リレーション : 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 の翻訳です。

softark
山の中の半農半プログラマ。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした