part_os
@part_os
Сложное в простом

Фильтрация по большому количеству параметров QueryBuilder, какие есть варианты?

Всем привет, имеем "супер сущность" в приложении с которой все связано - CoreEntity и её CoreEntityRepository, в котором есть метод на получение этой сущности с большим количеством параметров и innerJoin, leftJoin и большим количеством if(isset($option['nameOption]),
Есть ли какой то паттерн для избавления от этого, или какие то идеи?
public function findCoreEntity(array $options): array
{
 /** @var EntityRepository $repository */
        $repository = $this->entityManager->getRepository(CoreEntity::class);
        $queryBuilder = $repository->createQueryBuilder('c, 'c.id')
            ->innerJoin('c.firstEntity', 'f')
            ->innerJoin('c.secondEntity', 's')
            ->where('1 = 1');

        if (!empty($options['firstEntityID'])) {
            $queryBuilder->andWhere('f.id = :FIRST_ID')
                ->setParameter(':FIRST_ID', $options['firstEntityID']);
        }

       if (!empty($options['N+1EntityOption'])) {
            $queryBuilder->andWhere('n+1.id  IB (:N+1EntityOption)' )
                ->setParameter(':N+1EntityOption'', $options['N+1EntityOption'']);
        }

      if (PRICE::FILTER_PRICE_TYPE) {
            $queryBuilder
                ->innerJoin('c.prices', 'pp' , 'WITH', 'pp.type = :PRICE_TYPE')
                ->setParameter(':PRICE_TYPE', $type);

      }
}
  • Вопрос задан
  • 138 просмотров
Решения вопроса 1
part_os
@part_os Автор вопроса
Сложное в простом
Сделал примерно как Илья Зябиров описал

interface PropertyQueryOptionsInterface
{

    /**
     * @param array $attribute
     */
    public function fill(array $attribute): void;

    /**
     * @param QueryBuilder $queryBuilder
     */
    public function addWhere(QueryBuilder $queryBuilder): void;
}


class RangePropertyPriceOption implements PropertyQueryOptionsInterface
{

    public const TYPE = 'RangePropertyPriceOption';

    /**
     * @var string
     */
    protected $alias;

    /**
     * @var float
     */
    protected $min = null;

    /**
     * @var float
     */
    protected $max = null;

    /**
     * @param array $attribute
     */
    public function fill(array $attribute): void
    {

        if (isset($attribute['key'])) {
            $this->alias = $attribute['key'];
        }

        if (isset($attribute['value'])) {

            if (isset($attribute['value'][0])) {
                $this->min = $attribute['value'][0];
            }

            if (isset($attribute['value'][1]) && $attribute['value'][1] != 0) {
                $this->max = $attribute['value'][1];
            }
        }

    }

    public function addWhere(QueryBuilder $queryBuilder): void
    {

        $whereByValue = $this->alias === Property::FILTER_RANGE_PRICE ? 'price' : 'areaPrice';

        if (!is_null($this->min)) {

            $whereParameter = ':' . 'min_' . $whereByValue;

            $queryBuilder
                ->andWhere(sprintf('p.%s >= %s', $whereByValue, $whereParameter))
                ->setParameter($whereParameter, $this->min);
        }

        if (!is_null($this->max) && $this->max != 0) {

            $whereParameter = ':' . 'max_' . $whereByValue;

            $queryBuilder
                ->andWhere(sprintf('p.%s <= %s', $whereByValue, $whereParameter))
                ->setParameter($whereParameter, $this->max);
        }
    }
}


foreach ($options['propertyQueryOptions'] as $queryOption) {

                if ($queryOption instanceof PropertyQueryOptionsInterface) {
                    $queryOption->addWhere($queryBuilder);
                }

            }
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
Maksclub
@Maksclub
maksfedorov.ru
Doctrine Specification Pattern
или ваш реюзабельный QueryBuilder

Еще есть фильтры (но они так себе): Doctrine Filters
Ответ написан
Комментировать
passionkillah
@passionkillah
Backend-разработчик
Можно сделать интерфейс для фильтров и реализовывать его для каждого конкретного фильтра. В нем будут методы для получения алиаса (для того, чтобы превратить массив фильтров из запроса в массив классов), установления значения фильтра, а также добавления условия в queryBuilder. Получая из запроса массив фильтров, собираем массив классов, реализующих этот интерфейс (можно, кстати, сделать коллекцию, но это по желанию) и в репозитории проходимся по нему циклом и для каждого элемента вызываем метод, который добавляет условия к текущему queryBuilder'у.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы