Как использовать сложные критерии внутри репозитория доктрины 2?

Допустим, у меня есть таблица, в которой содержится информация о фестивалях.
Каждый фестиваль имеет дату начала и окончания.

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

Поэтому я перешел к классу репозитория объекта фестиваля и создал метод для этого.
Но аргумент критериев «findBy» ожидает массив, который все примеры рассматривают только как простой критерий (например, «array» («name» => «billy») »выберет все строки, у которых есть значение billy в их столбец имен), в котором используется только оператор сравнения.

Как использовать другие операторы, такие как

>, <, !=, IN, NOT IN, LIKE 

и так далее. ?

благодаря

Вам нужно будет написать свой собственный запрос (возможно, используя DQL), если вы хотите что-то конкретное. Я считаю, что встроенные методы «findBy» больше подходят для быстрого захвата объектов, если у вас есть менее конкретные критерии. Я не знаю ваших имен сущностей или где они хранятся. Может быть что-то вроде этого как функция в вашем репозитории фестиваля.

 public function findActiveFestivals($start, $end) { $qb = $this->_em->createQueryBuilder(); $qb->select('f') ->from('Festival', 'f') ->where('f.start >= :start') ->andWhere('f.end <= :end') ->setParameters(array('start' => $start, 'end' => $end)); return $qb->getQuery()->getArrayResult(); } 

В Doctrine 2.3 добавлен метод matching (), который позволяет использовать критерии .

Пример Джереми Хикса может быть написан так (обратите внимание, что это возвращает ArrayCollection вместо массива).

 public function findActiveFestivals($start, $end) { $expr = Criteria::expr(); $criteria = Criteria::create(); $criteria->where($expr->gte('start', $start)); $criteria->andWhere($expr->lte('end', $end); return $this->matching($criteria); } 

Лично я бы не использовал andWhere здесь и использовал еще несколько строк для улучшения читаемости, например:

 public function findActiveFestivals($start, $end) { $expr = Criteria::expr(); $criteria = Criteria::create(); $criteria->where( $expr->andX( $expr->gte('start', $start), $expr->lte('end', $end) ) ); return $this->matching($criteria); } и public function findActiveFestivals($start, $end) { $expr = Criteria::expr(); $criteria = Criteria::create(); $criteria->where( $expr->andX( $expr->gte('start', $start), $expr->lte('end', $end) ) ); return $this->matching($criteria); } 

Использование предложения IN очень просто.

 public function findFestivalsByIds($ids) { $expr = Criteria::expr(); $criteria = Criteria::create(); $criteria->where($expr->in('id', $ids)); return $this->matching($criteria); } 

Класс Criteria находится в пространстве имен Doctrine's not-really-ORM-or-DBAL Common, например, их ArrayCollection (который поддерживает критерии дольше, чем EntityRepository).

Его целью является развязанный способ создания не-репозитарного кода для создания сложных критериев. Поэтому должно быть хорошо использовать этот класс вне репозитория. QueryBuilder также поддерживает критерии . Поэтому даже при построении более сложных запросов, требующих QueryBuilder, вы можете использовать критерии, чтобы обеспечить гибкость кода, отличного от базы данных, в том, что он запрашивает.

это не ответ на дон-вопрос Дорона, у которого есть репозиторий сущности, который не заставляет нас использовать запрос вообще …

 $this->em->getRepository($this->entity)->findBy(array $criteria); 

но что он спросил, как сложный оператор в массиве $ критериев. Обычный формат массива $criteria – это array('field'=> $value);

У меня была такая же проблема некоторое время назад, когда мои репозитории Doctrine стали очень уродливыми из-за сложных запросов. Мне также пришлось преобразовать Yii ActiveRecord (с объектами Criteria) в Doctrine, а у Doctrine не было объектов Criteria в то время.

Я нашел blogpost от Benjamin Eberlei, у которого есть интересное решение этой проблемы на основе шаблона спецификации .

Это дает вам возможность отложить манипулирование объектом Query Builder с другими классами.

 $spec = new AndX( new Equals('ended', 0), new OrX( new LowerThan('endDate', new \DateTime()), new AndX( new IsNull('endDate'), new LowerThan('startDate', new \DateTime('-4weeks')) ) ) ); return $this->em->getRepository('Advertisement')->match($spec)->execute() 

Кроме того, вы можете составить 2 или более классов вместе, что создает красивые многократные элементы:

 public function myQuery(User $user) { $spec = new AndX( new ExpiredAds(), new AdsByUser($user) ); return $this->em->getRepository('Advertisement')->match($spec)->execute(); } 

В этом случае ExpiredAds () и AdsByUser () содержат структуру, как в первом примере кода.

Если вы считаете, что решение будет работать для вас, позвольте мне предложить две библиотеки, которые вы можете установить через композитор:

  • Happyr \ Doctrine-Спецификация
  • RikBruil \ Doctrine-Спецификация (отказ от ответственности: я автор этого)