CakePHP 分页将值变为空
CakePHP paginate turns values to null
我有这个函数可以获取所有 "feedings" 及其 "feedingsupps"。在函数中,我计算了一些字段的总和:
/* FeedingTable.php */
public function feedings_with_totals($herd_id)
{
$feedings = $this->find('all',[
'contain' => [
'Herds',
'Herds.Users',
'Feedingsupps'
]
])
->where(['Feedings.herd_id'=>$herd_id])
->order(['Feedings.id'=>'desc']);
foreach($feedings as $f)
{
$collection = new Collection($f->feedingsupps);
$f->sum_weight = $collection->sumOf('weight');
$f->sum_dryweight = $collection->sumOf('dryweight_total');
$f->sum_price = $collection->sumOf('price_total');
}
return $feedings;
}
当我调用这个函数并调试它时,它看起来像我想要的:
[
(int) 0 => object(App\Model\Entity\Feeding) {
'id' => (int) 19,
...
'sum_weight' => (float) 109,
'sum_dryweight' => (float) 92.71,
'sum_price' => (float) 17.1775,
然后我分页:
$feedings = $this->paginate($feedings);
之后 "sum" 字段变为空:
[
(int) 0 => object(App\Model\Entity\Feeding) {
'id' => (int) 19,
...
'sum_weight' => null,
'sum_dryweight' => null,
'sum_price' => null,
为什么分页会这样?
分页器不会修改您的字段,它所做的是再次 运行查询,因为应用分页器选项会使查询处于脏状态,并删除可能缓冲的结果集。因此分页器返回的结果集与您在方法中修改的结果集不同。
即使您在那里做的事情可行,您也不应该那样做,因为您将 a) 运行 查询两次,并且 b) 与您正在获取的分页器查询不同,并且处理 table 的 all 行(这可能是一个非常昂贵的操作,无论如何都是不必要的)。
您的计算应该在结果格式化程序中,在请求结果集时应用一次:
$feedings->formatResults(function (\Cake\Collection\CollectionInterface $results) {
return $results->map(function ($row) {
$collection = collection($row['feedingsupps']);
$row['sum_weight'] = $collection->sumOf('weight');
$row['sum_dryweight'] = $collection->sumOf('dryweight_total');
$row['sum_price'] = $collection->sumOf('price_total');
return $row;
});
});
或者应该在 SQL 级别完成:
$feedings
->select([
'sum_weight' => $feedings->func()->sum('Feedingsupps.weight'),
'sum_dryweight' => $feedings->func()->sum('Feedingsupps.dryweight_total'),
'sum_price' => $feedings->func()->sum('Feedingsupps.price_total'),
])
->enableAutoFields(true)
->leftJoinWith('Feedingsupps')
->group('Feedings.id');
在这两种情况下,只会对实际获取的记录进行计算,查询只会 运行 一次。
另见
我有这个函数可以获取所有 "feedings" 及其 "feedingsupps"。在函数中,我计算了一些字段的总和:
/* FeedingTable.php */
public function feedings_with_totals($herd_id)
{
$feedings = $this->find('all',[
'contain' => [
'Herds',
'Herds.Users',
'Feedingsupps'
]
])
->where(['Feedings.herd_id'=>$herd_id])
->order(['Feedings.id'=>'desc']);
foreach($feedings as $f)
{
$collection = new Collection($f->feedingsupps);
$f->sum_weight = $collection->sumOf('weight');
$f->sum_dryweight = $collection->sumOf('dryweight_total');
$f->sum_price = $collection->sumOf('price_total');
}
return $feedings;
}
当我调用这个函数并调试它时,它看起来像我想要的:
[
(int) 0 => object(App\Model\Entity\Feeding) {
'id' => (int) 19,
...
'sum_weight' => (float) 109,
'sum_dryweight' => (float) 92.71,
'sum_price' => (float) 17.1775,
然后我分页:
$feedings = $this->paginate($feedings);
之后 "sum" 字段变为空:
[
(int) 0 => object(App\Model\Entity\Feeding) {
'id' => (int) 19,
...
'sum_weight' => null,
'sum_dryweight' => null,
'sum_price' => null,
为什么分页会这样?
分页器不会修改您的字段,它所做的是再次 运行查询,因为应用分页器选项会使查询处于脏状态,并删除可能缓冲的结果集。因此分页器返回的结果集与您在方法中修改的结果集不同。
即使您在那里做的事情可行,您也不应该那样做,因为您将 a) 运行 查询两次,并且 b) 与您正在获取的分页器查询不同,并且处理 table 的 all 行(这可能是一个非常昂贵的操作,无论如何都是不必要的)。
您的计算应该在结果格式化程序中,在请求结果集时应用一次:
$feedings->formatResults(function (\Cake\Collection\CollectionInterface $results) {
return $results->map(function ($row) {
$collection = collection($row['feedingsupps']);
$row['sum_weight'] = $collection->sumOf('weight');
$row['sum_dryweight'] = $collection->sumOf('dryweight_total');
$row['sum_price'] = $collection->sumOf('price_total');
return $row;
});
});
或者应该在 SQL 级别完成:
$feedings
->select([
'sum_weight' => $feedings->func()->sum('Feedingsupps.weight'),
'sum_dryweight' => $feedings->func()->sum('Feedingsupps.dryweight_total'),
'sum_price' => $feedings->func()->sum('Feedingsupps.price_total'),
])
->enableAutoFields(true)
->leftJoinWith('Feedingsupps')
->group('Feedings.id');
在这两种情况下,只会对实际获取的记录进行计算,查询只会 运行 一次。
另见