Зачем нужен ListView?

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

Подготовка

Для начала нам необходимo определиться какой список мы будем выводить. Для простого примера возьмем список новостей. Для этого необходимо создать простую таблицу News, в которой будут храниться наши записи. SQL запрос для создания таблицы:

CREATE TABLE IF NOT EXISTS `news` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `visibility` tinyint(1) NOT NULL,
  `date` int(11) NOT NULL,
  `header` varchar(255) NOT NULL,
  `text` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3;

Далее создаем модель с помощью gii, в итоге получим следующий код модели (файл: /project-folder/models/News.php):

<?php
namespace app\models;
use Yii;
/** * This is the model class for table "news". * * @property integer $id * @property integer $visibility * @property integer $date * @property string $header * @property string $text */ class News extends \yii\db\ActiveRecord { /** * @inheritdoc */ public static function tableName() { return 'news'; }
/** * @inheritdoc */ public function rules() { return [ [['visibility', 'date', 'header', 'text'], 'required'], [['visibility', 'date'], 'integer'], [['text'], 'string'], [['header'], 'string', 'max' => 255] ]; }
/** * @inheritdoc */ public function attributeLabels() { return [ 'id' => 'ID', 'visibility' => 'Visibility', 'date' => 'Date', 'header' => 'Header', 'text' => 'Text', ]; } }

Далее создаем контроллер для новостей (с помощью gii), получим следующий код контроллера (файл: /project-folder/controllers/NewsController.php):

<?php
namespace frontend\controllers;
use Yii;
class NewsController extends \yii\web\Controller { public function actionIndex() { $this->view->title = 'News List'; return $this->render('index'); } }

Вместе с контроллером будет создан и view со следующим кодом (файл: /project-folder/views/news/index.php):

<?php
/* @var $this yii\web\View */
?>
<h1>news/index</h1>
<p> You may change the content of this page by modifying the file <code><?= __FILE__; ?></code>. </p>

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

Минимальный код для вывода списка записей с помощью виджета ListView

Для вывода списка необходимо добавить в файл /project-folder/views/news/index.php следующий код:

<?php
use app\models\News; use yii\widgets\ListView; use yii\data\ActiveDataProvider;
$dataProvider = new ActiveDataProvider([ 'query' => News::find()->where(['visibility'=>1])->orderBy('date DESC'), 'pagination' => [ 'pageSize' => 20, ], ]);
echo ListView::widget([ 'dataProvider' => $dataProvider, 'itemView' => '_list', ]);

И создать файл для вывода записей по шаблону (файл: /project-folder/views/news/_list.php):

<?php
use yii\helpers\Html;
use yii\helpers\HtmlPurifier;
?>
<div class="news-item"> <h2><?= Html::encode($model->header) ?></h2> <?= HtmlPurifier::process($model->text) ?> </div>

Разберем код подробнее

Разберемся немного подробнее. В файл /project-folder/views/news/index.php мы сначала подключаем модель News с помощью пространства имен (строка: 3):

use app\models\News;

Далее таким же образом подключаем виджет ListView (строка: 4):

use yii\widgets\ListView;

И подключаем провайдер данных ActiveDataProvider, который работает с ActiveQuery и возвращает массив объектов моделей с их связями. Используется для отображения данных ActiveRecord (строка: 5).

use yii\data\ActiveDataProvider;

Далее мы инициализируем ActiveDataProvider, который мы подключили выше (что логичнее делать в контроллере, но об этом позже):

$dataProvider = new ActiveDataProvider([
    'query' => News::find()->where(['visibility'=>1])->orderBy('date DESC'),
    'pagination' => [
        'pageSize' => 20,
    ],
]);

И вызываем виджет ListView, который мы подключили выше, для вывода списка записей и переменной $dataProvider по шаблону который указан в фале /project-folder/views/news/_list.php.

echo ListView::widget([
    'dataProvider' => $dataProvider,
    'itemView' => '_list',
]);

В шаблоне /project-folder/views/news/_list.php мы подключаем набор статических методов для создания часто используемых HTML тегов (строка: 2):

use yii\helpers\Html;

И подключаем класс (хелпер) который очищает HTML от любого вредоносного кода (строка: 3):

use yii\helpers\HtmlPurifier;

Далее выводим сам шаблон с использованием подключенных классов.

Вывода списка записей с помощью виджета ListView

Перенесем получения списка данных из представления (view) в контроллер. Для этого необходимо подправить контроллер /project-folder/controllers/NewsController.php, подключить к нему модель News и провайдер данных ActiveDataProvider, соответственно эти подключения убрать из представления /project-folder/views/news/index.php. Таким образом контроллер /project-folder/controllers/NewsController.php примет вид:

<?php
namespace frontend\controllers;
use Yii;
use app\models\News; use yii\data\ActiveDataProvider;
class NewsController extends \yii\web\Controller { public function actionIndex() { $dataProvider = new ActiveDataProvider([ 'query' => News::find()->where(['visibility'=>1])->orderBy('date DESC'), 'pagination' => [ 'pageSize' => 10, ], ]); $this->view->title = 'News List'; return $this->render('index', ['listDataProvider' => $dataProvider]); } }

А представление (view) project-folder/views/news/index.php примет вид:

<?php
use yii\widgets\ListView;
echo ListView::widget([ 'dataProvider' => $listDataProvider, 'itemView' => '_list', ]);

Шаблон вывода записей /project-folder/views/news/_list.php остается без изменений.

