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

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なんてのも辿るみたいなんだけどこれは必要なのか?

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
ユーザーは見つかりませんでした