Typecho 主题功能适配 SQLLite 和 PostgreSQL 的解决方案
最近在制作 Typecho default-ultra 主题,在这个主题中我加入了输出随机文章的功能。代码片段如下:
$select = $this->select()->from('table.contents')
->where('table.contents.password IS NULL OR table.contents.password = ""')
->where('table.contents.status = ?', 'publish')
->where('table.contents.created <= ?', time())
->where('table.contents.type = ?', 'post')
->limit($this->parameter->limit)
->order('RAND()');乍一看,这个代码片段本身没什么问题,使用过程中也没什么问题。
然而:我是在 PHP84 + MySQL8 的环境下开发和运行的,确实没问题,但是考虑到有用户使用 SQLLite 和 PostgreSQL,那就有问题了。
在 MySQL 中,生成随机数的函数是 RAND,然而在 SQLLite 和 PostgreSQL 中,生成随机数的函数是 RANDOM,如果使用的是 SQLLite 和 PostgreSQL,那这里必然会报错。
再者,在 PostgreSQL 中,判断空字符串不能直接用双引号,因为双引号会被解析为标识符,这里也会报错。
所以,在编写主题时,涉及到 SQL 语句的,还是要充分考虑数据库的兼容性~
修改代码片段:
// 获取db对象
$db = Typecho_Db::get();
// 获取数据库适配器名称
$adapterName = $db->getAdapterName();
// 根据数据库适配器名称,设定不同的SQL
if ($adapterName == 'pgsql' || $adapterName == 'Pdo_Pgsql' || $adapterName == 'Pdo_SQLite' || $adapterName == 'SQLite') {
$orderBy = 'RANDOM()';
} else {
$orderBy = 'RAND()';
}
$select = $this->select()->from('table.contents')
->where('table.contents.password IS NULL OR table.contents.password = \'\'')
->where('table.contents.status = ?', 'publish')
->where('table.contents.created <= ?', time())
->where('table.contents.type = ?', 'post')
->limit($this->parameter->limit)
->order($orderBy);完美解决。