Yii2: Разбираемся с GridView

Картинка в gridview yii2

Специально для данной заметки, я подготовил пример использованием разных параметров GridView. Исходники модуля и всего приложения, доступны на битбакете.

За основу взять код, полученный при помощи генератора Gii. Типичный код GridView после автоматической генерации:

<?= GridView::widget([
        'dataProvider' => $dataProvider,
        'columns' => [
            ['class' => 'yii\grid\SerialColumn'],

            'id',
            'parent_id',
            'name:ntext',
            'url:ntext',
            'category_image:ntext',
            // 'created_at',
            // 'updated_at',

            ['class' => 'yii\grid\ActionColumn'],
        ],
    ]); ?>

В результате получается вполне годный вид:

yii2 gridview category

 

Однако, всем не угодишь и первоначальный скелет можно очень сильно преобразить, даже не влезая в дебри написания своего GridView.

Настройки таблицы gridview в yii2

По-умолчанию, генерируемая виджетом таблица, имеет класс class=»table table-striped table-bordered». Переопределить класс можно через свойство tableOptions:

<?= GridView::widget([
        'dataProvider' => $dataProvider,
        'filterModel' => $searchModel,,
        'tableOptions' => [
            'class' => 'table table-striped table-bordered'
        ],
...

Настройки строк gridview yii 2.0

Добавить класс строкам можно через свойство rowOptions. Рассмотрим вариант с использованием анонимной функции.

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'rowOptions'=>function ($model, $key, $index, $grid){
        $class=$index%2?'odd':'even';
        return [
            'key'=>$key,
            'index'=>$index,
            'class'=>$class
        ];
    },
]); ?>

Шаблон GridView в yii2

По-умолчанию, шаблон GridView содержит информацию об общем количестве записей и отображенных записей summary , саму таблицу с данными items и блок постраничной навигации pager. Настраивается шаблон gridview через свойство layout. Простой пример:

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
'layout'=>"{sorter}\n{pager}\n{summary}\n{items}",
...
]); ?>

Свойство summary позволяет переопределить соответствующее поле.

Свойства showFooter и showHeader управляют отображением заголовка и футера GridView.

Свойство showOnEmpty разрешает отображение пустой таблицы, в случае отсутствия данных для отображения.

Замена пустых данных в GridView

emptyCell позволяет задать значение для отображения в пустых ячейках.

Отображение управляющих кнопок в GridView

Настройка вывода и вида кнопок в GridView осуществляется указанием класса, шаблона и других параметров столбца.

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
         ['class' => 'yii\grid\SerialColumn'],
...
         [
            'class' => 'yii\grid\ActionColumn',
            'header'=>'Действия', 
            'headerOptions' => ['width' => '80'],
            'template' => '{view} {update} {delete}{link}',
        ],
    ],
]); ?>

Вывести нестандартные кнопки можно при помощи анонимных функций.

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
        ...
        [
            'class' => 'yii\grid\ActionColumn',
            'template' => '{view} {update} {delete} {link}',
            'buttons' => [
                'update' => function ($url,$model) {
                    return Html::a(
                    '<span class="glyphicon glyphicon-screenshot"></span>', 
                    $url);
                },
                'link' => function ($url,$model,$key) {
                    return Html::a('Действие', $url);
                },
            ],
        ],
    ],
]); ?>

Формат данных в столбцах GridView

Для установки своих атрибутов ячейкам таблицы GridView в Yii 2.0, достаточно указать их в параметре contentOptions. Атрибуты могут быть определены как массивом, так и анонимной функцией function ($model, $key, $index, $column), которая может вычислять и возвращать массив атрибутов, таких как class, style, data-key и других.

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
        ...
        // Один вариант
        [
            'attribute'=>'parent_id',
            'label'=>'Родительская категория',
            'contentOptions' =>function ($model, $key, $index, $column){
                return ['class' => 'name'];
            },
            'content'=>function($data){
                return "value";
            }
        ],
        // Другой вариант
        [
            'attribute'=>'category_image',
            'contentOptions' =>['class' => 'table_class','style'=>'display:block;'],
            'content'=>function($data){
                return "value";
            }
        ],
        ...
        ['class' => 'yii\grid\ActionColumn'],
    ],
]); ?>

Сокращенный формат

Yii 2.0 GridView позволяет сократить код настройки поля до вида  ‘attribute:format:label’, где attribute — данные из модели, format — шаблон вывода данных (‘raw’ , ‘text’ , ‘html’ , ‘image’, ‘datetime’,  ‘time’, ‘date’, [‘date’, ‘php:Y-m-d’]  и другие), label — заголовок столбца. В итоге, код

'columns' => [
    ['class' => SerialColumn::className()],
    [
        'class' => DataColumn::className(), // Не обязательно
        'attribute' => 'name',
        'format' => 'text',
        'label' => 'Name',
    ],
    ['class' => CheckboxColumn::className()],
]

можно сократить до

'columns' => [
    ['class' => SerialColumn::className()],
    'name:text:Name',
    ['class' => CheckboxColumn::className()],
]

Класс DataColumn::className() присваивается автоматически, если он не указан.  Формат данных обрабатывается formatter, используемым GridView. По-умолчанию это yii\i18n\Formatter.

Картинка в Yii 2.0 GridView

Картинка в gridview yii2

 

Отобразить картинку в GridView можно несколькими способами:

Самый простой: указать тип поля после двоеточия ‘categoryImagePath:image’. Второй вариант — расширенная настройка поля.

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
    ...
        // Простой вариант. Автоматическое формирование изображения
        'category_image:image',
        // Второй вариант. Формирование изображения и его параметров через анонимную функцию
        [
            'label' => 'Картинка',
            'format' => 'raw',
            'value' => function($data){
                return Html::img(Url::toRoute($data->category_image),[
                    'alt'=>'yii2 - картинка в gridview',
                    'style' => 'width:15px;'
                ]);
            },
        ],
    ...
    ],
]); ?>

Ссылка в GridView

Настроим поле для вывода ссылки из модели.

...
[
    'label' => 'Ссылка',
    'format' => 'raw',
    'value' => function($data){
        return Html::a(
            'Перейти',
            $data->url,
            [
                'title' => 'Смелей вперед!',
                'target' => '_blank'
            ]
        );
    }
],
...

Данные из связанных моделей в GridView

Связанные данные выводятся аналогично данным самой модели.

// Простой вариант, но без возможности сортировки по полю
 'parent.name',
// Вариант с возможностью сортировки по полю
[
    'attribute'=>'parent_id',
    'label'=>'Родительская категория',
    'format'=>'text', // Возможные варианты: raw, html
    'content'=>function($data){
        return $data->getParentName();
    },
    'filter' => Category::getParentsList()
],

В модели Category  описаны соответствующие методы.

public function getParent()
{
    return $this->hasOne(Category::className(), ['id' => 'parent_id']);
}

public function getParentName()
{
    $parent = $this->parent;

    return $parent ? $parent->name : '';
}

Вывод даты и времени в GridView

Отобразить данные в формате даты/времени можно либо прямым указанием типа данных для вывода ‘created_at:datetime’, ‘created_at:date’, ‘created_at:time’ или с использованием расширенного варианта.

// Самый простой вариант. Доступные модификаторы - date:datetime:time
'created_at:time',
// Расширенный вариант с использованием стандартных шаблонов вывода даты/времени
[
    'attribute'=>'created_at',
    'label'=>'Создано',
    'format'=>'datetime', // Доступные модификаторы - date:datetime:time
    'headerOptions' => ['width' => '200'],
],
// Вариант с явным указанием формата вывода даты/времени
[
    'attribute' => 'updated_at',
    'format' =>  ['date', 'HH:mm:ss dd.MM.YYYY'],
    'options' => ['width' => '200']
],

DropDownList в фильтре GridView Yii 2.0

По-умолчанию, GridView использует текстовый фильтр. Для создания фильтра в виде выпадающего меню, достаточно указать массив значений, по которым будет производиться фильтрация в параметре filter. Сортировка и фильтр данных по связанным полям уже описана в соответствующей заметке.

Массив можно задать вручную или получать из модели.

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
...
        [
            'attribute'=>'isactive',
            'filter'=>array("1"=>"Активно","2"=>"Не активно"),
        ],
...
        ['class' => 'yii\grid\ActionColumn'],
    ],
]); ?>

Второй вариант

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
...
        [
            'attribute'=>'parent_id',
            'label'=>'Родительская категория',
            'format'=>'text', // Возможные варианты: raw, html
            'content'=>function($data){
                return $data->getParentName();
            },
            'filter' => Category::getParentsList()
        ],
...
        ['class' => 'yii\grid\ActionColumn'],
    ],
]); ?>

Получение списка категорий, имеющих дочерние, организовано в модели.

public static function getParentsList()
{
    // Выбираем только те категории, у которых есть дочерние категории
    $parents = Category::find()
        ->select(['c.id', 'c.name'])
        ->join('JOIN', 'category c', 'category.parent_id = c.id')
        ->distinct(true)
        ->all();

    return ArrayHelper::map($parents, 'id', 'name');
}

Заключение

Стандартный виджет Yii2 фреймворка GridView имеет богатые возможности для отображения данных. Возможно как отображение «сырых» данных, так и вычисление их на лету, при помощи анонимных функций. Размещение активного содержимого в ячейках GridView будет описано в другом материале.

