How to use a Yii fixture object that's not in the defaultScope? Is there a way of using resetScope() with Yii fixtures?

StackOverflow https://stackoverflow.com/questions/18610368

Question

Here's a test file:

class MyTest extends CDbTestCase 
{
    public $fixtures = array(
        'my_data'   => 'MyData',
    );

    public function testMyFunction()
    {
        $myObjectNotInDefaultScope = $this->my_data('out_of_scope_object');

        //Can't do anything with $myObjectNotInDefaultScope since it returns null
        // Is it possible to use resetScope?
        // I can always set a primary key for the object and use findByPk but that's a hack

    }
}

and here's the corresponding fixture:

<?php
return array(
    'out_of_scope_object' => array(
        'title' => 'This one is out of scope',
        'status' => 'archived', // so not in the default scope
    ),
    'in_scope_object' => array(
        'title' => 'This one is in scope',
        'status' => 'active',
    ),
);

Both rows in the fixture are added to the db table, so that's not the problem. I can access both rows via the primary keys that they're allocated. But I can't access the out of scope object in this way:

$myObjectNotInDefaultScope = $this->my_data('out_of_scope_object');

which when you're testing is really how you want to access it, I think.

I have a less than satisfactory solution in use for now of allocating the object a primary key value and using findByPk (edit: with resetScope()) to load the object. I would prefer to use the normal way of working with fixtures instead, if that's possible.

Edit: To clarify a little in response to some posts:

It is possible to use fixtures as a method to return an object. This would work:

$myObjectInDefaultScope = $this->my_data('in_scope_object');

but this wouldn't work BECAUSE it's not in the default scope and there's seemingly no way currently of running resetScope() for a fixture method call:

$myObjectNotInDefaultScope = $this->my_data('out_of_scope_object');

Why do I need to do this? Well, I might want to test my unarchive method, for example. Seems reasonable to me. (As mentioned before, I can get round this a little inelegantly by using a primary key to load the object corresponding to the fixture).

Although I can access the fixture data as an array using:

$arrayNotInDefaultScope = $this->my_data['out_of_scope_object'];

it's returning an array not an object, so I can't test the object's methods on an array.

Was it helpful?

Solution

To answer my own question, there is currently no way to use resetScope() with Yii fixtures (v 1.14). It could be implemented with some effort but given that Yii2 is on its way, it's probably not worth the effort of generating a pull request that may never make it in to the source.

For now, IMO, the cleanest workaround is:

1) Define a primary key in the fixture

2) Get the primary key from the fixture array and look up the object using it:

$arrayOutOfScopeObject = $this->my_data['out_of_scope_object'];
$myObjectNotInDefaultScope = MyObject::model()
             ->resetScope()
             ->findByPk($arrayOutOfScopeObject['id']);

You could, of course, save yourself the effort of looking up the pk from the fixture by hard-coding the pk value in your test code, but that leaves your test code vulnerable to being broken by changes to a fixture that's shared with other tests.

OTHER TIPS

You are using the fixtures as a method, whilst it is an array of object.

So instead of:

$myObjectNotInDefaultScope = $this->my_data('out_of_scope_object');

You should be doing:

$myObjectNotInDefaultScope = $this->my_data['out_of_scope_object'];

Check the guide for more info

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top