Yii 1.1: Using standard filters in CGridView custom fields

21 followers

In this article I'll try to explain how to use standard quick search fields in CGridView with customized columns.
For example:
We have a record in a database with field switch having 0 or 1 values. After that we want a user to see on or off instead 1 or 0.
So we do the usual thing:

<?php $this->widget('zii.widgets.grid.CGridView', array(
//.....
array(
    'name'=>'switch',
    'header'=>'Switch',
    'type'=>'raw',
    'value'=>'Mii::getSwitch($data->switch)'
),
//.....
));

Mii::getSwitch - is my own helper witch returns on or off according to the current switch value (in the original it returns an image).
After that the user can see on and off values in the column, but he will not be able to filter columns typing on or off in the quicksearch field.
So we do the following thing in model search() function:

public function search()
{
    // Warning: Please modify the following code to remove attributes that
    // should not be searched.
    $criteria=new CDbCriteria;
    //....other fields
    $criteria->compare('switch',$this->getSwitch($this->switch));
    return new CActiveDataProvider(get_class($this), array('criteria'=>$criteria,));
}
 
//function that returns usual 0 or 1 value dependently user input
public function getSwitch($switch)
{
    if(is_null($switch)) return $switch; //null shows all records
    if(is_numeric($switch)) return $switch; //here we save an ability to search with `0` or `1` value
    if($switch == 'on') {
        return 1; //all fields with `switch` = 1
    } elseif($switch == 'off') {
        return 0; //all fields with `switch` = 0
    } else {
        return null; //all fields
    }
}

In this simple way you can teach standard filter fields to search in customized columns.

Another example:
The column shows news author name according to their id. In this situation we must return reverse value. The column returns it in the following way: id->author and customized filter must return author->id. Lets write simple function:

public function getAuthor($author)
{
     if(empty($author)) return null; //return al if author is empty
     if(is_numeric($author)) return $author; //return fields if id is entered
     $criteria=new CDbCriteria;
     $criteria->select='author_id'; //select id field
     $criteria->compare('author_login',$author,true); //seach author name. partialMatch is on
     $am=authorsModel::model()->find($criteria);
     if(empty($am)) return 0; //if author not found - returns 0
     return $am->attributes['adm_id']; //returns author id
}

That is all!

Note: This was written simple examples. Situation, when there are several authors which logins starts from equal letters must return an array with their IDs.

Example with several authors starting from equal letters:

public function getAuthor($author)
     {
         if(empty($author)) return null;
         if(is_numeric($author)) return $author;
         $criteria=new CDbCriteria;
         $criteria->select='author_id';
         $criteria->distinct = true;
         $criteria->compare('author_login',$author,true);
         $am=authorsModel::model()->findAll($criteria);
         if(empty($am)) return 0;
         if(count($am) == 1) return $am[0]->attributes['author_id'];
         $ids = array();
         foreach($am as $a_id)
         {
             $ids[] = $a_id->attributes['author_id'];
         }
         return $ids;
     }

Total 4 comments

#4163 report it
at 2011/06/11 12:13am
how to make onclick change on or off?

how to make automatic change on or off if user click on that's values?

#3128 report it
mintaraga at 2011/03/18 03:11pm
Switch example another alternative
array(
    'header'=>'Brand',
    'name'=>'brand_id',
    'filter'=>CHtml::listData(Brand::model()->findAll(array('order'=>'name')),'id','name'),
    'value'=>'$data->brand->name'
),

that code will be create a dropdown list filter.

if you need to keep filter with text field u need some modified like this step 1

array(
    'header'=>'Brand',
    'name'=>'brand_id',
    'value'=>'$data->brand->name'
),

step 2 u need to modified the function search() on models

public function search()
{
    ...
 
    $criteria=new CDbCriteria;
    $criteria->join="LEFT JOIN brandname t1 ON t.brand_id = t1.brand_id ";
 
    ...
 
    $criteria->compare('t1.name,$this->brand_id,true);
 
    return new CActiveDataProvider(get_class($this), array(
            'criteria'=>$criteria,
    ));
}

so the the filter will keep shown as textfield and u can search using text

#2330 report it
GOsha at 2010/12/13 10:16am
@Alban - good comment

It was only simple example for more difficult situations. In original switch returns an image according to its state, In example - only on/off. For me filter in search function must validate (on,off),(1,0),('вкл','выкл') and other different lingual pairs. Thats why it was separate function.

#2329 report it
juban_ at 2010/12/13 10:05am
Switch example alternative

A simpler approach for the "Swich" example :

array(
    'name'=>'switch',
    'header'=>'Switch',
    'filter'=>array(0=>"Off",1=>"On"),
    'value'=>'@$data->switch ? "On" : "Off"',
),

No need to change your 'search' method in that case.

It also works with BELONG_TO relations, for example :

array(
    'header'=>'Brand',
    'name'=>'brand_id',
    'filter'=>CHtml::listData(Brand::model()->findAll(array('order'=>'name')),'id','name'),
    'value'=>'$data->brand->name'
),

Regards.

Alban.

Leave a comment

Please to leave your comment.

Write new article