Cakephp PHP WEB開発

Cakephp2のfieldsのアスタリスク(全指定)を3以降での対応方法

※本サイトはPR表記を含みます。

業務で 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つずつ指定してくことは可能ですが、全フィールドしてはどのみちアソシエーションが必要になりそうです。

結論: 「*」アスタリスクを利用したい場合、アソシエーションを張りましょう。

 

-Cakephp, PHP, WEB開発
-