CakePHPで2つのテーブルを連結させる(2)

雑誌(magazines)が出版社(publishers)に属する、という形で magazines のほうから Model::$belongsTo を使って連結できたので、今度は出版社が持っている雑誌の一覧を出してみます。

<h2>出版社一覧</h2>
<table>
	<tr>
		<td>id</td>
		<td>name</td>
		<td>Magazine.name</td>
	</tr>
<?php foreach($Publishers as $item) : ?>
	<tr>
		<td><?php echo $item['Publisher']['id'] ?></td>
		<td><?php echo $item['Publisher']['name'] ?></td>
		<td><?php echo $item['Magazine']['name'] ?></td> ★
	</tr>
<?php endforeach ; ?>
</table>

こんな風に、$Publishers のループの中で、$item[‘Magazine’][‘name’] で参照できれば良いなと。

モデルの Magazine で Model::$belongsTo を設定してあるので、逆向きもできているんじゃないかなぁ、と期待してそのまま動かすと。

なエラーが出ます。逆向きは自動で設定してくれないのですね。。。
なので、Publisher モデルに加筆します。

<!-- models/publisher.php -->
<?php
class Publisher extends AppModel
{
	var $name = 'Publisher ';
	var $useTable = 'T200';
	var $hasMany = array('Magazine' =>
		array(
			'className' => 'Magazine',
			'conditions' => '',
			'order' => 'Magazine.T200id ASC',
            'limit' => 10,
			'foreignKey' => 'T200id',
            'dependent' => true,
            'exclusive' => false,
            'finderQuery' => ''));
}
?>

Mode::$hasMany の詳しい使い方は、マニュアルを見るとして、これを実行するとやっぱりエラーがでます。

「Undefined index: name」というエラーが出ているので、どうやら、Magazine は見つかったらしいけど、name が見つからない。で、print_r($Publishers) で見てみると、Magazine 以降はツリー構造になっているのですね。

Array
(
    [0] => Array
        (
            [Publisher] => Array
                (
                    [id] => 1
                    [name] => 平和システム
                )
 
            [Magazine] => Array
                (
                    [0] => Array
                        (
                            [id] => 1
                            [name] => 逆引き大全F#555
                            [T200id] => 1
                            [price] => 1000
                            [publisher_id] => 1
                        )
 
                    [1] => Array
                        (
                            [id] => 2
                            [name] => 逆引き大全CakePHP555
                            [T200id] => 1
                            [price] => 2000
                            [publisher_id] => 1
                        )
 
                )
 
        )
    [1] => Array
        (
            [Publisher] => Array
                (
                    [id] => 2
                    [name] => 日経BB社
                )
 
            [Magazine] => Array
                (
                    [0] => Array
                        (
                            [id] => 3
                            [name] => ひと目で分かるOracleアプリケーション入門
                            [T200id] => 2
                            [price] => 3000
                            [publisher_id] => 2
                        )
 
                )
 
        )
 

なので、アクセスの仕方としては、$item[‘Magazine’][0][‘name’] のように添え字が間に挟まるわけですが、これだと一覧表には不便です(多分、出版社→その配下の雑誌を表示、のように遷移する場合に使うのかと)。

仕方がないので、Model::$belongsTo を使ってみます。意味的には変なのですが。

<!-- models/publisher.php -->
<?php
class Publisher extends AppModel
{
	var $name = 'Publisher ';
	var $useTable = 'T200';
    var $belongsTo = array('Magazine' =>
		array(
			'className' => 'Magazine',
			'conditions' => 'Magazine.T200id = Publisher.id',
			'order' => 'Publisher.id ASC',
			'foreignKey' => ''));
}
?>

外部キー(foreignKey)を指定することはできないので、join の条件(conditions)を直接指定します。
ここでハマるのは、T100, T200 の元のテーブル名を使うことができなくて(それはそれで良いのですが)、Magazine, Publisher というモデル名を使うところですね。SQL 文で別名定義しているところの制限なので、MySQL だけの制限かもしれません。

これを実行すると、めでたく一覧表が出ます。

がッ!!! 一見大丈夫そうにみえて、ああ、left join を使っているので雑誌を出していない出版社の名前も一覧に出てきます。これは、まぁこれで良いのかと思いますが。

でも left join でループしない場合はどうするんでしょうね?という疑問が(これはまだ解決せず)

カテゴリー: CakePHP パーマリンク