CGridView with multiple models

I have been trying to work through the following scenario to no avail. Would appreciate if someone could help me out with this.

Given the db:

In my CGridView for City I would like to also display Name from Country.

The farthest that I got was being able to display a dropdown list of the Country Names (so the filter works) but I could not get the Country Names to populate the fields in CGridView as that column kept referencing the City Model.




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

	'id' => 'city-grid',

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

	'filter' => City::model(),

	'columns' => array(


           ...


           'CountryName'=>array(

	     'name'=>'Name',

	     'value'=>'$Country->Name',

	     'filter' => GxHtml::listDataEx(Country::model()->findAll(array('order'=>'Name')), 'Name', 'Name'),

	     ),



Here is my current code minus all the attempts I have gone through to try and make this happen. This works properly to display City(CityId, Name) and Region(Name).

views/city/admin.php




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

	'id' => 'city-grid',

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

	'filter' => City::model(),

	'columns' => array(

		'CityId',

		

		'Name',

			array(

				'name'=>'RegionCode',

				'value'=>'GxHtml::valueEx($data->regionCode)',

				'filter'=>GxHtml::listDataEx(Region::model()->findAllAttributes(null, true)),

			),

			

		array(

			'class' => 'CButtonColumn',

		),

	),

)); ?>



models/_base/BaseCity.php




public function relations() {

		return array(

			'regionCode' => array(self::BELONGS_TO, 'Region', 'RegionCode'),

		); 

	}


public function attributeLabels() {

	return array(

		'CityId' => Yii::t('app', 'City Id'),

		'RegionCode' => Yii::t('app', 'Region'),

		'Name' => Yii::t('app', 'Name'),

	);

}


public function search() {

	$criteria = new CDbCriteria;


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

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

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


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

		'criteria' => $criteria,

	));

}



Try this:




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

        'id' => 'city-grid',

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

        'filter' => City::model(),

        'columns' => array(

                'CityId',

                

                'Name',

                array(

                        'name'=>'RegionCode',

                        'value'=>'GxHtml::valueEx($data->regionCode)',

                        'filter'=>GxHtml::listDataEx(Region::model()->findAllAttributes(null, true)),

                ),

                array(

                        'name'=>'CountryCode',

                        'value'=>'GxHtml::valueEx($data->regionCode->countryCode)',

                        'filter'=>GxHtml::listDataEx(Country::model()->findAllAttributes(null, true)),

                ),

                array(

                        'class' => 'CButtonColumn',

                ),

        ),

)); ?>



@mentel using the code that you provided yields this:


Property "City.CountryCode" is not defined. 

This is the same error as I was getting before. Doesn’t this mean I have to have something declared for this as everything else is taken care of in the relationships in BaseCity? Do I have to create a function to utilize the Country model?

With rawtaz’s guidance in chat, if I go with this:




'CountryName'=>array(

      ...

      'name'=>'regionCode.countryCode.Name',



as in




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

        'id' => 'city-grid',

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

        'filter' => City::model(),

        'columns' => array(

        'CityId',

	'Name',

	   array(

		'name'=>'RegionCode',

		'value'=>'GxHtml::valueEx($data->regionCode)',

		'filter'=>GxHtml::listDataEx(Region::model()->findAllAttributes(null, true)),

		),

			

	'CountryName'=>

           array(

		'header' => 'Country',

		'name'=>'regionCode.countryCode.Name',

		'value'=>'$data->regionCode->countryCode->Name',

		'filter' => GxHtml::listDataEx(Country::model()->findAll(array('order'=>'Name')), 'Name', 'Name'),

		),

	array(

	  'class' => 'CButtonColumn',

	),

	),

)); ?>



Then the Country Name value is filled in on the grid as I wanted. The downside is ‘value’ and ‘filter’ no longer mean anything in ‘CountryName’=>array so the field is no longer searchable and the dropdown I once had is gone.

Even though I once had a dropdown properly displaying the Country Names as I wanted, after further testing, I realized the search was still going off the City model. So from here I can modify the search method in the City model or maybe directly modify the view itself to build in the correct search functionality (probably harder for me).

I have come across multiple variations of using different models within


