Cakephp 3 — поиск подзапроса ownToMany

У меня есть таблица продуктов, относящаяся ко многим тегам и категориям. Теги и категории также принадлежат продуктам ToMany.

Я пытаюсь реализовать функцию поиска, которая будет включать любые продукты, параметры поиска которых соответствуют продуктам с тегами, продуктам по категориям, а также названию или описанию любого продукта.

Это то, что у меня есть в моем контроллере:

public function index()
{
    $this->paginate = [
        'sortWhitelist' => [
            'Products.title',
            'Products.msrp',
            'Products.sale_price',
        ],
        'limit'   => 48,
        'order'   => ['Products.title' => 'asc']
    ];
    $products = $this->Products->find();
    if ($search = $this->request->query('search')) {
        $matchingCategories = $this->Products->find()->matching('Categories', function ($q) use ($search) {
            return $q->where(['Categories.name LIKE' => "%$search%"]);
        });
        $matchingTags = $this->Products->find()->matching('Tags', function ($q) use ($search) {
            return $q->where(['Tags.name LIKE' => "%$search%"]);
        });
        $products
            ->where(['Products.title LIKE' => "%$search%"])
            ->orWhere(['Products.description LIKE' => "%$search%"])
            ->orWhere(['Products.id IN' => $matchingCategories])
            ->orWhere(['Products.id IN' => $matchingTags]);
    }

    $this->set('products', $this->paginate($products));
    $this->set('_serialize', ['products']);
}

Вы можете видеть, чего я пытаюсь добиться здесь, но это явно не работает. Я могу заставить любую 1 часть уравнения работать, то есть я могу получить продукты с соответствующими категориями, или продукты с соответствующими тегами, или продукты с совпадениями в их заголовке или описании, но я не могу получить все продукты, которые подходят для поиска в любой из этих частей.


person Battousai    schedule 14.01.2017    source источник


Ответы (1)


Похоже, все, что мне нужно было сделать, это выбрать только поле id в подзапросах следующим образом:

$matchingCategories = $this->Products->find()->select(['Products.id'])->matching('Categories', function ($q) use ($search) {
    return $q->where(['Categories.name LIKE' => "%$search%"]);
});

ПРИМЕЧАНИЕ. Я открыт для предложений по улучшению.

person Battousai    schedule 14.01.2017
comment
Что ж, здесь не так уж много вариантов ... другой вариант - левое соединение Categories и Tags и добавление условий LIKE на уровне Products. Может дать вам лучшую производительность, может дать вам худшую, как почти всегда с SQL, это зависит. Немного другим вариантом было бы использование EXISTS вместо IN — опять же, производительность может быть лучше, может быть хуже. - person ndm; 14.01.2017
comment
@ndm Спасибо за комментарий. Я поиграю с ним, чтобы увидеть, смогу ли я добиться лучшей производительности. - person Battousai; 14.01.2017