この記事でわかること
- belongsToManyの使い方
- belongsToManyな関係のデータの保存方法
前提
想定
塾講師の管理システムを作るとします。
今回実装したい機能は、講師の担当教科を設定できるようにすることです。
例:ジョージ先生は数学、物理を担当している。
使用するテーブル
- teachers:講師情報(名前など)を管理するテーブル
- subjects:教科テーブル(nameカラムに「数学」や「英語」などが入る)
- teachers_subjects:講師がどの教科を教えることができるのかを保持しているテーブル
CREATE TABLE teachers (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
created DATETIME,
modified DATETIME
);
CREATE TABLE subjects (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
created DATETIME,
modified DATETIME
);
CREATE TABLE teachers_subjects (
teacher_id INT NOT NULL,
subject_id INT NOT NULL,
PRIMARY KEY (teacher_id, subject_id),
FOREIGN KEY subject_key(subject_id) REFERENCES subjects(id),
FOREIGN KEY teacher_key(teacher_id) REFERENCES teachers(id)
);
belongsToManyについて
belongsToManyは “Teachers belongsToMany Subjects” (先生が多くの科目に属する) ということになります。
belongsToMany アソシエーションでは**三つのデータベーステーブルが必要
です。
今回で言えば、 teachers 、 subjects および teachers_subjects で、
結合(中間)テーブルは、関連する二つのテーブルの名前をアンダースコアーで結びつけるという規約があります。
**
例
こんな感じでデータを保持します。
- ジョージ先生は数学、物理を担当している。
- ロレイン先生は国語、英語、歴史を担当している。
teachersテーブル
id | name |
---|---|
1 | ジョージ |
2 | ロレイン |
subjectsテーブル
id | name |
---|---|
1 | 数学 |
2 | 国語 |
3 | 英語 |
4 | 歴史 |
5 | 地理 |
6 | 物理 |
7 | 化学 |
teachers_subjectsテーブル
id | teacher_id | subject_id |
---|---|---|
1 | 1 | 1 |
2 | 1 | 6 |
3 | 2 | 2 |
4 | 2 | 3 |
5 | 2 | 4 |
アソシエーション
両方のモデルの中で belongsTo アソシエーションを定義することができます。
class TeachersTable extends Table
{
public function initialize(array $config)
{
$this->belongsToMany('Subjects');
}
}
class SubjectsTable extends Table
{
public function initialize(array $config)
{
$this->belongsToMany('Teachers');
}
}
belongsToManyな関係のデータの保存方法
では実際に、担当科目を設定できるようにしていきます。
まず、TeachersからSubjectsのデータを保存できるようにします。
class Teacher extends Entity
{
protected $_accessible = [
'name' => true,
'subjects' => true //←これを忘れると保存できないので注意
];
}
講師を追加するためのaddアクションです。
本来はフォームから受け取ったデータを保存するべきですが割愛します。
<?php
namespace App\Controller;
class TeachersController extends AppController
{
public function add()
{
$data = [
'name' => 'ジョージ',
'subjects' => [
['subject_name' => '数学'],
['subject_name' => '物理']
]
];
$teachers = TableRegistry::get('Teachers');
$teacher = $teachers->newEntity($data, [
'associated' => ['Subjects'],
]);
$this->Teachers->save($teacher);
return $this->redirect(['action' => 'index']);
}
}
これだけで講師(teachers)、教科(subjects)、その講師が担当できる教科(teachers_subjects)が一度に保存できました。
なかなか便利ですね〜
今まで、teachers_subjectsのような中間テーブルを手動で保存していたので、これからはもっとスマートに書けそうです。