Cgridview With Has_Many Relationship

I actually started writing this to ask for help, but found my error before I finished. Instead of letting it all go to waste I thought I would share my example. Hopefully it will help someone else.

I have the following relationship in my User model:


'email' => array(self::HAS_MANY, 'Email', 'user_id'), 

Now I know that CGridView and HAS_MANY relationships don’t get along, but I’m stubborn and I had a special case. Each user has only one primary email so I wanted to identify this HAS_ONE relationship in the many emails of the user and not only use the primary email in CGridView, but also allow it to be contextually searched and filtered (ASC, DESC). This is how I did it:

User Model




class User extends CActiveRecord

{

        public $email_primary;


    	public function rules()

	{

		return array(

			array('email_primary', 'safe', 'on'=>'search'), 

		);

	}


	public function search()

	{


		$criteria=new CDbCriteria;


		$criteria->with = array(

		    'email'=>array(

		          'together'=>true

		     )

		);

		

		

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

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

		

		$criteria->compare('profile.lastname',$this->profile_lastname,true);

		$criteria->compare('profile.firstname',$this->profile_firstname,true);

		

		

		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria, 

			'sort'=>array(

				'attributes'=>array(

					'email_primary'=>array(

						'asc'=>'email.email', 

						'desc'=>'email.email DESC', 

					),

					'*',

				),

			),

		));

	}

	

	public function primaryEmail() {

		foreach ($this->email as $email) {

			if($email->primary == 1)

			{

				return $this->email_primary = $email->email;

			}

		}

	}



Grid View





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

	'id'=>'user-grid',

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

	'filter'=>$model,

	'columns'=>array(

		array(

			'name'=>'email_primary', 

			'header'=>'Email',

			'value'=>'$data->primaryEmail()', 

		),

		array(

			'class'=>'CButtonColumn',

		),

	),

)); ?>



All questions and criticisms welcome!

Thanks for sharing this. I am also stuck up with relations.Myself has two tables ‘student’ and ‘marks’.Aim is to display the student details along with marks. The query is correct joining two tables. The issue is not able to display the fields in the joined table(marks).

model page



public function relations()

	{

		

		return array(

				'marks' => array(self::HAS_MANY, 'Marks', 'sID','joinType'=>'inner join'),

			

		);

		

	}


public function search()

	{

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

		// should not be searched.

	

		$criteria	        = new CDbCriteria;

		$criteria->with 	= "marks";

		$criteria->order	= "studentName asc";

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

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

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

		$criteria->compare('marks.mark1',$this->mark1,true);

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

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

		return new CActiveDataProvider($this, array(

				'criteria'=>$criteria,

		));

	} 


controller page



public function actionIndex()

	{		

		$model = new ExtendedStudent();	

		$this->render('index',array('list'=>$model));

		

	}

View page





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

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

		'id'=>'studgrid',

		'columns'=>array(

				array(

						'id'=>'autoId',

						'class'=>'CCheckBoxColumn',

						'selectableRows'=> '10',						

					  ),

				array(

						'name'=>'studentName',


						'value'=>'CHtml::encode($data->studentName)'

					  ),

				array(

						  'name'=>'studentcity',

						  'header'=>'City',


						'value' => 'CHtml::encode($data->student->studentcity)'							

					),

				 array(

						'header'=>'M1',

						'name'=>'mark1',						

				 		'value' => '$data->marks==null?"":$data->marks->mark1',

				 	


				),

		)); 

Could you please tell how to show the joined table column in grid?Any help is appreciated.

Student HAS_MANY Marks and that I know of, you are not able to use this type of relationship without some customization on your part, such as in my original post.

To demonstrate the problem, here is your code but narrated from the perspective of the computer that’s trying to run it.




  // Ok so were going to find some Students, here we go...


  // Found a Student row, ok great now what

  $criteria = new CDbCriteria;


  // With the students Marks, well he has 13 of them but alright what next 

  $criteria->with = "marks";


  // Oh so Im supposed to put put this student in a row, alright no problem

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

    //... *snipped*


    // Students name, easy here you go

    array(

      'name'=>'studentName',

      'value'=>'CHtml::encode($data->studentName)'

    ),


    // Marks mark1, ok no probl...    wait a second

    // I have 13 marks here but can only put it into 1 row

    // What am I supposed to just pick one?

    // Well I guess I could... but then oh no, what if I pick the wrong one???

    // OH THE HUMANITY! FOR THE LOVE OF SCIEN...     *error*

    array(

      'header'=>'M1',

      'name'=>'mark1',						

      'value' => '$data->marks==null?"":$data->marks->mark1',

    ),

  ));



So maybe I had a little too much fun with that, but the point is you cant put multiple rows into 1. Which means we need to get our creative programming juices flowing and write a custom solution. Here’s a couple possibilities:

[list=1]

[*]Take the many Marks found a cram the data you need into one variable

[*]Repeat the Student rows count(Marks) number of times

[/list]

Option number one seems the easiest but comes with one caveat: you cant sort in the grid view with this column. Well, at least not with the example Im about to give you:




        // Add this to your Students model

	public function getMarks()

	{

		$data = '';

		foreach($this->mark as $mark)

		{

			$data .= $mark->mark1;

		}

		return $data;

	}




        // In grid view

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

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

		'id'=>'studgrid',

		'columns'=>array(

                        // Call User->getMarks() to get a string of all Marks 

		        array(

			        'id'=>'M1',

				'value'=> array($model, 'getMarks'),

                        ),

                )

        ));			



This code isn’t tested and still I’m a Yii rookie so you’ll probably have to fix a few things.

How would you add filtering to this with ajax? What should the condition be in search function?