こんにちは!フリーエンジニアのせきです。
CakePHPでは、モデルにモデル同士の関連を定義することができます。
この記事では、
・アソシエーションとは何か知りたい
・アソシエーションの種別ごとの使い方を知りたい
といった内容について、わかりやすく解説します!
アソシエーションとは
CakePHPでは、モデル同士の関連をアソシエーションといいます。
アソシエーションを使うことで、一度の処理で関連する複数のモデルからデータを取得したり、保存したりすることができます。
アソシエーションには4つの種類があります。
次の章から、それぞれのアソシエーションについて解説していきます。
アソシエーションの使い方
hasOne
hasOneは「1対1」の関連を表します。
例えば、1人の顧客は1つの生年月日を持ちます。
この時、顧客と生年月日は「1対1」の関係になります。
この章では、顧客テーブルと生年月日テーブルを作成し、hasOneの関係になるように設定していきます。
以下のようなテーブルを作成し、データを登録しておきます。
顧客テーブルのテーブル定義
create table users ( id int not null auto_increment, -- ID name varchar(32), -- 名前 primary key (id) );
顧客テーブルの初期データ
id | name |
---|---|
1 | 小林 |
2 | 田中 |
3 | 小沢 |
生年月日テーブルのテーブル定義
create table user_birthdays ( id int not null auto_increment, -- ID user_id int not null, -- ユーザID year int, -- 年 month int, -- 月 day int, -- 日 primary key (id) );
生年月日テーブルは顧客テーブルを参照する外部キーuser_idフィールドを持ちます。
外部キーは、デフォルトでは「相手側のモデル名(単数形)_id」を使用します。
生年月日テーブルの初期データ
id | user_id | year | month | day |
---|---|---|---|---|
1 | 1 | 1970 | 3 | 5 |
2 | 2 | 1975 | 10 | 10 |
3 | 3 | 1965 | 2 | 28 |
それぞれのModelを作成しておきます。
顧客テーブルのModel
src\Model\Entity\User.php
<?php namespace App\Model\Entity; use Cake\ORM\Entity; class User extends Entity { }
src\Model\Table\UsersTable.php
<?php namespace App\Model\Table; use Cake\ORM\Table; class UsersTable extends Table { }
生年月日テーブルのModel
src\Model\Entity\UserBirthday.php
<?php namespace App\Model\Entity; use Cake\ORM\Entity; class UserBirthday extends Entity { }
src\Model\Table\UserBirthdaysTable.php
<?php namespace App\Model\Table; use Cake\ORM\Table; class UserBirthdaysTable extends Table { }
hasOneアソシエーションは、Tableオブジェクトのinitialize()に以下のように定義します。
$this->hasOne('モデル名');
UsersTableに、initialize()を追加します。
public function initialize(array $config) { $this->hasOne('UserBirthdays'); }
このように定義しておくと、UsersのControllerでcontainを使用し、UserBirthdaysのデータを取得することができます。
bakeでControllerの雛形を作成します。
bin/cake bake controller users
bakeについては、以下の記事で詳しく解説しています!
作成された「src\Controller\UsersController.php」のindexメソッドを、以下のように修正します。
public function index() { $query = $this->Users->find('all')->contain(['UserBirthdays']); $this->set('users', $query); }
「find(‘all’)」で全件検索し、「contain(‘UserBirthdays’)」でUserBirthdaysのデータも一緒に取得するように指定しています。
一覧表示のTemplateを作成します。
src\Template\Users\index.ctp
<table cellpadding="0" cellspacing="0"> <thead> <tr> <th>ID</th> <th>名前</th> <th>生年月日</th> </tr> </thead> <tbody> <?php foreach ($users as $user): ?> <tr> <td><?= $user->id ?></td> <td><?= $user->name ?></td> <td><?= $user->user_birthday->year ?>/<?= $user->user_birthday->month ?>/<?= $user->user_birthday->day ?></td> </tr> <?php endforeach; ?> </tbody> </table>
UserBirthdaysのデータは「$user->user_birthday」で取得することができます。
表示してみます。
http://[サーバ名]/[プロジェクト名]/users/
UserBirthdaysのデータも取得できています。
hasMany
hasManyは「1対多」の関連を表します。
例えば、1人の顧客が複数の注文データを持つことができるので、顧客と注文は「1対多」の関係になります。
hasManyについては、以下の記事で詳しく解説しています!
belongsTo
belongsToは「多対1」の関連を表します。
hasManyの章で、顧客と注文は「1対多」の関係になると解説しましたが、belongsToはその逆で、注文と顧客は「多対1」の関係になります。
belongsToについては、以下の記事で詳しく解説しています!
belongsToMany
belongsToManyは「多対多」の関連を表します。
例えば、顧客は複数の商品を注文し、商品は複数の顧客から注文されます。
この時、顧客と商品は「多対多」の関係になります。
通常、多対多の関連を表すには中間テーブルを使用します。
今回の例だと、注文のデータがあって顧客と商品が多対多の関連を持つので、注文テーブルが中間テーブルになります。
usersテーブル(顧客)とproductsテーブル(商品)の中間テーブルは、デフォルトではusers_productsテーブルと命名します。
users_productsテーブルは、user_idフィールドを持ち顧客テーブルと1対多、さらにproduct_idフィールドを持ち商品テーブルとも1対多の関係となります。
belongsToManyアソシエーションは、他のアソシエーションと同様、Tableオブジェクトのinitialize()に以下のように定義します。
$this->belongsToMany('モデル名');
次のように、両方のモデルでbelongsTo アソシエーションを定義することができます。
src\Model\Table\UsersTable.php
<?php namespace App\Model\Table; use Cake\ORM\Table; class UsersTable extends Table { public function initialize(array $config) { $this->belongsToMany('Products'); } }
src\Model\Table\ProductsTable.php
<?php namespace App\Model\Table; use Cake\ORM\Table; class ProductsTable extends Table { public function initialize(array $config) { $this->belongsToMany('Users'); } }
検索も他のアソシエーション同様、Controllerでcontainを使用し、関連テーブルのデータを取得することができます。
$query = $this->Users->find('all')->contain(['Products']);
CakePHP3.0より前はbelongsToManyアソシエーションではなく、hasAndBelongsToManyが使用されていたので、注意してください。
まとめ
今回はアソシエーションの使い方について解説しました。
実際にシステム等で使用されるテーブルには多くの関連が存在します。
アソシエーションの種別をひとつずつ覚えて、ぜひマスターしてください。
アソシエーションについて忘れてしまったら、この記事を思い出して下さい!