symfony2: как использовать group_concat в QueryBuilder
У меня есть вложенный набор (с использованием дерева Gedmo), который называется «Местоположение». У объекта «Appartment» есть location_id и что мне нужно сделать для сопоставления скалярного значения, называемого, например, «path» для запроса, который возвращает все квартиры.
В Doctrine1 у меня был этот код:
/** * Add "path" to each element * * @param Doctrine_Query $query * @param string $separator */ protected function addScalar_path(Doctrine_Query $query, $separator=", ") { $subquery = "k99.root_id=o.root_id AND k99.lft=o.rgt AND k99.leveladdSelect("(SELECT GROUP_CONCAT(k99.name ORDER BY k99.level SEPARATOR '$separator') FROM Location k99 WHERE $subquery) AS path") ; }
Примечание: для первичного запроса используется псевдоним «o». Этот код позволит мне использовать
- Doctrine2 ORM не сохраняет изменения в поле DateTime
- EntityManager закрыт
- Что такое прокси в доктрине 2?
- Есть ли способ указать class реализации Doctrine2 Entitymanager в Symfony2?
- Глубокий клонированный объект Doctrine с связанными объектами
{foreach .... as $appartment} {$appartment->path} ...
Что бы напечатать:
Australia, Victoria, Melbourne, ...other children...
Как сделать то же самое в D2? И как даже включить расширения доктрины в мой проект symfony2?
- Symfony 2: создание службы из репозитория
- Функция Doctrine 2 mysql FIELD в порядке
- Первичный ключ владельца в качестве столбца объединения
- Различия между страtagsями GeneratedValue
- Утечка памяти Symfony2 Doctrine2 / превышение предела памяти
- Загрузка файла Symfony2
- В чем разница между fetch = "EAGER" и fetch = "LAZY" в доктрине
- Использование EntityManager внутри объектов Doctrine 2.0
Если вы хотите использовать его в QueryBuilder, вы должны:
1) добавить функции DQL GroupConcat: GroupConcat
2) Регистрация GroupConcat: Пользовательские функции DQL
Другая альтернатива – использовать NativeQuery: Native SQL
В symfony2, регистрирующем функцию DQL, очень просто добавить GROUP_CONCAT в config.yml, например:
entity_managers: default: dql: string_functions: GROUP_CONCAT: YourBundle\Query\Mysql\GroupConcat
Для получения дополнительной информации посетите раздел «Регистрация пользовательских функций DQL»
Если кто-то наткнется на этот пост, в Github теперь есть repository расширений Doctrine . В репо есть инструкции по его использованию. Вы можете использовать композитор для его установки, а затем использовать любую интересующую вас функцию.
РЕДАКТИРОВАТЬ:
Что касается пользователя Tushar, способ использования GROUP_CONCAT в DQL Doctrine2 – простая установка расширений Doctrine :
composer require beberlei/DoctrineExtensions
Чтобы включить его: добавьте в свой config.yml следующее:
doctrine: orm: dql: string_functions: group_concat: DoctrineExtensions\Query\Mysql\GroupConcat
Затем в вашем коде вы сможете теперь использовать Group Concat в своих DQL:
$this->createQueryBuilder('location') ->select('location') ->addSelect("GROUP_CONCAT(DISTINCT location.name SEPARATOR '; ') AS locationNames"); $result = $queryBuilder->getQuery()->getResult();
Или в случае оригинального вопроса:
$query->addSelect("(SELECT GROUP_CONCAT(k99.name ORDER BY k99.level SEPARATOR '$separator') FROM Location k99 WHERE $subquery) AS path");
Просто добавление к ответу @ a.aitboudad:
Функция DQL, связанная с GroupConcat, по-видимому, имеет «ограниченную поддержку для GROUP_CONCAT».
Вот полная версия поддержки: Конфигурация, как он упоминал.
// ------------------------------------------------- // Complete support of GROUP_CONCAT in Doctrine2 // ------------------------------------------------- // Original Article: http://habrahabr.ru/post/181666/ // Automated translation to English: http://sysmagazine.com/posts/181666/ // Original github commit: https://github.com/denisvmedia/DoctrineExtensions/blob/d1caf21cd7c71cc557e60c26e9bf25323a194dd1/lib/DoctrineExtensions/Query/Mysql/GroupConcat.php /** * DoctrineExtensions Mysql Function Pack * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to [email protected] so I can send you a copy immediately. */ namespace DoctrineExtensions\Query\Mysql; use Doctrine\ORM\Query\AST\Functions\FunctionNode, Doctrine\ORM\Query\Lexer; /** * Full support for: * * GROUP_CONCAT([DISTINCT] expr [,expr ...] * [ORDER BY {unsigned_integer | col_name | expr} * [ASC | DESC] [,col_name ...]] * [SEPARATOR str_val]) * */ class GroupConcat extends FunctionNode { public $isDistinct = false; public $pathExp = null; public $separator = null; public $orderBy = null; public function parse(\Doctrine\ORM\Query\Parser $parser) { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); $lexer = $parser->getLexer(); if ($lexer->isNextToken(Lexer::T_DISTINCT)) { $parser->match(Lexer::T_DISTINCT); $this->isDistinct = true; } // first Path Expression is mandatory $this->pathExp = array(); $this->pathExp[] = $parser->SingleValuedPathExpression(); while ($lexer->isNextToken(Lexer::T_COMMA)) { $parser->match(Lexer::T_COMMA); $this->pathExp[] = $parser->StringPrimary(); } if ($lexer->isNextToken(Lexer::T_ORDER)) { $this->orderBy = $parser->OrderByClause(); } if ($lexer->isNextToken(Lexer::T_IDENTIFIER)) { if (strtolower($lexer->lookahead['value']) !== 'separator') { $parser->syntaxError('separator'); } $parser->match(Lexer::T_IDENTIFIER); $this->separator = $parser->StringPrimary(); } $parser->match(Lexer::T_CLOSE_PARENTHESIS); } public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) { $result = 'GROUP_CONCAT(' . ($this->isDistinct ? 'DISTINCT ' : ''); $fields = array(); foreach ($this->pathExp as $pathExp) { $fields[] = $pathExp->dispatch($sqlWalker); } $result .= sprintf('%s', implode(', ', $fields)); if ($this->orderBy) { $result .= ' ' . $sqlWalker->walkOrderByClause($this->orderBy); } if ($this->separator) { $result .= ' SEPARATOR ' . $sqlWalker->walkStringPrimary($this->separator); } $result .= ')'; return $result; } } // ------------------------------------------------- // Example of usage: // ------------------------------------------------- $query = $this->createQueryBuilder('c') ->select(" c as company, GroupConcat(b.id, ';', b.headOffice, ';', b.city, ';', s.name ORDER by b.id SEPARATOR '|') AS branches ")->leftJoin('c.branches', 'b') ->leftJoin('b.country', 's') ->groupBy('c.id') ->setFirstResult(0) ->setMaxResults(10) ->getQuery(); $result = $query->getResult();
У меня была схожая проблема. GROUP_CONCAT не позволяет использовать CASE-WHEN внутри. Эта библиотека исправила мои проблемы, так что, возможно, это будет полезно.