Подтвердить что ты не робот

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

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

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

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

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

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

и т.д.?

Спасибо

4b9b3361

Ответ 1

Вам нужно будет написать свой собственный запрос (возможно, используя 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();
}

Ответ 2

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

Пример Джереми Хикса может быть написан следующим образом (обратите внимание, что это возвращает 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);
}

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

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

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

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

Ответ 3

Это не ответ на вопрос Дорона У доктрины есть репозиторий сущности, который не делает нас с использованием запроса вообще...

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

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

Ответ 4

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

Я нашел блог-блог Бенджамин Эберлей, который имеет интересное решение этой проблемы на основе шаблон спецификации.

Это дает вам возможность отложить манипулирование объектом 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() содержат структуру, как в первом примере кода.

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