"With" declaration inside various scopes.

Hi,

dunno really how to name the topic so it’s informative enough.

I have A model that has relation HAS_MANY to B model.

A relations:


'b'=>array(self::HAS_MANY, 'B', 'a_id')

Now, B has several relations and some scopes that allow include that relations into model with options.

For example, B relations:




'c'=>array(self::HAS_MANY, 'C', 'b_id'),

'd'=>array(self::HAS_MANY, 'D', 'b_id'),

'e'=>array(self::HAS_MANY, 'E', 'b_id'),



Now i have scopes in B model:




public function c_or_d() {

    // some logic here

    $with = array('c'=>array('index'=>'id'));

    return $this->with($with);

}

public function e_with_options() {

    // even more logic

    $with = array('e'=>array('joinType'=>'INNER JOIN', 'index'=>'id'));

    return $this->with($with);

}



Now somewhere else i do:




A::model()->with(

    array(

        'b'=>array(

            'scopes'=>array('c_or_d', 'e_with_options')

        )

    )

)->findByPk($id);



Now, what happens is that only the LAST scope applies its "with". So in above case only "e_with_options" will apply the "with" criteria. If i swap them, the "c_or_d" will apply the "with".

That happens first time to me, i’ve tried A LOT of different options, no way to declare 2 with with scopes.

Is it meant to be like this?

Thank you.

I hope that this is not a bug. Unfortunately i can’t check it out. I tried to analyze Yii source code in CDbCriteria and in CActiveRecord and it seems to be right, but it doesn’t work as intended. Latter “with” replaces the one before, but should be merged.

http://www.yiiframework.com/doc/guide/1.1/en/database.ar#parameterized-named-scopes

Note how it’s shown about getting current criteria and merge options into it.

Check for CActiveRecord->with() code to see that it does exactly the same:

http://www.yiiframework.com/doc/api/1.1/CActiveRecord#with-detail

Also, i did try use same code as in the tutorial. I even tried to declare one “with” through scope and another one as direct “with” of relation. It doesn’t work.

Like this:




A::model()->with(

    array (

        'b'=>array(

            'scopes'=>'c_or_d',

            'with'=>'e'

        )

    )

)->findByPk($id);



Basically you cant declare any more “with” relations if at least one is declared (called) through a scope for same relation. I’m pretty sure there is an issue with scope merging the relation’s "with"s. Or i’m so blind that i missed something.

Update:

Just in case, i’ve tried to check again with code from tutorial. That’s how i have the scopes right now:




    public function c_or_d() {

        // some logic here

        $this->getDbCriteria()->mergeWith(

            array(

                'with'=>array(

                    'c'=>array('index'=>'id')

                )

            )

        );

        return $this;

    }


    public function e_with_options() {

        // even more logic

        $this->getDbCriteria()->mergeWith(

            array(

                'with'=>array(

                    'e'=>array('joinType'=>'INNER JOIN', 'index'=>'id')

                )

            )

        );

        return $this;

    }



I run same AR query:


$model = A::model()->with(

            array(

                'b'=>array(

                    'scopes'=>array('c_or_d', 'e_with_options')

                )

            )

        )->findByPk(1);

Only the last “with” is applied. First one doesn’t.

Ok, finally after some research, i’ve found where is the issue.

The 2 lines state:




if(isset($criteria['with']))

    $this->with=$criteria['with'];



which basically overwrites existing "with" criteria.

The proper way would be something like




if(isset($criteria['with']))

    if(isset($this->with))

        $this->with=CMap::mergeArray($this->with, $criteria['with']);

    else

        $this->with=$criteria['with'];



Don’t see any workaround for the moment without huge changes (that’s the Relation’s base class there).

Can you post all info into github issue?

Done.

Issue #586

Thank you for your patch!