Doctrine 2 DQL MySQL equivalent to ROUND()?

You need to implement a custom DQL function for that.

There's some examples in DoctrineExtensions.

You can implement it like following:

<?php

namespace MyApp\DQL;

use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\SqlWalker;

class Round extends FunctionNode
{
    private $arithmeticExpression;

    public function getSql(SqlWalker $sqlWalker)
    {

        return 'ROUND(' . $sqlWalker->walkSimpleArithmeticExpression(
            $this->arithmeticExpression
        ) . ')';
    }

    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {

        $lexer = $parser->getLexer();

        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);

        $this->arithmeticExpression = $parser->SimpleArithmeticExpression();

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

You can then register it in the configuration while bootstrapping the ORM:

$config = new \Doctrine\ORM\Configuration();

$config->addCustomNumericFunction('ROUND', 'MyApp\DQL\Round');

A bit cleaner approach would be using slightly modified @Ocramius code.

Put this piece of code in: src/YourNamespace/YourMainBundle/DoctrineFunctions/ directory as the Round.php filename:

<?php
namespace YourApp\YourMainBundle\DoctrineFunctions;

use Doctrine\ORM\Query\AST\Functions\FunctionNode,
    Doctrine\ORM\Query\Lexer;

class Round extends FunctionNode
{
    private $arithmeticExpression;

    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {

        $lexer = $parser->getLexer();

        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);

        $this->arithmeticExpression = $parser->SimpleArithmeticExpression();

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

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        return 'ROUND(' . $sqlWalker->walkSimpleArithmeticExpression($this->arithmeticExpression) . ')';
    }
}

Then put this in your app/config/config.yml:

doctrine:
    dql:
        numeric_functions:
            round: YourApp\YourMainBundle\DoctrineFunctions\Round

That would allow you to use the ROUND() function directly in your DQL SELECT queries; no matter if done with QueryBuilder or directly via createQuery()


If you want to be able to specify rounding precision, you can use the class that is provided here. If you are using symfony, install the bundle, as you'll also get extra standard mysql functions.

The code of the linked resource is also available below:

<?php
namespace Mapado\MysqlDoctrineFunctions\DQL;
use \Doctrine\ORM\Query\AST\Functions\FunctionNode;
use \Doctrine\ORM\Query\Lexer;
/**
 * MysqlRound
 *
 * @uses FunctionNode
 * @author Julien DENIAU <[email protected]>
 */
class MysqlRound extends FunctionNode
{
    /**
     * simpleArithmeticExpression
     *
     * @var mixed
     * @access public
     */
    public $simpleArithmeticExpression;
    /**
     * roundPrecision
     *
     * @var mixed
     * @access public
     */
    public $roundPrecision;
    /**
     * getSql
     *
     * @param \Doctrine\ORM\Query\SqlWalker $sqlWalker
     * @access public
     * @return string
     */
    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        return 'ROUND(' .
                $sqlWalker->walkSimpleArithmeticExpression($this->simpleArithmeticExpression) .','.
                $sqlWalker->walkStringPrimary($this->roundPrecision) .
        ')';
    }
    /**
     * parse
     *
     * @param \Doctrine\ORM\Query\Parser $parser
     * @access public
     * @return void
     */
    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
        $parser->match(Lexer::T_COMMA);
        $this->roundPrecision = $parser->ArithmeticExpression();
        if ($this->roundPrecision == null) {
            $this->roundPrecision = 0;
        }
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
}