'with' is not applied when using a scope

Hi,

I tried to define a scope with a relation, like this:


    public function scopes()

    {

        return array(

            'localized'=>array(

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

                'condition' => 'PiiInfo.language = "'.Yii::app()->language.'" or PiiInfo.language IS NULL',

            ),

            'active'=>array(

                'with' => 'PiiInfo',

                'condition' => 

                    '(PiiInfo.status = '.PiiInfo::STATUS_ACTIVE.' OR PiiInfo.status = '.PiiInfo::STATUS_LOCKED.')',

            ),

        );

    }



  • Tried with an array and a string

But when I execute this:




$models = PiiPage::model()->active()->localized()->findAll($criteria);



I just get this error:


CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'PiiInfo.status' in 'where clause'

When I query with ‘with’:


$models = PiiPage::model()->active()->localized()->with('PiiInfo')->findAll($criteria);

Everything works fine. So why can’t I apply the relation within the scope?

A feature, a bug, a bug in front of the computer?

Testing on:

Yii 1.1.0

PHP 5.3 Mac OS X

Best regards,

schmunk

I noticed that as well some time ago and thought it was already fixed in svn (was obviously looking at an unrelated issue ticket).

I think it’s a bug.

I think the reason is that with(‘something’) returns a CActiveFinder instance (puts actual relational query into the query string), were a scope only merges the options like condition, limit or with. So with scopes only, it’s obviously impossible to do eager loading.


	public function __call($name,$parameters)

	{

		...


		$scopes=$this->scopes();

		if(isset($scopes[$name]))

		{

			$this->getDbCriteria()->mergeWith($scopes[$name]);

			return $this;

		}


		...

	}


	public function with()

	{

		if(func_num_args()>0)

		{

			$with=func_get_args();

			if(is_array($with[0]))  // the parameter is given as an array

				$with=$with[0];

			return new CActiveFinder($this,$with);

		}

		else

			return $this;

	}

Maybe it’s possible to modify __call function to check for with option?

Hi Y!!,

thanks for your insight.

I had a talk with mike today and he said, that the main problem is that there could be multiple aliases for the same table and that this would result in performance loss or broken SQL queries … as far as I an understand this issue, I am not that deep into SQL.

Best regards,

schmunk

Hmm I see, thanks for info. Maybe some core dev can look into this (again), if it’s really not possible okay, but if it’s possible in some way I would like to see this in the future. Or at least let us know how to do it if you think it can not find the way into core due to possible problems. :)

Thanks. I just fixed this bug. Could you please help verify it?

Only works partially for me. If I try it with defaultScope() it works, if try it with scopes() it fails.

My relations(), defaultScope() and scopes():




public function relations()

{

   return array(

      'slug' => array(self::HAS_ONE, 'UserSlug', 'userId'),

   );

}




public function defaultScope()

{

   return array(

      'condition' => "slug.text = 'test'",

      'with' => 'slug',

   );

}


public function scopes()

{

   return array(

      'test' => array(

         'condition' => "slug.text = 'test'",

         'with' => 'slug',

      ),

   );

)




So to summarize, this works and creates a correct join query:


User::model()->findAll();

This fails (with defaultScope() removed):


User::model()->test()->findAll();

It returns the error:

and generates the db query:

Hi Qiang,

does currently not work for me.

Quick Answer …

Works:


$models = PiiHtml::model()->localized()->checkAccess()->with('PiiInfo')->findAll($criteria);


Querying SQL: SELECT `t`.`id` AS `t0_c0`, `t`.`name` AS `t0_c1`, `t`.`html`

AS `t0_c2`, `t`.`piiInfoId` AS `t0_c3`, `PiiInfo`.`id` AS `t1_c0`,

`PiiInfo`.`model` AS `t1_c1`, `PiiInfo`.`modelId` AS `t1_c2`,

`PiiInfo`.`language` AS `t1_c3`, `PiiInfo`.`status` AS `t1_c4`,

`PiiInfo`.`type` AS `t1_c5`, `PiiInfo`.`checkAccess` AS `t1_c6`,

`PiiInfo`.`createdBy` AS `t1_c7`, `PiiInfo`.`createdAt` AS `t1_c8`,

`PiiInfo`.`modifiedBy` AS `t1_c9`, `PiiInfo`.`modifiedAt` AS `t1_c10`,

`PiiInfo`.`begin` AS `t1_c11`, `PiiInfo`.`end` AS `t1_c12`,

`PiiInfo`.`keywords` AS `t1_c13`, `PiiInfo`.`customData` AS `t1_c14`,

`PiiInfo`.`parentId` AS `t1_c15` FROM `PiiHtml` `t`  LEFT OUTER JOIN

`PiiInfo` `PiiInfo` ON (`PiiInfo`.`modelId`=`t`.`id`) WHERE

(((PiiInfo.language = "de_de" or PiiInfo.language IS NULL) AND

(PiiInfo.checkAccess IS NULL )) AND (begin < NOW() AND type = 'blog')) AND

(PiiInfo.model = "PiiHtml") ORDER BY begin DESC LIMIT 2



Not:


$models = PiiHtml::model()->localized()->checkAccess()->findAll($criteria);


system.db.CDbCommand

Querying SQL: SELECT * FROM `PiiHtml` `t` WHERE ((PiiInfo.language =

"de_de" or PiiInfo.language IS NULL) AND (PiiInfo.checkAccess IS NULL ))

AND (begin < NOW() AND type = 'blog') ORDER BY begin DESC LIMIT 2

21:24:41.42943

error

system.db.CDbCommand

Error in querying SQL: SELECT * FROM `PiiHtml` `t` WHERE ((PiiInfo.language

= "de_de" or PiiInfo.language IS NULL) AND (PiiInfo.checkAccess IS NULL ))

AND (begin < NOW() AND type = 'blog') ORDER BY begin DESC LIMIT 2

No Exception in browser … updated to r1796

Best regards,

schmunk

Could you please try again with r1797?

Works like a charm! Thanks.

Superquick bugfixing like in good old Prado-times :lol:

btw: This is my scope definition:


        return array(

            'localized'=>array(

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

                'condition' => 'PiiInfo.language = "'.Yii::app()->language.'" or PiiInfo.language IS NULL',

            ),

            'checkAccess'=>array(

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

                'condition' => 'PiiInfo.checkAccess IS NULL '.$checkAccess,

            ),

        );



Works indeed, but only when passing an array to the with option - is this expected?

Anyhow, thanks for the quick fix qiang! :)

Yes, an array is required, as stated by the API doc of CDbCriteria::with.

Alright thanks. Was just wondering cause it worked before the fix without array.

does it work with ver. 1.0.x?

Hmmm, I don’t think so, because the latest 1.0 release is from December.

It won’t work even with the latest stable 1.1, this is from January.

http://www.yiiframework.com/download/

Pick the nighty (I haven’t tested it)

http://www.yiiframework.com/files/yii-1.1-dev.tar.gz

Or get it from svn, I have no problems on the trunk so far.

And I am also waiting for 1.1.1 …

Best regards,

schmunk

thanks for help…

I have one more question…

does it work with MANY:MANY relations?

I see no reason why it shouldn’t work. With is just a property of a criteria, just try it ;)

I am asking while I’ve tried it…

and it does not work… I’ve tested it with revision 1855.

Many-Many still dont work in scopes for me. This my code:





'published'=>array(

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

                'condition'=>'t.status = 1 AND source.id = 1',

 ),




I m using 1.1.2 (May 2, 2010)

… maybe i’m doin somethingh wrong?

Confirm. It works with HAS_ONE relation, doesn’t with HAS_MANY and MANY MANY :frowning: