【发布时间】:2020-05-18 11:09:15
【问题描述】:
我阅读了其他一些问题,但它们已经很老了。我正在使用 CakePHP 3.7.9。 我阅读了有关虚拟字段的文档,here 和 here。
到目前为止:
Proforma.php
class Proforma extends Entity
{
protected $_accessible = [
'customer_id' => true,
'proforma_number' => true,
'proforma_date' => true,
'payment_date' => true,
'proforma_state_id' => true,
'customer' => true,
'proforma_state' => true,
'item_proformas' => true
];
protected $_virtual = [
'total'
];
protected function _getTotal()
{
$q = TableRegistry::getTableLocator()->get('item_proformas')->find();
$v = $q
->select(['total' => $q->func()->sum('total')])
->where(['proforma_id' => $this->id])
->first()['total'];
if ($v == null) $v = 0;
return $v;
}
}
在视图中我可以轻松访问该字段:
<td class="text-right"><?= $proforma->item_proformas ? $this->Number->currency($proforma->total) : '' ?></td>
但是当我尝试在 Controller 中进行查询时,即:
$query = $this->Proformas->find();
debug($query);
$query->select(['value' => $query->func()->sum('total')]);
找不到字段total。这里是调试的输出:
object(Cake\ORM\Query) {
'(help)' => 'This is a Query object, to get the results execute or iterate it.',
'sql' => 'SELECT Proformas.id AS `Proformas__id`, Proformas.customer_id AS `Proformas__customer_id`, Proformas.proforma_number AS `Proformas__proforma_number`, Proformas.proforma_date AS `Proformas__proforma_date`, Proformas.payment_date AS `Proformas__payment_date`, Proformas.proforma_state_id AS `Proformas__proforma_state_id` FROM proformas Proformas',
'params' => [],
'defaultTypes' => [
'Proformas__id' => 'integer',
'Proformas.id' => 'integer',
'id' => 'integer',
'Proformas__customer_id' => 'integer',
'Proformas.customer_id' => 'integer',
'customer_id' => 'integer',
'Proformas__proforma_number' => 'string',
'Proformas.proforma_number' => 'string',
'proforma_number' => 'string',
'Proformas__proforma_date' => 'date',
'Proformas.proforma_date' => 'date',
'proforma_date' => 'date',
'Proformas__payment_date' => 'date',
'Proformas.payment_date' => 'date',
'payment_date' => 'date',
'Proformas__proforma_state_id' => 'integer',
'Proformas.proforma_state_id' => 'integer',
'proforma_state_id' => 'integer'
],
'decorators' => (int) 0,
'executed' => false,
'hydrate' => true,
'buffered' => true,
'formatters' => (int) 0,
'mapReducers' => (int) 0,
'contain' => [],
'matching' => [],
'extraOptions' => [],
'repository' => object(App\Model\Table\ProformasTable) {
'registryAlias' => 'Proformas',
'table' => 'proformas',
'alias' => 'Proformas',
'entityClass' => 'App\Model\Entity\Proforma',
'associations' => [
(int) 0 => 'customers',
(int) 1 => 'proformastates',
(int) 2 => 'invoices',
(int) 3 => 'itemproformas'
],
'behaviors' => [],
'defaultConnection' => 'default',
'connectionName' => 'default'
}
}
为什么即使暴露了虚拟字段也没有插入到查询中?
上面链接的文档说:
请记住,虚拟字段不能用于查找。如果您希望它们成为实体的 JSON 或数组表示的一部分,请参阅公开虚拟字段。
然后:
默认情况下,将实体转换为数组或 JSON 时不会导出虚拟字段。为了公开虚拟字段,您需要使它们可见。在定义实体类时,您可以提供应公开的虚拟字段列表
所以公开虚拟字段应该让我在查找中使用它们。
【问题讨论】:
-
我不确定“请记住虚拟字段不能在查找中使用”的哪一部分不清楚。看看你是如何在 PHP 中编写一个特殊的函数来进行计算的?您对将其转换为 SQL 代码以使其成为查询的一部分的期望是什么?
-
“公开”一个虚拟字段是指在您将实体(已从 SQL 读取)转换为替代表示时使该字段可用。
-
因为英语不是我的主要语言,我知道公开虚拟字段会使它们可用于 JSON 和数组(如查询)。在“不能用于查找”之后的“如果你愿意”对我来说听起来像是使用的解决方案!
-
JSON 和数组是输出格式,通过在查询结果上运行 PHP 代码生成。该代码可以使用您的函数添加虚拟字段。但这一切都是在查询运行完成后发生的。
-
这里肯定有误会。虚拟字段用于对单个实体进行计算。
_getTotal对订单记录有意义,例如,列包括price、tax和shipping,并将这三者相加得出该订单的总金额。如果您想对多行进行总计,那是 query functions 或 custom finder 的工作。