Sort and filter a custom or composite CGridView column - that may even contain data from different tables.

You are viewing revision #16 of this wiki article.
This version may not be up to date with the latest version.
You may want to view the differences to the latest version or see the changes made in this revision.

« previous (#15)next (#17) »

  1. SCENARIO 1
  2. SCENARIO 2

SCENARIO 1

Overview

I have a table (account) which contains "General Ledger" accounts. Each account has its own account_description - such as 'inventory', 'sales', etc.

In a second table (client), I have the names of all the clients. The fields are client_surname, client_name1, client_name2 and client_name3.

All clients have accounts, but not all accounts are linked to a client. So viewed from the account's perspective, this is a normal one-to-many relation (actually one-to-zero/one) with account being parent and client being child.

Objective

Use only one gridview column. If the account does not have a client - then display the account_description (account tbl) in the gridview column; otherwise display the client's names and surname (client tbl) in the column.

So for some rows, this column will contain data from account tbl; while in other rows, this column will contain data from client tbl;

Model
class account_model extends CActiveRecord
{
	/* Gridview Attributes */
	public $varFullname;
	
	/* Own defined Getter function to combine fields */
	public function getCompiledFullname()
	{
		/* Test if account is linked to a Client. If not, use account_description, otherwise use client names and surname. */
		if ($this->client !== null)
		{
			return  
				$this->client->client_surname . ' ' .
				$this->client->client_name1 . ' ' .
				$this->client->client_name2 . ' ' .
				$this->client->client_name3;
		}
		else
		{
			return $this->account_description;
		}
	}
	
	public function relations()
	{
		return array(
			'client' => array(self::HAS_ONE, 'client', 'accnt_nr'),
		);
	}
	
	public function rules()
	{
		return array(
			array('varFullname', 'safe', 'on'=>'search'),
		);
	}
	
	public function attributeLabels()
	{
		return array(
			'account_description' => 'Name',
		);
	}

	public function search()
	{
		$criteria		= new CDbCriteria;
		$sort 			= new CSort;
		
		/* Eager loading if Account has a Client */
		$criteria->with = array(
			'client' => array()
		);

		/* Filter criteria 
		Testing for null values is important because unused name fields
		will be null and they will filter out records if untreated.

	 	The following compare statement works like this:
		if(account_description == null)
	  	then (use surname and names in comparison)
	  	else (use account_description in comparison).
	  	Compare them to $this->varFullname.  

		Note: IFNULL = MySql; ISNULL = SQL Server*/

		$criteria->compare(
			"IFNULL(account_description,
				CONCAT(	IFNULL(client_surname,''),
						IFNULL(client_name1,''),
						IFNULL(client_name2,''),
						IFNULL(client_name3,''))
			)", $this->varFullname, true);

		/* Sort criteria */
		$sort->attributes = array(
			/* 	if (account_description is null)
				then (sort by client_surname, client_name1...), 
				else (sort by account_description) */
			'varFullname'=>array(
		        'asc'=>"IFNULL(account_description,
					CONCAT(	IFNULL(client_surname,''),
							IFNULL(client_name1,''),
							IFNULL(client_name2,''),
							IFNULL(client_name3,''))
				)",
		        'desc'=>"IFNULL(account_description,
					CONCAT(	IFNULL(client_surname,''),
							IFNULL(client_name1,''),
							IFNULL(client_name2,''),
							IFNULL(client_name3,''))
				) desc",
		    ),
			'*',
		);
		
		/* Default Sort Order*/
		$sort->defaultOrder= array(
			'varFullname'=>CSort::SORT_ASC,
		);
	
		return new CActiveDataProvider($this, array(
			'pagination'=>array('pageSize'=>20),
			'criteria'=>$criteria,
			'sort'=>$sort,
		));
	}

}
CGridView Column
array(
	'name'	=> 'varFullname',
	'value'	=> '($data->CompiledFullname) ? $data->CompiledFullname : ""',
	'header'=> CHtml::encode($model->getAttributeLabel('account_description')),
	'filter'=> CHtml::activeTextField($model, 'varFullname'),
),

SCENARIO 2

Overview

In this second scenario, you want to display the name of a colour in the CGridView column, based on the value of the 'type' property in your table.

Model
public $varColour;

public function getCompiledColour()
{
	if($this->type == 1)
	{
		return 'Red';
	}
	elseif($this->type == 2)
	{
		return 'Yellow';
	}
	else
	{
	return 'Green';
	}
}

public function rules()
{
	return array(
		array('varColour', 'safe', 'on'=>'search'),
	);
}

public function attributeLabels()
{
	return array(
		'varColour' => 'Colour',
	);
}

public function search()
{
	$criteria	= new CDbCriteria;
	$sort 		= new CSort;

	/* Filter Criteria */
	$criteria->compare(
		"CASE t.type
			WHEN 1 THEN 'Red'
     		WHEN 2 THEN 'Yellow'
			ELSE 'Green' 
		END", $this->varColour, true);

	/* Sort Criteria */
	$sort->attributes = array(
		
		'varColour'=>array(
	        'asc'=>"
				CASE t.type
					WHEN 1 THEN 'Red'
	         		WHEN 2 THEN 'Yellow'
					ELSE 'Green' 
				END",
	        'desc'=>"
				CASE t.type
					WHEN 1 THEN 'Red'
	         		WHEN 2 THEN 'Yellow'
					ELSE 'Green' 
				END	desc",
	    ),

		'*',
	);
	
	return new CActiveDataProvider($this, array(
		'pagination'=>array(
			'pageSize'=>20,
		),
		'criteria'=>$criteria,
		'sort'=>$sort,
	));
}
CGridView Column
array(
	'name'=>'varColour',
	'value'=>'($data->CompiledColour) ? $data->CompiledColour : ""',
	'header'=> CHtml::encode($model->getAttributeLabel('varColour')),
	'filter' => CHtml::activeTextField($model, 'varColour'),
),
6 0
6 followers
Viewed: 64 900 times
Version: Unknown (update)
Category: How-tos
Written by: Gerhard Liebenberg
Last updated by: Gerhard Liebenberg
Created on: Nov 18, 2013
Last updated: 7 years ago
Update Article

Revisions

View all history

Related Articles