生成具有绑定值的整个 SQL 语句以用作缓存函数的键 - CakePHP 4

Generate whole SQL statement with binding value to use as a key for cache function - CakePHP 4

问题描述

我想将查询结果缓存为整个 SQL 语句而不是 SQL 语句的一部分,如下例所示:

// Generate a key based on a simple checksum
// of the query's where clause
$query->cache(function ($q) {
    return md5(serialize($q->clause('where')));
});

以上示例取自 link:https://book.cakephp.org/4/en/orm/query-builder.html#caching-loaded-results

我试过的

我可以获得完整的 SQL 没有像这样的绑定值:

$query->sql()

绑定值如下:

$bindings = $query->getValueBinder()->bindings();

现在我需要弄清楚如何将两者结合起来。最好是 CakePHP 中有一个内置函数,它只会给我 SQL 和绑定值。

我找到了解决方法。 DebugKit 中有一个名为 interpolate() 的私有函数,它使用绑定值创建完整的 SQL 语句。

由于该函数是私有的,您必须将其复制并保存在您的源代码中。

这是插值函数:

    /**
     * Helper function used to replace query placeholders by the real
     * params used to execute the query.
     *
     * @param string $sql The SQL statement
     * @param array $bindings The Query bindings
     * @return string
     */
    private static function interpolate($sql, array $bindings)
    {
        $params = array_map(function ($binding) {
            $p = $binding['value'];

            if ($p === null) {
                return 'NULL';
            }
            if (is_bool($p)) {
                return $p ? '1' : '0';
            }

            if (is_string($p)) {
                $replacements = [
                    '$' => '\$',
                    '\' => '\\\\',
                    "'" => "''",
                ];

                $p = strtr($p, $replacements);

                return "'$p'";
            }

            return $p;
        }, $bindings);

        $keys = [];
        $limit = is_int(key($params)) ? 1 : -1;
        foreach ($params as $key => $param) {
            $keys[] = is_string($key) ? "/$key\b/" : '/[?]/';
        }

        return preg_replace($keys, $params, $sql, $limit);
    }
}

然后调用它并像这样传递 SQL 和绑定值,以获得具有绑定值的整个 SQL 语句:

$sql = $query->sql();
$bindings = $query->getValueBinder()->bindings();

// to make the example easier, I have saved the interpolate function in controller
$properSqlStatement = $this->interpolate($sql, $bindings);

耶!