Full GROUP_CONCAT support in Doctrine2
Hello to all.
It so happened that in the project I'm working on now, it was required to use the GROUP_CONCAT () function. Unfortunately, Doctrine2 out of the box does not support this feature. The existing extension from one of the Doctrine2 developers (Benjamin Eberlei) is listed as “limited support for GROUP_CONCAT”. I understand that using this function automatically makes the project dependent on MySQL, but it is not planned to change the DBMS as gloves. So let's leave this question outside the scope of the post.
Since I did not find a ready-made solution by googling, I decided to write it myself (taking Benjamin's development as a basis). There is nothing special to comment on, so I just submit it to the public for trial:
Usage example:
White papers:
Registering a custom DQL function in Doctrine2 .
How to connect to custom DQL functions in Symfony2 .
Description of the MySQL function GROUP_CONCAT .
It so happened that in the project I'm working on now, it was required to use the GROUP_CONCAT () function. Unfortunately, Doctrine2 out of the box does not support this feature. The existing extension from one of the Doctrine2 developers (Benjamin Eberlei) is listed as “limited support for GROUP_CONCAT”. I understand that using this function automatically makes the project dependent on MySQL, but it is not planned to change the DBMS as gloves. So let's leave this question outside the scope of the post.
Since I did not find a ready-made solution by googling, I decided to write it myself (taking Benjamin's development as a basis). There is nothing special to comment on, so I just submit it to the public for trial:
/**
* 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 kontakt@beberlei.de so I can send you a copy immediately.
*/namespaceDoctrineExtensions\Query\Mysql;
useDoctrine\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])
*
*/classGroupConcatextendsFunctionNode{
public $isDistinct = false;
public $pathExp = null;
public $separator = null;
public $orderBy = null;
publicfunctionparse(\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);
}
publicfunctiongetSql(\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;
}
}
Usage example:
$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();
White papers:
Registering a custom DQL function in Doctrine2 .
How to connect to custom DQL functions in Symfony2 .
Description of the MySQL function GROUP_CONCAT .