How is the Criteria from scopes() applied to the Criteria in search()

AR class’s definition is as follow:

<?php

/**

  • This is the model class for table "tb_entry".

  • The followings are the available columns in table ‘tb_entry’:

  • @property string $id

  • @property string $name

  • @property string $dir

*/

class Entry extends CActiveRecord

{

/**


 * Retrieves a list of models based on the current search/filter conditions.


 * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.


 */


public function search()


{


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


	// should not be searched.





	&#036;criteria=new CDbCriteria;





	&#036;criteria-&gt;compare('id',&#036;this-&gt;id,true);


	&#036;criteria-&gt;compare('name',&#036;this-&gt;name,true);





	return new CActiveDataProvider(get_class(&#036;this), array(


		'criteria'=&gt;&#036;criteria,


	));


}





public function scopes()


{


    return 'published'=&gt;array(


            'condition'=&gt;'status=1',


    );


}

}

when i use the ar class as follow:

Entry::model()->published()->search(), i will get the ‘status = 1’ applied to the CDbCriteria which is instanced by the search() method. Can somebody plz show me how this happened, in which class and which method? and are there and doc mentioned this?

Each AR class keeps an internal CDbCriteria object which is used to pile up the scope criterias. You can fetch it through YourAR::model()->getDbCriteria(). Each time you call a scope method, the scope criterias are merged into this internal critiera. When you perform any “find*()” method (which is what also happens inside a CActiveDataProvider), all conditions from this internal criteria are merged to your query. Note, that this criteria is kept on the model level. So it’s shared among all instances of this class, too.

You can reset this criteria with YourAr::model()->resetScopes().

code sample




	public function published()

    {

        $criteria = $this->getDbCriteria();

        $criteria->compare('published', 1);

        return $this;

    }



Edit.

if you are using




Entry::model()->published()->search()



then in publish method you need only to set class variable ex:




	public function published($publish = 1)

    {

    	$this->published = $publish;

        return $this;

    }



Thanks Mike, thanks for the clue, but i think you may make some mistake. I think the model() method of the CActiveRecord make all this happend.




	public static function model($className=__CLASS__)

	{

		if(isset(self::$_models[$className]))

			return self::$_models[$className];

		else

		{

			$model=self::$_models[$className]=new $className(null);

			$model->_md=new CActiveRecordMetaData($model);

			$model->attachBehaviors($model->behaviors());

			return $model;

		}

	}



When calling this method it will always return the same instance, so the scope() i call previously will be applied to the criteria instance which is created inside the search() method, cause they reference to the same model instance. You mention that the criteria is shared among all intance i think is not right.

I also try with this code




$instance = new Entry();

$instance->published();

$instance->search();



when i instance a new Entry, and call the scope(), this time the criteria will not be applied to the one created by the search() method.

Read carefully what i wrote above:

Hi,

This will also work as well when you utilise a scope




$instance = new Entry();

$instance->published()->search();



To see the published scope look here please: http://www.yiiframework.com/doc/guide/1.1/en/database.ar#named-scopes