42 thoughts on “Yii2: Разбираемся с GridView”

  1. Алекс

    Спасибо! Очень полезно написано, куда интереснее чем читать мануалы.

    1. Нурик

      Как мне изменить ширина колонки в gridView?

  2. bob

    Большое спасибо, все качественно и понятно!

  3. Denis

    Спасибо огромное, что собрал всю информацию в наглядном виде по GRIDу.
    Большая просьба, сделай такую же инфу по view. Волнует использование Nested Layouts и Blocks в структуре Views.
    Заранее огромное спасибо)!

  4. Александр

    Большое спасибо за материал!
    Хотелось бы еще увидеть как поэтапно сделать такой же левый sidebar

  5. SunriZe

    Большое спасибо за отличный материал! ^^

  6. Myres

    Спасибо, добрый человек! Все что нужно нашел в Вашей статье! В закладки по любому!

  7. Илья

    Отличный материал, большое спасибо за публикацию!

  8. Иван

    Здравствуйте! Подскажите как изменить стиль полей фильтра? По умолчанию слишком большой padding стоит и не видно значение фильтра :(

  9. Иосиф

    Доброго времени суток!
    у Html::activeDropDownList() можно выставить такую штуку ‘prompt’=>’— Укажите группу — ‘

    а как подобное реализовать в простом
    ‘filter’ => array(
    ‘val1’=>’name1’
    )

    ?
    заранее спасибо!

    1. nix Автор записи

      используйте Html::dropDownList() для фильтра

  10. Volodymyr

    Доброго дня, я прочитав статтю з задоволенням
    дякую

  11. Александр

    Скажите пожалуйста, как выглядит примерный route для этого куска кода:

    Html::img(Url::toRoute($data->category_image)

    Url::toRoute() — вот это меня интересует, как это работает? По идее он должен сгенерировать правильный URL для статики-картинки? А как выглядит сам роут тогда?

    1. nix Автор записи

      Роут (маршрут) — путь до действия, которое нужно вызвать — модуль/контроллер/действие.
      Для статичных изображений используй Url::to().
      Если $data->category_image == ‘images/cat_image.jpg’, тогда Url::to(‘@web/’ . $data->category_image) == ‘/images/cat_image.jpg’.
      Для создания абсолютного пути Url::to(‘@web/’ . $data->category_image, true) == ‘http://site.ru/images/cat_image.jpg’

  12. Евгений

    Подскажите пожалуйста, что за переменная $data в анонимной функции?

    1. nix Автор записи

      Все просто. Идем в доку и видим, какие параметры передаются анонимной функции.

  13. Олег

    Подскажите, как в сокращенном формате
    attribute:format:label
    вывести decimal с двумя знаками после запятой:
    [
    ‘label’ => ‘Summ’,
    ‘attribute’ => ‘summ’,
    ‘format’ => [‘decimal’, 2]
    ],

  14. Vit

    Кто подскажет как убрать номера строк (1 колонка) в GridView?

    1. nix Автор записи

      Просто удали строку [‘class’ => ‘yii\grid\SerialColumn’].

  15. Yuriy

    Через стандартно сгенерированный через gii CRUD с gridView содержимое ячейки отображается в одну строку. Если текста много — появляется длинющий скрол. Подскажите как сделать нормальное отображение с переносом текста.

    1. Yuriy

      Решил проблему, через ‘options’ => [‘width’ => ’70’].
      Спасибо за статью, она реально крутая.

  16. Akula22

    при такой выборке со свзяанной моделью return $data->getCategoryName(); получается очень много запросов БД, каждая итерация делает запрос, можно как-то пофиксить?

    1. ssiunov

      Стало быть нужно связи в запросе к БД наводить. В модели поиска в методе search() нужно запрос дополнить. Примерно так:

      public function search($params) {
      $query = Classes::find()
      ->select([‘CONCAT_WS(«—», DATE_FORMAT(s.begin_time, «%Y»), DATE_FORMAT(s.end_time, «%y»)) AS season_label’, ‘c.*’])
      ->from([«c» => Classes::tableName()])
      ->innerJoin([«s» => Seasons::tableName()], «c.season_id = s.id»);

    2. Valkinaz

      Вдруг кому-то пригодится, написал так.

      [
      ‘attribute’ => ‘department_id’,
      ‘filter’ => Model::getList(), // Массив [ ‘id’ => ‘name’ ]
      ‘content’ => function ($model, $key, $index, $column){
      return $column->filter[$model->department_id];
      }
      ]

      1. Gransplash

        Valkinaz, пригодилось )). Спасибо, Вам очень помогли

        1. Valkinaz

          Не за что, единственное, поторопился отправить тогда, а редактировать уже нельзя.
          Model::getList() стоит вынести в отдельную переменную, а уже потом ее использовать, чтобы не было запросов на каждой записи.

  17. Crazy DemonДмитрий Синицын

    Приветствую Вас уважаемый Nix! Спасибо за хорошую статью и весь сайт в целом!

    Возник такой вопрос, сделал в гриде DropDown по второму варианту (только выборка идёт из этой же базы, полю делаю GROUP BY). А как мне значению по умолчанию, пустое поле чтобы выводить все записи, добавить описание?
    Т.е. [‘prompt’ => ‘Все’] навесить на первый элемент списка?

    Нашел пример такой:
    ‘filter’ => Html::dropDownList(‘PostsSearch[active]’,
    …………
    [
    ‘prompt’ => ‘Все’
    ]),
    Но не понимаю как тут передать данные Category::getParentsList() в dropDownList :(

    Может быть в Вашем примере есть возможность добавить этот «prompt»?

    1. nix Автор записи

      Примерно так:
      'filter' => Html::activeDropDownList($searchModel, 'parent_id', Category::getParentsList(), ['prompt' => 'Все'])

      Подробнее в мануале.

  18. Антон

    Подскажите пожалуйста, как редактировать данные таблицы напрямую? Нужно просто нажать 2 раза на нужную строку после чего ее можно изменить прямо в таблице. Нигде не могу найти подобную инструкцию =(

  19. Hargian

    Спасибо большое за статью!!! Была очень полезна

  20. Александр

    Очень интересно, подробно и красиво.
    Спасибо за статью.
    А как вывести в gridview посты из дочерних категорий при выборе родительской? т.е. именно посты на странице постов выводятся с фильтром по категориям, но при выборе в фильтре родительской отображаются только посты родительской, а хотело8сь бы получить все посты дочерних категорий

  21. Тимур

    Хорошая статья, спасибо! Хотелось бы мне её немного еще увеличить.

  22. Норайр

    А как делать такое

    У меня в базе поле active добавляется Y или N
    как в GridView показать Да или нет