以下の環境、手順でHABTMの中継モデルをloadModelすると、ロードされるモデルがAppModelになってしまい定義したメソッドが実行できない問題があったためメモしておきます。
- CakePHP 2.8.0
-
CakePHPのモデル
- Node
- Item
- ItemsNode(HABTM中継モデル)
NodeとItemはお互いにHasAndBelongsToManyの関係で、ItemsNodeモデルが中継しています。
ItemsNodeにはnode_idとitem_id以外に、ステータスやメモ的なフィールドを設けてあり、ItemsNodeモデルにもメソッドを実装しています。
このとき、HABTMのアソシエーションを使ったfindを行ったあとに中継モデルのItemsNodeをloadModelすると、$this->ItemsNodeがAppModelになってしまいます。 *1
ExampleController.php
public function index(){
$this->loadModel('Node');
$nodes = $this->Node->find('all', array(
'contain' => array(
'Item'
),
));
$this->loadMode('ItemsNode');
debug(get_class($this->ItemsNode)); // 'AppModel'になってしまう
// $this->ItemsNodeがAppModelになってしまうため
// ItemsNodeに定義したメソッドが存在せず、指定したメソッドをクエリと判断されてしまいエラーが出る
$this->ItemsNode->getExample(); // SQL Query: getExample
}
これはNodeモデルでHABTMの絡むfindを行ったときに処理の中で中継モデルを使用していることが原因と推測できたので*2 Nodeのfindの前に$this->loadModel(‘ItemsNode’)を置くことで解決しました。
ExampleController.php
public function index(){
$this->loadModel('Node');
$this->loadMode('ItemsNode');
debug(get_class($this->ItemsNode)); // 正しく'ItemsNode'が取れた
// $this->loadMode('ItemsNode') してからfind
$nodes = $this->Node->find('all', array(
'contain' => array(
'Item'
),
));
// 正しいモデルがロードできているので問題なく実行できる
$this->ItemsNode->getExample();
}
かなりレアケースだと思いますが、過去に何度かこのケースで時間を費やしているのでメモしておきました。
