cakephp:join したデータから Entity を作成
contain で関係するテーブルのデータを取得した場合、そのデータを Entity として取得できますが、
join でデータを取得した場合は Entity で取得できません。
そんなとき join したデータを Entity で取得する方法を紹介します。
※ちなみにこの記事の対象のバージョンは cakephp4 ですが、cakephp3 でも行けると思います。
まず contain の例です。
users->items という関係でデータを取得する例は以下の通りです。
$entUser = \Cake\ORM\TableRegistry::getTableLocator('Users')->find()->contain(['Items'])->first();
echo $entUser->item->title;
これを join メソッドを使って同じ出力をすると以下の通りになります。
$entUser = \Cake\ORM\TableRegistry::getTableLocator('Users')->find()->join([
'Items' => [
'table' => 'items',
'conditions' => ['Users.item_id = Items.id'],
]
])->first();
echo $entUser->Items['title'];
このように Items に格納されているデータは Entity ではないので アロー演算子(->)ではなく配列として参照しなければいけません。
「なんでやねん、contain で書けばええやん、ぶっとばすぞ」って思うでしょうが、
上記は例のために簡単にしただけで、ど~しても join で書かなければいけない複雑なテーブル構成の場合があると思います。
加えて join で取得したデータを配列じゃなくて、ど~してもエンティティとして取得したいときがあるかもしれませんので、
そんなときの方法として見てくださいませ。
で、どうするかと言うと User エンティティにバーチャルフィールドとして定義してしまえば簡単に実現できます。
src\Model\Entity\User.php
namespace App\Model\Entity;
class User extends Entity{
protected function _getItem(){
if( empty($this->item) == false ) return $this->item;
if( empty($this->Items) || is_array($this->Items) == false ) return null;
$this->item = \Cake\ORM\TableRegistry::getTableLocator('Items')->newEntity(
$this->Items,
['accessibleFields' => ['id' => true]],
);
$this->item->setNew(false)->clean();
return $this->item;
}
}
上記のように Userエンティティにバーチャルフィールド _getItem メソッドを定義してその中で取得した配列をエンティティに変換してしまえば join しても contain した時と同じように「$entUser->item->title;」で items のデータを参照できます。
次の cake のバージョンでは join しても勝手に Entity にしてくれるマッピング定義とかつけて欲しいな、、とか思いつつ、以上、join したデータから Entity を作成する方法でした。