widget and foreign key

in a widget :


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

	'dataProvider'=>$dataProvider,

	'columns'=>array(

		

		array(

			'name'=>'superuser',

'value'=>'User::itemAlias("AdminStatus",$data->superuser)',

		),





            array(

			'name'=>'subscription.subscriptionstart',                    'value'=>'Subscription::model()->findByPk($data->id)->subscriptionstart',

		),




	),

));

And a have a beautiful error : Trying to get property of non-object

But when a replace : ‘value’=>‘Subscription::model()->findByPk([color="#FF0000"]$data->id[/color])->subscriptionstart’,

by : ‘value’=>‘Subscription::model()->findByPk([color="#FF0000"]3[/color])->subscriptionstart’, for exemple, all is ok.

The problem seems to be when data->id asn’t a link to Subscription::model() (relation HAS_MANY)

How to solve it ?

Thanks

Hi there,

if $data is actually a Subscription Model (you are trying to initialize it by passing data->id to Subscription::model()->findByPk… then Why dont you just use subscriptionstart as the name of the Column?

IMHO is a bit strange that procedure…

Excuse me, i haven’t been enough accurate. :(

ths $data is on the Table User (extension : http://www.yiiframework.com/extension/yii-user/ )

In fact, it’s like this : User:id and Subscription:id_users foreign key on id table user.

To resume : I would like the subscription of a user …

Thanks a lot

  1. one way:

Then maybe we should look into the relations() of the model and set one to its subscription




public function relations(){

   return array( 'subscription'=>array(self::HAS_ONE, 'Subscription', 'id_user'));

}



Then when you create the CActiveDataProvider make sure you call the with(‘subscription’). Afterwards on your value=’$data->subscription->start_date’.

  1. another option:

Create a property on your model:




public function getSubscriptionDate(){

    return Subscription::model()->findByPk($this->id)->start_date;

}



After, on the column name just put: subscriptionDate. Should work.

Cheers

In user.php :


<?php


class User extends CActiveRecord

{


	/**

	 * @return array relational rules.

	 */

	public function relations()

	{

		$relations = array(

			'profile'=>array(self::HAS_ONE, 'Profile', 'user_id'),

                        'subscription'=>array(self::HAS_MANY, 'Subscription', 'id_users'),

		);

		if (isset(Yii::app()->getModule('user')->relations)) $relations = array_merge($relations,Yii::app()->getModule('user')->relations);

		return $relations;

	}

	




}

in Subcription.php :


<?php


/**

 * This is the model class for table "{{subscription}}".

 *

 * The followings are the available columns in table '{{subscription}}':

 * @property integer $id

 * @property integer $id_users

 * @property integer $subscriptionstart

 * @property integer $subscriptionend

 * @property string $amount

 *

 * The followings are the available model relations:

 * @property Users $idUsers0

 */

class Subscription extends CActiveRecord

{


	/**

	 * @return array relational rules.

	 */

	public function relations()

	{

		// NOTE: you may need to adjust the relation name and the related

		// class name for the relations automatically generated below.

		return array(

			'idUsers0' => array(self::BELONGS_TO, 'User', 'id_users'),

		);

	}


}

in AdminController.php (extension yii_user)


<?php


class AdminController extends Controller

{

	/**

	 * Manages all models.

	 */

	public function actionAdmin()

	{

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

                    'criteria'=>array(

                        'with'=>array('subscription'),

                        'together'=>true,

                        ),

			'pagination'=>array(

				'pageSize'=>Yii::app()->controller->module->user_page_size,

			),

                    //'pagination'=>array( 'pageSize'=>30),

		));


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

			'dataProvider'=>$dataProvider,

		));

	}

	

}

Now in index.php :


<?php

$this->breadcrumbs=array(

	UserModule::t('Users')=>array('admin'),

	UserModule::t('Manage'),

);

?>

<h1><?php echo UserModule::t("Manage Users"); ?></h1>


<?php echo $this->renderPartial('_menu', array(

		'list'=> array(

			CHtml::link(UserModule::t('Create User'),array('create')),

		),

	));

