Lab / YII

YII2 Как создать представление ListView + исходники.

Yii2 ListView это виджет который используется для создания прдставления на основе вашего списка данных из БД. Данный виджет крайне удобен для вывода ваших материалов с пагинатором. Более того ListView имеет очень гибкие настройки. Сегодня я покажу вам элементарный пример его использования.

Подготовка

Для начала необходимо создать проект на YII2 и подготовить данные которые мы будем выводить через наше представление. Предположим наша БД будет называтся "post" которую вы уже наполнили её рыбными данными, а также создали модель Post. Давайте добавим в наш контроллер Post ответ на запрос "list":

// PostController.php
use app\models\Post;

class PostController extends \yii\web\Controller
 public function actionList()
 {
 $dataProvider = new ActiveDataProvider([
 'query' => Post::find()->where(['status' => 1])->orderBy('id DESC'),
 'pagination' => [
 'pageSize' => 10,
 ],
 ]);

 $this->view->title = 'Posts List';
 return $this->render('list', ['listDataProvider' => $dataProvider]);
 }
}

Описанный медот формирует ответ на запрос по ссылке: /index.php?r=post/list и рендерит шаблон из list.php что расположен в папке /views/post/ Давайте посмотрим, как сделать представление ListView в list.php.

Настройка представления ListView

В самом простом примере вы просто выводите ListView передаёте dataProvider в list.php файл предствавления и всё готово!

/* list.php view file*/

<?= 
ListView::widget([
 'dataProvider' => $listDataProvider,
]); 
?>

Но в таком случае ListView просто отобращает список id материалов. По умолчанию он будет отображать список моделей key. Так что нам прийдётся немного настроить данное представление. В следующем изображении описанны наиболее важные опции для кастомизации ListView.

yii2-listview-config.png

dataProvider

dataProvider используется для указания источника данных. это объект, который исполняется в yii\data\DataProviderInterface. Обычно этот объект является экземпляром ActiveDataProvider класса.

Options

options представляет собой массив, для создания HTML атрибутов обёртки ListView представления. Например:

<?= 
ListView::widget([
 'dataProvider' => $listDataProvider,
 'options' => [
 'tag' => 'div',
 'class' => 'list-wrapper',
 'id' => 'list-wrapper',
 ],
]);
?>

Layout

layout пределяет структуру разметки ListView. По умолчанию его значение является строкой со следующим содержимым: "{summary}\n{items}\n{pager}". Это означает, во-первых, отрендерить заголовок ListView. Затем последовательность объектов массива и в конце пагинатоа. Вы леко можете это переопределить, например переместив пагинатор наверх, вот так:

<?= 
ListView::widget([
 'dataProvider' => $listDataProvider,
 'options' => [
 'tag' => 'div',
 'class' => 'list-wrapper',
 'id' => 'list-wrapper',
 ],
 'layout' => "{pager}\n{items}\n{summary}",
]);
?>

itemView

itemView может быть либо строкой, либо функцией обратного вызова. Его работа заключается в том, чтобы сказать ListView как визуализировать каждый отдельный элемент списка с данными из модели.

Передача строки

Для передачи строки, строка должна быть именем файла из части шаблона. Например, мы можем создать _list_item.php часть шаблона для определения HTML-разметки каждого элемента списка. Затем мы передаём эту часть в основной шаблон представления itemView таким образом:

<?= 
ListView::widget([
 'dataProvider' => $listDataProvider,
 'options' => [
 'tag' => 'div',
 'class' => 'list-wrapper',
 'id' => 'list-wrapper',
 ],
 'layout' => "{pager}\n{items}\n{summary}",
 'itemView' => '_list_item',
]);
?>

В такой конфигурации будет четыре переменные неявно передающиеся и доступные в _list_item части шаблона.

Передача Callback'а

Альтернативным вариантом может послужить передача callback'а в itemView и данный callback будет вызыватся каждый раз при рендеринге элемента списка.

<?=
ListView::widget([
 'dataProvider' => $listDataProvider,
 'options' => [
 'tag' => 'div',
 'class' => 'list-wrapper',
 'id' => 'list-wrapper',
 ],
 'layout' => "{pager}\n{items}\n{summary}",
 'itemView' => function ($model, $key, $index, $widget) {
 return $this->render('_list_item',['model' => $model]);

 // or just do some echo
 // return $model->title . ' posted by ' . $model->author;
 },
]);
?>

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

function ($model, $key, $index, $widget)

Шаблон элемента _list_item.php может иметь следующий вид:

<?php
// _list_item.php
use yii\helpers\Html;
use yii\helpers\Url;
?>

<article class="item" data-key="<?= $model->id; ?>">
 <h2 class="title">
 <?= Html::a(Html::encode($model->title), Url::toRoute(['post/show', 'id' => $model->id]), ['title' => $model->title]) ?>
 </h2>

 <div class="item-excerpt">
 <?= Html::encode($model->excerpt); ?>
 </div>
</article>

Когда и почему

Итак, когда же мы должны передать callback в itemView? Я думаю, что при следующих сценариях будет очень удобно использовать функцию обратного вызова для itemView:

Пагинатор

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

ListView::widget([
 'dataProvider' => $listDataProvider,
 'options' => [
 'tag' => 'div',
 'class' => 'list-wrapper',
 'id' => 'list-wrapper',
 ],
 'layout' => "{pager}\n{items}\n{summary}",
 'itemView' => function ($model, $key, $index, $widget) {
 return $this->render('_list_item',['model' => $model]);

 // or just do some echo
 // return $model->title . ' posted by ' . $model->author;
 },
 'pager' => [
 'firstPageLabel' => 'first',
 'lastPageLabel' => 'last',
 'nextPageLabel' => 'next',
 'prevPageLabel' => 'previous',
 'maxButtonCount' => 3,
 ],
]);

Данный пагинатор абстранируется от классов навяззаных в yii\widgets\LinkPager. Для получения дополнительных возможностей кастомизации пагинатора ListView представления, обратитесь к официальной документации YII2 LinkPager.

Итоги

В итоге у нас есть образцы кода для настройки Yii2 ListView. Ниже пример кода собранный вместе:

<?= 
ListView::widget([
 'dataProvider' => $listDataProvider,
 'options' => [
 'tag' => 'div',
 'class' => 'list-wrapper',
 'id' => 'list-wrapper',
 ],
 'layout' => "{pager}\n{items}\n{summary}",
 'itemView' => function ($model, $key, $index, $widget) {
 return $this->render('_list_item',['model' => $model]);

 // or just do some echo
 // return $model->title . ' posted by ' . $model->author;
 },
 'itemOptions' => [
 'tag' => false,
 ],
 'pager' => [
 'firstPageLabel' => 'first',
 'lastPageLabel' => 'last',
 'nextPageLabel' => 'next',
 'prevPageLabel' => 'previous',
 'maxButtonCount' => 3,
 ],
]);
?>

Скачать исходники можно на моём гитхабе github.com/markxxv/yii2-listview-sample