Содержание статьи:
- Зачем нужен CGridView
- Подготовка
- Базовый вывод списка записей
- Стилизация виджета CGridView
- Поиск в виджете CGridView
- Настройка и стилизация колонок виджета CGridView
- Вывод данных со связанных таблицы
- Выпадающий список для поиска записей в виджете CGridView
- Поиск по дате с помощью datepicker
- Кнопки управления записями
- Выбор количества записей на страницу
- Итого
- Вывод
- Дополнительно
Зачем нужен CGridView
CGridView отображает список элементов данных в виде таблицы.
Каждая строка таблицы - это данные одного элемента из источника данных (чаще всего таблицы), а столбец обычно представляет атрибут элемента (некоторые столбцы могут соответствовать сложному выражению атрибутов или могут быть статическим текстом).
CGridView поддерживает сортировку и разбиение на страницы элементов из коробки. Сортировка и разбиение на страницы может быть реализована в режиме AJAX или в обычном запросе. Преимущество использования CGridView в том, что при отключенном JavaScript в браузере пользователя, сортировка и разбиение на страницы автоматически превращаются в обычные запросы и виджет нормально продолжает работать.
Подготовка
Для реализации примера нам потребуется 2 таблицы. Первая таблица будет содержать список статей, назовем ее posts. SQL запрос на создание таблицы:
CREATE TABLE IF NOT EXISTS `posts` ( `id` int(11) NOT NULL AUTO_INCREMENT, `url` varchar(255) NOT NULL, `header` varchar(255) NOT NULL, `text` longtext NOT NULL, `visibility` tinyint(1) NOT NULL, `date` int(11) NOT NULL, `userId` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
Вторая будет содержать информацию о авторе статьи, назовем ее user. SQL запрос на создание таблицы:
CREATE TABLE IF NOT EXISTS `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `email` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
Связь между таблицами user и posts будет один ко многим, т.е. 1 пользователь может иметь много статей. Для этих таблиц мы сгенерируем модели с помощью gii.
Также нам потребуется контроллер /protected/controllers/PostsController.php для вывода списка записей. И представление /themes/themeName/posts/list.php для вывода виджета CGridView.
Для получения привлекательного вида виджета будем использовать стиль Bootstrap 3. Предполагаю что Вы его уже подключили или можете использовать свой стиль.
И так приступим.
Базовый вывод списка записей
Код контроллера (файл: /protected/controllers/PostsController.php):
<?php
class PostsController extends Controller {
//...
/** * Список записей */ public function actionList() { $model = new Posts('search'); $this->render('list', array('model' => $model)); } }
Код представления (view) (файл: /themes/themeName/views/posts/list.php):
<?php
$this->widget('zii.widgets.grid.CGridView', array( 'dataProvider' => $model->search(), 'columns' => array( 'id', 'header', 'visibility', ), ));
В итоге мы получим следующие:
На данном этапе мы имеем список записей сортировку по полям (для сортировки необходимо кликнуть по заголовку таблицы нужной колонки) и постраничную навигацию.
Стилизация виджета CGridView
Продолжим. Стилицируем виджет CGridView под стиль Bootstrap 3. Для этого приведем представление к следующему виду (файл: /themes/themeName/views/posts/list.php):
<?php
$this->widget('zii.widgets.grid.CGridView', array( 'dataProvider' => $model->search(),
'id' => 'posts-grid', 'htmlOptions' => array('class' => 'table'), 'itemsCssClass' => 'table table-hover table-striped', 'loadingCssClass' => 'grid-preloader', 'columns' => array( 'id', 'header', 'visibility', ), ));
Теперь немного подробнее.
Строка 6, идентификатор виджета
'id' => 'posts-grid',
Строка 7, класс обертки виджета CGridView:
'htmlOptions' => array('class' => 'table'),
Строка 8, класс для таблицы виджета CGridView:
'itemsCssClass' => 'table table-hover table-striped',
Строка 9, класс прелоадера ajax загрузки данных. На данном этапе это сортировка и постраничная навигация:
'loadingCssClass' => 'grid-preloader',
Все стили уже есть в Bootstrap 3, кроме grid-preloader, CSS для этого класса:
.grid-preloader{
background: url(/themes/themeName/images/preloader.gif) no-repeat center 0;
width: 100%;
z-index: 9999;
}
При желании можно оставить стандартный прелоадер виджета, для этого просто удалите строку содержащую класс прелоадера (строка: 9).
Также необходимо добавить CSS стиль для классов .desc и .asc которые добаляються при сортировки в заголовок таблицы:
.sort-link.desc{
background:url(/themes/themeName/images/down.gif) right center no-repeat;
padding-right: 10px;
}
.sort-link.asc{
background:url(/themes/themeName/images/up.gif) right center no-repeat;
padding-right: 10px;
}
down.gif и up.gif можно заменить своими или взять их из фреймворка (/framework/zii/widgets/assets/gridview).
Стилизация постраничного навигатора
Для полноты картины необходимо привести в порядок вид постраничной навигации, добавим следующий код в виджет:
'pagerCssClass' => 'text-center',
'pager' => array(
'nextPageLabel' => '<span>»</span>',
'prevPageLabel' => '<span>«</span>',
'lastPageLabel' => '<span>»»</span>',
'firstPageLabel' => '<span««</span>',
'selectedPageCssClass' => 'active',
'hiddenPageCssClass' => 'disabled',
'htmlOptions' => array('class' => 'pagination'),
'class' => 'CLinkPager',
'header' => false,
'pageSize' => 5,
),
Итого, код представления примет вид (файл: /themes/themeName/views/posts/list.php):
<?php
$this->widget('zii.widgets.grid.CGridView', array( 'dataProvider' => $model->search(),
'id' => 'posts-grid', 'htmlOptions' => array('class' => 'table'), 'itemsCssClass' => 'table table-hover table-striped', 'loadingCssClass' => 'grid-preloader',
'pagerCssClass' => 'text-center', 'pager' => array( 'nextPageLabel' => '<span>»</span>', 'prevPageLabel' => '<span>«</span>', 'lastPageLabel' => '<span>»»</span>', 'firstPageLabel' => '<span>««</span>', 'selectedPageCssClass' => 'active', 'hiddenPageCssClass' => 'disabled', 'htmlOptions' => array('class' => 'pagination'), 'class' => 'CLinkPager', 'header' => false, 'pageSize' => 5, ),
'columns' => array( 'id', 'header', 'visibility', ), ));
Подробнее о настройки постраничного навигатора можно прочитать здесь: http://кодер.укр/записи/yii_framework_настройка_и_стилизация_виджета_clinkpager_часть_2
Количество записей виджета CGridView на страницу
Для того что бы изменить количество записей на одну страницу необходимо поправить код модели Posts, метод search()(файл: /protected/models/Posts.php):
<?php
class Posts extends CActiveRecord { //... public function search() { //... return new CActiveDataProvider($this, array( 'pagination' => array( 'pageSize' => 5, ), 'criteria' => $criteria, )); } //... }
В итоге виджет будет выглядеть следующим образом:
Поиск в виджете CGridView
Для того что бы добавить поиск по полям виджет CGridView в действие actionList() контроллера PostsController необходимо добавить следующий код:
$request = Yii::app()->request->getParam('Posts');
$model->unsetAttributes();
if (isset($request)) {
$model->attributes = $request;
}
Итого код действия примет вид (файл: /protected/controllers/PostsController.php):
<?php
class PostsController extends Controller {
//...
/**
* Список записей
*/
public function actionList() {
$model = new Posts('search');
$request = Yii::app()->request->getParam('Posts');
$model->unsetAttributes(); // clear any default values
if (isset($request)) {
$model->attributes = $request;
}
$this->render('list', array('model' => $model));
}
}
А в представление добавить код:
'filter' => $model,
Следовательно код представления примет вид (файл: /themes/themeName/views/posts/list.php):
<?php
$this->widget('zii.widgets.grid.CGridView', array( 'dataProvider' => $model->search(), 'filter' => $model,
'id' => 'posts-grid', 'htmlOptions' => array('class' => 'table'), 'itemsCssClass' => 'table table-hover table-striped', 'loadingCssClass' => 'grid-preloader',
'pagerCssClass' => 'text-center', 'pager' => array( 'nextPageLabel' => '<span>»</span>', 'prevPageLabel' => '<span>«</span>', 'lastPageLabel' => '<span>»»</span>', 'firstPageLabel' => '<span>««</span>', 'selectedPageCssClass' => 'active', 'hiddenPageCssClass' => 'disabled', 'htmlOptions' => array('class' => 'pagination'), 'class' => 'CLinkPager', 'header' => false, 'pageSize' => 5, ),
'columns' => array( 'id', 'header', 'visibility', ), ));
Для полей по которым необходимо производить поиск по части значения (т.е. не точное совпадение) необходимо в методе search() при вызове compare третьим параметром ставить значение true. Например как в случае поиска по заголовку, а для поиска по id нам необходимо точное совпадение, пример:
<?php
class Posts extends CActiveRecord {
//...
public function search() {
//...
$criteria->compare('id', $this->id);
$criteria->compare('header', $this->header, true);
//...
}
//...
}
После чего виджет будет выглядеть следующим образом:
Настройка и стилизация колонок виджета CGridView
Приведем в порядок вид колонок. Уменьшим размер для поля поиска по id, увеличим поле поиска по заголовку, в колонке visibility вместо 0 и 1 будем выводить "Не опубликовано" или "Опубликовано" в виде иконок. Для этого нам необходимо значение элемента columns виджета привести к следующему виду:
array(
array(
'name' => 'id',
'filterHtmlOptions' => array('class' => 'user-filter-id'),
),
array(
'name' => 'header',
'filterHtmlOptions' => array('class' => 'user-filter-header'),
),
array(
'name' => 'visibility',
'header' => 'Пуб.',
'htmlOptions' => array('class' => 'user-filter-visibility'),
'filterHtmlOptions' => array('class' => 'user-filter-visibility'),
'value' => '($data->visibility == 1 ? "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-open\" title=\"Опубликовано\"></span>" : "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-close\" title=\"Не опубликовано\"></span>")',
'type' => 'html'
),
),
СSS стили:
.user-filter-id{
width: 30px;
}
.user-filter-id input{
width: 30px;
}
.user-filter-header input{
width: 100%;
}
.user-filter-visibility input{
width: 30px;
}
В итоге код представления примет вид (файл: /themes/themeName/views/posts/list.php):
<?php
$this->widget('zii.widgets.grid.CGridView', array( 'dataProvider' => $model->search(), 'filter' => $model,
'id' => 'posts-grid', 'htmlOptions' => array('class' => 'table'), 'itemsCssClass' => 'table table-hover table-striped', 'loadingCssClass' => 'grid-preloader',
'pagerCssClass' => 'text-center', 'pager' => array( 'nextPageLabel' => '<span>»</span>', 'prevPageLabel' => '<span>«</span>', 'lastPageLabel' => '<span>»»</span>', 'firstPageLabel' => '<span>««</span>', 'selectedPageCssClass' => 'active', 'hiddenPageCssClass' => 'disabled', 'htmlOptions' => array('class' => 'pagination'), 'class' => 'CLinkPager', 'header' => false, 'pageSize' => 5, ), 'columns' => array( array( 'name' => 'id', 'filterHtmlOptions' => array('class' => 'user-filter-id'), ), array( 'name' => 'header', 'filterHtmlOptions' => array('class' => 'user-filter-header'), ), array( 'name' => 'visibility', 'header' => 'Пуб.', 'htmlOptions' => array('class' => 'user-filter-visibility', 'style' => 'width:30px;text-align:center'), 'filterHtmlOptions' => array('class' => 'user-filter-visibility'), 'value' => '($data->visibility == 1 ? "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-open\" title=\"Опубликовано\"></span>" : "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-close\" title=\"Не опубликовано\"></span>")', 'type' => 'html' ), ), ));
После чего виджет будет выглядеть так:
Вывод данных со связанных таблицы
Добавим в список статей информация о авторе статьи, для этого в модель Posts добавим связь в метод relations() (файл: /protected/models/Posts.php):
<?php
class Posts extends CActiveRecord { //... public function relations() { return array( //... 'user' => array(self::BELONGS_TO, 'User', 'userId'), ); } //... }
И добавим колонку "автор" в виджет CGridView:
array(
'name' => 'userId',
'header' => 'Автор',
'value' => '$data["user"]["name"];',
),
После чего код представления примет вид:
<?php
$this->widget('zii.widgets.grid.CGridView', array( 'dataProvider' => $model->search(), 'filter' => $model,
'id' => 'posts-grid', 'htmlOptions' => array('class' => 'table'), 'itemsCssClass' => 'table table-hover table-striped', 'loadingCssClass' => 'grid-preloader',
'pagerCssClass' => 'text-center', 'pager' => array( 'nextPageLabel' => '<span>»</span>', 'prevPageLabel' => '<span>«</span>', 'lastPageLabel' => '<span>»»</span>', 'firstPageLabel' => '<span>««</span>', 'selectedPageCssClass' => 'active', 'hiddenPageCssClass' => 'disabled', 'htmlOptions' => array('class' => 'pagination'), 'class' => 'CLinkPager', 'header' => false, 'pageSize' => 5, ),
'columns' => array( array( 'name' => 'id', 'filterHtmlOptions' => array('class' => 'user-filter-id'), ), array( 'name' => 'header', 'filterHtmlOptions' => array('class' => 'user-filter-header'), ), array( 'name' => 'visibility', 'header' => 'Пуб.', 'filter' => array('' => 'Все', 1 => 'Опубликовано', 0 => 'Не опубликовано'), 'htmlOptions' => array('class' => 'user-filter-visibility', 'style' => 'width:30px;text-align:center'), 'filterHtmlOptions' => array('class' => 'user-filter-visibility'), 'value' => '($data->visibility == 1 ? "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-open\" title=\"Опубликовано\"></span>" : "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-close\" title=\"Не опубликовано\"></span>")', 'type' => 'html' ), array( 'name' => 'userId', 'header' => 'Автор', 'value' => '$data["user"]["name"];', ), ), ));
После чего виджет будет выглядеть так:
Выпадающий список для поиска записей в виджете CGridView
Для поиска по записям в виджете CGridView можно использовать выпадающий список (select). Приведем два простых примера поиска с использованием выпадающего списка
Простой выпадающий список
Для примера простого выпадающего списка будем использовать колонку visibility и вместо обычного поля ввода дадим возможность выбора из трех вариантов: Все, Опубликовано, Не опубликовано. Для этого нам необходимо поправить колонку visibility и добавить в нее следующий код (например, после элемента header):
'filter' => array('' => 'Все', 1 => 'Опубликовано', 0 => 'Не опубликовано'),
С помощью CSS уменьшим длину select'a:
.user-filter-visibility select{
width: 40px;
}
Выпадающий список из связанной таблицы
Сделаем поиск с помощью выпадающего списка по авторам статьи, для этого необходимо в колонку userId добавить следующий код:
'filter' => array('' => 'Все') + CHtml::listData(User::model()->findAll(), 'id', 'name'),
Код представления
После добавления выпадающих списков в фильтр виджета CGridView, представление примет вид (файл: /themes/themeName/views/posts/list.php):
<?php
$this->widget('zii.widgets.grid.CGridView', array( 'dataProvider' => $model->search(), 'filter' => $model,
'id' => 'posts-grid', 'htmlOptions' => array('class' => 'table'), 'itemsCssClass' => 'table table-hover table-striped', 'loadingCssClass' => 'grid-preloader',
'pagerCssClass' => 'text-center', 'pager' => array( 'nextPageLabel' => '<span>»</span>', 'prevPageLabel' => '<span>«</span>', 'lastPageLabel' => '<span>»»</span>', 'firstPageLabel' => '<span>««</span>', 'selectedPageCssClass' => 'active', 'hiddenPageCssClass' => 'disabled', 'htmlOptions' => array('class' => 'pagination'), 'class' => 'CLinkPager', 'header' => false, 'pageSize' => 5, ),
'columns' => array( array( 'name' => 'id', 'filterHtmlOptions' => array('class' => 'user-filter-id'), ), array( 'name' => 'header', 'filterHtmlOptions' => array('class' => 'user-filter-header'), ), array( 'name' => 'visibility', 'header' => 'Пуб.', 'filter' => array('' => 'Все', 1 => 'Опубликовано', 0 => 'Не опубликовано'), 'htmlOptions' => array('class' => 'user-filter-visibility', 'style' => 'width:30px;text-align:center'), 'filterHtmlOptions' => array('class' => 'user-filter-visibility'), 'value' => '($data->visibility == 1 ? "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-open\" title=\"Опубликовано\"></span>" : "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-close\" title=\"Не опубликовано\"></span>")', 'type' => 'html' ), array( 'name' => 'userId', 'header' => 'Автор', 'filter' => array('' => 'Все') + CHtml::listData(User::model()->findAll(), 'id', 'name'), 'value' => '$data["user"]["name"];', ), ), ));
Виджет будет выглядеть так:
Поиск по дате с помощью datepicker
Для того что бы добавить поиск по дате, сначала необходимо добавить колонку с датой и в элементе filter подключить datepicker:
array(
'name' => 'date',
'type' => 'raw',
'filter' => $this->widget('zii.widgets.jui.CJuiDatePicker', array(
'model' => $model,
'attribute' => 'date',
'language' => 'ru',
'options' => array(
'showAnim' => 'fold',
'dateFormat' => 'dd.mm.yy',
'changeMonth' => 'true',
'changeYear' => 'true',
'showButtonPanel' => 'true',
),
), true),
'filterHtmlOptions' => array('class' => 'user-filter-date'),
'value' => 'Yii::app()->dateFormatter->format("dd.M.yyyy", $data->date)',
),
Что бы datepicker работал после ajax загрузки данных (после поиска, сортировки или постраничного навигатора) необходимо добавить в виджет CGridView следующий параметр:
'afterAjaxUpdate' => 'reinstallDatePicker',
а в конец представления после вызова виджета CGridView:
Yii::app()->clientScript->registerScript('re-install-date-picker', "
function reinstallDatePicker(id, data) {
$('#Posts_date').datepicker(jQuery.extend({showMonthAfterYear:false},jQuery.datepicker.regional['ru'],{
'showAnim' : 'fold',
'dateFormat' : 'dd.mm.yy',
'changeMonth' : 'true',
'changeYear' : 'true',
'showButtonPanel' : 'true'}));
}
");
Т.к. дата у нас хранится в Unix time нам необходимо подправить метод search() в модели Posts. Вместо строки содержащей:
criteria->compare('date', $this->date);
Вставить следующий код:
//$criteria->compare('date', $this->date);
if(!empty($this->date) && !empty($this->date)){
$criteria->condition = "date BETWEEN '" .
strtotime($this->date) .
"' AND '" .
(strtotime($this->date) + 86400) .
"'";
}
В итоге представление примет вид (файл: /themes/themeName/views/posts/list.php):
<?php
$this->widget('zii.widgets.grid.CGridView', array( 'dataProvider' => $model->search(), 'filter' => $model,
'id' => 'posts-grid', 'afterAjaxUpdate' => 'reinstallDatePicker', 'htmlOptions' => array('class' => 'table'), 'itemsCssClass' => 'table table-hover table-striped', 'loadingCssClass' => 'grid-preloader',
'pagerCssClass' => 'text-center', 'pager' => array( 'nextPageLabel' => '<span>»</span>', 'prevPageLabel' => '<span>«</span>', 'lastPageLabel' => '<span>»»</span>', 'firstPageLabel' => '<span>««</span>', 'selectedPageCssClass' => 'active', 'hiddenPageCssClass' => 'disabled', 'htmlOptions' => array('class' => 'pagination'), 'class' => 'CLinkPager', 'header' => false, 'pageSize' => 5, ),
'columns' => array( array( 'name' => 'id', 'filterHtmlOptions' => array('class' => 'user-filter-id'), ), array( 'name' => 'date', 'type' => 'raw', 'filter' => $this->widget('zii.widgets.jui.CJuiDatePicker', array( 'model' => $model, 'attribute' => 'date', 'language' => 'ru', 'options' => array( 'showAnim' => 'fold', 'dateFormat' => 'dd.mm.yy', 'changeMonth' => 'true', 'changeYear' => 'true', 'showButtonPanel' => 'true', ), ), true), 'filterHtmlOptions' => array('class' => 'user-filter-date'), 'value' => 'Yii::app()->dateFormatter->format("dd.M.yyyy", $data->date)', ), array( 'name' => 'header', 'filterHtmlOptions' => array('class' => 'user-filter-header'), ), array( 'name' => 'visibility', 'header' => 'Пуб.', 'filter' => array('' => 'Все', 1 => 'Опубликовано', 0 => 'Не опубликовано'), 'htmlOptions' => array('class' => 'user-filter-visibility', 'style' => 'width:30px;text-align:center'), 'filterHtmlOptions' => array('class' => 'user-filter-visibility'), 'value' => '($data->visibility == 1 ? "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-open\" title=\"Опубликовано\"></span>" : "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-close\" title=\"Не опубликовано\"></span>")', 'type' => 'html' ), array( 'name' => 'userId', 'header' => 'Автор', 'filter' => array('' => 'Все') + CHtml::listData(User::model()->findAll(), 'id', 'name'), 'value' => '$data["user"]["name"];', ), ), ));
Yii::app()->clientScript->registerScript('re-install-date-picker', " function reinstallDatePicker(id, data) { $('#Posts_date').datepicker(jQuery.extend({showMonthAfterYear:false},jQuery.datepicker.regional['ru'],{ 'showAnim' : 'fold', 'dateFormat' : 'dd.mm.yy', 'changeMonth' : 'true', 'changeYear' : 'true', 'showButtonPanel' : 'true'})); } ");
И модель Posts примет вид:
<?php
class Posts extends CActiveRecord { //... public function search() { $criteria = new CDbCriteria;<p> $criteria->compare('id', $this->id); $criteria->compare('header', $this->header, true); $criteria->compare('text', $this->text, true); $criteria->compare('visibility', $this->visibility); if(!empty($this->date) && !empty($this->date)){ $criteria->condition = "date BETWEEN '" . strtotime($this->date) . "' AND '" . (strtotime($this->date) + 86400) . "'"; } $criteria->compare('userId', $this->userId); return new CActiveDataProvider($this, array( 'pagination' => array( 'pageSize' => 5, ), 'criteria' => $criteria, )); } //... }
После внесения этих изменений виджет будет выглядеть так:
О том как сделать поиск по диапазону дат можно посмотреть здесь: Yii Framework, CGridView поиск по диапазону дат (date range) с помощью виджета datepicker
Кнопки управления записями
Для управления записями (просмотр, редактирование, удаление) нам необходимы кнопки (ссылки и т.д.) добавить их очень просто.
Стандартные кнопки управления
Для добавления стандартных кнопок управления записями необходимо добавить еще одну колонку с кодом:
array(
'class' => 'CButtonColumn',
'template' => {view}{update}{delete}',
),
Свои кнопки управления записями
Часто бывает так, что необходимо изменить стандартный url редактирования, удаления просмотра записи, для этого добавим свои кнопки управления записями. В код виджета CGridView в элемент columns вставим следующий код:
array(
'class' => 'CButtonColumn',
'template' => '<nobr>{view} {edit} {delete}</nobr>',
'buttons' => array(
'view' => array(
'label' => '<span aria-hidden="true" class="glyphicon glyphicon-eye-open"></span>',
'imageUrl' => false,
'url' => 'Yii::app()->createUrl("posts/default/detail", array("url"=>$data->url))',
),
'edit' => array(
'label' => '<span aria-hidden="true" class="glyphicon glyphicon-pencil"></span>',
'url' => 'Yii::app()->createUrl("posts/edit", array("id"=>$data->id))',
),
'delete' => array(
'label' => '<span aria-hidden="true" class="glyphicon glyphicon-remove"></span>',
'imageUrl' => false,
'deleteConfirmation' => 'Are you sure you want to delete this post?',
'url' => 'Yii::app()->createUrl("posts/delete", array("id"=>$data->id))',
),
),
),
В итоге мы получим свои иконки кнопок и url к ним. Так же при нажатии на кнопку удаления будет вызвано окно с подтверждением удаления записи.
В итоге код представления примет следующий вид (файл: /themes/themeName/views/posts/list.php):
<?php
$this->widget('zii.widgets.grid.CGridView', array( 'dataProvider' => $model->search(), 'filter' => $model,
'id' => 'posts-grid', 'afterAjaxUpdate' => 'reinstallDatePicker', 'htmlOptions' => array('class' => 'table'), 'itemsCssClass' => 'table table-hover table-striped', 'loadingCssClass' => 'grid-preloader',
'pagerCssClass' => 'text-center', 'pager' => array( 'nextPageLabel' => '<span>»</span>', 'prevPageLabel' => '<span>«</span>', 'lastPageLabel' => '<span>»»</span>', 'firstPageLabel' => '<span>««</span>', 'selectedPageCssClass' => 'active', 'hiddenPageCssClass' => 'disabled', 'htmlOptions' => array('class' => 'pagination'), 'class' => 'CLinkPager', 'header' => false, 'pageSize' => 5, ),
'columns' => array( array( 'name' => 'id', 'filterHtmlOptions' => array('class' => 'user-filter-id'), ), array( 'name' => 'date', 'type' => 'raw', 'filter' => $this->widget('zii.widgets.jui.CJuiDatePicker', array( 'model' => $model, 'attribute' => 'date', 'language' => 'ru', 'options' => array( 'showAnim' => 'fold', 'dateFormat' => 'dd.mm.yy', 'changeMonth' => 'true', 'changeYear' => 'true', 'showButtonPanel' => 'true', ), ), true), 'filterHtmlOptions' => array('class' => 'user-filter-date'), 'value' => 'Yii::app()->dateFormatter->format("dd.M.yyyy", $data->date)', ), array( 'name' => 'header', 'filterHtmlOptions' => array('class' => 'user-filter-header'), ), array( 'name' => 'visibility', 'header' => 'Пуб.', 'filter' => array('' => 'Все', 1 => 'Опубликовано', 0 => 'Не опубликовано'), 'htmlOptions' => array('class' => 'user-filter-visibility', 'style' => 'width:30px;text-align:center'), 'filterHtmlOptions' => array('class' => 'user-filter-visibility'), 'value' => '($data->visibility == 1 ? "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-open\" title=\"Опубликовано\"></span>" : "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-close\" title=\"Не опубликовано\"></span>")', 'type' => 'html' ), array( 'name' => 'userId', 'header' => 'Автор', 'filter' => array('' => 'Все') + CHtml::listData(User::model()->findAll(), 'id', 'name'), 'value' => '$data["user"]["name"];', ), array( 'class' => 'CButtonColumn', 'template' => '<nobr>{view} {edit} {delete}</nobr>', 'buttons' => array( 'view' => array( 'label' => '<span aria-hidden="true" class="glyphicon glyphicon-eye-open"></span>', 'imageUrl' => false, 'url' => 'Yii::app()->createUrl("posts/default/detail", array("url"=>$data->url))', ), 'edit' => array( 'label' => '<span aria-hidden="true" class="glyphicon glyphicon-pencil"></span>', 'url' => 'Yii::app()->createUrl("posts/edit", array("id"=>$data->id))', ), 'delete' => array( 'label' => '<span aria-hidden="true" class="glyphicon glyphicon-remove"></span>', 'imageUrl' => false, 'deleteConfirmation' => 'Are you sure you want to delete this post?', 'url' => 'Yii::app()->createUrl("posts/delete", array("id"=>$data->id))', ), ), ), ), ));
Yii::app()->clientScript->registerScript('re-install-date-picker', " function reinstallDatePicker(id, data) { $('#Posts_date').datepicker(jQuery.extend({showMonthAfterYear:false},jQuery.datepicker.regional['ru'],{ 'showAnim' : 'fold', 'dateFormat' : 'dd.mm.yy', 'changeMonth' : 'true', 'changeYear' : 'true', 'showButtonPanel' : 'true'})); } ");
Вид виджета:
Выбор количества записей на страницу
Для удобства сделаем выпадающий список с выбором количества записей на страницу. Для этого действие actionList() контроллера PostsController добавим следующий код:
if (isset($_GET['pageSize'])) {
Yii::app()->user->setState('pageSize', (int) $_GET['pageSize']);
unset($_GET['pageSize']);
}
В метод search() модели Posts:
public function search() {
//...
return new CActiveDataProvider($this, array(
'pagination' => array(
'pageSize' => Yii::app()->user->getState('pageSize', 5),
),
'criteria' => $criteria,
));
}
В представлении перед виджетом CGridView:
$pageSize = Yii::app()->user->getState('pageSize', 5);
И в виджет CGridView, например, вместо заголовка колонок с кнопками добавим код выпадающего списка с выбором количества элементов на страницу:
'header' => CHtml::dropDownList(
'pageSize', $pageSize, array(
5 => 5,
10 => 10,
20 => 20,
50 => 50,
100 => 100
),
array(
'onchange' => "$.fn.yiiGridView.update('posts-grid',{ data:{pageSize: $(this).val() }})"
)
),
Не забудьте проверить совпадает ли идентификатор (id) виджета (строка 7) с идентификатором (id) в строке 10 (posts-grid).
Итого
В итоге мы имеем следующий код. Код модели Posts:
<?php
class Posts extends CActiveRecord { //... public function relations() { return array( 'user' => array(self::BELONGS_TO, 'User', 'userId'), ); }
public function search() { $criteria = new CDbCriteria;
$criteria->compare('id', $this->id); $criteria->compare('url', $this->url, true); $criteria->compare('header', $this->header, true); $criteria->compare('text', $this->text, true); $criteria->compare('visibility', $this->visibility); if(!empty($this->date) && !empty($this->date)){ $criteria->condition="date BETWEEN '" . strtotime($this->date) . "' AND '" . (strtotime($this->date) + 86400) . "'"; } $criteria->compare('userId', $this->userId);
return new CActiveDataProvider($this, array( 'pagination' => array( 'pageSize' => Yii::app()->user->getState('pageSize', 5), ), 'criteria' => $criteria, )); } //... }
Код контроллера PostsController:
<?php
class PostsController extends Controller {
/** * Список записей */ public function actionList() { $this->pageHeader = $this->pageTitle = $this->breadcrumbsTitle = 'Список статей'; $this->breadcrumbs = array( 'Модератор' => '/модератор', $this->breadcrumbsTitle ); $model = new Posts('search'); if (isset($_GET['pageSize'])) { Yii::app()->user->setState('pageSize', (int) $_GET['pageSize']); unset($_GET['pageSize']); } $request = Yii::app()->request->getParam('Posts'); $model->unsetAttributes(); if (isset($request)) { $model->attributes = $request; } $this->render('list', array( 'model' => $model, )); }
}
Код представления:
<?php
$pageSize = Yii::app()->user->getState('pageSize', 5);
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => $model->search(),
'filter' => $model,
'id' => 'posts-grid',
'afterAjaxUpdate' => 'reinstallDatePicker',
'htmlOptions' => array('class' => 'table'),
'itemsCssClass' => 'table table-hover table-striped',
'loadingCssClass' => 'grid-preloader',
'pagerCssClass' => 'text-center',
'pager' => array(
'nextPageLabel' => '<span>»</span>',
'prevPageLabel' => '<span>«</span>',
'lastPageLabel' => '<span>»»</span>',
'firstPageLabel' => '<span>««</span>',
'selectedPageCssClass' => 'active',
'hiddenPageCssClass' => 'disabled',
'htmlOptions' => array('class' => 'pagination'),
'class' => 'CLinkPager',
'header' => false,
'pageSize' => 5,
),
'columns' => array(
array(
'name' => 'id',
'filterHtmlOptions' => array('class' => 'user-filter-id'),
),
array(
'name' => 'date',
'type' => 'raw',
'filter' => $this->widget('zii.widgets.jui.CJuiDatePicker', array(
'model' => $model,
'attribute' => 'date',
'language' => 'ru',
'options' => array(
'showAnim' => 'fold',
'dateFormat' => 'dd.mm.yy',
'changeMonth' => 'true',
'changeYear' => 'true',
'showButtonPanel' => 'true',
),
), true),
'filterHtmlOptions' => array('class' => 'user-filter-date'),
'value' => 'Yii::app()->dateFormatter->format("dd.M.yyyy", $data->date)',
),
array(
'name' => 'header',
'filterHtmlOptions' => array('class' => 'user-filter-header'),
),
array(
'name' => 'visibility',
'header' => 'Пуб.',
'filter' => array('' => 'Все', 1 => 'Опубликовано', 0 => 'Не опубликовано'),
'htmlOptions' => array('class' => 'user-filter-visibility', 'style' => 'width:30px;text-align:center'),
'filterHtmlOptions' => array('class' => 'user-filter-visibility'),
'value' => '($data->visibility == 1 ? "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-open\" title=\"Опубликовано\"></span>" : "<span aria-hidden=\"true\" class=\"glyphicon glyphicon-eye-close\" title=\"Не опубликовано\"></span>")',
'type' => 'html'
),
array(
'name' => 'userId',
'header' => 'Автор',
'filter' => array('' => 'Все') + CHtml::listData(User::model()->findAll(), 'id', 'name'),
'value' => '$data["user"]["name"];',
),
array(
'class' => 'CButtonColumn',
'template' => '<nobr>{view} {edit} {delete}</nobr>',
'buttons' => array(
'view' => array(
'label' => '<span aria-hidden="true" class="glyphicon glyphicon-eye-open"></span>',
'imageUrl' => false,
'url' => 'Yii::app()->createUrl("posts/default/detail", array("url"=>$data->url))',
),
'edit' => array(
'label' => '<span aria-hidden="true" class="glyphicon glyphicon-pencil"></span>',
'url' => 'Yii::app()->createUrl("posts/edit", array("id"=>$data->id))',
),
'delete' => array(
'label' => '<span aria-hidden="true" class="glyphicon glyphicon-remove"></span>',
'imageUrl' => false,
'deleteConfirmation' => 'Are you sure you want to delete this post?',
'url' => 'Yii::app()->createUrl("posts/delete", array("id"=>$data->id))',
),
),
'header' => CHtml::dropDownList(
'pageSize', $pageSize, array(
5 => 5,
10 => 10,
20 => 20,
50 => 50,
100 => 100
),
array(
'onchange' => "$.fn.yiiGridView.update('posts-grid',{ data:{pageSize: $(this).val() }})"
)
),
),
),
));
Yii::app()->clientScript->registerScript('re-install-date-picker', "
function reinstallDatePicker(id, data) {
$('#Posts_date').datepicker(jQuery.extend({showMonthAfterYear:false},jQuery.datepicker.regional['ru'],{
'showAnim' : 'fold',
'dateFormat' : 'dd.mm.yy',
'changeMonth' : 'true',
'changeYear' : 'true',
'showButtonPanel' : 'true'}));
}
");
СSS стили:
.user-filter-id{
width: 30px;
}
.user-filter-id input{
width: 30px;
}
.user-filter-date{
width: 110px;
}
.user-filter-date input{
width: 110px;
}
.user-filter-visibility select{
width: 40px;
}
.user-filter-header input{
width: 100%;
}
.user-filter-visibility input{
width: 30px;
}
.sort-link.desc{
background:url(/themes/themeName/images/down.gif) right center no-repeat;
padding-right: 10px;
}
.sort-link.asc{
background:url(/themes/themeName/images/up.gif) right center no-repeat;
padding-right: 10px;
}
Окончательный вид виджета:
Вывод
Виджет CGridView при умелом использовании значительно ускорит разработку и упростит работу с выводом табличных данных, а также сортировку, фильтрацию и навигацию по этим данным.
Дополнительно
Подробный список свойств виджета можно посмотреть на официальном сайте Yii Framework: http://www.yiiframework.com/doc/api/1.1/CGridView
devreadwrite.com



Подборка адаптивных шаблонов для вашей CMS
Статьи по
Как получить и установить HTTPS сертификат на сайта

Комментарии
Как поведёт себя подобное решение, если в таблице будет около миллиона записей?
ОтветитьПоиск по записям справится?