Допустим, у меня есть таблица, в которой содержится информация о фестивалях.
Каждый фестиваль имеет дату начала и окончания.
Я хочу выбрать все праздники, которые являются живыми (что происходит) на определенную дату.
Смысл, я хочу выбрать все фестивали, которые их дата начала будет до или в заданную дату, и что их конечная дата будет после или в ту же дату.
Поэтому я перешел к классу репозитория объекта фестиваля и создал метод для этого.
Но аргумент критериев «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 () содержат структуру, как в первом примере кода.
Если вы считаете, что решение будет работать для вас, позвольте мне предложить две библиотеки, которые вы можете установить через композитор: