Using filters with CGridView and CArrayDataProvider

  1. Model
  2. Controller
  3. View

Using filters on CGridView with CActiveDataProvider is easy, but with CArrayDataProvider it is a bit tricky.

To use the filters you have to create a separate model class. I used some code from the following forum topic: link

Note: Normally, when you have an array of CModels, you should use CActiveDataProvider instead!

Here is some example code:

Model

Copy and include this class into your application.

<?php

/**
 * Filterform to use filters in combination with CArrayDataProvider and CGridView
 * @see http://www.yiiframework.com/wiki/232/using-filters-with-cgridview-and-carraydataprovider/
 */
class FiltersForm extends CFormModel
{
	/**
	 * @var array filters, key => filter string
	 */
	public $filters = array();

	/**
	 * Override magic getter for filters
	 * @param string $name
	 */
	public function __get($name)
	{
		if (!array_key_exists($name, $this->filters)) {
			$this->filters[$name] = '';
		}
		return $this->filters[$name];
	}

	/**
	 * Override magic setter for filters
	 * @param string $name
	 * @param mixed $value
	 */
	public function __set($name, $value)
	{
		$this->filters[$name] = $value;
	}

	/**
	 * Filter input array by key value pairs
	 * @param array $data rawData
	 * @return array filtered data array
	 */
	public function filter(array $data)
	{
		foreach ($data AS $rowIndex => $row) {
			foreach ($this->filters AS $key => $searchValue) {
				if (!is_null($searchValue) AND $searchValue !== '') {
					$compareValue = null;

					if ($row instanceof CModel) {
						if (isset($row->$key) == false) {
							throw new CException("Property " . get_class($row) . "::{$key} does not exist!");
						}
						$compareValue = $row->$key;
					} elseif (is_array($row)) {
						if (!array_key_exists($key, $row)) {
							throw new CException("Key {$key} does not exist in array!");
						}
						$compareValue = $row[$key];
					} else {
						throw new CException("Data in CArrayDataProvider must be an array of arrays or an array of CModels!");
					}

					if (stripos($compareValue, $searchValue) === false) {
						unset($data[$rowIndex]);
					}
				}
			}
		}
		return $data;
	}

}

(By @KonApaz) If you want to apply full comparisons (>, <, >=, <=, =) use this

if (substr($searchValue, 0, 2) == '<=') {
    if ($compareValue > substr($searchValue, 2)) {
        unset($data[$rowIndex]);
    }
} else if (substr($searchValue, 0, 2) == '>=') {
    if ($compareValue < substr($searchValue, 2)) {
        unset($data[$rowIndex]);
    }
} else if ($searchValue[0] == '<') {
    if ($compareValue >= substr($searchValue, 1)) {
        unset($data[$rowIndex]);
    }
} else if ($searchValue[0] == '>') {
    if ($compareValue <= substr($searchValue, 1)) {
        unset($data[$rowIndex]);
    }
} else if (stripos($compareValue, $searchValue) === false) {
    unset($data[$rowIndex]);
}

Controller

// Create filter model and set properties
$filtersForm=new FiltersForm;
if (isset($_GET['FiltersForm']))
    $filtersForm->filters=$_GET['FiltersForm'];

// Get rawData and create dataProvider
$rawData=User::model()->findAll();
$filteredData=$filtersForm->filter($rawData);
$dataProvider=new CArrayDataProvider($filteredData);

// Render
$this->render('index', array(
    'filtersForm' => $filtersForm,
    'dataProvider' => $dataProvider,
));

View

$columns = array(
	array(
		'header'=>CHtml::encode('Name'),
		'name'=>'username',
	),
	array(
		'header'=>CHtml::encode('Organisation'),
		'name'=>'organisation',
	),
);

$this->widget('zii.widgets.grid.CGridView', array(
    'id'=>'area-grid',
    'dataProvider'=>$dataProvider,
    'columns'=>$columns,
    'filter'=>$filtersForm,
));
19 0
29 followers
Viewed: 93 950 times
Version: 1.1
Category: How-tos
Written by: marcovtwout
Last updated by: yugene
Created on: Sep 12, 2011
Last updated: 11 years ago
Update Article

Revisions

View all history

Related Articles