В первой части, мы разобрали возможности настройки визуального оформления виджета 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 вы сбросите фильтры? Кнопочку красивую нарисовать — да, но фильтры тут причем?