В первой части, мы разобрали возможности настройки визуального оформления виджета CGridView, на примерах разобрали как настроить или изменить стандартные кнопки, вывод пейджинации, формат выводимых данных. Теперь поговорим о настройках источников данных для CGridView.
Для начала вновь взглянем на типовой пример использования CGridView:
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'country-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'id',
'name',
'region',
array(
'class'=>'CButtonColumn',
),
),
)); ?>
Источник данных для будущей таблицы передается в параметре dataProvider в виде объекта CActiveDataProvider. В моем примере выводится список стран и $model в представлении — это объект класса Country. Для получения источника данных используется метод класса Country с именем search.
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('name',$this->name,true);
$criteria->compare('region',$this->region,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
Метод возвращает объект CActiveDataProvider, применяя к нему условия выборки $criteria.
Чтобы добавить условия вывода данных в источник данных для CGridView нужно добавить критерии, например так:
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('name',$this->name,true);
$criteria->compare('region',$this->region,true);
$criteria->addCondition('moderation=0');
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
Теперь в таблице CGridView будут только записи у которых поле moderation равно 0. Варьировать условия можно передавая в метод параметры, например так:
public function search($moderation='')
{
$criteria=new CDbCriteria;
$criteria->compare('name',$this->name,true);
$criteria->compare('region',$this->region,true);
if(is_numeric($moderation))
$criteria->addCondition('moderation='.$moderation);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
'dataProvider'=>$model->search(),
'dataProvider'=>$model->search(1),
для получения только промодерированных данных
'dataProvider'=>$model->search(0),
для получения только не промодерированных данных.
Очень просто. Нужно явно указать pageSize в параметрах объекта CActiveDataProvider
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
'pagination' => array('pageSize' => 20)
));
Возможности критерий в Yii — это тема для отдельной статьи. Но так как в прошлой статье я начала говорить о связанных данных, остановимся на этом моменте подробнее.
Для добавления связанной таблицы нужно во-первых создать эту связь в моделе в методе relations:
public function relations()
{
return array(
'region' => array(self::HAS_ONE, 'Region', array('id' => 'region')),
);
}
Описанная связь указывает что для каждой записи Country соответствует одна запись таблицы Region. Поле id в таблице Region должно быть равно полю region таблицы Country. Подробнее о связях ActiveRecord в Yii постараюсь написать отдельно, тк это тоже слишком обширная тема, чтобы раскрывать ее тут.
Теперь используем эту связь для построения источника дынных:
$criteria->with = array('region');
Теперь при выводе данных в CGridView можно обращаться к полям модели Region, например так $data->region->title
Если по каким либо причинам вам не нравится использовать метод search, вы можете использовать любой другой метод, возвращающий объект CActiveDataProvider.
Для начала посмотрим как этот фильтр работает.
array( 'name' => 'region', 'filter' => Region::getAll(), 'value' => 'Region::getNameByID($data->region)', ),
Или отключить его, установив параметр filter в false. По умолчанию фильтр является текстовым полем. В моем примере, метод Region::getAll() возвращает массив в формате ключ=>значение. Фильтр использует его для построения выпадающего списка. При установке значения фильтра, происходит AJAX-запрос, все данные фильтров передаются в виде GET параметров в текущий action контроллера.
$model=new Country('search');
$model->unsetAttributes();
if(isset($_GET['Country']))
$model->attributes=$_GET['Country'];
$this->render('admin',array(
'model'=>$model,
));
Если существуют GET параметры, то они присваиваются в атрибуты текущего объекта. Для связанных данных прис Обратите внимание, присвоить данные таким образом можно только тем атрибутам, которые в модели указаны как безопасные.
public function rules()
{
return array(
array('name, region', 'required'),
array('name, region', 'safe'),
);
}
Если фильтр CGridView не работает, в первую очередь проверьте, указан ли атрибут, по которому вы пытаетесь фильтровать, в качестве безопасного в правилах данной модели.
$criteria->compare('name',$this->name,true);
$criteria->compare('region',$this->region,true);
Тут добавляются условия, сравнивающие атрибуты текущего объекта с полями. Данные фильтра были присвоены к атрибутам текущего объекта на прошлом шаге. Третий параметр влияет на сравнение с подстрокой. Те вместо name=$this->name в случаи когда третий параметр выставлен в false будет выполнен поиск по условию name like %$this->name%.
Для сброса фильтра достаточно очистить все поля. Но пользователи привыкли к кнопке «Очистить фильтр». Ее мы сейчас и создадим.
Для этого нужно создать свой класс, назовем его ButtonWithResetButtonColumn, отнаследованный от CButtonColumn. Поместим фаил этого класса в protected/components
class ButtonWithResetButtonColumn extends CButtonColumn {
public function renderFilterCellContent() {
$js = "
jQuery(document).on('click', '#{$this->grid->id} .reset', function() {
var $ = jQuery,
id = $(this).data('grid-id'),
inputSelector = '#' + id + ' .filters input, ' + '#' + id + ' .filters select';
$(inputSelector).each(function(index, elem) {
$(elem).val('');
});
var data = $.param($(inputSelector));
$.fn.yiiGridView.update(id, {data: data});
return false;
});
";
Yii::app()->getClientScript()->registerScript(__CLASS__ . '#' . $this->id, $js);
echo "<input class='reset' data-grid-id='{$this->grid->id}' type='button' value='Reset'>";
}
}
Класс дорисовывает кнопку с надписью Reset и создает JS событие, которое очищает все поля фильтра и вызывает ajax обнавление грида.
Теперь осталось использовать наш новый класс вместо CButtonColumn в вызове виджета:
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'country-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'id',
'name',
'region',
array(
'class'=>'ButtonWithResetButtonColumn',
),
),
)); ?>
Почему после смены странички, фильтр не сбрасывается?
А должен? А как же тогда просматривать вторую и последующие страницы отфильтрованных результатов? Если вам нужно «сбросить фильтр» нужно удалить все GET-параметры из запроса кроме номера страниц. Как? Либо через action в контроллере либо переопределить ссылки на страницы в настройках грида.
Решено. Надо добавить ‘ajaxUrl’, так как после смены странички неизвестно куда отправлять запрос
«Кнопка сбросить фильтр для CGridView» решение куда банальнее ‘btn btn-info’]) ?>
И как с помощью CSS класса bootstrap вы сбросите фильтры? Кнопочку красивую нарисовать — да, но фильтры тут причем?