Вопрос по symfony, doctrine-orm – symfony2: как использовать group_concat в QueryBuilder

19

У меня есть объект с вложенным множеством (с использованием дерева Gedmo), который называется "Location". Сущность "Квартира" имеет location_id и что мне нужно сделать, чтобы отобразить скалярное значение, например, "путь" quot; на запрос, который возвращает все квартиры.

В 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.lft AND k99.rgt>=o.rgt AND k99.level<=o.level" ;

    $query->addSelect("(SELECT GROUP_CONCAT(k99.name ORDER BY k99.level SEPARATOR '$separator') FROM Location k99 WHERE $subquery) AS path") ;
}

Примечание: & quot; o & quot; псевдоним используется для основного запроса. Этот код позволит мне использовать

{foreach .... as $appartment}
   {$appartment->path}
...

Который напечатал бы:

Australia, Victoria, Melbourne, ...other children...

Как сделать то же самое в D2? И как вообще включить расширения доктрины в мой проект symfony2?

Возможный дубликатsymfony2: Using group_concat in QueryBuilder(Doctrine) j0k

Ваш Ответ

4   ответа
30

Если вы хотите использовать его в QueryBuilder, вы должны:

1) добавить функции DQL GroupConcat:GroupConcat

2) Регистрация GroupConcat:Пользовательские функции DQL

другая альтернатива - использовать NativeQuery:Родной SQL


В symfony2 зарегистрировать функцию DQL очень просто, просто добавьте GROUP_CONCAT в config.yml, например:

    entity_managers:
        default:
            dql:
                string_functions:
                    GROUP_CONCAT: YourBundle\Query\Mysql\GroupConcat

Для получения дополнительной информации посетитеРегистрация пользовательских функций DQL

Решение о добавлении GroupConcat и регистрации работало как шарм. Если вы используете ORM (по умолчанию), config.yml выглядит следующим образом: doctrine & gt; orm & gt; dql & gt; string_functions & gt; GROUP_CONCAT
Я ОЧЕНЬ опытный пользователь Doctrine1, но D2 убивает меня. Есть ли пример кода для того, что мне нужно? Мне также нужен QB вместо NativeQuery. И как мне вообще зарегистрировать GroupConcat в проекте Symfony2? Zeljko
+1 для родного SQL. Кроме того, это немного тяжело для неопытных доктринеров, и это все еще лучшее решение ...
Смотрите выше, я добавил способ регистрации Group_Concat в Symfony2, но для Native Query вы можете посмотреть официальный пример,
Я попробовал то, что вы сказали о режиме NativeSql, я уже использовал этот метод раньше, но теперь тот же запрос, который работает непосредственно в phpmyadmin, возвращает пустой массив из запроса Native SQL доктрины ... SELECT GROUP_CONCAT (id) FROM Products GROUP BY категория, линия, тип
6

Просто дополнение к ответу @ a.aitboudad:
 Похоже, что связанная с DQL функция GroupConcat имеет ограниченную поддержку GROUP_CONCAT & # xBB ;.
Here is the full support version : The configuration is as he mentioned.

// -------------------------------------------------
// 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();
@StepanYudin: фактически упоминается во 2-й строке: "Оригинальная статья:habrahabr.ru/post/181666& Quot;
это самый ужасный способ использовать функции mysql в запросе. почему doctrine2 ограничил использование функций mysql напрямую.
Проверьте комментарий Дениса В. Авторское право отсутствует
Они украли эту функцию, которую я написал сам, пожалуйста, измените кредит на эту:habrahabr.ru/post/181666 (sysmagazine.com, кажется, сделал автоматический перевод моей статьи).
16

Если кто-нибудь сталкивался с этим сообщением, теперьРасширения доктрины хранилище в Github. В репо есть инструкции по его использованию. Вы можете использовать composer для его установки, а затем использовать любую функцию, которая вас интересует.

EDIT:

Ради пользователя Tushar, способ использования GROUP_CONCAT в DQL Doctrine2 прост в установке.Расширения доктрины:

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");
0

У меня была похожая проблема. GROUP_CONCAT не позволяет использовать CASE-WHEN внутри. Эта библиотека исправил мои проблемы, так что, возможно, это будет полезно.

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