#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 довольно новая, и эта часть, похоже, развивалась в последнее время. Лично я бы поднял проблему с этим поведением и посмотрел, что говорят люди из проекта. Если ничего другого, вы могли бы в конечном итоге получить улучшенную документацию…