at_yasu's blog

ロード的なことを

対多リレーションと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
                                )

                        )

                )

        )

)