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 のイニシャライズ時、以下のようなロジックでした。
- Projectモデルのインスタンス を作成
- Projectモデルで設定されているリレーションに該当するモデルのインスタンスを作成(Userなど)
- リレーションテーブルを扱うのインスタンス ProjectsUserを作成
- その際、デフォルト実装である AppModel のインスタンスとして作成
- 上記作成したインスタンスはすべてキャッシュ
- ProjectsUserを作成するが、すでにキャッシュされているためそれを使用
つまり、上記処理がcontroller の uses句内で宣言された順に処理されているため、ProjectsUserをロードするとき、先に処理したProjectモデルのリレーションとして作成されたProjectsUserが優先されていたわけです。
今日の格言
リレーショナルテーブルのモデルを作ったら、uses 句内では必ず先に宣言すること。