有没有办法在Phalcon中使用新的PostgreSQL 9.3 JSON运算符?

时间:2014-01-13 15:46:09

标签: php phalcon postgresql-9.3

我正在寻找一种方法来利用PostgreSQL JSON operators中的新Phalcon Framework

一个简单的表格来演示:

CREATE TABLE "user"
(
  id_user serial NOT NULL,
  data json,
  CONSTRAINT pk_user PRIMARY KEY (id_user)
)

以及在psql中运行正常的查询:

select * from "user" where data->>'email' = 'john@example.com';

然而,当用于Phalcon model时:

$users = UserModel::query()
            ->where("data->>'email' = :email:")
            ->bind(['email' => 'john@example.com'])
            ->execute();

它会产生语法错误:

ERROR: Syntax error, unexpected token >, near to '>'email' = :email:', when parsing: SELECT [Pht\Cli\Model\UserModel].* FROM [Pht\Cli\Model\UserModel] WHERE data->>'email' = :email:

我猜这与PHQL parser无法处理语法有关。但问题仍然存在:如何在Phalcon中使用JSON查询

我试图将JSON语法包装成Db\RawValue

$users = UserModel::query()
            ->where(new RawValue("data->>'email' = 'john@example.com'"))
            ->execute();

但似乎它仅用于更新/插入:

ERROR: Conditions must be string

我总是可以写一个原始查询,但这显然不是可行的方法。也可以在Model::findModel::findAll中使用语法。

4 个答案:

答案 0 :(得分:1)

现在你可以使用内置的postgres函数json_extract_path_text

UserModel::query()->where("json_extract_path_text(data, 'email') = :email:");

答案 1 :(得分:0)

查看是否有实现->>运算符的基础函数,并使用它。您可以pg_operator查找oprname的{​​{1}};在那里,您将看到->>识别基础功能。对于不同的数据类型组合,可能有多个条目,因此您必须选择正确的条目。如果需要,您可以oprcode加入oprleftoprright以获取类型名称。

那会给你一个临时的解决方法。更好的方法是避免尝试在框架中解析SQL,或修复其解析器以处理复杂的运算符。

答案 2 :(得分:0)

在深入研究源代码并阅读论坛之后,我找到了基于this forum post的非常好的解决方法。基本思想是使用自定义数据库函数语法,在执行查询之前捕获并解析特殊的虚拟函数:

UserModel::query()->where("PG_JSON_PATH(\"data->>'email'\") = :email:");

为了实现这个目的,我们需要一个专门的Postgres适配器(下面的那个也使用这个hack潜入子查询,就像在原帖中一样):

class Postgresql93 extends \Phalcon\Db\Adapter\Pdo\Postgresql
{
    public function query($sqlStatement, $bindParams = null, $bindTypes = null)
    {
        $sqlStatement = $this->handle93syntax($sqlStatement);
        return parent::query($sqlStatement, $bindParams, $bindTypes);
    }

    private function handle93syntax($sqlStatement)
    {
        $specials = join('|', ['SUB_QUERY', 'PG_JSON_PATH']);
        $pattern = "/($specials)[\\s]*\\([\\s]*\\'(.*)\\'[\\s]*\\)/";

        $sqlStatement = preg_replace_callback(
            $pattern,
            function(array $matches){
                $content = str_replace("''", "'", $matches[2]);
                return $content;
            },
            $sqlStatement
        );

        return $sqlStatement;
    }
}

答案 3 :(得分:0)

根据Craig的回答,您可以在Postgres上执行此查询以查找您要查找的运算符以及要在查询中使用的等效oprcode: 例如: SELECT oprcode FROM pg_operator WHERE oprname = '->>';

您将获得许多结果,使用适当的结果。

谢谢,