Проверьте, содержит ли массив какой-либо элемент другого массива в построителе запросов доктрины.

Я хотел бы знать, можно ли проверить, содержит ли массив какой-либо элемент другого массива в построителе запросов доктрины.

В моем случае я хочу получить все продукты (предметы), у которых есть хотя бы одна категория в массиве, переданном в параметре.

Связь между товаром и категорией:

/**
 *  @ORM\ManyToMany(targetEntity="Category")
 *  @ORM\JoinTable(name="items_categories",
 *      joinColumns={@ORM\JoinColumn(name="item_id", referencedColumnName="id", nullable=false)},
 *      inverseJoinColumns={@ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=false)}
 *      )
 */
private $categories;

Моя первая попытка из репозитория предметов (я знаю, что это работает, если у меня есть только одно значение для проверки):

public function getListItemsFromCatList($listCat) {
    $qb = $this->createQueryBuilder('i');

    $qb->select('i')
            ->where($qb->expr()->like('i.categories', ':listCat'))
            ->setParameter('listCat', '%"' . $listCat . '"%');

    return $qb->getQuery()->getResult();
}

$listCat — это массив объектов категории:

array (size=5)
  0 => 
    object(ItemBundle\Entity\Category)[518]
      private 'id' => int 22
      private 'children' => 
        object(Doctrine\ORM\PersistentCollection)[520]
          private 'snapshot' => 
            array (size=2)
              ...
          private 'owner' => 
            &object(ItemBundle\Entity\Category)[518]
          private 'association' => 
            array (size=15)
              ...
          private 'em' => 
            object(Doctrine\ORM\EntityManager)[796]
              ...
          private 'backRefFieldName' => string 'parent' (length=6)
          private 'typeClass' => 
            object(Doctrine\ORM\Mapping\ClassMetadata)[579]
              ...
          private 'isDirty' => boolean false
          protected 'collection' => 
            object(Doctrine\Common\Collections\ArrayCollection)[515]
              ...
          protected 'initialized' => boolean true
      private 'parent' => null
      private 'name' => string 'Luxe' (length=4)
  1 => 
    object(ItemBundle\Entity\Category)[504]
      private 'id' => int 25
      private 'children' => 
        object(Doctrine\ORM\PersistentCollection)[505]
          private 'snapshot' => 
            array (size=0)
              ...
          private 'owner' => 
            &object(ItemBundle\Entity\Category)[504]
          private 'association' => 
            array (size=15)
              ...
          private 'em' => 
            object(Doctrine\ORM\EntityManager)[796]
              ...
          private 'backRefFieldName' => string 'parent' (length=6)
          private 'typeClass' => 
            object(Doctrine\ORM\Mapping\ClassMetadata)[579]
              ...
          private 'isDirty' => boolean false
          protected 'collection' => 
            object(Doctrine\Common\Collections\ArrayCollection)[500]
              ...
          protected 'initialized' => boolean false
      private 'parent' => 
        object(ItemBundle\Entity\Category)[512]
          private 'id' => int 23
          private 'children' => 
            object(Doctrine\ORM\PersistentCollection)[513]
              ...
          private 'parent' => 
            object(ItemBundle\Entity\Category)[518]
              ...
          private 'name' => string 'Bijoux' (length=6)
      private 'name' => string 'Bagues' (length=6)

person LedZelkin    schedule 16.01.2017    source источник
comment
См. мое редактирование № 2, которое, я думаю, может сработать.   -  person Alvin Bunk    schedule 17.01.2017


Ответы (2)


Я бы решил это, добавив соединение.

public function getListItemsFromCatList($listCat) {

    $em = $this->getDoctrine()->getManager();

    $qb = $em->createQueryBuilder();
    $qb->select('i')           
        ->from('AppBundle:Item', 'i')
        ->innerJoin('i.categories','cat')
        ->where('cat IN (:listCat)')
       ->setParameter('listCat', $listCat);

    return  = $qb->getQuery()->getResult();
}

