Joh*_* N. 5 php mysql cakephp cakephp-model cakephp-2.4
我们经常处理类似如下的代码:
return $this->find(
'all', [
'fields' => ['DISTINCT Tag.tag', 'COUNT(Tag.tag) as count'],
'group' => ['Tag.tag'],
'order' => ['count' => 'DESC']
]);
Run Code Online (Sandbox Code Playgroud)
此查询引导我们进行以下输出:
[0] => Array
(
[Tag] => Array
(
[tag] => walls.io
)
[0] => Array
(
[count] => 15
)
)
Run Code Online (Sandbox Code Playgroud)
如您所见,查询以"某种方式错误"嵌套返回结果.遗憾的是,"count"字段被放入伪[0] - 阵列中.
IIRC,CakePHP在内部使用像Tag__field这样的语法来正确嵌套虚拟字段.
将代码更改为Model __-语法时,问题保持不变:
return $this->find(
'all', [
'fields' => ['DISTINCT Tag.tag', 'COUNT(Tag.tag) as Tag__count'],
'group' => ['Tag.tag'],
'order' => ['COUNT(Tag.tag)' => 'DESC']
]);
Run Code Online (Sandbox Code Playgroud)
输出:
[0] => Array
(
[Tag] => Array
(
[tag] => walls.io
)
[0] => Array
(
[Tag__count] => 15
)
)
Run Code Online (Sandbox Code Playgroud)
解决方法1:array_map
CakePHP专业人士:有没有比select语句后手动映射数组更好/更优雅的解决方案?
$tags = array_map(function($tag) {
$tag['Tag']['count'] = $tag[0]['count'];
unset($tag[0]);
return $tag;
}, $tags);
Run Code Online (Sandbox Code Playgroud)
解决方法2:虚拟字段
如上所述,虚拟字段的使用可以解决此问题:
$this->virtualFields = ['count' => 'COUNT(Tag.Tag)'];
return $this->find(
'all', [
'group' => ['Tag.tag'],
'order' => [$this->getVirtualField('count') => 'DESC']
]);
Run Code Online (Sandbox Code Playgroud)
不幸的是,使用此解决方案,根本无法指定任何字段.只有完全离开"fields"-key,数组的嵌套才能按预期工作.当选择$ fields = ['Tag.tag',$ this-> getVirtualField('count')]时,嵌套再次出错.
CakePHP专业人员:你知道一个方法,即使你指定自己的字段,嵌套也是正确的吗?
查看CakePHP代码,不存在这样的方法。
看一下文件lib/Cake/Model/Datasource/Database/Mysql.php。
找到名为的方法:Mysql::resultSet( $results ); (大约第 240 行)。
该方法将结果映射到数组。为了确定列是否是表的一部分,它使用PDOStatement::getColumnMeta(). 对于您的“虚拟列”,该方法将返回一个空表,因此 CakePHP 代码将单独放置它,请参阅else分支
$this->map[$index++] = array(0, $column['name'], $type);
为了避免 else 分支,您必须使用虚拟字段,但随后您会遇到您注意到的其他问题。
因此,您只剩下 array_map 解决方案,或者您可以尝试重载该 Mysql 类并在如何识别列适合的位置添加自定义逻辑。