NTTドコモ様_dカーシェア
NTTドコモ様_dカーシェア
2009.06.03

HABTMで関連づいたモデルのレコードを取得する

まっちー

唐突だけれど、今、UserとCategoryがhasAndBelongsToMany(以下HABTM)で関連づいているとする。

この場合、usersテーブルとcategoriesテーブルの他に、両者を関連づける結合テーブルというのが別に必要になる。この結合テーブルには、インデックスとなるidの他に、user_idとcategory_idのカラムを用意してやる必要がある。

ちなみにCakePHPの命名規約に従うなら、結合テーブルには結合する二つのテーブルの名前(複数形)をアンダーバーでつなげたものをテーブル名につけるらしい。ついでに、二つのテーブル名のうち、アルファベット順で先に来る方を前に持ってくるらしい。だからuserとcategoryではcategoryの方が前になる。したがって、今回の場合の結合テーブルの名前はcategories_usersになる。

さて、仮に今、categories_usersテーブルの中身がこんな感じになっていたとして、この中からcategory_idが1のユーザーだけを取得したいとする。

id user_id category_id
1 1 1
2 1 2
3 2 1
4 2 3
5 3 3

最初はどうやれば良いのか全く分からず、とりあえず↓こんなソースを書いて取得してた。

$param = array('conditions' => array('Category.id' => 1);

$data = $this->Category->find('all', $param);

$this->set(compact('data'));

Categoryモデルの方でもUserとHABTMでアソシエーションを設定しておけば、Categoryの方でfindしてもUserの情報を取ってきてくれる。

array([0] =>
 € € € € € € € array([Category] =>
 € € € € € € € € € € € € € € € € array([id] => 1
 € € € € € € € € € € € € € € € € € € € € € € [name] => カテゴリ名
 € € € € € € € € € € € € € € € € )

 € € € € € € € € € € € € € [User] =>
 € € € € € € € € € € € € € € € € array([0] =>
 € € € € € € € € € € € € € € € € € € € € € € € € array([id] => 1
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € [name] => ユーザー名
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € [CategoriesUser] =>
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € array([id] => 1
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € [user_id] => 1
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € <pre>[code] => 1
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € )
 € € € € € € € € € € € € € € € € € € € € € € € € )

 € € € € € € € € € € € € € € € € € € € € € € € [1] =>
 € € € € € € € € € € € € € € € € € € € € € € € € € array([id] => 2
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € [name] => ユーザー名
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € [CategoriesUser] =>
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € array([id] => 3
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € [user_id] => 2
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € <pre>[code] => 1
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € )
 € € € € € € € € € € € € € € € € € € € € € € € € € )
 € € € € € € € € € € € € € € € € )
 € € € € € € € € )
)

$dataをprint_rすると、だいたいこんな感じの情報が見られるはず。どこか間違っているかもしれないけど、まああまり気になさらずに……何となく雰囲気だけ伝わればオッケーってことで、流し見る程度に……配列がいっぱいあると目が疲れるしね。

あとはviewの方で表示したいものを表示すれば良い。

echo $data[0]['Category']['name']; € ←カテゴリ名が表示される

echo $data[0]['User'][0]['name']; € ←user_idが1のユーザー名が表示される

何か醜いっすね、上の二行……まあしかたない。

ちなみに、The Cookbookを参考にするとこんなやり方になる。

$this->User->bindModel(array('hasOne' => array('CategoriesUser')));

$param = array('conditions' =>
 € € € € € € € € € € € € € € € € € array('CategoriesUser.category_id' => 1),
 € € € € € € € € € € € € € € 'fields' =>
 € € € € € € € € € € € € € € € € € array('User.*')
 € € € € € € € € ));

$data = $this->User->find('all', $param)

$this->set(compact('data'));

どうやら一時的にhasOneでアソシエーションするらしい。*はSQLのSELECT文のときに使う*と同じ意味……だと思われる?

array([0] =>
 € € € € € € € array([Program] =>
 € € € € € € € € € € € € € € € € array([id] => 1
 € € € € € € € € € € € € € € € € € € € € € € [name] => ユーザー名
 € € € € € € € € € € € € € € € € )

 € € € € € € € € € € € € € [Category] =>
 € € € € € € € € € € € € € € € € array([0] =>
 € € € € € € € € € € € € € € € € € € € € € € € € array([id] => 1
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € [name] => カテゴリ名
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € [CategoriesUser] =>
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € array([id] => 1
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € [user_id] => 1
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € <pre>[code] => 1
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € )
 € € € € € € € € € € € € € € € € € € € € € € € € )
 € € € € € € € € € € € € € € € € )
 € € € € € € € € )

 € € € € € [1] =>
 € € € € € € € array([Program] =>
 € € € € € € € € € € € € € € € € array([id] => 2
 € € € € € € € € € € € € € € € € € € € € € € [name] => ユーザー名
 € € € € € € € € € € € € € € € € )

 € € € € € € € € € € € € € [Category] =>
 € € € € € € € € € € € € € € € € array([0] =>
 € € € € € € € € € € € € € € € € € € € € € € € € array([id] => 1
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € [name] => カテゴリ名
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € [CategoriesUser] =>
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € array([id] => 3
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € [user_id] => 2
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € <pre>[code] => 1
 € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € )
 € € € € € € € € € € € € € € € € € € € € € € € € )
 € € € € € € € € € € € € € € € € )
 € € € € € € € )
)

配列の中身がちょっと違うだけで、取得できている情報は基本的には一緒、だよな……? 一緒じゃなきゃ困るんだけど。

配列の結果を見てもパターン1の方が自分的にはこざっぱりしているような気がしないでもないのだけど、やっぱりパターン2のやり方の方が良いんだろうか?