Настройка вывода списка записей ListView

Вид виджета ListView и его работу можно настроить под свои нужды.

Часто используемые свойства виджета ListView

Название Тип Описание
dataProvider Данные списка
itemView string Имя представления (view) для вывода записи
options array Настройка внешнего контейнера списка (HTML атрибуты для контейнера)
layout atring Макет списка
summary string Информация о списке
summaryOptions array Настройка контейнера для summary (HTML атрибуты для контейнера)
itemOptions
array Настройка контейнера записи списка (HTML атрибуты для контейнера)
emptyText string Текст при отсутствии элементов списка
emptyTextOptions array Настройка контейнера для emptyText (HTML атрибуты для контейнера)
pager array Постраничная навигация

Options. Настройка внешнего контейнера списка

options - массив для настройки HTML атрибутов внешнего контейнера ListView. Например заключим наш список в блок (div) с классом и идентификатором news-list:

<?php
use yii\widgets\ListView;
echo ListView::widget([ 'dataProvider' => $listDataProvider, 'itemView' => '_list',
'options' => [ 'tag' => 'div', 'class' => 'news-list', 'id' => 'news-list', ],
]);

Layout. Макет списка

Макет определяющий как должны быть организованы различные секции списка. Значение по умолчанию: {summary}\n{items}\n{pager}, где {summary} - информация о списке (общее количество элементов и количество элементов показано на странице), {items} - список, {pager} - постраничный навигатор. Пример:

<?php
use yii\widgets\ListView;
echo ListView::widget([ 'dataProvider' => $listDataProvider, 'itemView' => '_list',
'layout' => "{pager}\n{summary}\n{items}\n{pager}", ]);

Summary. Информация о списке

Информацию о списке {summary} также можно настроить под свои нужды.

{begin} начальный номер строки на странице
{end} последний номер строки на странице
{count} количество строк в списке на странице
{totalCount} общее количество строк в списке
{page} номер текущей страницы
{pageCount} общее число страниц в списке

Пример:

<?php
use yii\widgets\ListView;
echo ListView::widget([ 'dataProvider' => $listDataProvider, 'itemView' => '_list',
'layout' => "{pager}\n{summary}\n{items}\n{pager}", 'summary' => 'Показано {count} из {totalCount}' ]);

SummaryOptions. Настройка контейнера для summary

Заключим summary в тег <span></span> с классом my-summary:

<?php
use yii\widgets\ListView;
echo ListView::widget([ 'dataProvider' => $listDataProvider, 'itemView' => '_list', 'layout' => "{pager}\n{summary}\n{items}\n{pager}", 'summary' => 'Показано {count} из {totalCount}' 'summaryOptions' => [ 'tag' => 'span', 'class' => 'my-summary' ], ]);

ItemOptions. Настройка контейнера записи списка

Например обернем каждую запись в блок (div) с классом news-item, пример:

<?php
use yii\widgets\ListView;
echo ListView::widget([ 'dataProvider' => $listDataProvider, 'itemView' => '_list',
'itemOptions' => [ 'tag' => 'div', 'class' => 'news-item', ], ]);

EmptyText. Текст при отсутствии элементов списка

Если список пуст, то необходимо пользователю вывести сообщение об этом, например:

<?php
use yii\widgets\ListView;
echo ListView::widget([ 'dataProvider' => $listDataProvider, 'itemView' => '_list',
'emptyText' => 'Список пуст', ]);

EmptyTextOptions. Настройка контейнера для emptyText

Заключим текст в тег <p></p>:

<?php
use yii\widgets\ListView;
echo ListView::widget([ 'dataProvider' => $listDataProvider, 'itemView' => '_list', 'emptyText' => 'Список пуст',
'emptyTextOptions' => [ 'tag' => 'p' ], ]);

Pager. Постраничная навигация

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

<?php
use yii\widgets\ListView;
echo ListView::widget([ 'dataProvider' => $listDataProvider, 'itemView' => '_list', 'pager' => [ 'firstPageLabel' => 'Первая', 'lastPageLabel' => 'Последняя', 'nextPageLabel' => 'Следующая', 'prevPageLabel' => 'Предыдущая', 'maxButtonCount' => 5, ], ]);

Все настройки можно посмотреть здесь: http://www.yiiframework.com/doc-2.0/yii-widgets-linkpager.html

Итого

Окончательный вид project-folder/views/news/index.php:

<?php
use yii\widgets\ListView;
echo ListView::widget([ 'dataProvider' => $listDataProvider, 'itemView' => '_list',
'options' => [ 'tag' => 'div', 'class' => 'news-list', 'id' => 'news-list', ],
'layout' => "{pager}\n{summary}\n{items}\n{pager}", 'summary' => 'Показано {count} из {totalCount}', 'summaryOptions' => [ 'tag' => 'span', 'class' => 'my-summary' ],
'itemOptions' => [ 'tag' => 'div', 'class' => 'news-item', ],
'emptyText' => '<p>Список пуст</p>', 'emptyTextOptions' => [ 'tag' => 'p' ],
'pager' => [ 'firstPageLabel' => 'Первая', 'lastPageLabel' => 'Последняя', 'nextPageLabel' => 'Следующая', 'prevPageLabel' => 'Предыдущая', 'maxButtonCount' => 5, ], ]);

Дополнительно

С официальной документацией виджета можно ознакомиться здесь: http://www.yiiframework.com/doc-2.0/yii-widgets-listview.html