端くれプログラマの備忘録 CakePHP [CakePHP] 簡単なサンプルを作ってHABTMの動きを確かめる

[CakePHP] 簡単なサンプルを作ってHABTMの動きを確かめる

CakePHP初心者ゆえクックブックを読んだだけではどうもしっくりこないので、簡単なサンプルを作ってhasAndBelongsToMany(HABTM)の動きを確かめてみる。

アソシエーション: モデル同士を繋ぐ — CakePHP Cookbook 2.x ドキュメント
http://book.cakephp.org/2.0/ja/models/associations-linking-models-together.html

例題は「製品」対「部品」の多対多リレーション

例題として「製品」と「部品」の多対多リレーションを定義してみる。ある「部品」は特定の「製品」にしか使われていないかもしれないし、またある「部品」は複数の「製品」に使われているかもしれない。すなわち、「製品」と「部品」の間には排他関係の無い多対多のリレーションが存在する。

テーブル定義

あくまでサンプルなので、テーブルには最低限のカラムしか持たせていない。

# 製品テーブル
CREATE TABLE `products` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
    `created` datetime DEFAULT NULL,
    `modified` datetime DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
# 部品テーブル
CREATE TABLE `parts` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
    `created` datetime DEFAULT NULL,
    `modified` datetime DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
# HABTMのための中間テーブル
CREATE TABLE `products_parts` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `product_id` int(10) unsigned NOT NULL,
    `part_id` int(10) unsigned NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

モデル定義

// Product.php
<?php
App::uses('AppModel', 'Model');
class Product extends AppModel {
    public $name = 'Product';
    public $hasAndBelongsToMany = array(
        'Part' => array(
            'className' => 'Part',
            'joinTable' => 'products_parts',
            'foreignKey' => 'product_id',
            'associationForeignKey' => 'part_id',
            'unique' => true,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'finderQuery' => '',
            'deleteQuery' => '',
            'insertQuery' => ''
        )
    );
}
?>
// Part.php
<?php
App::uses('AppModel', 'Model');
class Part extends AppModel {
    public $name = 'Part';
}
?>

コントローラ定義

とりあえずscaffoldに頼る。

// ProductsController.php
<?php
class ProductsController extends AppController {
    public $name = 'Products';
    public $scaffold;
}
?>

実行

実行すると期待通りの動作が確認できた。

まずは製品一覧を表示。

CakePHP-the-rapid-development-php-framework-Scaffold-Index-Products-Mozilla-Firefox_00

製品を[View]すると、製品に(多対多リレーションで)紐付けされている部品のリストも表示される。

CakePHP-the-rapid-development-php-framework-Scaffold-View-Products-Mozilla-Firefox_00

製品を[Edit]すると、紐付けする部品を複数選択可能なリストボックスが表示される。

CakePHP-the-rapid-development-php-framework-Scaffold-Edit-Products-Mozilla-Firefox_00

Scaffoldを使ったお陰で簡単に実装できた。自力でコントロールを書いて実装するとなると大変そう。