Обратите внимание, что этот подход будет фильтровать категории внутри элементов. Это означает, что когда вы пытаетесь получить категории из данного элемента i, $i->getCategories(), будут возвращены только те категории из i, которые соответствуют $listCat.

Если вам нужно будет использовать все категории из каждого элемента, даже те, которые не соответствуют $listCat. Я рекомендую вам использовать подзапросы для фильтрации и основной запрос для возврата полных элементов. Оставьте комментарий, если вам нужна дополнительная помощь в этом.

person Vinícius Fagundes    schedule 17.01.2017
comment
В моем случае просто иметь категорию, которая соответствует $listCat, все в порядке. Так что спасибо за этот ответ - person LedZelkin; 17.01.2017

Вместо этого попробуйте использовать построитель запросов следующим образом:

$em = $this->getDoctrine()->getManager();
$qb = $em->createQueryBuilder();
$qb->select('i')
    ->from('AppBundle:Item', 'i')
    ->where('i.categories LIKE :listCat')
    ->setParameter('listCat', '%"' . $listCat . '"%');

return  = $qb->getQuery()->getResult();

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

РЕДАКТИРОВАНИЕ № 2 — на основе комментариев

Вам нужно перебрать массив и получить имя (я думаю), которое, я думаю, является категорией, которую вы ищете. В этом коде я показываю создание в цикле переменной $cats, а затем ее использование в запросе IN.

foreach ($listCat as $item){
    $cats = $cats . "'" . $item.getName() . "'".',';
}
$cats = substr($cats, -1);


$em = $this->getDoctrine()->getManager();
$qb = $em->createQueryBuilder();
$qb->select('i')
    ->from('AppBundle:Item', 'i')
    ->where("i.categories IN (:listCat)")
    ->setParameter('listCat', $cats);

return  = $qb->getQuery()->getResult();

Можешь попробовать? Я думаю, вам нужно что-то вроде этого.

person Alvin Bunk    schedule 16.01.2017
comment
Это то же самое, что и мой тест. Для информации: $listcat — это массив объектов категории. Так что это не может работать (я только что попробовал, и я получаю следующую ошибку: Примечание: преобразование массива в строку) - person LedZelkin; 17.01.2017
comment
Является ли $listCat массивом? - person Alvin Bunk; 17.01.2017
comment
Пожалуйста, покажите пример того, что содержит $listCat. Может быть, вы можете использовать IN вместо этого? - person Alvin Bunk; 17.01.2017
comment
Готово, но я не думаю, что это сработает, потому что i.categories тоже коллекция. Было бы здорово иметь поведение на этом опубликовать - person LedZelkin; 17.01.2017
comment
Я получаю эту ошибку: [Semantical Error] line 0, col 47 near 'categories IN': Error: Invalid PathExpression. StateFieldPathExpression or SingleValuedAssociationField expected. Я думаю, что это нормально, потому что предложение IN ожидает только одно значение с левой стороны (i.categories) - person LedZelkin; 17.01.2017
comment
Пока $cats содержит правильный формат, он должен работать. Я отредактировал, чтобы включить одинарные кавычки вокруг строк. Кроме того, я вижу, что вы можете напрямую использовать массив. Мой ответ должен работать независимо. Пожалуйста, найдите время, чтобы устранить неполадки, прежде чем публиковать дальнейшие комментарии. - person Alvin Bunk; 17.01.2017
comment
Спасибо за помощь, но, как я уже говорил, у меня все еще та же ошибка, и это кажется логичным. - person LedZelkin; 17.01.2017
comment
Я только что сделал проверку этой ошибки , и я думаю, вам нужно добавить IDENTITY(i.id) или любой другой составной ключ. Возможно, вы захотите расследовать это. Извините, я не мог помочь больше. - person Alvin Bunk; 17.01.2017