原则:如何添加采用可选参数的自定义函数


Doctrine: how to add custom functions that take optional parameter?

根据官方解释,我想创建我的自定义MySQL函数ROUND((,它可以接受(不是强制性的(另一个参数。

到目前为止,我已经这样做了:

<?php
namespace HQF'Bundle'PizzasBundle'DQL;
use 'Doctrine'ORM'Query'AST'Functions'FunctionNode;
use 'Doctrine'ORM'Query'Lexer;
class MysqlRound extends FunctionNode
{
    public $simpleArithmeticExpression;
    public function getSql('Doctrine'ORM'Query'SqlWalker $sqlWalker)
    {
        return 'ROUND(' . $sqlWalker->walkSimpleArithmeticExpression(
            $this->simpleArithmeticExpression
        ) . ')';
    }
    public function parse('Doctrine'ORM'Query'Parser $parser)
    {
        $lexer = $parser->getLexer();
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
}

但是如何实现ROUND(XX)可以,ROUND(XX, YY)也可以的事实呢?

您需要声明第二个参数,并像这样使用Lexer

namespace HQF'Bundle'PizzasBundle'DQL;
use 'Doctrine'ORM'Query'AST'Functions'FunctionNode;
use 'Doctrine'ORM'Query'Lexer;
class MysqlRound extends FunctionNode
{
    private $firstExpression = null;
    private $secondExpression = null;
    public function parse('Doctrine'ORM'Query'Parser $parser)
    {
        $lexer = $parser->getLexer();
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->firstExpression = $parser->ArithmeticPrimary();
        // parse second parameter if available
        if(Lexer::T_COMMA === $lexer->lookahead['type']){
            $parser->match(Lexer::T_COMMA);
            $this->secondExpression = $parser->ArithmeticPrimary();
        }
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
    public function getSql('Doctrine'ORM'Query'SqlWalker $sqlWalker)
    {
        // use second parameter if parsed
        if (null !== $this->secondExpression){
            return 'ROUND(' 
                . $this->firstExpression->dispatch($sqlWalker)
                . ', '
                . $this->secondExpression->dispatch($sqlWalker)
                . ')';
        }
        return 'ROUND(' . $this->firstExpression->dispatch($sqlWalker) . ')';
    }
}

编辑

这里已经编写了许多Doctrine2扩展。所有这些都归功于@beberlei的伟大工作。有许多函数可用(IFELSEIFNULLNULLIFCOSACOS等(,但并非所有函数都可用(缺少ROUNDGREATESTLEAST,但如果需要,您仍然可以自己编写它们。(

我还在这里找到了GREATEST实现https://raw.githubusercontent.com/rodgermd/mura-show.com/master/src/Rodger/GalleryBundle/DoctrineExtension/Greatest.php(c(rodgermd@github:

namespace Rodger'GalleryBundle'DoctrineExtension;
use Doctrine'ORM'Query'Lexer,
    Doctrine'ORM'Query'AST'Functions;

class Greatest extends Functions'FunctionNode {
  protected $firstExpression, $secondExpression;
  public function getSql('Doctrine'ORM'Query'SqlWalker $sqlWalker)
  {
    return sprintf("GREATEST(%s, %s)", 
            $this->firstExpression->dispatch($sqlWalker), 
            $this->secondExpression->dispatch($sqlWalker));
  }
  public function parse('Doctrine'ORM'Query'Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER); // (2)
        $parser->match(Lexer::T_OPEN_PARENTHESIS); // (3)
        $this->firstExpression = $parser->ArithmeticPrimary(); // (4)
        $parser->match(Lexer::T_COMMA); // (5)
        $this->secondExpression = $parser->ArithmeticPrimary(); // (6)
        $parser->match(Lexer::T_CLOSE_PARENTHESIS); // (3)
    }
}