業務で Cake2 から Cake3/4 へ大幅アップデートを行うプロジェクトに絶賛参画中です。
Cake2は既にサポートが今年(2022年)の6/15で終了し、急ピッチで行なう必要があります。
https://qiita.com/bezeklik/items/72d1ff8393f66673e2bc#cakephp
単に、Cakeアップデートといっても、ポチったり、hogefuga --update
とか打ったりして、はい、終了~で終われば最高ですが、そうはいきませんね..。
特にCake2から3は多くの破壊的変更があり、移行といっても、ゼロから作り直すと言っても過言ではない程、変更されています。
移行するにあたっては、エンジニアの趣味思考によって、Laravelであったり、モダンなツールを導入したり、色々案はあるとは思います。
重要なのは、作り方がモダンかどうかではなく、組織内で従来使用してきたフレームワークに対して蓄積されたノウハウやハウツーを活かすことの方が大事だと僕自身はそう思います。
モダンツールを追っかける(不要とは言ってないデス。それも大事)と、組織の財産(ノウハウ)をある意味捨てることになってしまうので、勿体無い。
そして、Cakephpも開発(サポート)は続けられているので、今後も頑張って欲しいと思います。
今回はCake2からCake3以降アップデート作業の中で、忘備録として残します。
Cake2のfieldsでのセレクト指定(*)がCake3以降では使えなくなった
Cake2では、DBデータを取得する際にカラム指定で多用することになるfields
、*
(アスタリスク)を指定できていたのですが、Cake3以降ではそれができません。
■ Cake2
$this->Hoge->find('first', [ 'fields' => ['Hoge.*', 'Fuga.name'], // Cake2はSQLのSELECT * がまんまな感じで利用可だった 'contain' =>['Fuga'], ]);
が、Cake3以降では(*)アスタリスクを使えなくなったので、下記の様に指定します。
■ Cake3 / Cake4
// initializeでアソシエーションの定義が必要 $this->Hoges->find() ->select($this) // 自身のモデルを全指定 ->select($this->Fugas) // containのテーブルモデルを全指定 ->contain(['Fugas']) ->first();
Cake3以降でのカラム指定は、それまで fields()
部分だった箇所は select()
に変更になっています。そして、自身のモデルの全てを指定する場合、$this
を指定することができます。contain()
部分で指定したモデルがある場合、さらにselect()をつなげて指定すれば良いでしょう。
containのモデルを全て指定したい場合は、逆に何もselectで指定しなくとも、紐づいて全て取得されるはずなので、問題ありませんね。
クエリビルダについて: 追記
■ クエリビルダ内にselect()
を使用している場合
例えば、クエリビルダにselect()を指定し、各フィールドを選んでいる場合で、さらにcontain内モデルテーブルを全取得したい場合に簡潔に書ける方法が enableAutoFields(true)
です。
$query->select(['id', 'title']) ->contain(['Comments', 'Tags']) ->enableAutoFields(true); // contain先のモデルを全取得 }]);
Q.じゃあ $this->join() の場合はどうやって指定するん?
A. initialize() でアソシエーションの定義は必要になるのじゃ
ということで、join 単独で自由にその場限りにクエリを叩くことは可能なのですが、「*」の代わりとなる、$this 系の指定とか enableAutoFields() の(アソシエーションが存在しないため) 利用ができません。なので、それらを使用してセレクトを指定したい場合、
// アソシエーションを貼っておく public function initialize(array $config): void { parent::initialize($config); $this->belongsTo('Hoges'); } // なんかしらんけけどカスタムファインダを例にしてもた public function findHoge(Query $query, array $options): \Cake\ORM\Query { // アソシエーションがあるから$this->Hogesが指定できる $query->select($this->Hoges); $query->join(['table' => 'hoges', 'alias' => 'Hoges', 'type' => 'inner', 'conditions' => 'HogeFugas.hoge_id = Hoges.id']); return $query; }
ちなみに、アソシエーションの定義がなくとも、
public function findHoges(Query $query, array $options): \Cake\ORM\Query { // テーブル名.カラム名 の形で指定できるが、全指定はできない。その場合はやはりアソシエートが必要になる $query->select(['Hoges.name']); $query->join(['table' => 'hoges', 'alias' => 'Hoges', 'type' => 'inner', 'conditions' => 'HogeFugas.hoge_id = Hoges.id']); return $query; }
「各テーブル名.名カラム」を1つずつ指定してくことは可能ですが、全フィールドしてはどのみちアソシエーションが必要になりそうです。
結論: 「*」アスタリスクを利用したい場合、アソシエーションを張りましょう。