Подтвердить что ты не робот

Функция Doctrine 2 mysql FIELD в порядке

Я пытаюсь использовать функцию MySQL FIELD в предложении order by в запросе. Я предполагаю, что Doctrine 2 не поддерживает функцию FIELD из коробки - это правда? Если да, то как я могу его использовать? Должен ли я включить весь свой запрос в собственный запрос? Существует ли расширение Doctrine 2, которое добавляет эту функциональность?

4b9b3361

Ответ 1

Джереми Хикс, спасибо за ваше расширение. Я не знал, как связать вашу функцию с доктриной, но, наконец, я нахожу ответ.

$doctrineConfig = $this->em->getConfiguration();
$doctrineConfig->addCustomStringFunction('FIELD', 'DoctrineExtensions\Query\Mysql\Field');

Мне нужна функция FIELD, чтобы упорядочить мои объекты, которые я выбираю выражением IN. Но вы можете использовать эту функцию только в SELECT, WHERE, BETWEEN, а не в ORDER BY.

Решение:

$qb
            ->select("r, field(r.id, " . implode(", ", $ids) . ") as HIDDEN field")
            ->from("Entities\Round", "r")
            ->where($qb->expr()->in("r.id", $ids))
            ->orderBy("field");

Чтобы не добавлять псевдоним FIELD в строку результатов, вам нужно поставить ключевое слово HIDDEN. Таким образом, это, как быть способным значения порядка в выражении IN в Доктрине 2.2.

Ответ 2

Вы можете добавить поддержку функции FIELD() DQL, но вместо этого реализовать ее как стандартное выражение SQL CASE.. WHEN. Таким образом, ваша функция будет работать как на MySQL, так и на Sqlite, что особенно полезно, если вы похожи на меня и хотите запускать свои модульные тесты в sqlite в памяти.

Этот класс во многом основан на работе Джереми Хикса (я просто изменил метод getSql())

class Field extends FunctionNode
{
    private $field = null;
    private $values = array();

    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);

        // Do the field.
        $this->field = $parser->ArithmeticPrimary();

        // Add the strings to the values array. FIELD must
        // be used with at least 1 string not including the field.

        $lexer = $parser->getLexer();

        while (count($this->values) < 1 ||
                $lexer->lookahead['type'] != Lexer::T_CLOSE_PARENTHESIS) {
            $parser->match(Lexer::T_COMMA);
            $this->values[] = $parser->ArithmeticPrimary();
        }

        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        $query = '(CASE ' . $this->field->dispatch($sqlWalker);
        for ($i=0, $limiti=count($this->values); $i < $limiti; $i++) {
            $query .= ' WHEN ' . $this->values[$i]->dispatch($sqlWalker) . ' THEN     ' . $i;
        }
            $query .= ' END)';

        return $query;
    }
}

Ответ 4

Если поле, которое вы хотите "упорядочить по", является типом данных ENUM, тогда ORDER BY будет работать в том порядке, в котором значения были определены для этого поля ENUM.

Например, у меня была заявка, определенная как enum('n','pe','o','ap','c'), которая давала странный порядок. Упорядочение было исправлено после обновления перечисления до: enum('ap','c','n','o','pe')