CakePHP で連結テーブルのモデルは先に宣言すること

sugimoto です。最近、CakePHPを使ってます。

しばらくRails を使っていたこともあり、わかりやすい所もある反面、衝撃的に違うところがあったりして試行錯誤な毎日です。

先日、連結テーブルに「並び順」カラムを持たせて、hasManyAndBelongsToなリレーションの順番をつけようとしたところ、うまく動きませんでした。

プロジェクトとユーザーを以下のようなテーブルで関連つけていました
projects
users
projects_users

このとき、「各プロジェクトの参加者ごとに並び順を設定したい」という要望があり、 projects_users に position カラムを持たせて並び順を設定することにしました。

positionカラムの更新をするために ProjectsUser という中途半端なmodel クラスを作ったところ、問題発生。

projects_controller のuses 句で ProjectsUser を設定しているにもかかわらず、ProjectsUser の関数が呼べず、controller内での $this->ProjectsUser の実体がなぜか AppModel となっていました。

AppController など、ソースを確認したところ、controller のイニシャライズ時、以下のようなロジックでした。

  1. Projectモデルのインスタンス を作成
  2. Projectモデルで設定されているリレーションに該当するモデルのインスタンスを作成(Userなど)
  3. リレーションテーブルを扱うのインスタンス ProjectsUserを作成
  4. その際、デフォルト実装である AppModel のインスタンスとして作成
  5. 上記作成したインスタンスはすべてキャッシュ
  6. ProjectsUserを作成するが、すでにキャッシュされているためそれを使用

つまり、上記処理がcontroller の uses句内で宣言された順に処理されているため、ProjectsUserをロードするとき、先に処理したProjectモデルのリレーションとして作成されたProjectsUserが優先されていたわけです。

今日の格言

リレーショナルテーブルのモデルを作ったら、uses 句内では必ず先に宣言すること。

ソフトウェアエンジニアのためのバグトラッキングシステム : Ciklone

ソフトウェアエンジニアのためのバグトラッキングシステム

ソフトウェアエンジニアのためのバグトラッキングシステム

Comments are closed.