プログラマの竹内です。
CakePHP の便利な機能で、モデルの「アソシエーション」機能があります。
関連付けた複数テーブルのデータを一度に取得できる機能です。
今回はこのアソシエーションの1つ、「hasAndBelongsToMany」なモデルデータを、ページ分割してデータ取得してくれる「paginate」メソッドで使うことができないかなあ?というお話。
1. hasAndBelongsToMany とは
例えば、以下のようなテーブルが3つあり、
ユーザーにタグをつけて検索したいという場合。
●users テーブル
id name
●users_tags テーブル
id user_id tag_id
●tags テーブル
id name
モデルには以下のように記述します。
var $hasAndBelongsToMany = array(
'Tag' => array(
'className' => 'Tag',
'joinTable' => 'users_tags',
'foreignKey' => 'user_id',
'associationForeignKey' => 'tag_id',
)
);
find と同様に、モデルのデータを取得してくる paginate ですが、表面的に同じような使い方をすると期待する結果が取得できない場合があります。
通常テーブルのデータ(例えば、ユーザー名を取得する)なら
$this->paginate('User', array('User.name'=>'ひろし'));
などという感じで取得することができます。
しかし、hasAndBelongsToMany のデータを取得する場合、
例えばタグで検索しようとして
$this->paginate('User', array('UsersTag.tag_id'=>1));
などとやっても、このままでは取得することができません。
3. paginate メソッドでモデル結合する。
しょうがないので、検索のSQLでデータを結合して取得してくるようにします。
コントローラー冒頭の宣言で
var $paginate = array('User' =>
array(
'conditions'=>array(
'User.del_flag'=>false
),
'limit'=>10,
'order'=>array(
'User.id'=>'asc'
),
'joins'=>array(
array('type'=>'LEFT', 'alias'=>'UsersTag', 'table'=>'users_tags',
'conditions'=>'User.id = UsersTag.user_id')
)
)
);
と記述します。
これで、
$this->paginate('User', array('UsersTag.tag_id'=>1));
のような方法によるデータの取得が可能になりました。
後記
だいぶ遠回りしていますが、CakePHP の機能でまだまだ不備のある点がよくわかって面白いです。
P.S. bindModel を使う手もありそうですが、恒久的なデータの取得に向かなさそうなので避けました。
















