Где инструкции не добавляются

#doctrine #doctrine-orm

#доктрина #доктрина-orm

Вопрос:

Я пытаюсь создать запрос динамически. Это начальное состояние в порядке. Это начальное предложение where, которое должно присутствовать в каждом запросе

 $qb->add('where', $qb->expr()->andx(
    $qb->expr()->eq('s.competitor', $competitor),
    $qb->expr()->eq('s.ignored', $ignored),
    $qb->expr()->eq('s.id', $params['s_id']),
    $qb->expr()->eq('s.id', 'k.targetSite')
), true);
  

Но приложение, которое я создаю, позволяет пользователям фильтровать. Когда это произойдет, я хочу добавить дополнительные предложения where в мой конструктор запросов. Когда эта строка выполняется позже в коде, она перезаписывает приведенный выше оператор where .

 $qb->add('where',  $qb->expr()->like($col, $val), true );
  

Из того, что я прочитал, 3-й параметр $append должен сохранять предыдущие инструкции, но этого не происходит. В Doctrine 1.2 я мог бы просто сделать что-то вроде этого:

 foreach($filter as $col => $val) {
    $dql->addWhere($col = ?, array($val));
}
  

Как мне динамически добавлять предложения where в мой QueryBuilder?

Обновить

Вот полное утверждение

 $where = array('col' => 'k.text', 'val' => 'some word%');

$qb = $this->entityManager->createQueryBuilder()
    ->select('s, sc')
    ->from('DashboardEntitySection', 'sc')
    ->innerJoin('sc.keyword', 'k')
    ->innerJoin('sc.site', 's')
    ->leftJoin('k.keywordCategory', 'kc')
    ->leftJoin('k.keywordSubCategory', 'ksc');

$qb->add('where', $qb->expr()->andx(
    $qb->expr()->eq('s.competitor', $competitor),
    $qb->expr()->eq('s.ignored', $ignored),
    $qb->expr()->eq('s.id', $params['s_id']),
    $qb->expr()->eq('s.id', 'k.targetSite')
), true);

if ($where) {
    $qb->add('where', $qb->expr()->andx(
             $qb->expr()->like($where['col'], $where['val'])
    ), true);
}

$qb->addGroupBy('k.id');
    $qb->addGroupBy('s.id');

$qb->setFirstResult( $params['start'] )
   ->setMaxResults( $params['limit'] );

$q = $qb->getQuery();
echo $q->getSql();
  

И вывод таков

 SELECT s0_.id AS id0, k1_.id AS id1, k1_.name AS name2, k2_.id AS id3, k2_.name AS   name4, k3_.id AS id5, k3_.text AS text6, k3_.search_vol AS search_vol7, s4_.id AS id8, s4_.sub_domain AS sub_domain9, MIN(s0_.rank) AS sclr10, MAX(s0_.created) AS sclr11 
FROM section s0_ 
INNER JOIN keyword k3_ ON s0_.k_id = k3_.id 
INNER JOIN site s4_ ON s0_.s_id = s4_.id 
LEFT JOIN keyword_category k1_ ON k3_.k_cat_id = k1_.id 
LEFT JOIN keyword_sub_category k2_ ON k3_.k_subcat_id = k2_.id 
WHERE k3_.text LIKE 'some word%' 
GROUP BY k3_.id, s4_.id LIMIT 25 OFFSET 0
  

Если я не добавлю в это if ($where) предложение, то первые andx инструкции where все еще будут на месте. Но когда я пытаюсь динамически добавлять их, добавляется только последний оператор WHERE, все остальные удаляются. Я должен также добавить, что я тоже пробовал это так.

 if ($where) {
    $qb->add('where', $qb->expr()->like($where['col'], $where['val']), true);
}
  

Я могу успешно использовать

 $qb->andWhere( $qb->expr()->like($where['col'], $where['val']) );
  

Но в документах API для Query Builder указано, что способ, которым я пытаюсь его использовать, также должен быть действительным. Хотел убедиться, что я все делаю правильно, или это ошибка.

Комментарии:

1. Можете ли вы вставить сгенерированный оператор DQL сюда с примером фильтра?

2. Я добавил полную инструкцию, с которой я работаю.

Ответ №1:

Вы можете использовать -> andWhere () в обычном режиме (и это также устранит вашу проблему).

Doctrine 2 QueryBuilder — довольно инновационная концепция (поскольку в ней сочетаются как программный, так и свободный стили), и с ней, вероятно, связаны ошибки.

Один момент, на который вы должны обратить внимание в своем коде: вместо того, чтобы играть с -> add(‘where’, …), вы должны думать программно. Добавьте больше элементов в объект AndX() и в конце свяжите с -> add(‘where’, …) (или даже лучше: -> where(…))

Ответ №2:

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

В add() переданная вами часть DQL, похоже, добавляется только в том случае, если эта часть уже сохранена в виде массива в построителе запросов:

    $isMultiple = is_array($this->_dqlParts[$dqlPartName]);
   ...

    if ($append amp;amp; $isMultiple) {
        if (is_array($dqlPart)) {
            $key = key($dqlPart);

            $this->_dqlParts[$dqlPartName][$key][] = $dqlPart[$key];
        } else {
            $this->_dqlParts[$dqlPartName][] = $dqlPart;
        }
    } else {
        $this->_dqlParts[$dqlPartName] = ($isMultiple) ? array($dqlPart) : $dqlPart;
    }
  

И предложение WHERE, в отличие от большинства других частей DQL, не инициализируется массивом:

 private $_dqlParts = array(
    'select'  => array(),
    'from'    => array(),
    'join'    => array(),
    'set'     => array(),
    'where'   => null,
    'groupBy' => array(),
    'having'  => null,
    'orderBy' => array()
);
  

Теперь это немного похоже на то, что так задумано, но Doctrine 2 довольно новая, и эта часть, похоже, развивалась в последнее время. Лично я бы поднял проблему с этим поведением и посмотрел, что говорят люди из проекта. Если ничего другого, вы могли бы в конечном итоге получить улучшенную документацию…