[solved] how filter cgridview with join table and some condition and paging

usually CGridView with default filter (one model at one table) like this :

in controller :




$model=new model_A('search');

$this->render('rendering_file',array(

			'datacall'=>$model,

		));



in view :




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

	'id'=>'data-logs',

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

	'filter'=>$datacall,

	'columns'=>array(

			...

			...




if model_A has criteria, then become :

in controller : (with CDbCriteria)




$model=new model_A('search');

$merge=new CDbCriteria;

if(!Yii::app()->request->isAjaxRequest)

	$merge->order = 'some_field ASC';


if(isset($_GET['model_A']))

{

	$model->attributes=$_GET['model_A'];

	$merge->order = 'some_field ASC'; //just customize this after filtering

}

$this->render('rendering_file',array(

			'merge'=>$merge,

			'datacall'=>$model,

		));



in view :




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

	'id'=>'data-logs',

	'dataProvider'=>$datacall->search($merge),

	'filter'=>$datacall,

	'columns'=>array(

			...

			...



with some additional data on model_A :




public function search($merge=null) //add $merge == null

	{

		$criteria=new CDbCriteria;


		$criteria->compare('no',$this->no);

		...bla bla


		if($merge!==null) //add this line

			$criteria->mergeWith($merge); //add this line

			

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

			'criteria'=>$criteria,

		));

	}




[size="6"]And my question :[/size]

how send dataProvider on CGridView on the view file

if i have some joining tables

(e.q. : model_A represent table A, model_B represent table B )

i wanna search on table B where i have to join with table A on field e.q. ‘student_id’

i make :

in controller :




$model=new model_B('search');

$merge=new CDbCriteria;

if(!Yii::app()->request->isAjaxRequest)

{

	$merge->join = 'table_A ta ON ta.student_id=t.student_id';

	$merge->order = 'some_field ASC';


}

if(isset($_GET['model_B']))

{

	$model->attributes=$_GET['model_B'];

	$merge->join = 'table_A ta ON ta.student_id=t.student_id';

	$merge->order = 'some_field ASC'; //just customize this after filtering

}

$this->render('rendering_file',array(

			'merge'=>$merge,

			'datacall'=>$model,

		));



in view :




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

	'id'=>'data-logs',

	'dataProvider'=>$datacall->search($merge),

	'filter'=>$datacall,

	'columns'=>array(

			...

			array(

				'name' => 'some_field_on_model_A',

				'value' => '$data->relation_to_model_A->some_field_on_model_A', //it occurs error

					),



with some additional data on model_B :




public function relations()

	{

		return array(

			'relation_to_model_A' => array(self::BELONGS_TO, 'table_A', 'student_id'),

			'relation_to_model_C' => array(self::BELONGS_TO, 'table_B', 'period_id'),

		);

	}

public function search($merge=null) //add $merge == null

	{

		$criteria=new CDbCriteria;


		$criteria->compare('no',$this->no);

		...bla bla


		if($merge!==null) //add this line

			$criteria->mergeWith($merge); //add this line

			

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

			'criteria'=>$criteria,

		));

	}



the problem :

  1. i couldnt search on filter, just loading and finish, not filtering my input

  2. i couldnt print column with data on another table (field on table A)

or

could you show me some tutorial how using CGridView filtering when models are joining with CDbCriteria?

or using another db classes?

thanks :)


jefriyanto

model B relation




public function relations()

        {

                return array(

                        'student' => array(self::BELONGS_TO, 'table_A', 'student_id'),  

                );

        }



controller








if(!Yii::app()->request->isAjaxRequest)

