Accessing Fields from foreign keys table

I have an aplication that uses three tables:




Company - Fields:

id

name


DocType - Fields:

id

name


Documents - Fields:

id

year

id_company - foreign key Company->id

id_doctype - foreign key DocType->id



The models, views and controllers were generated with the fullmodel and fullcrud options of gii with the gtc extension

The relations in the controllers are defined as follows:




Company

			'documents' => array(self::HAS_MANY, 'Documents', 'id_company'),

			'userCompanys' => array(self::HAS_MANY, 'UserCompany', 'id_company'),


DocType


			'documents' => array(self::HAS_MANY, 'Documents', 'id_doctype'),

Documents

			'idDoctype0' => array(self::BELONGS_TO, 'Doctype', 'id_doctype'),

			'idCompany0' => array(self::BELONGS_TO, 'Company', 'id_company'),



After i create some companies, documents and doctypes the documents appear in the company view with the year and a link to related document item.

The code in the Company view that shows the related documents thatresult from the foreign key is:




<ul><?php foreach($model->documents as $foreignobj) { 


				printf('<li>%s</li>', CHtml::link($foreignobj->year, array('documents/view', 'id' => $foreignobj->id)));

				} ?></ul>



I would like to change the view to show also the doctype name.

I tried using $foreignobj->id_company->name, $foreignobj->userCompanys->Name and $foreigobj->id_company[0]->name (the index 0 is just for testing) with no success.

What should i do ?

Thanks in advance

First of all try this




$foreignobj->idDocType0->name



/Tommy

You’re absolutely right.

That worked!!!

My mistake. Did not pay the necessary attention to what i was writing because the answer was already there.

Thanks a bunch!!!!!

Another related question:

I would like to change the output of the documents to something like a zii.widgets.grid.CGridView like in the admin view of gii generated code.

The thing is i’m trying to use the $model->documents but i get a uncatched exception like this:




Fatal error: Call to a member function getData() on a non-object in ... framework\zii\widgets\CBaseListView.php on line 105



Help anyone ??

Have a look att the search() method of your model, then add something like below. This will fetch primary and all the related data in one query (eager loading)




$criteria->with=array('documents', 'documents.idDoctype0');

$criteria->together = true;



/Tommy

Same problem.

However i managed to make it by changing the ‘dataProvider’ from $model->documents to new CArrayDataProvider($model->documents)

This solution was working fine until i found out i couldn’t sort the columns in the zii.widgets.grid.CGridView

Any ideas ?

I had a closer look at the error message you got. My answer was not relevant to this error

What it says is that the value you passed to the dataProvider property of CGridView is not an object. In Gii generated code for admin you’ll find a call to model->search(), which will return a CActiveDataProvider object. Please check what value you used for dataProvider when you received the error.

/Tommy

$model->documents

That would be an array of AR objects, not a CActiveDataProvider object. You may take a closer look at the search() method in the Gii-generated models. Add something like below to the search() method in the model file corresponding to $model above (probably Company.php)




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



The grid should now be able to display companies and iterate over related documents in a column partial view. (Edit: I haven’t tried yet but I expect it’s possible to avoid the nested iteration by using $criteria->join)

Another approach would be to add a company (belongs_to) relationship to the Document model and base the query on the Gii-generated admin code for Document.




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



(Access with company.name or $data->company->name depending on type of column definition)

There’s a lot of forum threads related to CActiveDataProvider and CGridView.

/Tommy

In your first sugestion what should be the value passed to dataprovider property of CGridView ?

No, you should still pass $model->search() to the grid.




public function search()

{

  ...

  $criteria=new CDbCriteria;

  $criteria->with = ...;

  //or (se added text in my previous post)

  $criteria->join = ...;

  ...

  return new CActiveDataProvider(

    get_class($this), 

    array('criteria'=>$criteria,)

  );

}



/Tommy

I’m not sure i understand what your saying.

The thing is i want the grid to contain only the documents obtained from the relation of the company model with the documents model. Don’t forget the model used in this view is obtained from the companies table that as relation defined with documents model (See first post).

So far you used lazy loading. I suggested eager loading (the with part). On second thought you should be able to access the related fields by lazy loading (e.g $data->documents[0]->year) but you’ll probably experience other problems (pagination/sorting). Don’t forget to pass $model->search() (or some other dataprovider instance) to the grid.

It’s getting late here but I’ll be back tomorrow. You may want to read more about relational AR in the guide.

/Tommy

Thanks for the tip.

After reading this i managed to find a solution.

What i did was:

In the Documents Model i created a new function:




        public function searchByCompanyId($id_company)

	{

		$criteria=new CDbCriteria;


		$criteria->compare('id_company',$id_company);


		return new CActiveDataProvider('Documents', array(

			'criteria'=>$criteria,

		));

	}



In the gridview of related documents in the changed it to look like this:




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

        'id'=>'documents-grid',

        'dataProvider'=>Documents::searchByCompanyId($model->id),

        'columns'=>array(

            array(

                'name'=>'year',

                'header'=>Yii::t('app','Year'),

            ),

            array(

                'name'=>'id_doctype',

                'value'=>'CHtml::value($data,\'idDoctype0.name\')',

                'header'=>Yii::t('app','Document Type'),

            ),

...



This way i have sorting in the grid view

Hope this helps someone else to.

Thanks guys.