?>


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

	'dataProvider'=>$dataProvider,

	'columns'=>array(

		array(

			'name' => 'id',

			'type'=>'raw',

			'value' => 'CHtml::link(CHtml::encode($data->id),array("admin/update","id"=>$data->id))',

		),

		array(

			'name' => 'username',

			'type'=>'raw',

			'value' => 'CHtml::link(CHtml::encode($data->username),array("admin/view","id"=>$data->id))',

		),

		array(

			'name'=>'email',

			'type'=>'raw',

			'value'=>'CHtml::link(CHtml::encode($data->email), "mailto:".$data->email)',

		),

		array(

			'name' => 'createtime',

			'value' => 'date("d.m.Y H:i:s",$data->createtime)',

		),


		array(

			'name' => 'lastvisit',

			'value' => '(($data->lastvisit)?date("d.m.Y H:i:s",$data->lastvisit):UserModule::t("Not visited"))',

		),

		array(

			'name'=>'status',

			'value'=>'User::itemAlias("UserStatus",$data->status)',

		),

		array(

			'name'=>'superuser',

			'value'=>'User::itemAlias("AdminStatus",$data->superuser)',

		),


            array(

                'name' => 'subscription.subscriptionstart',

                'value' => '$data->subscription->subscriptionstart',

		),


		array(

			'class'=>'CButtonColumn',

		),

	),

));




?>

And i always have a problem :(

Really thanks a lot antonio to take time to help me.

Second Option :

User.php :


<?php


class User extends CActiveRecord

{


        public function getSubscriptionStart(){

            return Subscription::model()->findByPk($this->id)->subscriptionstart;

        }


}

in index.php :


<?php

$this->breadcrumbs=array(

	UserModule::t('Users')=>array('admin'),

	UserModule::t('Manage'),

);

?>

<h1><?php echo UserModule::t("Manage Users"); ?></h1>


<?php echo $this->renderPartial('_menu', array(

		'list'=> array(

			CHtml::link(UserModule::t('Create User'),array('create')),

		),

	));

?>


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

	'dataProvider'=>$dataProvider,

	'columns'=>array(

		array(

			'name' => 'id',

			'type'=>'raw',

			'value' => 'CHtml::link(CHtml::encode($data->id),array("admin/update","id"=>$data->id))',

		),




            array(

                'name' => 'SubscriptionStart',

                //'value' => 'SubscriptionStart',

	    	),


		array(

			'class'=>'CButtonColumn',

		),

	),

));


and the same error <img src='http://www.yiiframework.com/forum/public/style_emoticons/default/sad.gif' class='bbc_emoticon' alt=':(' />


?>



I progress :

Second solution :


<?php


class User extends CActiveRecord

{


        public function getSubscriptionStart(){

            return Subscription::model()->findByAttributes('id_users', $this->id)->subscriptionstart;

        }


}

$this->id return the id of the user. And id_users is the foreign key link with id of the table user.

Well, now a have the error : Invalid argument supplied for foreach()

I think that return a arry instead of a value…how to solve it ?

Please…thanks a lot

You made a mistake in findByAttributes (http://www.yiiframework.com/doc/api/1.1/CActiveRecord#findByAttributes-detail) attributes must be in array.

Well, finally i do this :


<?php


class User extends CActiveRecord

{


        public function getSubscriptionStart(){

            //return Subscription::model()->findByAttributes('id_users', $this->id)->subscriptionstart;


            $Mysubscriptionstart = Yii::app()->db->createCommand()

            ->select('subscriptionstart')

            ->from('tbl_subscription')

            ->where('id_users = '.$this->id);

            //->queryRow();

            return date("d.m.Y H:i:s",$Mysubscriptionstart->queryScalar());


      

        }


}

and in index :


<?php

$this->breadcrumbs=array(

	UserModule::t('Users')=>array('admin'),

	UserModule::t('Manage'),

);

?>

<h1><?php echo UserModule::t("Manage Users"); ?></h1>


<?php echo $this->renderPartial('_menu', array(

		'list'=> array(

			CHtml::link(UserModule::t('Create User'),array('create')),

		),

	));

?>


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

	'dataProvider'=>$dataProvider,

	'columns'=>array(


            array(

                'name' => 'subscriptionStart',

                //'value' => '$data->subscription->subscriptionStart',

	    	),

		array(

			'class'=>'CButtonColumn',

		),

	),

));




?>



ok, the result is good…but, getSubscriptionStart() is call for each row, so before i had 7 request and now 14 …so i don’t agree with this solution …

Any idea ?

Thanks a lot antonio

