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. Алекс

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

  2. Denis

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

  3. Александр

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

  4. Myres

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

  5. Иван

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

  6. Иосиф

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

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

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

  7. Александр

    Скажите пожалуйста, как выглядит примерный 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’

  8. Евгений

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

  9. Олег

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

  10. Yuriy

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

    1. Yuriy

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

  11. 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. Valkinaz

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

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

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

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

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

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

  13. Антон

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

  14. Александр

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

  15. Норайр

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

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *