Данный пост будет интересен тем кто начинает знакомится с Yii framework, то есть пользователям от начального до среднего уровня знаний данного фреймворка, а так же тем кто любит похоливарить на тему какой из фреймворков круче.
И так, я здесь хочу вам показать насколько гибко и функционально можно настроить CGridView, как можно добавлять в нее различные фильтры по реляционным данным, как добавлять виджеты такие как CJuiDatePicker.
Необходимые инструменты
При написание поста, я использовал Yii Framework 1.1.12 и в качестве СУБД использовал MySQL и по этому все примеры приведенного кода будут привязаны к ним.
Ну что начнем?
Рассмотрим ситуацию типичного блога, у нас будет самая обычная табличка постов, пользователей, категорий данных постов, тегов и комментариев к постам.
Мы будим рассматривать настройку CgridView, на табличке постов, поскольку посты в блоге являются основной сущностью и все остальные сущности привязаны к ним.
Настраиваем реляции для модели Post
Контроллер мы оставим практически по дефолту
В модель Tag мы добавим новый метод который будет возвращать нам массив подходящий по формату для вставки в фильтр таблички в качестве выпадающего списка
Добавим метод возвращающий полное Ф.И.О., в модель User
Подобный метод нам нужно добавить в модель Post для отображения списка всех тегов которые относятся к статье
Дальше мы будим работать только с моделью Post и с отображением в котором у нас выводится наша CGridView.
Для поиска по тегам с реляцией MANY_MANY я использую дополнительное поле в модели постов
Для фильтрации мы должны расширить метод Post::search().
У меня он выглядит так —
Для вывода списка тегов в табличке, в виде одной строки мы воспользуемся созданным нами ранее магическим методом Post::getTagsToString()
Аналогично мы сделаем с отображением полного Ф.И.О. автора поста
Далее интереснее, прикручиваем стандартный виджет CJuiDatePicker к фильтру таблички
Добавляем новую колонку таблички с такими параметрами
Но это еще не все, если ваша табличка использует ajaxUpdate то фильтр с датами будет ломаться после обновления таблички с помощью ajax. Что бы исправить это мы должны по событию afterAjaxUpdate пере инициализировать календарик, делается это так
Кастомизация таблички происходит тоже достаточно легко, например если нам нужно заменить изображение какой то из кнопочек или скрыть их, для стандартных кнопочек мы можем использовать свойства —
{button_name}ButtonImageUrl
{button_name}ButtonLabel
{button_name}ButtonOptions
{button_name}ButtonUrl
пример заменим картинку кнопки стандартной кнопки update
или например мы хотим создать свою кнопочку
Напоследок
Я бы хотел оставить здесь несколько полезных ссылок на экстеншены которые помогут вам с апгрейдом ваших CGridView
Позволяет скрывать стандартные кнопки view, update и delete по заданному критерию
Алфавитная пагинация
Отображаем табличку в древовидном формате
Исходник, дамп базы внутри.
И так, я здесь хочу вам показать насколько гибко и функционально можно настроить CGridView, как можно добавлять в нее различные фильтры по реляционным данным, как добавлять виджеты такие как CJuiDatePicker.
Необходимые инструменты
При написание поста, я использовал Yii Framework 1.1.12 и в качестве СУБД использовал MySQL и по этому все примеры приведенного кода будут привязаны к ним.
Ну что начнем?
Рассмотрим ситуацию типичного блога, у нас будет самая обычная табличка постов, пользователей, категорий данных постов, тегов и комментариев к постам.
CREATE TABLE IF NOT EXISTS `tbl_comment` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` text COLLATE utf8_unicode_ci NOT NULL,
`status` int(11) NOT NULL,
`create_time` int(11) DEFAULT NULL,
`author` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`url` varchar(128) COLLATE utf8_unicode_ci DEFAULT NULL,
`post_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_comment_post` (`post_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;
CREATE TABLE IF NOT EXISTS `tbl_post` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`content` text COLLATE utf8_unicode_ci NOT NULL,
`status` int(11) NOT NULL,
`create_time` datetime NOT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`author_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_post_author` (`author_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;
CREATE TABLE IF NOT EXISTS `tbl_posts_tags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_post` int(11) NOT NULL,
`id_tag` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `tbl_tag` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`frequency` int(11) DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `tbl_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`first_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`last_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`father_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`salt` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`profile` text COLLATE utf8_unicode_ci,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=2 ;
Мы будим рассматривать настройку CgridView, на табличке постов, поскольку посты в блоге являются основной сущностью и все остальные сущности привязаны к ним.
Настраиваем реляции для модели Post
public function relations(){
return array(
//Теги
'tags' => array(self::MANY_MANY, 'Tag', 'tbl_posts_tags(id_post, id_tag)'),
//Автор поста
'author' => array(self::BELONGS_TO, 'User', 'author_id'),
//Комментарии
'comments' => array(self::HAS_MANY, 'Comment', 'post_id', 'condition'=>'comments.status='.Comment::STATUS_APPROVED, 'order'=>'comments.create_time DESC'),
//Подсчет количества комментариев
'commentCount' => array(self::STAT, 'Comment', 'post_id', 'condition'=>'status='.Comment::STATUS_APPROVED),
);
}
Контроллер мы оставим практически по дефолту
public function actionAdmin(){
$model=new Post('search');
if(isset($_GET['Post'])){
$model->setAttributes($_GET['Post'], false);
$model->id_tag = isset($_GET['Post']['id_tag']) ? $_GET['Post']['id_tag'] : '';
}
$this->render('admin',array(
'model'=>$model,
));
}
В модель Tag мы добавим новый метод который будет возвращать нам массив подходящий по формату для вставки в фильтр таблички в качестве выпадающего списка
public function getForFilter(){
return CHtml::listData(
self::model()->findAll(array(
'select' => array('id', 'name')
)), 'id', 'name'
);
}
Добавим метод возвращающий полное Ф.И.О., в модель User
public function getFullFio(){
return $this->last_name.' '.$this->first_name.' '.$this->father_name;
}
Подобный метод нам нужно добавить в модель Post для отображения списка всех тегов которые относятся к статье
public function getTagsToString(){
$t = CHtml::listData( $this->tags, 'id', 'name' );
return implode(',', $t);
}
Дальше мы будим работать только с моделью Post и с отображением в котором у нас выводится наша CGridView.
Для поиска по тегам с реляцией MANY_MANY я использую дополнительное поле в модели постов
public $id_tag = '';
Для фильтрации мы должны расширить метод Post::search().
У меня он выглядит так —
public function search($defaultCriteria = null){
$criteria = $defaultCriteria != null ? $defaultCriteria : new CDbCriteria;
//Указываем какие реляции нам нужно доставать при создании таблички
//для облегчения запроса мы не будим тащить все поля, мы укажем какие поля нам нужны для поиска и отображения
$criteria->with = array(
'tags' => array(
'select' => array('id', 'name')
),
'author' => array(
'select' => array('last_name', 'first_name', 'father_name')
),
'commentCount'
);
$criteria->together = true;
if(!empty($this->author_id)){
//В фильтр id_author у нас есть возможность писать любой критерий поиска по имени, фамилии или отчеству
$criteria->addSearchCondition(
new CDbExpression( 'CONCAT(author.last_name, " ", author.first_name, " ", author.father_name)' ),
$this->author_id
);
}
//составляем критерий запроса
if(isset($this->id_tag) && !empty($this->id_tag)){
$criteria->compare('tags.id', '='.$this->id_tag, true);
}
$criteria->compare('t.id', '='.$this->id, true);
$criteria->compare('t.create_time', '='.$this->create_time, true);
$criteria->compare('t.update_time', '='.$this->update_time, true);
$criteria->compare('t.title', $this->title, true);
$criteria->compare('t.status', '='.$this->status);
return new CActiveDataProvider('Post', array(
'criteria'=>$criteria,
'sort'=>array(
'defaultOrder'=>'t.status, t.update_time DESC',
),
));
}
Для вывода списка тегов в табличке, в виде одной строки мы воспользуемся созданным нами ранее магическим методом Post::getTagsToString()
...
array(
'name'=>'id_tag',
'value'=>'$data->tagsToString',
'filter'=>Tag::model()->forFilter,
),
...
Аналогично мы сделаем с отображением полного Ф.И.О. автора поста
...
array(
'name'=>'author_id',
'value'=>'isset($data->author) ? $data->author->fullFio : ""'
),
...
Далее интереснее, прикручиваем стандартный виджет CJuiDatePicker к фильтру таблички
Добавляем новую колонку таблички с такими параметрами
...
array(
'name' => 'create_time',
'type' => 'raw',
'htmlOptions' => array('align' => 'center', 'style' => 'width: 123px;'),
'filter' => $this->widget('zii.widgets.jui.CJuiDatePicker', array(
'model' => $model,
'id' => 'create_time',
'attribute' => 'create_time',
'htmlOptions' => array('style' => 'width: 80px;'),
'options' => array(
'dateFormat' => 'yy-mm-dd',
'changeYear' => true
),
), true)
),
...
Но это еще не все, если ваша табличка использует ajaxUpdate то фильтр с датами будет ломаться после обновления таблички с помощью ajax. Что бы исправить это мы должны по событию afterAjaxUpdate пере инициализировать календарик, делается это так
...
'afterAjaxUpdate' => 'function(){
jQuery("#create_date").datepicker({
dateFormat: "yy-mm-dd",
changeYear:true
});
}',
...
Кастомизация таблички происходит тоже достаточно легко, например если нам нужно заменить изображение какой то из кнопочек или скрыть их, для стандартных кнопочек мы можем использовать свойства —
{button_name}ButtonImageUrl
{button_name}ButtonLabel
{button_name}ButtonOptions
{button_name}ButtonUrl
пример заменим картинку кнопки стандартной кнопки update
...
array(
'class'=>'CButtonColumn',
'updateButtonImageUrl' => Yii::app()->baseUrl.'/images/configure.gif'
),
...
или например мы хотим создать свою кнопочку
...
array(
'class' => 'ext.myButtonColumn',
'template'=> '{on} {off} ',
'buttons' => array(
'off' => array(
'label' => 'Активировать',
'imageUrl' => Yii::app()->baseUrl.'/images/cancel.gif',
'visible' => '$data->active == 0',
'url' => 'Yii::app()->createAbsoluteUrl("post/on")',
),
'on' => array(
'label' => 'Деактивировать',
'imageUrl' => Yii::app()->baseUrl.'/images/flag.gif',
'visible' => '$data->active == 1',
'url' => 'Yii::app()->createAbsoluteUrl("post/off")',
),
),
)
...
Напоследок
Я бы хотел оставить здесь несколько полезных ссылок на экстеншены которые помогут вам с апгрейдом ваших CGridView
Позволяет скрывать стандартные кнопки view, update и delete по заданному критерию
Алфавитная пагинация
Отображаем табличку в древовидном формате
Исходник, дамп базы внутри.