You are right, I think the best is to achieve solution one where you actually get working the first solution. I still wondering why isn’t allowing you to access your subscription object. Are the relations ok? Have you tried , on the first option, build a CActiveDataProvider from that settings and try to reach subscription afterwards -just testing, do not display the CDGridview. Test it and lets see.





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

                    'criteria'=>array(

                        'with'=>array('subscription'),

                        'together'=>true,

                        ),

                        'pagination'=>array(

                                'pageSize'=>Yii::app()->controller->module->user_page_size,

                        ),

                    //'pagination'=>array( 'pageSize'=>30),

                ));


echo $dataProvider->subscription->subscriptionstart;




I tested and it’s not working but if a try this :


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

                    'criteria'=>array(

                        'with'=>array('subscription'),

                        'together'=>true,

                        ),

                        'pagination'=>array(

                                'pageSize'=>Yii::app()->controller->module->user_page_size,

                        ),

                    //'pagination'=>array( 'pageSize'=>30),

                ));


echo $dataProvider->status;



it’s not working too ! echo $dataProvider->etcetc seems to be not testable here :(

Really thanks to try to help me…( I can send you the project but it’s normal if you don’t have time to look at it…)

in trace i have this :


 CDbSchema->_tableNames: { }

        CDbSchema->_tables:         

          {{users}}: CMysqlTableSchema ID:#13

            schemaName: null

            name: 'tbl_users'

            rawName: '`tbl_users`'

            primaryKey: 'id'

            sequenceName: ''

            foreignKeys: { }

            columns:             

              id: CMysqlColumnSchema ID:#14

                name: 'id'

                rawName: '`id`'

                allowNull: false

                dbType: 'int(11)'

                type: 'integer'

                defaultValue: null

                size: 11

                precision: 11

                scale: null

                isPrimaryKey: true

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

              username: CMysqlColumnSchema ID:#15

                name: 'username'

                rawName: '`username`'

                allowNull: false

                dbType: 'varchar(20)'

                type: 'string'

                defaultValue: null

                size: 20

                precision: 20

                scale: null

                isPrimaryKey: false

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

              password: CMysqlColumnSchema ID:#16

                name: 'password'

                rawName: '`password`'

                allowNull: false

                dbType: 'varchar(128)'

                type: 'string'

                defaultValue: null

                size: 128

                precision: 128

                scale: null

                isPrimaryKey: false

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

              email: CMysqlColumnSchema ID:#17

                name: 'email'

                rawName: '`email`'

                allowNull: false

                dbType: 'varchar(128)'

                type: 'string'

                defaultValue: null

                size: 128

                precision: 128

                scale: null

                isPrimaryKey: false

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

              activkey: CMysqlColumnSchema ID:#18

                name: 'activkey'

                rawName: '`activkey`'

                allowNull: false

                dbType: 'varchar(128)'

                type: 'string'

                defaultValue: ''

                size: 128

                precision: 128

                scale: null

                isPrimaryKey: false

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

              createtime: CMysqlColumnSchema ID:#19

                name: 'createtime'

                rawName: '`createtime`'

                allowNull: false

                dbType: 'int(10)'

                type: 'integer'

                defaultValue: 0

                size: 10

                precision: 10

                scale: null

                isPrimaryKey: false

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

              lastvisit: CMysqlColumnSchema ID:#20

                name: 'lastvisit'

                rawName: '`lastvisit`'

                allowNull: false

                dbType: 'int(10)'

                type: 'integer'

                defaultValue: 0

                size: 10

                precision: 10

                scale: null

                isPrimaryKey: false

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

              superuser: CMysqlColumnSchema ID:#21

                name: 'superuser'

                rawName: '`superuser`'

                allowNull: false

                dbType: 'int(1)'

                type: 'integer'

                defaultValue: 0

                size: 1

                precision: 1

                scale: null

                isPrimaryKey: false

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

              status: CMysqlColumnSchema ID:#22

                name: 'status'

                rawName: '`status`'

                allowNull: false

                dbType: 'int(1)'

                type: 'integer'

                defaultValue: 0

                size: 1

                precision: 1

                scale: null

                isPrimaryKey: false

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

            CComponent->_e: null

            CComponent->_m: null

          )

          {{subscription}}: CMysqlTableSchema ID:#23

            schemaName: null

            name: 'tbl_subscription'

            rawName: '`tbl_subscription`'

            primaryKey: 'id'

            sequenceName: ''

            foreignKeys:             

              id_users:               

                0: 'tbl_users'

                1: 'id'

            columns:             

              id: CMysqlColumnSchema ID:#24

                name: 'id'

                rawName: '`id`'

                allowNull: false

                dbType: 'int(11)'

                type: 'integer'

                defaultValue: null

                size: 11

                precision: 11

                scale: null

                isPrimaryKey: true

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

              id_users: CMysqlColumnSchema ID:#25

                name: 'id_users'

                rawName: '`id_users`'

                allowNull: false

                dbType: 'int(11)'

                type: 'integer'

                defaultValue: null

                size: 11

                precision: 11

                scale: null

                isPrimaryKey: false

                isForeignKey: true

                CComponent->_e: null

                CComponent->_m: null

              )

              subscriptionstart: CMysqlColumnSchema ID:#26

                name: 'subscriptionstart'

                rawName: '`subscriptionstart`'

                allowNull: false

                dbType: 'int(10)'

                type: 'integer'

                defaultValue: null

                size: 10

                precision: 10

                scale: null

                isPrimaryKey: false

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

              subscriptionend: CMysqlColumnSchema ID:#27

                name: 'subscriptionend'

                rawName: '`subscriptionend`'

                allowNull: false

                dbType: 'int(10)'

                type: 'integer'

                defaultValue: null

                size: 10

                precision: 10

                scale: null

                isPrimaryKey: false

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

              amount: CMysqlColumnSchema ID:#28

                name: 'amount'

                rawName: '`amount`'

                allowNull: false

                dbType: 'decimal(5,2)'

                type: 'string'

                defaultValue: null

                size: 5

                precision: 5

                scale: 2

                isPrimaryKey: false

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

              activ: CMysqlColumnSchema ID:#29

                name: 'activ'

                rawName: '`activ`'

                allowNull: true

                dbType: 'tinyint(1)'

                type: 'integer'

                defaultValue: null

                size: 1

                precision: 1

                scale: null

                isPrimaryKey: false

                isForeignKey: false

                CComponent->_e: null

                CComponent->_m: null

              )

            CComponent->_e: null

            CComponent->_m: null

          )

        CDbSchema->_connection: CDbConnection#10(...)

        CDbSchema->_builder: CDbCommandBuilder ID:#30

          CDbCommandBuilder->_schema: CMysqlSchema#12(...)

          CDbCommandBuilder->_connection: CDbConnection#10(...)

          CComponent->_e: null

          CComponent->_m: null

        )

        CDbSchema->_cacheExclude: { }

