PHP
CakePHP

CakePHPのアソシエーションがわからなくなったとき用

More than 3 years have passed since last update.

http://book.cakephp.org/2.0/ja/models/associations-linking-models-together.html

http://blog.ecworks.jp/archives/268

http://qiita.com/kazu56/items/eaaa0c2d7294a28ac21c

http://qiita.com/moriyant/items/b57ee4fc45af2fc03194

hasとbelongが、すぐどっちがどっちかわからなくなる。

「持っている」とかアバウトな言葉じゃなくてテーブル定義で教えてくれ。


結論


hasMany

相手テーブルに、自分テーブル.idへの外部キーがある。

hasOne

hasManyだけど外部キーがUNIQUE。

belongsTo

自分のテーブルに、相手テーブル.idの外部キーがある。

hasAndBelongsToMany

中間テーブルでくっついてるやつ。


hasMany

ユーザは複数の趣味を持っている。任意入力。


User.php

class User{

$hasMany = [
'Hobby'=>[
'className' => 'Hobby',
],
];
}


usersテーブル

特に趣味に関する項目はない。



hobbiesテーブル

id

user_id ← users.idに外部キー
name

趣味をスペース区切りとかで複数入力してもらい、それをそのまま保存するタイプのユーザ登録。

よくある構造のテーブルです。


hasOne

ユーザはひとつのプロフィールを持っている。


User.php

class User{

$hasOne = [
'Profile'=>[
'className' => 'Profile',
],
];
}


usersテーブル

プロフィールに関する項目はない。



profilesテーブル

id

user_id ← users.idに外部キー、かつUNIQUE制約
family_name
first_name

この構造は公式の例なのですが、でもこういう場合普通はusersテーブルに個人情報入れるよな。

hasOneを使うということはつまりテーブルの垂直分割なので、あまり使う必要性が感じられない。


belongsTo

ユーザは職業IDを持っている。


User.php

class User{

$belongsTo = [
'Employment'=>[
'className' => 'Employment',
],
];
}


usersテーブル

id

employment_id ← employments.idに外部キー


employmentsテーブル

id

name

employmentsテーブルには「学生」「会社員」「無職」などのデータが入っていて、ユーザ登録時にその項目を選択してIDを登録するというよくある形態。


hasAndBelongsToMany

ユーザは複数の趣味を持っている。選択式。


User.php

class User{

$hasAndBelongsToMany = [
'Hobby'=>[
'className' => 'Hobby',
'with' => 'UserHobby',
'foreignKey' => 'hobby_id',
'associationForeignKey' => 'user_id',
],
];
}


usersテーブル

特に趣味に関する項目はない。



hobbiesテーブル

id

name


user_hobbiesテーブル

id

user_id ← users.idに外部キー
hobby_id ← hobbies.idに外部キー

hasManyの趣味は直接入力でしたが、こちらは予め項目が表示されており、その中からチェックボックスで複数選択するタイプの登録フォーム。

UserとHobbyにUserHobbyへのhasMany、UserHobbyからUserとHobbyへのbelongsToを書けばだいたい同じ意味になると思うけど、めんどうなので一気に書けるとかそういうかんじですかね。


その他

リレーションがあるだけひたすら書いておくだけで、findすると勝手に拾ってきてくれて便利なのですが、SQLの発行数がえらいことになります。

辿る深さはrecursiveで制御できますが、何故か特定の先だけ制御する方法がありません。

A→B→C→D


E→F→G

H→I

J

なんてテーブルがあったとして、Dが欲しいんだと$this->A->recursive = 3と設定するとSQLが何十個も発行されます。

や、Bの先だけ欲しいんだと$this->A->B->recursive=2;$this->A->E->recursive=-1;とか書いても、どうも効かないみたいです。

そういう記事が全く見当たらないんだけどできないんじゃろうか。

あとrecursive深くするとA→B→A→Bなんてのも辿るみたいなんだけどこれは必要なのか?