将问号转换为参数的自定义 Doctrine DQL 函数

Custom Doctrine DQL function with Question Mark being converted into parameter

我正在使用 Symfony 2.6 和 Doctrine 2.5,我正在尝试制作自定义 DQL 函数来实现“?” Postgres 运算符(用于确定具有特定键的元素是否存在于 Postgres 的 jsonb 字段中)http://www.postgresql.org/docs/9.4/static/functions-json.html

这是代码(从https://github.com/boldtrn/JsonbBundle的DQL代码复制而来,我只是改了问号)

class HasElement extends FunctionNode
{
    public $leftHandSide = null;
    public $rightHandSide = null;

    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->leftHandSide = $parser->ArithmeticPrimary();
        $parser->match(Lexer::T_COMMA);
        $this->rightHandSide = $parser->ArithmeticPrimary();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        return '(' .
        $this->leftHandSide->dispatch($sqlWalker) . " ? " .
        $this->rightHandSide->dispatch($sqlWalker) .
        ')';
    }
}

但是在创建查询时问号被认为是参数占位符,我收到语法错误并且在设置参数之前在查询中它被替换为 $2。

SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near ""
LINE 1: ...id = r1_.id WHERE r0_.file_id =  AND (r0_.attrs  )

查询应该是“(r0_attrs ? $1)”

有没有什么方法可以在 DQL 中使用问号而不将其视为参数?我尝试转义并替换为 unicode 序列,但没有用

编辑: 虽然这个问题的答案与这个被标记为重复的答案相同(使用函数而不是别名运算符),但错误是不同的. Doctrine 的解析出现在 PDO 参数分配之前,如果不是这样的话我会得到这个错误:

PDOException: SQLSTATE[HY093]: Invalid parameter number: no parameters were bound: SELECT * FROM tbl WHERE hst ? 'foo'

除此之外,只是大致流程相同,具体答案不同(需要使用不同的函数)

我一直在寻找 solution/alternative,我发现 ? 是函数 jsonb_exists(column_name, key) 的别名,我将在我的自定义 DQL 函数中使用它。

同样的事情也适用于 ?|?&

所以 class 变成了这个

class JsonbExistence extends FunctionNode
{
    public $leftHandSide = null;
    public $rightHandSide = null;
    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->leftHandSide = $parser->ArithmeticPrimary();
        $parser->match(Lexer::T_COMMA);
        $this->rightHandSide = $parser->ArithmeticPrimary();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        // We use a workaround to allow this statement in a WHERE. Doctrine relies on the existence of an ComparisonOperator
        return 'jsonb_exists(' .
        $this->leftHandSide->dispatch($sqlWalker) .', '.
        $this->rightHandSide->dispatch($sqlWalker) .
        ')';
    }
}

这不是 doctrine/symfony 问题,而是与 PDO 相关。

你可以查看这个How to prevent PDO from interpreting a question mark as a placeholder?

这主要是尝试使用相同的运算符,但使用 PHP PDO 库。