Email me (check my profile) the two objects (User and Subscription) together with their correspondent tables. I will check it.

I sent you an email.

Really thanks

Found your problem, here the solution for others to see:

On the user module





public function relations()

    {

        $relations = array(

             'profile'=>array(self::HAS_ONE, 'Profile', 'user_id'),

             'subscription'=>array(self::HAS_ONE, 'Subscription', 'id_users'), // changed this

        );

        if (isset(Yii::app()->getModule('user')->relations)) $relations = array_merge($relations,Yii::app()->getModule('user')->relations);

        return $relations;

    }



The other one is in your AdminController:




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

            'criteria'=>array(

                'with'=>array('subscription'=>array('select'=>'{{subscription}}.subscriptionstart','joinType'=>'INNER JOIN')),

            )

        ));



Now you can put pagination or whatever you wish.

Cheers

Thanks a lot to antonio . you help me a lot.

I will post the final code, but i have a last problem : The lEFT_JOIN condition :

Explanation :


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

                    'criteria'=>array(

                        'with'=>array('subscription'=>array('select'=>'{{subscription}}.*','joinType'=>'LEFT OUTER JOIN',

                                ),

                            ),

                        'together'=>true,

                        ),

                       // 'addcondition'=>'activ=1',

			'pagination'=>array(

				'pageSize'=>Yii::app()->controller->module->user_page_size,

			),

                        //'TotalItemCount'=>'8',

                        


                    //'pagination'=>array( 'pageSize'=>30),

		));

With this data provider, i have a classic left join with a little problem…only one row by user…but it’s not the problem.

A would like all the user and only the subscription of the user where subscription.activ=1

