対多リレーションとM2Mリレーションの複合化
メッセージサイトを作りたいとする。
メッセージは、メッセージ本体があるTextテーブル、ヘッダーなどの情報があるMessageテーブルの二つで成り立っており、ユーザ情報はUserテーブルでまかなっている。
この場合、Messageテーブルには送信主と送信先のレコードを入れるのだが、送信主は一人、送信先は複数あるとする。
- 送信主は一人なので、Message.user_id で User テーブルと関連づけがされる。
- 送信先は複数なので、中間テーブル(sender)を迂回して、Userテーブルと関連付けがされる。
てなわけで、SQLにするとこんな感じ。
-- 送信先 -- M2Mの中間テーブル create table senders ( id integer auto_increment primary key, message_id char(36), user_id integer ); -- メッセージ -- -- user_id = 送信者 -- -- text_id = message text CREATE TABLE messages ( id char(36) primary key, text_id integer, user_id integer, sender_id integer ); -- メール本体 CREATE TABLE texts ( id integer auto_increment primary key, message text, message_id char(36), created datetime, modified datetime ); -- ユーザテーブル CREATE TABLE users ( id integer auto_increment primary key, username varchar(50), password varchar(50) );
-
- M2Mと対多関連に対応したModelの作成
一番肝心なModelの作成。ユーザには、対多(Messageの送信者)およびM2M(Messageの受信者)の関連付けがされていると知らせておき、Messageには、それ相応の事(belongsToとhasAndBelongsToMany)を書いておきます。
<?php class User extends AppModel { var $name = 'User'; // var $belongsTo = array('Message') var $hasMany = array( 'Message' => array( 'className' => 'Message', 'dependent' => true ) ); var $hasAndBelongsToMany = array( 'Message' => array( 'className' => 'Message', 'joinTable' => 'senders', 'with' => 'Sender', 'foreignKey' => 'user_id', 'associationForeginKey' => '' ) ); } class Text extends AppModel { var $name = 'Text'; // From var $hasMany = array( 'Message' => array( 'className' => 'Message', 'dependent' => true ) ); } class Sender extends AppModel { var $name = 'Sender'; } class Message extends AppModel { var $name = 'Message'; var $recursive = 1; var $belongsTo = array( 'Text','User' ); // To var $hasAndBelongsToMany = array( 'Senders' => array( 'className' => 'User', 'joinTable' => 'senders', 'with' => 'Sender', 'foreignKey' => 'message_id', 'associationForeginKey' => '' ) ); } ?>
-
- M2Mリレーションの新規レコード作成
マニュアルが眠くてあまり読んで無い上、力技なので、参考にしないで下さい。
<?php class MessagesController extends AppController { var $name = 'Messages'; ... // いろいろあります。 // トップページ。 // ログインしていない場合は、ログインページへ移動 function index () { $u = $this->Auth->user(); if (!$u) $this->redirect('/user/'); ... // ここでもいろいろあります if (!$message) { // メール本文作成 $this->Text->create(); $this->Text->saveAll(array('message'=>'Hellow The new world :)')); // メッセージを作成 $this->Message->create(); $this->Message->saveAll(array('text_id' => $this->Text->id, 'user_id' => 1)); $this->Text->save(array('message_id'=>$this->Message->id)); // リレーション $this->Sender->create(); $this->Sender->save(array('message_id'=>$this->Message->id, 'user_id'=>$u['User']['id'])); } } } ?>
-
- 結果
View側でMessageを見たら、こんなデータ構造になりました。
Array ( [0] => Array ( [Message] => Array ( [id] => 4a64d53d-21d8-4d93-a328-4692c0a818fc [text_id] => 6 [user_id] => 1 ) [Text] => Array ( [id] => 6 [message] => Hellow The new world :) [message_id] => 4a64d53d-21d8-4d93-a328-4692c0a818fc [created] => 2009-07-21 05:36:13 [modified] => 2009-07-21 05:36:13 ) [User] => Array ( [id] => 1 [username] => admin [password] => *** ) [Senders] => Array ( [0] => Array ( [id] => 1 [username] => admin [password] => *** [Sender] => Array ( [id] => 14 [message_id] => 4a64d53d-21d8-4d93-a328-4692c0a818fc [user_id] => 1 ) ) ) ) )