次のDBテーブルがあります:items、users、groups、itemImages。 (items、groups)と(users、groups)の間には多対多の関係があり、(items、itemImages)の間には1対多の関係があります。適切な外部キーはすべて、CakePHPで関連付けとして設定されています。
特定のIDを持つユーザーにメイングループとして割り当てられたグループ内にあるすべてのアイテムとそのメイン画像を選択するcontain()を使用してクエリを作成するにはどうすればよいですか?
明確にするために、プレーンSQLクエリは次のようになります。
SELECT items.id AS itemId, items.name, itemImages.url AS itemUrl
FROM items
INNER JOIN groups_items ON groups_items.item_id = items.id
INNER JOIN groups ON groups_images.group_id = groups.id
INNER JOIN groups_users ON groups_users.group_id = groups.id
INNER JOIN users ON groups_users.user_id = users.id
INNER JOIN itemImages ON itemImages.item_id = items.id
WHERE groups_users.isMainGroup = 1
AND users.id = :userId
AND itemImages.isMainImage = 1
私が今持っているCakePHPコード:
$items = $this->Items->find()
->hydrate(false)
->contain([
'Groups.Users' => function($q) use ($userId){
return $q->where(['isMainGroup' => 1, 'Users.id' => $userId]);
},
'ItemImages' => function($q){
return $q->where(['isMainImage' => 1]);
},
]);
//->select(['itemId' => 'Items.id', 'Items.name', 'itemUrl' => 'itemImages.url']);
matching()メソッドはこれを助けることができます
$items = $this->Items->find()
->hydrate(false)
->select(['Items.id', 'Items.name', 'itemImages.url'])
->distinct(['Items.id'])
->matching('Groups.Users', function ($q) use ($userId) {
return $q->where(['Groups.isMainGroup' => 1, 'Users.id' => $userId]);
})
->matching('ItemImages', function ($q) {
return $q->where(['ItemImages.isMainImage' => 1]);
})
->contain([
'ItemImages' => function ($q) {
return $q->autoFields(false)
->select(['id','url'])
->where(['ItemImages.isMainImage' => 1]);
}
]);
この場合、目的の結果がすでに_ matchingDataプロパティにあるため、最後のcontainステートメントを省略できると思います。
distict()スタメントに関する注意:
この関数は内部結合を作成するため、条件で行がまだフィルタリングされていない場合は行が重複する可能性があるため、検索クエリでdistinctを呼び出すことを検討することをお勧めします。
http://book.cakephp.org/3.0/en/orm/retrieveing-data-and-resultsets.html#filtering-by-associated-data