Byron Adams


Ramblings about code, life and everything else.


Yii GridView Performance

If you’re using the yii\grid\GridView widget to render large lists of data, including things like status icons, form fields or any other custom HTML columns, you may notice that it can be quite slow to render, in this post I’ll explain why, and how to avoid some extra rendering overhead.

In the example below, we have a simple grid with two columns, the first renders a link and the second some custom status icon.

<?= GridView::widget([
'layout' => '{summary}{pager}{items}{pager}',
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'pager' => [
'class' => yii\widgets\LinkPager::className(),
'firstPageLabel' => 'First',
'lastPageLabel' => 'Last',
],
'columns' => [
[
'attribute' => 'title',
'format' => 'html',
'value' => function (\app\models\Book $m) {
return Html::a($m->title, ['update', 'id' => $m->id]);
}
],
[
'attribute' => 'status_id',
'format' => 'html',
'value' => function (\app\models\Book $m) {
return Html::tag('span', null, [
'class' => "status-icon book_status-status-{$m->status_id}"
]);
}
]
],
]); ?>

This will become quite sluggish when attempting to render 50 or more records in a single request. Things quickly get out of hand when you start to add more and more columns to the grid; Clients want popovers to render when you hover over status icons, giving a summarized history of the record, or want to be able to update the record quickly from within the grid, you get the point.

Luckily some of the performance issues can be quickly remedied by simply changing the formatter your columns use.

In which format should the value of each data model be displayed as (e.g. “raw”, “text”, “html”, [‘date’, ‘php:Y-m-d’]). Supported formats are determined by the formatter used by the yii\grid\GridView. Default format is “text” which will format the value as an HTML-encoded plain text when yii\i18n\Formatter is used as the formatter of the GridView.

yii\grid\DataColumn::$format documentation

So unless you specify the format as raw there will be some extra overhead during the rendering process, this is an easy win in most cases but you should be aware that the HTML encoding that is applied to most other formats is important for security reasons, if you are rendering user created content, generally you want to encode it.

Another option for more expensive columns is to employ a cell caching technique; simply put you create a new column type which accepts a cache dependency as one of its properties, if will then render the cell contents only if it has not yet been cached, or it the cache dependency has invalidated the data. In the future I might add a post with an example of this.