LoginSignup
1
3

More than 5 years have passed since last update.

[PHP] CakePHP - HABTM(HasAndBelongsToMay)と中間テーブルの罠

Posted at

前提 - 罠にはまるひと

CakePHPで、こんなことをしているひとは罠にはまります。

  • モデル間アソシエーションとしてHABTM(HasAndBelongsToMany)を使っている
  • HABTMの中間テーブルをモデルとして使っている

図にすると以下のような感じです。
ModelAとModelBが多対多の関係にあります。
CakePHPで多対多を実現するときは、中間テーブルを使います。

本来であれば、中間テーブルにはModelAとModelBの主キーだけを格納しておくべきなのですが、普通にモデルとして使ってしまう場合です。

+--------+ n   n +--------+
+ ModelA +---+---+ ModelB |
+--------+   |   +--------+
             |
       +-----+-----+
       | Assoccor  |
       +-----------+       

罠の内容

CakePHP 1.3時代からあるネタのようです。

HABTMを持つモデルのfind等を呼び出すと、中間テーブルに対するモデルがAppModelのインスタンスとして生成されてしまい、自前で用意した中間テーブルに対するモデルが使われない。

何を言っているかわからn(ry

上の例で説明しますと、

ModelA#findModelB#findを呼び出すと、Assoccorクラスのインスタンスではなく、AppModelのインスタンスが、内部的なレジストリに登録されてしまいます。

ここでAssoccorクラスを使おうとすると、AppModelのインスタンスがやってきます。

コードで書くと、このような感じです。

SomeController.php
class SomeController {
    var $uses = array('ModelA', 'Assoccor');

    public function doSomething() {
        // ...
        $result = $this->ModelA->findAll();
        // ↑ ここで中間テーブルに対するモデルのインスタンスも生成されている

        // ...
        $this->Assoccor->someSpecialMethod(); 
        // ↑ AppModelのインスタンスになっているので、
        //   メソッドが見つからないというエラーになる
    }
}

解決策

アソシエーションを定義するとき、withパラメータで中間テーブルに対するクラス名も渡してあげます。

array('className' => 'ModelB',
      'joinTable' => 'model_a_model_b',
      'with'      => 'Assoccor'
      );

参考リンク

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3