CGridView filter with relations

Hi all

When I reference a relationship column in CGridView (i.e. to lookup a category code from a category ID), the filter box for that column disappears. How do I get this back?

I suspect I need to add a new criterion to CDbCriteria in my model, but I can’t figure out what it should be.

Many thanks.

I have just looked in the framework source and have found the following:


protected function renderFilterCellContent()

{

if($this->filter!==false && $this->grid->filter!==null && strpos($this->name,'.')===false)

...

So Yii does not display the filter cell when the column has a dot in its name (i.e. a relation)?

What would be the best way to work around this?

I’m pumping up this question… Anyone got an idea?

I’m having the same problem!

Same here… Hope anyone more familiar with the framework can point us to the right direction.

Actually i found my way around this … check this post.

I’m also trying to find a way around this.

In my case I have Addresses and Businesses

In my Address admin search I want to also have searchable the business information that is linked to the address.

Each Address is linked with a business_id foreign key to a business.

I can use the solution from eval’s posted link to display a text box for the filter on say the business name:




array(

      'name'=>'business_id',

      'value'=>'Businesses::model()->FindByPk($data->business_id)->name',

    ),



However I can’t figure out a way to have the other business information searchable, eg:




    array( 

      'name'=>'business.url', 

      'value'=>'Businesses::model()->FindByPk($data->business_id)->url',

    ),



If I use code like the above, I can get the url to display in the grid but even after looking through the forums I can’t find a method that will let me enable a filter for it as well.

I have the same problem,is anyone can help me?

You can set the property ‘filter’ of CDataColumn with the html you need.

You have also to edit the search function in order to filter correctly data (with subquery or join).

So in your CGridView you should set the Columns property in and for the related colum specify the filter you need (textfield or dropdownlist)

can you give me some example,thank you!

here is how I did it:

My model BuyerContracts, the search portion:




public function search()

	{

		// Warning: Please modify the following code to remove attributes that

		// should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('t.id',$this->id);


		$criteria->compare('t.offer_id',$this->offer_id);


		$criteria->compare('t.buyer_id',$this->buyer_id);


		$criteria->compare('t.campaign_id',$this->campaign_id);


		$criteria->compare('t.status',$this->status);


		$criteria->compare('t.credit_limit',$this->credit_limit);


		$criteria->compare('t.cap_limit',$this->cap_limit);


		$criteria->compare('date(t.starts_on)',$this->starts_on,true);


		$criteria->compare('date(t.expires_on)',$this->expires_on,true);


		$criteria->compare('date(t.created)',$this->created,true);


		$criteria->with = array(

								'offer'=>array('select'=>'offer.name'),

								'buyer'=>array('select'=>'buyer.name'),

								'campaign'=>array('select'=>'campaign.name'),

								);

		return new CActiveDataProvider(get_class($this), array(

			'criteria'=>$criteria,

		));

	}



and then the view that has the grid view:




<?php $this->widget('zii.widgets.grid.CGridView', array(

	'id'=>'buyer-contracts-grid',

	'dataProvider'=>$model->search(),

	'filter'=>$model,

	'columns'=>array(

		'id',

		//'offer_id',

		array(

			'filter'=>Offers::model()->forList(),

			'name'=>'offer_id',

			'value'=>'$data->offer->name'

		),

		//'buyer_id',

		array(

			'filter'=>Buyers::model()->forList(),

			'name'=>'buyer_id',

			'value'=>'$data->buyer->name'

		),

		//'campaign_id',

		array(

			'filter'=>Campaigns::model()->forList(),

			'name'=>'campaign_id',

			'value'=>'(isset($data->campaign) ? $data->campaign->name : "")'

		),

		//'status',

		array(

			'filter'=>array('inactive','active'),

			'name'=>'status',			

		),

		'credit_limit',

		'cap_limit',

		'price_per_lead',

		'starts_on',

		'expires_on',

		'created',

		//'last_modified',

		array(

			'class'=>'CButtonColumn',

		),

	),

)); ?>


Notice that for the filter bits, the model function Offers::model()->forlist() just returns a one dimensional array, like id=>name



I have same problem with relationship …

any one knows abt simple solution…?

–BhavikChauhan

Doing that I have a dropdown to filter. Without ‘filter’ I have the textField, but it filters by id and not by description…

How to have a textField to filter through descriptions?

Any help would be appreciated…

tia

leave the text field, and then change the sarch function of the model.

Is in that function that imputs are manages for became condition, change the condition like that:





 $criteria=new CDbCriteria;

 $criteria->with=array('relatedTable');

 $criteria->toghether= true;





 $criteria->compare('relatedTableDescriptionField', $this->related_field, true);




If you need a more detailed example, explain me how is your model structure

Can you show us what your forList() function looks like?

I recommend MrSoundless’ blog post on this - there are very clear instructions as to how to implement filtering and sorting on related models.

What if I need to put a constraint on the $criteria->with statement? Can I just add that after the select?

Maybe this will help GridView Filtering of Relational Data ring-of-relational-data/

Hi, everybody!

I have solved this problem.

We have a related column: this->table_name->related_column

It’s so easy:

  1. Add public $var_name in your model

  2. In model method search() add:

$criteria->with = ‘table_name’;

$criteria->compare(‘table_name.related_column’, $this->var_name, true);

  1. And edit view:

row in columns:

        array(


            'name'=&gt;'var_name',


            'value'=&gt;'&#036;data-&gt;table_name-&gt;related_column',


        ),

Works perfectly! Only needs one more step:

2b. In model method rules() modify the rule used by search() and append the new attribute ‘var_name’:

// The following rule is used by search().

// Please remove those attributes that should not be searched.

array(‘attribute1, attribute2, …, attributeN, var_name’, ‘safe’, ‘on’=>‘search’)