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

##初めに

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



##アソシエーションとは

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


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



##hasOneとは

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

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

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

`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`というプロフィールをもっている。
ユーザー（山田太郎や佐藤花子）は、一つのプロフィール（２や３）をもっているが、プロフィールは、一人のユーザーをもっている訳ではない。

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


```php

<?php
namespace App\Model\Table;
 
use Cake\ORM\Table;
 
class UsersTable extends Table
{
    public function initialize(array $config)
    {
        //　モデル名を入れる
        $this->hasOne('Profile');
    }
}
```



##hasMany

関係性は、１対多。

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

<?php
namespace App\Model\Table;
 
use Cake\ORM\Table;
 
class UsersTable extends Table
{
    public function initialize(array $config)
    {
        //　モデル名を入れる
        $this->hasMany('Articles');
    }
}
```



##belongsTo

関係性は、多対１。

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

<?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

<?php
namespace App\Model\Table;
 
use Cake\ORM\Table;
 
class ArticlesTable extends Table
{
    public function initialize(array $config)
    {
        $this->belongsToMany('モデル名');
    }
}
```


##追記


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

```php

<?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]


##まとめ


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

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