О возможностях Yii CGridView на примерах. Часть 2: источник данных

2 сентября, 2014
Метки:

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

Чтобы добавить условия вывода данных в источник данных для 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),

для получения только не промодерированных данных.

Как изменить число записей на странице в CGridView

Очень просто. Нужно явно указать pageSize в параметрах объекта CActiveDataProvider

 return new CActiveDataProvider($this, array(
     'criteria'=>$criteria,
     'pagination' => array('pageSize' => 20)
  ));

Как добавить связанные данные в CGridView

Возможности критерий в 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.

Настройка фильтра для CGridView

Для начала посмотрим как этот фильтр работает.

  • Шаг 1: настройка отображения фильтра в CGridView
    В представлении есть возможность задать фильтр для каждого поля

    array(
      'name'   => 'region',
      'filter' => Region::getAll(),
      'value'  => 'Region::getNameByID($data->region)',
    ),
    

    Или отключить его, установив параметр filter в false. По умолчанию фильтр является текстовым полем. В моем примере, метод Region::getAll() возвращает массив в формате ключ=>значение. Фильтр использует его для построения выпадающего списка. При установке значения фильтра, происходит AJAX-запрос, все данные фильтров передаются в виде GET параметров в текущий action контроллера.

  • Шаг 2: настройка контроллера
       $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 не работает, в первую очередь проверьте, указан ли атрибут, по которому вы пытаетесь фильтровать, в качестве безопасного в правилах данной модели.

  • Шаг 2: настройка условий фильтра
     $criteria->compare('name',$this->name,true);
     $criteria->compare('region',$this->region,true);
    

    Тут добавляются условия, сравнивающие атрибуты текущего объекта с полями. Данные фильтра были присвоены к атрибутам текущего объекта на прошлом шаге. Третий параметр влияет на сравнение с подстрокой. Те вместо name=$this->name в случаи когда третий параметр выставлен в false будет выполнен поиск по условию name like %$this->name%.

Кнопка сбросить фильтр для CGridView

Для сброса фильтра достаточно очистить все поля. Но пользователи привыкли к кнопке «Очистить фильтр». Ее мы сейчас и создадим.
Для этого нужно создать свой класс, назовем его 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',
        ),
    ),
)); ?>

Метки:

Оставить комментарий

5 комментариев »

    Alex

    Почему после смены странички, фильтр не сбрасывается?

      Developer

      А должен? А как же тогда просматривать вторую и последующие страницы отфильтрованных результатов? Если вам нужно «сбросить фильтр» нужно удалить все GET-параметры из запроса кроме номера страниц. Как? Либо через action в контроллере либо переопределить ссылки на страницы в настройках грида.


    Alex

    Решено. Надо добавить ‘ajaxUrl’, так как после смены странички неизвестно куда отправлять запрос


    Евгений

    «Кнопка сбросить фильтр для CGridView» решение куда банальнее ‘btn btn-info’]) ?>

      Developer

      И как с помощью CSS класса bootstrap вы сбросите фильтры? Кнопочку красивую нарисовать — да, но фильтры тут причем?


Оставить комментарий:









Копирование материалов разрешено при наличии активной ссылки на источник