如何在 GridView 中只调用一次函数?
How to invoke function only once in GridView?
我要警告:我不能使用array
,只能使用Active Record
。
所以我有一个 GridView 和列:
$gridColumns = [
['class' => SerialColumn::class],
[
'attribute' => 'cap',
'label' => 'Всего, Зан., Св.',
'format' => 'raw',
'value' => function($model) {
$data = Yii::$app->db->createCommand("SELECT * FROM dbFunction({$model->point_id}")->queryOne();
$html = <<< HTML
<div class="item">{$data['capacity']}</div>
<div class="item">{$data['occupied']}</div>
<div class="item">{$data['free']}</div>
HTML;
return $html;
},
],
];
echo GridView::widget([
'id' => 'my-table',
'columns' => $gridColumns,
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'rowOptions' => function($model) {
$data = Yii::$app->db->createCommand("SELECT * FROM dbFunction({$model->point_id}")->queryOne();
$class = $data['free'] === 0 ? 'free-point' : '';
if ($data['capacity'] === 0 && $data['occupied'] === 0 && $data['free'] === 0)
$class = 'd-none';
return [
'data-id' => $model->id,
'class' => $class,
];
},
]);
它工作正常,但 dbFunction
对每一行执行两次(第一次是针对单元格,第二次是针对行选项)。这个功能很重量级
问题是:有没有办法只执行一次这个函数(对于每次迭代)并在两个地方都使用函数的结果?不知道该怎么做,因为在幕后 Yii2 对 columns
使用循环,我猜,单独调用 rowOptions。怎么组合呢?
P.S。当然,我可以使用 js 为 rowOptions
编写条件,但这将是一个错误:它将被写为“显示 60 条记录中的 30 条”,但实际上它只会显示 5(或其他)。这就是为什么我想在后端解决问题。
我建议将加载数据的函数移动到模型中并将结果存储在模型的私有 属性 中。
例如这样的事情:
class MyModel extends ActiveRecord
{
private ?array $capacityData = null;
public function capacityData(): array
{
if ($this->capacityData === null) {
$this->capacityData = $this->getDb()->createCommand(
"SELECT * FROM dbFunction({$model->point_id})"
)->queryOne();
}
return $this->capacityData;
}
// ... other definitions ...
}
然后你可以像这样在多个地方使用它:
'value' => function($model) {
$data = $model->capacityData();
$html = <<< HTML
<div class="item">{$data['capacity']}</div>
<div class="item">{$data['occupied']}</div>
<div class="item">{$data['free']}</div>
HTML;
return $html;
},
或者像这样:
'rowOptions' => function($model) {
$data = $model->capacityData();
$class = $data['free'] === 0 ? 'free-point' : '';
if ($data['capacity'] === 0 && $data['occupied'] === 0 && $data['free'] === 0)
$class = 'd-none';
return [
'data-id' => $model->id,
'class' => $class,
];
},
SQL 查询只会在第一次调用 capacityData()
函数时执行。在下次调用期间,数据将在 $capacityData
属性.
中可用
顺便说一句。在隐藏行的 $rowOptions
属性 中添加 class 不会解决文本中错误数字“显示 60 条记录中的 30 条”的问题。文本显示正确数字的唯一方法是数据提供者不包含不应显示的行。
我认为您可以为此尝试使用查询缓存。像这样:
Yii::$app->db->cache(function ($db, $model) {
return $db->createCommand(
"SELECT * FROM dbFunction({$model->point_id})"
)->queryOne();
});
这样第二次调用将 return 缓存结果。
P.S。您还需要在数据库配置中配置缓存组件和查询缓存。
我要警告:我不能使用array
,只能使用Active Record
。
所以我有一个 GridView 和列:
$gridColumns = [
['class' => SerialColumn::class],
[
'attribute' => 'cap',
'label' => 'Всего, Зан., Св.',
'format' => 'raw',
'value' => function($model) {
$data = Yii::$app->db->createCommand("SELECT * FROM dbFunction({$model->point_id}")->queryOne();
$html = <<< HTML
<div class="item">{$data['capacity']}</div>
<div class="item">{$data['occupied']}</div>
<div class="item">{$data['free']}</div>
HTML;
return $html;
},
],
];
echo GridView::widget([
'id' => 'my-table',
'columns' => $gridColumns,
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'rowOptions' => function($model) {
$data = Yii::$app->db->createCommand("SELECT * FROM dbFunction({$model->point_id}")->queryOne();
$class = $data['free'] === 0 ? 'free-point' : '';
if ($data['capacity'] === 0 && $data['occupied'] === 0 && $data['free'] === 0)
$class = 'd-none';
return [
'data-id' => $model->id,
'class' => $class,
];
},
]);
它工作正常,但 dbFunction
对每一行执行两次(第一次是针对单元格,第二次是针对行选项)。这个功能很重量级
问题是:有没有办法只执行一次这个函数(对于每次迭代)并在两个地方都使用函数的结果?不知道该怎么做,因为在幕后 Yii2 对 columns
使用循环,我猜,单独调用 rowOptions。怎么组合呢?
P.S。当然,我可以使用 js 为 rowOptions
编写条件,但这将是一个错误:它将被写为“显示 60 条记录中的 30 条”,但实际上它只会显示 5(或其他)。这就是为什么我想在后端解决问题。
我建议将加载数据的函数移动到模型中并将结果存储在模型的私有 属性 中。
例如这样的事情:
class MyModel extends ActiveRecord
{
private ?array $capacityData = null;
public function capacityData(): array
{
if ($this->capacityData === null) {
$this->capacityData = $this->getDb()->createCommand(
"SELECT * FROM dbFunction({$model->point_id})"
)->queryOne();
}
return $this->capacityData;
}
// ... other definitions ...
}
然后你可以像这样在多个地方使用它:
'value' => function($model) {
$data = $model->capacityData();
$html = <<< HTML
<div class="item">{$data['capacity']}</div>
<div class="item">{$data['occupied']}</div>
<div class="item">{$data['free']}</div>
HTML;
return $html;
},
或者像这样:
'rowOptions' => function($model) {
$data = $model->capacityData();
$class = $data['free'] === 0 ? 'free-point' : '';
if ($data['capacity'] === 0 && $data['occupied'] === 0 && $data['free'] === 0)
$class = 'd-none';
return [
'data-id' => $model->id,
'class' => $class,
];
},
SQL 查询只会在第一次调用 capacityData()
函数时执行。在下次调用期间,数据将在 $capacityData
属性.
顺便说一句。在隐藏行的 $rowOptions
属性 中添加 class 不会解决文本中错误数字“显示 60 条记录中的 30 条”的问题。文本显示正确数字的唯一方法是数据提供者不包含不应显示的行。
我认为您可以为此尝试使用查询缓存。像这样:
Yii::$app->db->cache(function ($db, $model) {
return $db->createCommand(
"SELECT * FROM dbFunction({$model->point_id})"
)->queryOne();
});
这样第二次调用将 return 缓存结果。
P.S。您还需要在数据库配置中配置缓存组件和查询缓存。