Виджеты данных
Yii предоставляет набор виджетов, которые можно использовать для отображения данных. В то время как виджет DetailView может использоваться для отображения данных для одной записи, ListView и GridView могут использоваться для отображения списка или таблицы записей данных, предоставляя функции, такие как постраничная навигация, сортировка и фильтрация.
DetailView
Виджет DetailView отображает детали одной записи данных модели.
Он лучше всего подходит для отображения модели в обычном формате (например, каждый атрибут модели отображается как строка в таблице). Модель может быть экземпляром или подклассом yii\base\Model, например, активной записью или ассоциативным массивом.
DetailView использует свойство $attributes для определения атрибутов модели, которые должны быть отображены, и того, как они должны быть отформатированы. См. раздел форматирования для доступных вариантов форматирования.
Типичное использование DetailView выглядит следующим образом:
echo DetailView::widget([
'model' => $model,
'attributes' => [
'title', // title attribute (in plain text)
'description:html', // description attribute formatted as HTML
[ // the owner name of the model
'label' => 'Owner',
'value' => $model->owner->name,
'contentOptions' => ['class' => 'bg-red'], // HTML attributes to customize value tag
'captionOptions' => ['tooltip' => 'Tooltip'], // HTML attributes to customize label tag
],
'created_at:datetime', // creation date formatted as datetime
],
]);
Помните, что в отличие от yii\widgets\GridView, который обрабатывает набор моделей, DetailView обрабатывает только одну. Поэтому в большинстве случаев нет необходимости использовать замыкание, так как $model является единственной моделью для отображения и доступна в представлении как переменная.
Однако в некоторых случаях использование замыкания может быть полезным. Например, когда visible указано, и вы хотите предотвратить value вычисления в случае, если оно вычисляется до false:
echo DetailView::widget([
'model' => $model,
'attributes' => [
[
'attribute' => 'owner',
'value' => function ($model) {
return $model->owner->name;
},
'visible' => \Yii::$app->user->can('posts.owner.view'),
],
],
]);
ListView
Виджет ListView используется для отображения данных из источника данных. Каждая модель данных отображается с помощью указанного файла представления. Поскольку он предоставляет такие функции, как постраничная навигация, сортировка и фильтрация «из коробки», он удобен как для отображения информации пользователю, так и для создания пользовательского интерфейса управления данными.
Типичное использование выглядит следующим образом:
use yii\widgets\ListView;
use yii\data\ActiveDataProvider;
$dataProvider = new ActiveDataProvider([
'query' => Post::find(),
'pagination' => [
'pageSize' => 20,
],
]);
echo ListView::widget([
'dataProvider' => $dataProvider,
'itemView' => '_post',
]);
Файл представления _post может содержать следующее:
<?php
use yii\helpers\Html;
use yii\helpers\HtmlPurifier;
?>
<div class="post">
<h2><?= Html::encode($model->title) ?></h2>
<?= HtmlPurifier::process($model->text) ?>
</div>
В файле представления выше текущая модель данных доступна как $model. Кроме того, доступны следующие переменные:
-
$key: смешанный тип, значение ключа, связанное с элементом данных. -
$index: целое число, индекс элемента данных с нуля в массиве элементов, возвращаемом источником данных. -
$widget: ListView, экземпляр этого виджета.
Если вам нужно передать дополнительные данные в каждое представление, вы можете использовать свойство $viewParams для передачи пар «ключ-значение», как показано ниже:
echo ListView::widget([
'dataProvider' => $dataProvider,
'itemView' => '_post',
'viewParams' => [
'fullView' => true,
'context' => 'main-page',
// ...
],
]);
Эти значения также доступны как переменные в представлении.
GridView
Таблица данных или GridView — один из самых мощных виджетов Yii. Он очень полезен, если вам нужно быстро создать административную часть системы. Он получает данные из источника данных и отображает каждую строку с помощью набора столбцов, представляя данные в виде таблицы.
Каждая строка таблицы представляет данные одного элемента данных, а столбец обычно представляет атрибут элемента (некоторые столбцы могут соответствовать сложным выражениям атрибутов или статическому тексту).
Минимальный код, необходимый для использования GridView, следующий:
use yii\grid\GridView;
use yii\data\ActiveDataProvider;
$dataProvider = new ActiveDataProvider([
'query' => Post::find(),
'pagination' => [
'pageSize' => 20,
],
]);
echo GridView::widget([
'dataProvider' => $dataProvider,
]);
В приведенном выше коде сначала создается источник данных, а затем GridView используется для отображения каждого атрибута в каждой строке, взятой из источника данных. Отображаемая таблица имеет сортировку и постраничную навигацию по умолчанию.
Столбцы сетки
Столбцы таблицы сетки настраиваются с использованием классов yii\grid\Column, которые настраиваются в свойстве columns конфигурации GridView. В зависимости от типа столбца и настроек они способны отображать данные по-разному. По умолчанию используется класс yii\grid\DataColumn, который представляет атрибут модели и может быть отсортирован и отфильтрован.
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// Simple columns defined by the data contained in $dataProvider.
// Data from the model's column will be used.
'id',
'username',
// More complex one.
[
'class' => 'yii\grid\DataColumn', // can be omitted, as it is the default
'value' => function ($data) {
return $data->name; // $data['name'] for array data, e.g. using SqlDataProvider.
},
],
],
]);
Обратите внимание, что если часть конфигурации columns не указана, Yii пытается показать все возможные столбцы модели источника данных.
Классы столбцов
Столбцы сетки можно настроить, используя различные классы столбцов:
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'class' => 'yii\grid\SerialColumn', // <-- here
// you may configure additional properties here
],
Помимо предоставляемых Yii классов столбцов, которые мы рассмотрим ниже, вы можете создавать свои собственные классы столбцов.
Каждый класс столбца расширяется от yii\grid\Column, поэтому у вас есть некоторые общие параметры, которые вы можете задать при настройке столбцов сетки.
- header позволяет задать содержимое для строки заголовка.
- footer позволяет задать содержимое для строки подвала.
- visible определяет, должен ли столбец быть видимым.
-
content позволяет передать допустимую функцию обратного вызова PHP, которая вернёт данные для строки. Формат следующий:
function ($model, $key, $index, $column) { return 'a string'; }
Вы можете указать различные параметры HTML контейнера, передав массивы в:
Столбец данных
Столбец данных используется для отображения и сортировки данных. Это тип столбца по умолчанию, поэтому указание класса можно опустить при его использовании.
Основной настройкой столбца данных является свойство format. Его значения соответствуют методам компонента приложения formatter компонента приложения, который по умолчанию является Formatter:
echo GridView::widget([
'columns' => [
[
'attribute' => 'name',
'format' => 'text'
],
[
'attribute' => 'birthday',
'format' => ['date', 'php:Y-m-d']
],
],
]);
В приведенном выше примере text соответствует yii\i18n\Formatter::asText(). Значение столбца передается в качестве первого аргумента. Во втором определении столбца date соответствует yii\i18n\Formatter::asDate(). Значение столбца снова передаётся в качестве первого аргумента, а 'php:Y-m-d' используется как значение второго аргумента.
Список доступных форматировщиков см. в разделе о форматировании данных.
Для настройки столбцов данных также существует сокращенное форматирование, которое описано в документации API для columns.
Столбец действий
Столбец действий отображает кнопки действий, такие как обновление или удаление, для каждой строки.
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'class' => 'yii\grid\ActionColumn',
// you may configure additional properties here
],
Доступные свойства, которые вы можете настроить, это:
- controller — это идентификатор контроллера, который должен обрабатывать действия. Если не задано, будет использоваться текущий активный контроллер.
-
template определяет шаблон, используемый для составления каждой ячейки в столбце действий. Токены, заключённые в фигурные скобки, рассматриваются как идентификаторы действий контроллера (также называемые названиями кнопок в контексте столбца действий). Они будут заменены соответствующими функциями обратного вызова рендеринга кнопок, указанными в buttons. Например, токен
{view}будет заменён результатом функции обратного вызоваbuttons['view']. Если функция обратного вызова не найдена, токен будет заменён пустой строкой. Токены по умолчанию —{view} {update} {delete}. -
buttons — массив функций обратного вызова рендеринга кнопок. Ключи массива — названия кнопок (без фигурных скобок), а значения — соответствующие функции обратного вызова рендеринга кнопок. Функции обратного вызова должны использовать следующий сигнатур:
function ($url, $model, $key) { // return the button HTML code }В коде выше
$url— это URL, который столбец создаёт для кнопки,$model— объект модели, отображаемый для текущей строки, а$key— ключ модели в массиве источника данных. - urlCreator — функция обратного вызова, которая создаёт URL кнопки, используя указанную информацию о модели. Подпись функции обратного вызова должна быть такой же, как у yii\grid\ActionColumn::createUrl(). Если это свойство не задано, URL кнопок будут созданы с помощью yii\grid\ActionColumn::createUrl().
-
visibleButtons — массив условий видимости для каждой кнопки. Ключи массива — имена кнопок (без фигурных скобок), а значения — булевы
true/falseили анонимная функция. Если имя кнопки не указано в этом массиве, она будет отображаться по умолчанию. Функции обратного вызова должны использовать следующий сигнатур:function ($model, $key, $index) { return $model->status === 'editable'; }Или вы можете передать булево значение:
[ 'update' => \Yii::$app->user->can('update') ]
Столбец флажков
Столбец флажков отображает столбец флажков.
Чтобы добавить CheckboxColumn в GridView, добавьте его в конфигурацию columns следующим образом:
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
// ...
[
'class' => 'yii\grid\CheckboxColumn',
// you may configure additional properties here
],
],
Пользователи могут нажать на флажки, чтобы выбрать строки сетки. Выбранные строки можно получить, используя следующий JavaScript-код:
var keys = $('#grid').yiiGridView('getSelectedRows');
// keys is an array consisting of the keys associated with the selected rows
Столбец порядковых номеров
Столбец порядковых номеров отображает номера строк, начиная с 1 и далее.
Использование простое:
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'], // <-- here
// ...
Сортировка данных
Примечание: Этот раздел находится в разработке.
Фильтрация данных
Для фильтрации данных, GridView нуждается в модели, представляющей критерии поиска, которые обычно берутся из полей фильтра в таблице GridView. Распространённой практикой при использовании активных записей является создание класса модели поиска, который предоставляет необходимую функциональность (он может быть сгенерирован для вас Gii). Этот класс определяет правила валидации для отображения элементов управления фильтрами в таблице GridView и предоставляет метод search() , который вернёт поставщик данных с изменённым запросом, обрабатывающим критерии поиска.
Чтобы добавить возможность поиска для модели Post, мы можем создать модель PostSearch, как в следующем примере:
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
class PostSearch extends Post
{
public function rules()
{
// only fields in rules() are searchable
return [
[['id'], 'integer'],
[['title', 'creation_date'], 'safe'],
];
}
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
public function search($params)
{
$query = Post::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// load the search form data and validate
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
// adjust the query by adding the filters
$query->andFilterWhere(['id' => $this->id]);
$query->andFilterWhere(['like', 'title', $this->title])
->andFilterWhere(['like', 'creation_date', $this->creation_date]);
return $dataProvider;
}
}
Подсказка: Обратитесь к строителю запросов и, в частности, к условиям фильтрации, чтобы узнать, как создать запрос фильтрации.
Вы можете использовать эту функцию в контроллере, чтобы получить поставщик данных для GridView:
$searchModel = new PostSearch();
$dataProvider = $searchModel->search(Yii::$app->request->get());
return $this->render('myview', [
'dataProvider' => $dataProvider,
'searchModel' => $searchModel,
]);
А в представлении вы затем назначите $dataProvider и $searchModel свойству GridView:
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
// ...
],
]);
Отдельная форма фильтра
В большинстве случаев использование фильтров заголовков GridView достаточно, но в случае необходимости отдельной формы фильтра вы можете легко её добавить. Вы можете создать частичное представление _search.php со следующим содержимым:
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
/* @var $this yii\web\View */
/* @var $model app\models\PostSearch */
/* @var $form yii\widgets\ActiveForm */
?>
<div class="post-search">
<?php $form = ActiveForm::begin([
'action' => ['index'],
'method' => 'get',
]); ?>
<?= $form->field($model, 'title') ?>
<?= $form->field($model, 'creation_date') ?>
<div class="form-group">
<?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= Html::submitButton('Reset', ['class' => 'btn btn-default']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
и включить его в представление index.php следующим образом:
<?= $this->render('_search', ['model' => $searchModel]) ?>
Примечание: если вы используете Gii для генерации кода CRUD, отдельная форма фильтра (
_search.php) генерируется по умолчанию, но закомментирована в представленииindex.php. Разкомментируйте её, и она будет готова к использованию!
Отдельная форма фильтра полезна, когда требуется фильтрация по полям, которые не отображаются в GridView или для особых условий фильтрации, например, диапазона дат. Для фильтрации по диапазону дат мы можем добавить не-базовые атрибуты createdFrom и createdTo к модели поиска:
class PostSearch extends Post
{
/**
* @var string
*/
public $createdFrom;
/**
* @var string
*/
public $createdTo;
}
Расширьте условия запроса в методе search() следующим образом:
$query->andFilterWhere(['>=', 'creation_date', $this->createdFrom])
->andFilterWhere(['<=', 'creation_date', $this->createdTo]);
И добавьте соответствующие поля в форму фильтра:
<?= $form->field($model, 'creationFrom') ?> <?= $form->field($model, 'creationTo') ?>
Работа с отношениями моделей
При отображении активных записей в GridView вы можете столкнуться с ситуацией, когда вам нужно отобразить значения связанных столбцов, таких как имя автора записи, вместо просто его id. Для этого укажите имя атрибута в yii\grid\GridView::$columns как author.name, когда модель Post имеет отношение, названное author, а модель автора имеет атрибут name. GridView затем отобразит имя автора, но сортировка и фильтрация по умолчанию отключены. Вам необходимо настроить модель PostSearch , которая была представлена в предыдущем разделе, чтобы добавить эту функциональность.
Чтобы включить сортировку по связанному столбцу, вам нужно объединить связанную таблицу и добавить правило сортировки к компоненту сортировки поставщика данных:
$query = Post::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// join with relation `author` that is a relation to the table `users`
// and set the table alias to be `author`
$query->joinWith(['author' => function($query) { $query->from(['author' => 'users']); }]);
// since version 2.0.7, the above line can be simplified to $query->joinWith('author AS author');
// enable sorting for the related column
$dataProvider->sort->attributes['author.name'] = [
'asc' => ['author.name' => SORT_ASC],
'desc' => ['author.name' => SORT_DESC],
];
// ...
Для фильтрации также требуется вызов joinWith, как указано выше. Вам также нужно определить столбец для поиска в атрибутах и правилах следующим образом:
public function attributes()
{
// add related fields to searchable attributes
return array_merge(parent::attributes(), ['author.name']);
}
public function rules()
{
return [
[['id'], 'integer'],
[['title', 'creation_date', 'author.name'], 'safe'],
];
}
В search() вы затем просто добавите ещё одно условие фильтра с:
$query->andFilterWhere(['LIKE', 'author.name', $this->getAttribute('author.name')]);
Информация: В приведённом выше примере мы используем одну и ту же строку для имени отношения и псевдонима таблицы; однако, когда псевдоним и имя отношения отличаются, вы должны обращать внимание на то, где используется псевдоним, а где — имя отношения. Простое правило для этого — использовать псевдоним в каждом месте, где строится запрос к базе данных, и имя отношения во всех других определениях, таких как
attributes()иrules()и т. д.Например, если вы используете псевдоним
auдля таблицы отношения автора, оператор joinWith выглядит следующим образом:$query->joinWith(['author au']);Также можно просто вызвать
$query->joinWith(['author']);при определении псевдонима в определении отношения.Псевдоним должен использоваться в условии фильтра, но имя атрибута остаётся тем же:
$query->andFilterWhere(['LIKE', 'au.name', $this->getAttribute('author.name')]);То же самое относится к определению сортировки:
$dataProvider->sort->attributes['author.name'] = [ 'asc' => ['au.name' => SORT_ASC], 'desc' => ['au.name' => SORT_DESC], ];Кроме того, при указании defaultOrder для сортировки, вам необходимо использовать имя отношения вместо псевдонима:
$dataProvider->sort->defaultOrder = ['author.name' => SORT_ASC];
Информация: Для получения дополнительной информации о
joinWithи запросах, выполняемых в фоновом режиме, обратитесь к документации по активным записям о присоединении к отношениям.
Использование SQL-представлений для фильтрации, сортировки и отображения данных
Существует ещё один подход, который может быть быстрее и полезнее — SQL-представления. Например, если нам нужно отобразить GridView с пользователями и их профилями, мы можем сделать это так:
CREATE OR REPLACE VIEW vw_user_info AS
SELECT user.*, user_profile.lastname, user_profile.firstname
FROM user, user_profile
WHERE user.id = user_profile.user_id
Затем вам нужно создать ActiveRecord, который будет представлять это представление:
namespace app\models\views\grid;
use yii\db\ActiveRecord;
class UserView extends ActiveRecord
{
/**
* @inheritdoc
*/
public static function tableName()
{
return 'vw_user_info';
}
public static function primaryKey()
{
return ['id'];
}
/**
* @inheritdoc
*/
public function rules()
{
return [
// define here your rules
];
}
/**
* @inheritdoc
*/
public static function attributeLabels()
{
return [
// define here your attribute labels
];
}
}
После этого вы можете использовать активную запись UserView с моделями поиска, без дополнительной спецификации атрибутов сортировки и фильтрации. Все атрибуты будут работать из коробки. Обратите внимание, что у этого подхода есть несколько плюсов и минусов:
- вам не нужно указывать разные условия сортировки и фильтрации. Всё работает из коробки;
- он может быть намного быстрее из-за размера данных, количества SQL-запросов (для каждого отношения вам не потребуется дополнительный запрос);
- поскольку это просто отображение интерфейса пользователя на SQL-представление, ему не хватает некоторой логики предметной области, которая есть в ваших сущностях, поэтому, если у вас есть какие-либо методы, такие как
isActive,isDeletedили другие, которые повлияют на интерфейс пользователя, вам нужно будет дублировать их в этом классе тоже.
Несколько GridView на одной странице
Вы можете использовать более одного GridView на одной странице, но для того, чтобы они не мешали друг другу, требуется дополнительная настройка. При использовании нескольких экземпляров GridView вам необходимо настроить разные имена параметров для сгенерированных ссылок сортировки и постраничной навигации, чтобы каждый GridView имел собственную сортировку и постраничную навигацию. Для этого установите sortParam и pageParam экземпляров сортировки и постраничной навигации поставщика данных.
Предположим, мы хотим отобразить модели Post и User, для которых мы уже подготовили два поставщика данных в $userProvider и $postProvider:
use yii\grid\GridView;
$userProvider->pagination->pageParam = 'user-page';
$userProvider->sort->sortParam = 'user-sort';
$postProvider->pagination->pageParam = 'post-page';
$postProvider->sort->sortParam = 'post-sort';
echo '<h1>Users</h1>';
echo GridView::widget([
'dataProvider' => $userProvider,
]);
echo '<h1>Posts</h1>';
echo GridView::widget([
'dataProvider' => $postProvider,
]);
Использование GridView с Pjax
Виджет Pjax позволяет обновить определённый раздел страницы вместо перезагрузки всей страницы. Вы можете использовать его для обновления только содержимого GridView при использовании фильтров.
use yii\widgets\Pjax;
use yii\grid\GridView;
Pjax::begin([
// PJax options
]);
Gridview::widget([
// GridView options
]);
Pjax::end();
Pjax также работает для ссылок внутри виджета Pjax и для ссылок, указанных в Pjax::$linkSelector. Но это может быть проблемой для ссылок ActionColumn. Чтобы предотвратить это, добавьте атрибут HTML data-pjax="0" к ссылкам при редактировании свойства ActionColumn::$buttons.
GridView/ListView с Pjax в Gii
С версии 2.0.5 генератор CRUD Gii имеет опцию $enablePjax, которая может быть использована как через веб-интерфейс, так и через командную строку.
yii gii/crud --controllerClass="backend\\controllers\PostController" \ --modelClass="common\\models\\Post" \ --enablePjax=1
Это генерирует виджет Pjax, который оборачивает виджеты GridView или ListView.
Дополнительная информация
- Rendering Data in Yii 2 with GridView and ListView by Arno Slatius.
© 2008–2017 by Yii Software LLC
Licensed under the three clause BSD license.
http://www.yiiframework.com/doc-2.0/guide-output-data-widgets.html