[CakePHP]HABTMの中継モデルをloadModelするとAppModelになる件

photo credit: Household Accident via photopin (license)

以下の環境、手順で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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
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();
}

かなりレアケースだと思いますが、過去に何度かこのケースで時間を費やしているのでメモしておきました。

  1. Containビヘイビアでアソシエーションをコントロールしています [↩]
  2. ソースは追って無いんですが、なんとなく想像できたので [↩]
スポンサーリンク
336x280_1
336x280_1

シェアする

フォローする

スポンサーリンク
336x280_1