id以外のカラムでアソシエーション

CakePHPのデータベースアプリケーションで、「id」以外のカラムを使って複数テーブルを紐付けたいと思った時に少しつまづいたので、メモしておきます。

例として下記のようなテーブル構成を想定します。
脊椎動物に魚類や鳥類があって、無脊椎動物に甲殻類などがあるというような階層構造ですね。

分類テーブル(categories)
フィールド名 インデックス 備考
id int primary auto_increment
code varchar(32) unique  
large_code varchar(32)   外部キー:large_category.code
name varchar(64)    
created datetime    
modified datetime    
大分類テーブル(large_categories)
フィールド名 インデックス 備考
id int primary auto_increment
code varchar(32) unique  
name varchar(64)    
created datetime    
modified datetime    

特定の分類コード(category.code)が渡されると、大分類名称/分類名称という形で情報を返すメソッドを作成したいと思います。
分類クラスに下記のようなアソシエーションを定義します。

// 分類クラス定義の冒頭
class Category extends AppModel {
	var $name = 'Category';
	// バリデーション定義
	var $validate = array();
	// アソシエーション定義
	var $belongsTo = array(
		"LargeCategory" => array(
			"className" => "LargeCategory",
			"foreignKey" => "large_code"
		)
	);

/* 続く */

で、このようにメソッド本体を作ります。

/**
 * 指定カテゴリーの情報を返す
 * @param string 分類コード
 * @return mixed 配列
返す配列の形式
return = array(
	'large_code' => '大分類コード'
	'code' => '分類コード',
	'name' => '大分類/カテゴリー名',
 */
	public function getSingle($code){

		$record = $this->find(
			'first',array(
				'fields' => array(
					'LargeCategory.code',
					'Category.code',
					'LargeCategory.name',
					'Category.name'
				),
				'conditions' => array(
					'Category.code' => $code
				)
			)
		);

		if( $record ) {
			return array(
				'large_code' => $record['LargeCategory']['code'],
				'code' => $record['Category']['code'],
				'name' => $record['LargeCategory']['name'].'/'.$record['Category']['name'],
			);
		} else {
			return false;
		}
	}
}

これだけでは、実は大分類(large_categories)と紐づいた情報を取得することはできませんでした。
生成されたSQLを見ると分かるのですが、大分類テーブルのレコードを探すときに「id」のカラムを参照してしまっています。

SELECT `LargeCategory`.`code`, `Category`.`code`, `LargeCategory`.`name`, `Category`.`name`
FROM `categories` AS `Category`
LEFT JOIN `large_categories` AS `LargeCategory` ON (
	`Category`.`large_code` = `LargeCategory`.`id`
) WHERE ... /* 以下略 */

CakePHPでは「id」カラムを手がかりに検索を行うという設計が徹底されています。
大分類テーブルのレコードを検索する時に「code」のカラムを使うよう、主キーの設定を変更します。

// 大分類クラス定義
class DaiBunrui extends AppModel {
	public $name = 'LargeCategory';
	// アソシエーション用に主キー定義を変更
	public $primaryKey = 'code';

}

この例ではメンバー変数の初期値を変更してしまいましたが、特定メソッドを使う場合だけ、コントローラー側で主キーの設定を変えるということも可能です。

// Controller 内の処理
	// 主キーを一時的に変更
	$this->LargeCategory->primaryKey = 'code';
	// アソシエーションを設定
	$this->Category->$belongsTo = array(

	/* 中略 */

	);

	$result = $this->Category->getSingle($code);

	// 主キーを元に戻す
	$this->LargeCategory->primaryKey = 'id';
参考
primaryKey :: Model の属性 :: モデル :: CakePHPによる開発 :: マニュアル :: 1.2 Collection :: The Cookbook
カテゴリー: Webプログラミング   タグ:   この投稿のパーマリンク

コメントをどうぞ

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>