CakePHP 動的アソシエーション bindModel と、$reset パラメーターの落とし穴

複数のテーブルを結合するアソシエーションという機能があります。
hasOne とか hasMany とか belongsTo とか HABTM とか。

通常はモデルにアソシエーションを定義しておくのですが、そのうちこの「あらかじめモデルにアソシエーションを定義しておく」という方法に限界を感じてきます。
「このメソッドでは関連テーブルのデータを全部ひっぱってきたいけど、このメソッドではいらない」的な。

そこでおすすめしたいのが、動的アソシエーション(ダイナミックバインド)です。
コントローラ内で必要に応じてアソシエーションを設定したり解除したりすることができます。
この動的なアソシエーションが有効となるのは、その直後に実行されるモデル操作に限定されます。

アソシエーションを動的に設定

$this->Model->bindModel($params, $reset);

アソシエーションを動的に解除

$this->unbindModel($params, $reset);

つまりこうなります↓

> コントローラ

$this->Group->bindModel(array(
	'hasMany' => array('User'),
));

この動的なアソシエーションが使えれば、さらに先のレベルに進めること間違いなしですッ

意外と知られていない $reset パラメーターの落とし穴

Group と User があるとします。
User は Group に属しています。
Group のレコードを削除する時に、属する User のレコードも同時に削除したいとします。

> Group コントローラー

function delete($id = null) {
	$this->Group->bindModel(array(
		'hasMany' => array(
			'User' => array('dependent' => true), // 結合側のレコードも削除するかの真偽値
		),
	));
	$this->Group->delete($id));
}

がしかし、これでは User のレコードが削除されないのです。

CakePHP のコアファイルを読んでみます。

> model.php

function bindModel($params, $reset = true) {
// 省略
}
function unbindModel($params, $reset = true) {
// 省略
}

第2引数に $reset というものがあるではありませんか!!

$reset = 設定を維持的なものにする場合は true、変更する場合は false

ディフォルトでは $reset=true なので、find() などを行うと、動的なアソシエーション設定はリセットされてしまいます。
本来ならそれでいいのですが、一括削除ができないのはどうやらここに問題があるようです。

結論として、$reset パラメーターに false を渡せば解決ッ

function delete($id = null) {
	$this->Group->bindModel(array(
		'hasMany' => array(
			'User' => array('dependent' => true),
		),
	),false);
	$this->Group->delete($id));
}