Yii2: AR Default scope issue

Created on 11 Nov 2014  路  21Comments  路  Source: yiisoft/yii2

I have a class called UserClient

class UserClient
{
      public static function find()
      {
           $query = new UserClientQuery(get_called_class());
           return $query->byRoleCodeClient();
      }
}

class UserClientQuery
{
     public function byRoleCodeClient()
     {
        $this->andWhere(['role_code' => Role::CODE_CLIENT]);
        return $this;
     }
}

and when I try to do a query like this

DefaultScope not working

UserClient::find()->where(['username' => $username])->one()

DefaultScope working

UserClient::find()->one();
UserClient::find()->andWhere(['username' => $username])->one()

the where shouldn't cause issue when the class has defaultScope because my defaultScope is using andWhere and not where

Most helpful comment

Alternative is to create a separate model for admin panel where you need to see all statuses.

All 21 comments

Default scope is applied _before_ ->where(['username' => $username]) so it's expected that where overrides scope where condition.

isn't this a bug? I have a Class that is using SIngle table inheritance. my class is User UserClient UserAdmin

each class has a defaultScope for rode_code = admin and role_code = client

if the defaultScope is not working when we always do where() then defaultScope is kinda useless.. isn't it?

In yii 1, this kind of defaultScope is always working regardless of we use CdbCriteria() or findByPk() or findAll()

It is _default_ scope. That means it provides _default_ values, not values that are always applied. It was wrong in 1.1.

we are not doing a default values, but we are doing default query.. It look like the defaultScope is kinda useless now

using where() can be error prone when someone using where() and it override the default scope condition. I think this should be avoided in the framework itself if defaultScope is overrided by the where()

the most common code that everybody uses it is where() and not andWhere()

so If i use default scope then I need to replace all my code where() to andWhere or orWhere() and Ignore the where() method? it's sounds kinda not right I guess. It's lose the 1 method because of the default scope issue.

all I'm saying that if I have a class that uses default scope, and most of the time is using where() instead of andWhere, then this can be Error prone to most of the developer. because Yii 2 docs is always using where() and developer has kept in their mind to use where() than andWhere()

If you need "always apply" instead of "default", defaut scope is not the right tool for the job. Consider your own finder class that applies extra conditions right before the query instead.

it seems that the framework is lacking support for Single Table Inheritance. And I need to create a Finder class just to achieve a cleanliness of the code..

What do you suggest easier way that will not create a finder class. creating a finder class is more like a tricky way to achieve it.

There's no easier way if you want "always apply" type of scope regardless of conditions specified manually.

in Yii 1, we always have a parameter called resetScope whenever we want to reset it. here in Yii 2 we lose the beautiful feature of Default Scope. default scope is very useful when doing is_active = 1

I hope we can reconsider this feature. I don't think Yii 1 is wrong about default scope althrough it has some drawback.

defaultScope in 1.1 is a nightmare since there's no good way to override parts of it and project newcomers are thinking that no magic happens behind the scenes applying extra conditions.

At least name is totally confusing in 1.1 since it's not default, it's "always apply". It's better to be named stickyScope or something like that but we can't do the renaming because of backwards compatibiltiy.

In 2.0 there's quite clear way of achieving the same behavior. I'll adjust cookbook recipe about single table iheritance in order to show how to do it.

yes I agree that defaultScope can be nightmare sometimes, but if you are doing SingleTableInheritance, DefaultScope is powerful in this scenario..

Thanks @samdark , I'll appreciate your concern

I saw it.. cool. thanks

How would one now disable the condition from the default scope?
For example, I would like to do the following:

UserClient::find()->allRoles()->all();

The method allRoles() should just drop the condition that was set in byRoleCodeClient() and leave any other conditions that exist, but I am unsure how to do this.
Overriding the default scope with a where() is not an option, since you could have the following example:

UserClient::find()->andConditionA()->andConditionB()->allRoles()->all();

Here I wouldn't like to lose conditions A and B, but I would like to lose the default scope condition.

Sorry for resurrecting this old issue, but the example seemed just right for my problem.

It's better not to use default conditions which are not always default.

What would you suggest then would be the correct approach in solving the following problem.
I have several models that are soft-deletable and it's very convenient for me to use a default scope in which I filter out records that have been deleted. For most of the time I don't want to see them showing up in queries.

But administrators should be able to see the deleted records thus overriding the default condition.

Without a default scope I would have a lot of Model::find()->notDeleted() (or some equivalent). New team members could even possibly forget to call the notDeleted() and this would of course introduce a bug.

I'd introduce active() scope and watch out for newbies.

Alternative is to create a separate model for admin panel where you need to see all statuses.

So you are suggesting that I drop the default scope and go with Model::find()->active()?
What if you have a lot of these calls, wouldn't this be risking that you or someone else might forget calling active()

Great, I like the idea of an extra model, but I'm not sure if this would scale if you have a lot of models and they all have the soft-deletable behaviour.

That would scale well. Admin typically has more things which are different about the model for the same table.

Was this page helpful?
0 / 5 - 0 ratings