Yii2 ArrayDataProvider如何仅对当前页数据执行额外计算?
如何为ArrayDataProvider仅对当前页显示的条目执行额外计算?
问题背景
创建了如下ArrayDataProvider,$data包含1000条元素,希望仅对当前页显示的10条数据执行资源密集型计算,避免全量计算的性能问题:
$dataProvider = new ArrayDataProvider([ 'allModels' => $data, 'sort' => [ 'attributes' => [ 'quantity', ], 'defaultOrder' => [ 'quantity' => SORT_DESC, ] ], 'pagination' => [ 'pageSize' => 10 ] ]);
尝试直接修改getModels()返回的数组,但新增的value键在GridView中不显示,即使立即输出getModels()也看不到修改:
$allModels = $dataProvider->getModels(); foreach ($allModels as &$model) { // 复杂计算并赋值 $model['value'] = 123; }
解决方案
原因说明
getModels()返回的是模型数组的副本,而非引用,所以直接修改副本不会影响数据提供者内部存储的模型。需要将修改后的数组重新设置回数据提供者,或者利用回调在模型准备阶段处理。
方法一:修改后重新设置模型
获取当前页模型并修改,通过setModels()将修改后的数组存入数据提供者:
// 获取当前页经过分页、排序后的模型 $currentModels = $dataProvider->getModels(); // 对当前页模型执行计算 foreach ($currentModels as &$model) { // 替换为你的资源密集型计算逻辑 $model['value'] = 123; } unset($model); // 释放引用,避免后续变量污染 // 将修改后的模型重新设置回数据提供者 $dataProvider->setModels($currentModels);
方法二:利用prepareModels回调(推荐)
在初始化ArrayDataProvider时,通过prepareModels回调处理当前页模型,该回调会自动在数据提供者准备当前页数据时执行,仅处理当前页条目:
$dataProvider = new ArrayDataProvider([ 'allModels' => $data, 'sort' => [ 'attributes' => ['quantity'], 'defaultOrder' => ['quantity' => SORT_DESC], ], 'pagination' => ['pageSize' => 10], 'prepareModels' => function ($models) { // $models已经是分页、排序后的当前页数据 foreach ($models as &$model) { // 替换为你的资源密集型计算逻辑 $model['value'] = 123; } unset($model); return $models; }, ]);
说明
- 方法一适合在数据提供者初始化后,需要动态触发计算的场景;
- 方法二更优雅,无需手动处理分页逻辑,由数据提供者自动在合适时机执行计算。
内容的提问来源于stack exchange,提问作者daniil sidorov
相关产品推荐
相关产品推荐