{


$dataProvider=new CActiveDataProvider('model_B',array( 'criteria'=>array(

'with'=>'student',

//'condition'=>'egzamplecolumn="'.GET['something'].'" AND egzamplecolumn2="'.GET['something'].'" ',    // extra conditions

'order'=>'some_field ASC',        

 ),     

$this->render('rendering_file',array('dataProvider'=>$dataProvider,));

}else{


$this->render('rendering_file'); // something else


}







view





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

        'id'=>'data-logs',

        'dataProvider'=>$dataProvider,

        'columns'=>array(

          

   array(          

            'name'=>'some data A fild',

            'value'=>'$data->student->column',

        ),




         ),



thanks for your response,

buat i have tried with CActiveDataProvider and tried from yours

and the result :

Property "CActiveDataProvider.search" is not defined

my gridview must have filter enabled

if using $dataProvider variable like yours, the view (with filter gridview) must be :





	'dataProvider'=>$dataProvider->search($merge), //method search in CActiveDataProvider not defined

	'filter'=>$dataProvider, 



you dont need search merge

yeah, if i dont use merge,

how the filter must type up on view under ‘dataProvider’ => $datafromcontroller

(in this case, $datafromcontroller use CActiveDataProvider to generate condition query)

but we must put on filter on CGridView to enable filtering like this:




 'dataProvider'=>$datacall->search($merge), //how to type it with CActiveDataProvider

 'filter'=>$datacall,//how to type it with CActiveDataProvider



try something like this

model




public function search()

{

$criteria=new CDbCriteria;

$criteria->compare('column',$this->column);

$criteria->compare('relation.relation_id',$this->relation_id, true);

$criteria->with('relation');   

$dataprovider = new CActiveDataProvider(get_class($this));

return $dataprovider->setCriteria($criteria);

}



its CDbCriteria does not have a method named "with".

No, it has a property called ‘with’ :

http://www.yiiframework.com/doc/api/1.1/CDbCriteria#with-detail

it couldn’t :(

is $criteria on search() function , only use method?

$criteria->method()

not $criteria->properties() ?

and with is properties(), compare is method()

im little confused about it

Do not panic:


public function search()

{

$criteria=new CDbCriteria;

$criteria->compare('column',$this->column);

$criteria->compare('relation.relation_id',$this->relation_id, true);

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


$dataprovider = new CActiveDataProvider(get_class($this));

return $dataprovider->setCriteria($criteria);

}

okay thanks , it works,

but i couldnt print column on relation table (in this case table_A with model_A)

i have used ‘value’ => ‘$data->relation->column_on_table_A’,

exception :

Property "model_B.column_on_table_A" is not defined.

yea sory i wrote incorrect, with is array property

$criteria->with = array(‘relation’);

glad that helps :)

print out whole relation to see if works relation print_r($data->relation)

EDIT : or in model search method print out criteria

okay, i am totally confused :lol:

here is my coding :

i have relation :

[CENTER]1103

3d4f.jpg

and create :

controller :

[PHP]

$model=new dc_logs(‘search’);

if(isset($_GET[‘dc_logs’]))

{

$model->attributes=$_GET['dc_logs'];

}

//change total size paging was successful

if (isset($_GET[‘pageSize’]))

{

Yii::app()->user->setState('pageSize',(int)$_GET['pageSize']);


unset($_GET['pageSize']);

}

$this->render(‘view_logs’,array(

			'member'=>$model,


			));

[/PHP]

model dc_logs.php :

[PHP]

public function relations()

{

return array(


	'relation_to_member' => array(self::BELONGS_TO, 'member', 'nim'),


	);

}

public function search()

{

$criteria=new CDbCriteria;


$criteria->compare('period',$this->period);


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


$criteria->addSearchCondition('relation_to_member.nim',$this->nim);


	


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


	'pagination'=>array(


			'pageSize'=> Yii::app()->user->getState('pageSize',


			Yii::app()->params['defaultPageSize']),


			),


	'criteria'=>$criteria,


	));


}

[/PHP]

view_logs.php :

[PHP]

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

	'id'=&gt;'data-logs',


	'dataProvider'=&gt;&#036;member-&gt;search(),


	'filter'=&gt;&#036;member,


	'columns'=&gt;array(


			array(


				'name' =&gt; 'nim',


				'value' =&gt; '&#036;data-&gt;nim', //can also &#036;data-&gt;relation_to_member-&gt;nim 


				),


			array(


				'name' =&gt; 'name',


				'value' =&gt; '&#036;data-&gt;relation_to_member-&gt;name', //error exception Property &quot;dc_logs.name&quot; is not defined.


				),


	...


	...


										),

[/PHP]

note : filtering with nim is successful but i can not print value of table member with $data->relation_to_member->name, or $data->relation_to_member->birthdate , etc