So, if I do this :


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

                    'criteria'=>array(

                        'with'=>array('subscription'=>array('select'=>'{{subscription}}.*','joinType'=>'LEFT OUTER JOIN',

                             'condition'=>'activ=1',   ),

                            ),

                        

                        'together'=>true,

                        ),

                       // 'addcondition'=>'activ=1',

			'pagination'=>array(

				'pageSize'=>Yii::app()->controller->module->user_page_size,

			),

                        //'TotalItemCount'=>'8',

                        


                    //'pagination'=>array( 'pageSize'=>30),

		));

The sql generated is :


SELECT `t`.`id` AS `t0_c0`, `t`.`username` AS `t0_c1`, `t`.`email` AS `t0_c3`, `t`.`createtime` AS `t0_c5`, `t`.`lastvisit` AS `t0_c6`, `t`.`superuser` AS `t0_c7`, `t`.`status` AS `t0_c8`, `subscription`.`id` AS `t1_c0`, `subscription`.`id_users` AS `t1_c1`, `subscription`.`subscriptionstart` AS `t1_c2`, `subscription`.`subscriptionend` AS `t1_c3`, `subscription`.`amount` AS `t1_c4`, `subscription`.`activ` AS `t1_c5`, `subscription`.`id` AS `t1_c0` FROM `tbl_users` `t` LEFT OUTER JOIN `tbl_subscription` `subscription` ON (`subscription`.`id_users`=`t`.`id`) WHERE (activ=1) LIMIT 10

It do the same thing as an inner join, to solve it, i must do


SELECT `t`.`id` AS `t0_c0`, `t`.`username` AS `t0_c1`, `t`.`email` AS `t0_c3`, `t`.`createtime` AS `t0_c5`, `t`.`lastvisit` AS `t0_c6`, `t`.`superuser` AS `t0_c7`, `t`.`status` AS `t0_c8`, `subscription`.`id` AS `t1_c0`, `subscription`.`id_users` AS `t1_c1`, `subscription`.`subscriptionstart` AS `t1_c2`, `subscription`.`subscriptionend` AS `t1_c3`, `subscription`.`amount` AS `t1_c4`, `subscription`.`activ` AS `t1_c5`, `subscription`.`id` AS `t1_c0` FROM `tbl_users` `t` LEFT OUTER JOIN `tbl_subscription` `subscription` ON (`subscription`.`id_users`=`t`.`id`) [color="#FF0000"]AND[/color] (activ=1) LIMIT 10

So, how to add just the caractere string ‘AND activ=1’ to the end of the CActiveDataProvider ?

Thanks ::)

I believe the only thing you need to do is add this:

‘condition’=>’{{subscription}}.activ=1’

no, it generate this :

SELECT t.id AS t0_c0, t.username AS t0_c1, t.email AS t0_c3, t.createtime AS t0_c5, t.lastvisit AS t0_c6, t.superuser AS t0_c7, t.status AS t0_c8, subscription.id AS t1_c0, subscription.id_users AS t1_c1, subscription.subscriptionstart AS t1_c2, subscription.subscriptionend AS t1_c3, subscription.amount AS t1_c4, subscription.activ AS t1_c5, subscription.id AS t1_c0 FROM tbl_users t LEFT OUTER JOIN tbl_subscription subscription ON (subscription.id_users=t.id) [color="#FF0000"]WHERE[/color] (activ=1) LIMIT 10

and i would like :

SELECT t.id AS t0_c0, t.username AS t0_c1, t.email AS t0_c3, t.createtime AS t0_c5, t.lastvisit AS t0_c6, t.superuser AS t0_c7, t.status AS t0_c8, subscription.id AS t1_c0, subscription.id_users AS t1_c1, subscription.subscriptionstart AS t1_c2, subscription.subscriptionend AS t1_c3, subscription.amount AS t1_c4, subscription.activ AS t1_c5, subscription.id AS t1_c0 FROM tbl_users t LEFT OUTER JOIN tbl_subscription subscription ON (subscription.id_users=t.id) [color="#FF0000"]AND[/color] (activ=1) LIMIT 10

Then create a named scope on your subscription model and call one to active (http://www.yiiframework.com/doc/guide/1.1/en/database.ar#named-scopes) when you use with, do with ‘subscription:active’ http://www.yiiframework.com/doc/guide/1.1/en/database.arr#relational-query-with-named-scopes

That’s it !!!

One last, and it will be perfect, how to sort the column of the subscription model like the user model on the grid ?

Thanks a lot