アソシエーションの使い方
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)
);
顧客テーブルの初期データ
生年月日テーブルのテーブル定義
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については、以下の記事で詳しく解説しています!
【CakePHP入門】bakeの使い方
更新日 : 2019年4月20日
作成された「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/
![hasone]()
UserBirthdaysのデータも取得できています。
hasMany
hasManyは「1対多」の関連を表します。
例えば、1人の顧客が複数の注文データを持つことができるので、顧客と注文は「1対多」の関係になります。
hasManyについては、以下の記事で詳しく解説しています!
【CakePHP入門】アソシエーションのhasManyの使い方を理解しよう!
更新日 : 2017年8月10日
belongsTo
belongsToは「多対1」の関連を表します。
hasManyの章で、顧客と注文は「1対多」の関係になると解説しましたが、belongsToはその逆で、注文と顧客は「多対1」の関係になります。
belongsToについては、以下の記事で詳しく解説しています!
【CakePHP入門】アソシエーションのbelongsToの使い方を理解しよう!
更新日 : 2017年8月3日
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が使用されていたので、注意してください。
まとめ
今回はアソシエーションの使い方について解説しました。
実際にシステム等で使用されるテーブルには多くの関連が存在します。
アソシエーションの種別をひとつずつ覚えて、ぜひマスターしてください。
アソシエーションについて忘れてしまったら、この記事を思い出して下さい!