'columns' => array(

but don’t know what changes if any were part of the model to get things working.

I might be trying to tackle something beyond my knowledge but getting this figured out is important for me since I have multiple instances where I need to accomplish this same thing.

Ok making more forward progress. Right now I have:




<?php

$dataProvider = new CActiveDataProvider('Country', array(

  'criteria'=>array(

    'order'=>'Name',

  ),

));




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

     'id' => 'city-grid',

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

     'filter' => City::model(),

     'columns' => array( 

     'CityId',

     'Name',

	array(

	   'name'=>'RegionCode',

	   'value'=>'GxHtml::valueEx($data->regionCode)',

	   'filter'=>GxHtml::listDataEx(Region::model()->findAllAttributes(null, true)),

	),

     'CountryName'=>array(

	   'header' => 'Country',

	   'name'=>'Name',

	   'value'=>'$data->regionCode->countryCode->Name',

	   'filter' => GxHtml::listDataEx(Country::model()->findAll(array('order'=>'Name')), 'Name', 'Name'),

	),

     array(

	'class' => 'CButtonColumn',

     ),

   ),

)); ?>



This gives me the filled in column in the grid and a sorted dropdown list of the Country Name. Still need to fix the search functionality as the search is still based on the City model.

Not sure if this is the best way to go about things so still open to suggestions from others that got multiple models working through a different way in CGridView.

Finally got the chance to continue on with this but I am stuck. I would appreciate any help. Current open issues at the bottom of this post.

Here is my current code:

view


<?php


$dataProvider = new CActiveDataProvider('Country', array(

  'criteria'=>array(

    'order'=>'Name',

  ),

));


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

	'id' => 'city-grid',

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

	'filter' => $model,

	'columns' => array(

		'CityId',

		'Name',

		array(

		  'name'=>'RegionCode',

		  'value'=>'GxHtml::valueEx($data->regionCode)',

		  'filter'=>GxHtml::listDataEx(Region::model()->findAllAttributes(null, true)),

		),

		'CountryName'=>array(

		  'header' => 'Country',

		  'name'=>'countryName',

		  'value'=>'$data->regionCode->countryCode->Name',

		  'filter' => GxHtml::listDataEx(Country::model()->findAll(array('order'=>'Name')), 'Name', 'Name'),

		 ), 

	),  

)); ?>

model




abstract class BaseCity extends GxActiveRecord {

...

public $countryName;

...

public function search() {

  $criteria = new CDbCriteria;


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

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

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


  $criteria->compare('Country.Name', $this->countryName); 

		

  return new CActiveDataProvider($this, array(

    'criteria' => $criteria,

  ));

}

...

This gives me these (exactly what I want to see minus the search and sort functionality)…

showing proper list in Country Name dropdown

[b]

Current open issues:[/b]

[list=1]

[*]Country (Name) is no longer a sortable link on the grid

[*] When I select a Country from the dropdown I do not get a response. No error and no search results. As mentioned in my previous post before making the changes to my model when I made a selection in the dropdown on Country it was still searching the City Name not Country Name.

Would appreciate if someone could point me in the right direction.

[/list]

you need to add the relation to the criteria…

as you use


$criteria->compare('Country.Name', $this->countryName); 

I supose the relation name is country… so you need to add


$criteria->with(array('country'));

Fixed on IRC :D

Yes sir, thanks to you. I will fill in the details here in a bit so others have the reference.

Ok to fill in the blanks and reference for others. Again the credit goes to MrSoundless.

With the following code everything looks as it should (described in original question) and more importantly functions correctly!

[b]

Model[/b]


private $_countryName = null;

public function getCountryName()

{

   if ($this->_countryName === null && $this->regionCode !== null && $this->regionCode->countryCode !== null)

   {

	$this->_countryName = $this->regionCode->countryCode->Name;

	}

	  return $this->_countryName;

   }

   public function setCountryName($value)

   {

	$this->_countryName = $value;

   }




public function search() {

   $criteria = new CDbCriteria;

		

   $criteria->join = "INNER JOIN Region ON Region.RegionCode = t.RegionCode 

                      INNER JOIN Country ON Country.CountryCode = Region.CountryCode";

		

   ...

		

   $criteria->compare('Country.Name', $this->countryName, true);

		

   $sort = new CSort();

   $sort->attributes = array(

        'defaultOrder'=>'t.Name ASC',

        ...

	'countryName'=>array(

	  'asc'=>'Country.Name',

	  'desc'=>'Country.Name desc',

	),

   );

		

   return new CActiveDataProvider($this, array(

	'criteria' => $criteria,

	'sort'=>$sort,

   ));



View





$dataProvider = new CActiveDataProvider('Country', array(

  'criteria'=>array(

    'order'=>'Name',

  ),

));


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

   'id' => 'city-grid',

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

   'filter' => $model,

   'columns' => array(

      ...

      'CountryName'=>array(

	'header' => 'Country',

	'name'=>'countryName',

	'value'=> '$data->countryName',

	'filter' => GxHtml::listDataEx(Country::model()->findAll(array('order'=>'Name')), 'Name', 'Name'),

	),

      ...



I can show the name, but the filter dont work.

Any tip?

Thanks!!!