LoginSignup
8
8

More than 3 years have passed since last update.

CakePHP3の嵌りポイント

Last updated at Posted at 2019-10-04

CakePHPは簡単かつウェブサイトが楽に作れる大変ありがたいフレームワークですが、たまに嵌りポイントがあります。
使っていてハマった点を忘れないように纏めます。


No.1 - patchEntity, save等で孫テーブルがうまく動かない(マージ/保存できない)

親-子-孫の関係になっているテーブルに対し、hasOne/hasManyも定義しているのに親テーブル追加/更新で孫まで上手く反映されない。子まではうまく動く、get/findもうまく動く、エラーは出ない。という場合。
例: Companies --(hasMany)--> Users --(hasMany)--> UserSettings

可能性① associationの書き方が間違ってる

get()とは違い、ネストした中にもassociatedを再度書く必要がある

#get()の場合
$query = $companies->get($id, [
    'contain' => [ 'Users' => ['UserSettings'] ]
]);

#newEntity/patchEntityの場合
$company = $companies->newEntity($data, [
    'associated' => [
        'Users' => [
            'associated' => ['UserSettings']
            // ↑ここにも'associated'が必要
        ]
     ]
]);

公式マニュアルにも書いてあるものの、まさかget/findと違うことはないだろと思って読み飛ばしがち
*参考にさせてもらったページ(https://qiita.com/zaramme/items/719f77480c5f0cde0ae1)

可能性② Entityの$_accessibleに子/孫要素が入ってない

この指定がtrueになっていないと無視される。
bin bakeで自動で設定してくれるはずなものの、条件によっては?親側のEntityに書いてくれていない事があるようで、bakeしなおすか手動で追加が必要。
(普通にget/findしてアクセスするときと同様、hasOneなら単数形、hasManyなら複数形で子テーブルの名前を追加)

可能性③ dirtyフラグが立ってない

newEntityやpatchEntityでエンティティ作成後、手動で何か追加/変更した場合、dirty()も呼ばないと更新対象にならない。(公式)

$company->author->name = 'Master Chef';
$company->dirty('author', true);

No.2 - 更新処理で子/孫テーブルのデータが追記/作り直される(delete/insertされる)

例: Users --(hasMany)--> UserSettings
親テーブル更新時に子テーブルのデータもまとめて更新したいが、親はupdate処理されるものの、子テーブルのデータはupdateしてくれず、追加(or deleteで一回消され、insertで新規保存)されてしまう場合。
(どっちになるかはsaveStrategy次第)
updateでないため子テーブルのprimary keyが変わってしまい、他との関係性が壊れる。

可能性: 子/孫テーブルのprimary keyが渡されてない

Entityにprimary keyが無いとpatchしようがないので、追加/入れ直しになる。
ちゃんとあればupdate処理になる。

*patchEntityに渡すデータ(フォームからの入力、get/findで取ってくるデータ)の両方にprimary keyが必要。
 つまりパッチ元のget/find時にも更新したい関係テーブルをcontainで指定しておく必要がある。


No.3 - 単数/複数形の規約で混乱する

単数/複数の変形

規約で使い分けた気持ちは分かるけど不規則の場合はどうする?
実際のCakePHPの変換を出してくれるサイトを参照。(古い?)
最新Verで動いているcakePHP公式のサイトもあり。
pokemonは単複同型です。

DBからcontainで纏めて取ってきた子/孫テーブルの形は?

例: Companies --(hasMany)--> Users --(hasOne)--> Addressies

hasOne, belongsToは単数形、そのまま要素にアクセスできる。
$user->address->street ←addressと単数形になる

hasMany, belongsToManyは複数形で配列。
$company->users[0]->name


No.4 - 関連テーブルでのwhereで失敗する

そんなカラム無いといわれて失敗する。
hasMany先相手だとSQLが分割されるが原因で、普通にwhereに書くだけではダメ。
目的によってcontainにfunctionを指定、queryBuilderを渡す、matchingを使ったりする。
マニュアル参照
参考


No.5 - hasMany先の特定の1個だけくっつけて取得したい

StackOverflowのここが分かりやすい。
サブクエリで取ってくる「Join strategy - Using a subquery for the join condition」が個人的に好み。


No.6 - DebugKitが動かない

マニュアルの通りではあるけど

可能性① forceEnableしてない

安全のためローカル環境(localhostとか)出ないと動かないようになっている。
それでも動かしたい場合はマニュアルの通りforceEnableを設定する。
これが嫌なら、hostsにテスト環境をmytest.localとかで登録する手もある。

可能性② pdo_sqliteが無い

デフォルトでSQLliteを使ってるので、pdo_sqliteが無い場合は入れてやる必要がある。
普通にlogs/error.logに出るけどブラウザからは特に何も言われないので。

8
8
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
8
8