Доктрина ORM многие-ко-многим найти все по taglist - PullRequest
0 голосов

Я получил простое отношение m2m (book -> book_mark <- mark). Я хочу найти предмет (книгу) по 1-2-3 ... х-меток (меток). Пример: Book1 получил эти теги: [Mark1, Mark2, Mark3], Book2 получил эти теги: [Mark1, Mark3, Mark4]. Список поиска [Mark1, Mark2]. Я хочу найти только элементы, которые имеют ВСЕ теги из списка поиска, т.е. только Book1 в этом примере. </p>

Я пробовал много способов и провел много времени в Google, но не нашел ответа.

Самое близкое, что у меня есть, это:

    return $this->createQueryBuilder('b')
    ->select('b, m')
    ->leftJoin('b.marks_list', 'm')
    ->andWhere(':marks_list MEMBER OF b.marks_list')
    ->setParameter('marks_list', $marksList)
    ->getQuery()->getArrayResult();

Но он ищет книги, у которых есть хотя бы 1 из параметров, а не все вместе

Затем я решил, что я абсолютно неправ, и начал думать так:

 public function findAllByMarksList(array $marksList)
    {
        $qb = $this->createQueryBuilder('b')
            ->select('b, m')
            ->leftJoin('b.marks_list', 'm');
        for ($i = 0; $i<count($marksList); $i++){
            $qb->andWhere('m.id in (:mark'.$i.')')
                ->setParameter('mark'.$i, $marksList[$i]);
        }
        return $qb->getQuery()->getArrayResult();
    }

Но здесь я столкнулся с другой проблемой: этот код проверяет только 1 отметку, а затем всегда возвращает пустой набор, если число параметров больше 1. С наилучшими пожеланиями.

1 Ответ

0 голосов
/ 02 мая 2018

Итак, обновленный ответ ... Это работает (я имею отношение многих ко многим между обзорами и брендами), это та же самая ситуация, но, например, если у вас есть

Книга 1 - mark1, mark2, mark3

Книга 2 - mark1, mark2, mark3, mark4

с этим кодом вы также найдете book2, потому что все эти отметки находятся в этом списке.

Если вам нужно найти книгу, в которой есть только эти 3 тега, вам необходимо добавить проверку на счетчик. (Количество тегов = количество тегов)

    public function test()
{
    // just selecting for list for test

    $brandsList = $this->_em->createQueryBuilder()
        ->select('b')
        ->from('ReviewsAdminBundle:Brands', 'b')
        ->where('b.id in (:brandIds)')
        ->setParameter('brandIds', [6,4])
        ->getQuery()
        ->getResult();
    dump($brandsList);

    // query part

    $qb = $this->createQueryBuilder('r')
        ->select('r')
        ->leftJoin('r.brand', 'brands')
        ->where('r.published = 1');

    foreach ($brandsList as $oneBrand) {
        /** @var Brands $oneBrand */
        $identifier = $oneBrand->getId();
        $qb->andWhere(':brand'.$identifier.' MEMBER OF r.brand')
            ->setParameter('brand'.$identifier, $identifier);
    }

    dump($qb->getQuery()->getResult());
    die;
}

пс. Кроме того, вы можете проверить, что doctrine2 queryBuilder должен возвращать только результаты, совпадающие со значениями массива (идентификаторами): 0 / Null и / или One и / или многие идентификаторы должны возвращать один результат (близко к нашей ситуации)

И, я думаю, нет лучшего способа сделать это. Либо вы используете несколько andWhere для сравнения идентификатора, либо используйте MEMBER OF

...