CakePHP アソシエーションについて


初めに

個人的にアソシエーションに関して、非常に苦戦したと同時に、わかってきたのでアウトプット兼備忘録としてここに書く。

アソシエーションとは

モデル同士の繋がりの事。
アソシエーションには4つの種類があります。
- hasOne
- hasMany
- belongsTo
- belongsToMany

この4種類を一個ずつ噛み砕いていきます。

hasOneとは

関係性としては、1対1となる。

Cookbookの例をテーブル構造にして見てみる。
[https://book.cakephp.org/3.0/ja/orm/associations.html#hasone]

例:ユーザーは1つのプロフィールを持っている。

usersテーブル

id first_name last_name
1 太郎 山田
2 花子 佐藤
3 田中

profileテーブル

id user_id
1 1
2 2
3 3

profileテーブルには、usersテーブルのidに対する外部キーuser_idが存在する。

山田太郎は、というプロフィールをもち、佐藤花子は、3というプロフィールをもっている。
ユーザー(山田太郎や佐藤花子)は、一つのプロフィール(2や3)をもっているが、プロフィールは、一人のユーザーをもっている訳ではない。

テーブルオブジェクトのinitialize()メソッドには、以下のように定義する。


<?php
namespace App\Model\Table;

use Cake\ORM\Table;

class UsersTable extends Table
{
    public function initialize(array $config)
    {
        // モデル名を入れる
        $this->hasOne('Profile');
    }
}

hasMany

関係性は、1対多。

Cookbookの例をテーブル構造にして見てみる。
[https://book.cakephp.org/3.0/ja/orm/associations.html#hasmany]

例:ユーザーは複数の記事を持つことができる。

usersテーブル

id first_name last_name
1 太郎 山田
2 花子 佐藤
3 田中

articlesテーブル

id user_id title
1 1 こんばんは
2 1 また明日
3 2 初めまして
4 2 よろしく
5 3 こんにちは

山田太郎は、こんばんはまた明日という記事をもつ。
佐藤花子は、初めましてよろしくという記事をもつ。
usersテーブルidに対し、user_idを外部キーとして、articlesテーブルに置く必要があります。

テーブルオブジェクトのinitialize()メソッドには、以下のように定義する。


<?php
namespace App\Model\Table;

use Cake\ORM\Table;

class UsersTable extends Table
{
    public function initialize(array $config)
    {
        // モデル名を入れる
        $this->hasMany('Articles');
    }
}

belongsTo

関係性は、多対1。

Cookbookの例をテーブル構造にして見てみる。
[https://book.cakephp.org/3.0/ja/orm/associations.html#belongsto]

例:多くの記事がユーザーに属している。

usersテーブル

id first_name last_name
1 太郎 山田
2 花子 佐藤
3 田中

articlesテーブル

id user_id title
1 1 こんばんは
2 1 また明日
3 2 初めまして
4 2 よろしく
5 3 こんにちは

関係性としては、hasManyと逆のイメージ。

こんばんはまた明日という記事は、山田太郎というユーザーに属している。(山田太郎というユーザーの記事だ。という事)
同様に、初めましてよろしくという記事は、佐藤花子というユーザーに属している。

テーブルオブジェクトのinitialize()メソッドには、以下のように定義する。


<?php
namespace App\Model\Table;

use Cake\ORM\Table;

class ArticlesTable extends Table
{
    public function initialize(array $config)
    {
        // モデル名を入れる
        $this->belongsTo('Article');
    }
}

belongsToMany

関係性としては、多対多。

Cookbookの例をテーブル構造にして見てみる。
[https://book.cakephp.org/3.0/ja/orm/associations.html#belongstomany]

例:タグは多くの記事に属している。

articlesテーブル

id user_id title
1 2 初めまして
2 3 こんにちは
3 1 また明日
4 2 よろしく
5 1 こんばんは

article_tagsテーブル

id article_id tag_id
1 1 100
2 1 101
3 2 100
4 2 101
5 2 102
6 3 100
7 3 103
8 4 103
9 4 100
10 5 100

tagsテーブル

id name
100 初心者
101 初投稿
102 こんにちは
103 ありがとう

この関係性をテーブル構造で表すと中間テーブルが必要になる。

記事の情報をもつarticlesテーブル、タグの情報をもつtagsテーブル、この二つのテーブルの架け橋的存在として、article_tagsテーブルがある。

articleテーブルidに対し、article_idを外部キーとしてarticle_tagsテーブルに置き、tagsテーブルidに対し、article_idを外部キーとしてarticle_tagsテーブルに置く必要がある。

article_tagsテーブルを見ると、初心者というタグ(id = 100)は、初めましてという記事に属していれば、こんにちはという記事にも属している事がわかる。

article_tagsテーブル(中間テーブル)から見ると、articlesテーブルtagsテーブルはそれぞれ多対1の関係性になる。


<?php
namespace App\Model\Table;

use Cake\ORM\Table;

class ArticlesTable extends Table
{
    public function initialize(array $config)
    {
        $this->belongsToMany('モデル名');
    }
}

追記

今回記載しなかったが、アソシエーションを定義する時には、第二引数を連想配列の形または、関数呼び出し(->関数名())の形で条件を指定できる。
例として、第二引数を連想配列の形として定義した場合を記載する。


<?php
namespace App\Model\Table;

use Cake\ORM\Table;

class ArticlesTable extends Table
{
    public function initialize(array $config)
    {
        // 第二引数を連想配列として条件を定義
        $this->アソシエーション名('モデル名', [
            'foreignKey' => 'hoge_id',
            'joinType' => 'INNER'
        ]);
    }
}

foreignKeyや、joinType、が何を示しているのかわからない、または、他にどんな条件を定義できるかは、Cookbookを参考にして下さい。

参考:[https://book.cakephp.org/3.0/ja/orm/associations.html]

まとめ

アソシエーションに関わらず、モデルの繋がり(関係性)の理解は非常に大切です。インターン先でそれを実感しています。基礎的な事を中心に書きましたが、応用的に使えるような事をもっと自分の中で落とし込める事ができたら、この記事に追記していこうと思います。

これらの内容に不備、間違った情報等記載してましたら、コメント貰えると嬉しいです。