読者です 読者をやめる 読者になる 読者になる

blogですかい

株式会社Loco Partnersに勤めるエンジニアうちの一人のブログ。仕事、プライベートで学んだことなどを発信し、その内容がたとえ少数でも誰かの役に立ったらなら、それはとっても嬉しいなって

CakePHP2でHABTMなモデルを作った話

プログラミング PHP CakePHP

CakePHP歴1ヶ月未満の私が、CakePHP2.2.2にてhasAndBelongsToManyなアソシエーションを持つモデルを設計する際に少々てこずったのでその備忘録。

例えば、アニメの名前のテーブルと声優の名前のテーブルをひも付けたい、といった場合の話。(アニメの名前と声優の名前が多対多の関係のような)

当初わからなかったこと

  • ひも付けテーブル名はどうすれば良いのか
  • ひも付けモデルのクラス名、ファイル名はどうすれば良いのか
  • ひも付けモデル自体のアソシエーションをどうすれば良いのか
  • ひも付けをscaffoldで管理したい場合、コントローラのクラス名、ファイル名はどうすれば良いのか

解決のために参考にしたサイト
(公式、ver1.3の情報ですが・・・)
http://book.cakephp.org/1.3/ja/view/1044/hasAndBelongsToMany-HABTM

DBの設計
下図のようにテーブルを作成
中間テーブルの設計ルールについては後ほど記述します
f:id:oh-sky:20121109130141p:plain
データは例えば、下記のようにセット


INSERT INTO `animes` VALUES(1, '化物語');
INSERT INTO `animes` VALUES(2, 'とある魔術の禁書目録');
INSERT INTO `animes` VALUES(3, '俺の妹がこんなに可愛いわけがない');
INSERT INTO `animes` VALUES(4, '魔法少女まどか☆マギカ');
INSERT INTO `voiceactors` VALUES(1, '井口裕香');
INSERT INTO `voiceactors` VALUES(2, '花澤香奈');
INSERT INTO `voiceactors` VALUES(3, '喜多村英梨');
INSERT INTO `voiceactors` VALUES(4, '加藤英美里');

anime及びvoiceactorsモデル・コントローラの設計
とりあえず最低限の記述で

<?php
//app/Model/Anime.php
class Anime extends AppModel {
public $hasAndBelongsToMany = array('Voiceactor');
}


<?php
//app/Controller/AnimesController.php
class AnimesController extends AppController {
public $scaffold;
}

Voiceactor.php 及び VoiceactorsController.php も同じように記述します。

中間テーブル・モデル・コントローラの設計
中間テーブルの設計ルール

  • 中間テーブル名は両方のモデル名の複数形を辞書順に並べてアンダースコアで繋げたもの
  • テーブルには各モデルのPKを外部キーとするカラムを用意
  • 外部キーのフィールドを複合PKにしない
  • 必要がある場合は外部キーにユニーク制約を定義
  • PKのフィールド(id INT NOT NULL auto_increment)を用意する

上記ルールでER図のようにテーブルを作成しました

中間モデル
モデル名は「AnimesVoiceactor」のように、
辞書順のキャメルケースで後ろに来る名詞が単数形となる。
外部キーのモデルとのアソシエーションはbelongs to


<?php
//app/Model/AnimesVoiceactor.php
class AnimesVoiceactor extends AppModel {
public $belongsTo = array('Anime','Voiceactor');
}

scaffoldで中間モデルを操作するコントローラ
コントローラ名は「AnimesVoiceactorsController」のように、
辞書順のキャメルケースの複数形 + Controller

<?php
//app/Controller/AnimesVoiceactorsController.php
class AnimesVoiceactorsController extends AppController {
public $scaffold;
}

scaffoldでデータの操作
http://example.com/animes/ では、下図のように、ひも付くvoiceactorをmultipleなselectで選択できます。
f:id:oh-sky:20121109142134p:plain
http://example.com/animes_voiceactors/ では下図のようにひも付きデータが表示され、
f:id:oh-sky:20121109142156p:plain
addやeditアクションではプルダウンで選択してひも付きの操作ができます。
f:id:oh-sky:20121109142210p:plain


各テーブル、モデル、コントローラの名前は設定でどうにでもできるようですが、
とりあえず基本はこうだということで・・・