try this




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

                'id'=>'data-logs',

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

                'filter'=>$member,

                'columns'=>array(

                                array(

                                        'name' => 'nim',

                                        'value' => '$data->nim', //can also $data->relation_to_member->nim 

                                        ),

                                array(

                                        'name' => 'name',

                                        'value' => 'member::Model()->FindByPk($data->nim)->name', 

                                        ),







one more thing in model you have to setup wich atribute are safe to search

array(‘relation_to_member.nim,relation_to_member.name’, ‘safe’, ‘on’=>‘search’),

Solve but im using mergeWith in model

in this case, i want take data with a period condition in dc_logs table join with member

controller :

[PHP]

public function actionIndex()

{


	//criteria get condition member with certain period


	&#036;criteria=new CDbCriteria;


	&#036;criteria-&gt;order = &quot;period DESC&quot;;


	&#036;criteria-&gt;limit = &quot;0,1&quot;;


	&#036;periodedc=period::model()-&gt;find(&#036;criteria);





	&#036;model=new member('search');





	//data at first, default data with condition :


	&#036;merge=new CDbCriteria;		


	&#036;merge-&gt;condition = 'dc_logs.period = '.&#036;periodedc['period'];


	&#036;merge-&gt;join = 'JOIN dc_logs ON dc_logs.nim = t.nim';


			


	//if any filter in gridview


	if(isset(&#036;_GET['member']))


	{


		&#036;model-&gt;attributes=&#036;_GET['member'];


		&#036;merge-&gt;condition = 'dc_logs.period = '.&#036;periodedc['period']; //type again same condition with above


		&#036;merge-&gt;join = 'JOIN dc_logs ON dc_logs.nim = t.nim';


	}





	//if items/page changing from gridview


	if (isset(&#036;_GET['pageSize'])) 


	{


		&#036;merge-&gt;condition = 'dc_logs.period = '.&#036;periodedc['period']; //type again same condition with above


		&#036;merge-&gt;join = 'JOIN dc_logs ON dc_logs.nim = t.nim'; 


		Yii::app()-&gt;user-&gt;setState('pageSize',(int)&#036;_GET['pageSize']);


		unset(&#036;_GET['pageSize']);


	}


	


	&#036;this-&gt;render('data_member',array(


					'member'=&gt;&#036;model,


					'merge'=&gt;&#036;merge,


						));


}

[/PHP]

model :

[PHP]

public function search($merge=null) //add param $merge=null

{


	&#036;criteria=new CDbCriteria;


	


	&#036;criteria-&gt;compare('no',&#036;this-&gt;no);


	&#036;criteria-&gt;compare('t.nim',&#036;this-&gt;nim,true); //use t.nim cause join with another tabel (t=member)


	...


	//add &#036;merge to merge from controller


	if(&#036;merge&#33;==null)


		&#036;criteria-&gt;mergeWith(&#036;merge);


		


	return new CActiveDataProvider(get_class(&#036;this), array(


		//set paging


		'pagination'=&gt;array(


					'pageSize'=&gt; Yii::app()-&gt;user-&gt;getState('pageSize',


					Yii::app()-&gt;params['defaultPageSize']),


					),


		'criteria'=&gt;&#036;criteria,


	));


}

[/PHP]

view :

[PHP]

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

'id'=&gt;'data-member',


'dataProvider'=&gt;&#036;member-&gt;search(&#036;merge), //add param &#036;merge from controller


'filter'=&gt; &#036;member,


'columns'=&gt;array(


			array(


					'name'=&gt;'No',


					'value'=&gt;'&#036;this-&gt;grid-&gt;dataProvider-&gt;pagination-&gt;currentPage*&#036;this-&gt;grid-&gt;dataProvider-&gt;pagination-&gt;pageSize + &#036;row+1', 


					// sequence number item


					'filter' =&gt; false


					),


			array(


					'name' =&gt; 'nim',


					'value' =&gt; '&#036;data-&gt;nim',


					


					),


			array(


					'name' =&gt; 'nama_lengkap',


					'value'=&gt;'&#036;data-&gt;name',


					),


			...


			...


			array(


					'class'=&gt;'CButtonColumn',


					'template' =&gt; '{update}{delete}' ,


					'header'=&gt;CHtml::dropDownList(


											'pageSize',


											&#036;pageSize,


											array(1=&gt;'items',10=&gt;10,20=&gt;20,50=&gt;50,100=&gt;100,500=&gt;500), //set paging 10,20,50,100 or 500 items/page


											array(


												'onchange'=&gt;&quot;&#036;.fn.yiiGridView.update('data-member',{ data:{pageSize: &#036;(this).val() }})&quot;,


												)


											),


				),


	


),

)); ?>

[/PHP]

thanks for yiier’s response

but i used merge, not use WITH properties in search model cause still confused to using if we have some default condition in controller:)

Hi, i have same problem. How to reach with 3 tables ;D?. I have 3 tables: user, profil and school. how to to achive this?. thanks

if you using my coding (merge)

controller

[PHP]

public function actionIndex()

{





	&#036;model=new user('search');





	//data at first, default data with condition :


	&#036;merge=new CDbCriteria;		


	&#036;merge-&gt;condition = //some condition here


	&#036;merge-&gt;join = 'JOIN profile ON profile.user_id = t.user_id


			JOIN school ON school.school_id = t.school_id';


			


	//if any filter in gridview


	if(isset(&#036;_GET['member']))


	{


		&#036;model-&gt;attributes=&#036;_GET['member'];


		&#036;merge-&gt;condition = //some condition here


		&#036;merge-&gt;join = 'JOIN profile ON profile.user_id = t.user_id


				JOIN school ON school.school_id = t.school_id';


	}





	//if items/page changing from gridview


	if (isset(&#036;_GET['pageSize'])) 


	{


		&#036;merge-&gt;condition = //some condition here


		&#036;merge-&gt;join = 'JOIN profile ON profile.user_id = t.user_id


				JOIN school ON school.school_id = t.school_id';


		Yii::app()-&gt;user-&gt;setState('pageSize',(int)&#036;_GET['pageSize']);


		unset(&#036;_GET['pageSize']);


	}


	


	&#036;this-&gt;render('data_member',array(


					'member'=&gt;&#036;model,


					'merge'=&gt;&#036;merge,


						));


}

[/PHP]

model :

[PHP]

public $school_name,…,…; //create public variable

public function search($merge=null) //add param $merge=null

{


	&#036;criteria=new CDbCriteria;


	


	&#036;criteria-&gt;compare('no',&#036;this-&gt;no);


	&#036;criteria-&gt;compare('t.nim',&#036;this-&gt;nim,true); //use t.nim cause join with another tabel (t=member)


	


	&#036;criteria-&gt;with = array('relation_to_school','relation_to_profile');


	&#036;criteria-&gt;compare('relation_to_schoo.school_name', &#036;this-&gt;school_name);


	...


	//add &#036;merge to merge from controller


	if(&#036;merge&#33;==null)


		&#036;criteria-&gt;mergeWith(&#036;merge);


		


	return new CActiveDataProvider(get_class(&#036;this), array(


		//set paging


		'pagination'=&gt;array(


					'pageSize'=&gt; Yii::app()-&gt;user-&gt;getState('pageSize',


					Yii::app()-&gt;params['defaultPageSize']),


					),


		'criteria'=&gt;&#036;criteria,


	));


}

[/PHP]

view :

value = $data->relation_to_school->column_name_in_school

maybe it can errors, cause i never try how filtering with condition on another table

but you can observe it and reporting into this thread

thanks :)

Thanks for your suggestion. This is my code:




// model (User.php)

public $fullName;

public $schoolName;


public function search()

{

	$criteria = new CDbCriteria;

	$criteria->compare('user_id',$this->user_id);

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

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

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

	

	$criteria->join = 'LEFT JOIN profil p ON t.user_id=p.user_id LEFT JOIN school s ON t.user_id=s.user_id';

	$criteria->with = array('profil_relation', 'school_relation');

	$criteria->compare('p.fullname', $this->fullName, true);

	$criteria->compare('s.school_name', $this->schoolName, true);

	

	return new CActiveDataProvider('User', array(

		'criteria' => $criteria,

	));

}


// controller (UserController.php)

public function actionSearch()

{

	$model = new User('search');

	if(isset($_GET['User'])) {

		$model->attributes = $_GET['User'];

	}

	

	$this->render('advanced_search', array(

		'model'=>$model,

		));

	}

}	


// view (advanced_search.php)

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

	'id' => 'user-grid',

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

	'filter' => $model,

	'columns'=>array(

		'user_id',

		'username',

		'display_name',

		'email',

		array(

			'name' => 'fullName',

			'value' => '$data->profil->fullname'

		),

		array(

			'name' => 'schoolName',

			'value' => '$data->profil->school_name'

		),

		array(

			'class'=>'CButtonColumn',

		),

	),

));


// model User.php

public function relations()

{

  return array(

    'profil_relation' => array(self::HAS_ONE, 'Profil', 'user_id'),

  );

}


// model Profil.php

public function relations()

{

  return array(

    'user_relation' => array(self::BELONGS_TO, 'User', 'user_id'),

	'school_relation' => array(self::HAS_MANY, 'School', 'user_id'),

  );

}


// model School.php

public function relations()

{

  return array(

    'user_relation' => array(self::BELONGS_TO, 'User', 'user_id'),

    'profil_relation' => array(self::BELONGS_TO, 'Profil', 'user_id'),

  );

}



school has many result. for example school A, school B, school C.

school A (elementary school), school B(junior highschool), school C(undergraduate).

How to get the last school from the table?. any suggestion?. thanks again