Beforefind In Yii2

In Yii 1.x I used the following logic to override a query, filtering the information that the user would see:


 protected function beforeFind()

    {

        if (Yii::app()->user->getId()) {

            $criteria = new CDbCriteria();

            $criteria->condition = "user_id=:user_id";

            $criteria->params = array(':user_id' => Yii::app()->user->getId());

            $this->dbCriteria->mergeWith($criteria);

        }

        parent::beforeFind();

    }

The question is: How can I do the same thing using Yii 2.x ?

We need to make this function to our web system.

We make all in modulate and separate areas like: admin, site, module1, module2

For those modules we need to force a beforeFind query to make filters for some conditions to users logged in e etc.

Anyone?

Hi,

From here, slavcodev » 2013.05.06, 19:52

beforeFind - is not present and will not be.

Lifecycle of the model:

Creation:

  • constructor

  • init()

Search:

  • constructor

  • init() - original question was to change DB connection before find - it can be done here

  • afterFind()

In Yii 1.1, in cases as your I used scopes (defaultScope as well), in Yii2 scopes present. Define defaultScope for a model with same query as you did in beforeFind and it will be applied every time you call ActiveRecord. Read more here.

For the "afterFind()" method is a bad implementation, because this is executed after query executed and all model loaded.

For overwrite a new ActiveQuery for a default Scope, already will be added complex knowledge like someone that will not ever use "where()" method or for a "Scope", to not use before any "where()" condition, like:

"$model->find()->where()->active()->all()"

is really differente like:

"$model->find()->active()->where()->all()"

Where this last one will override the "active()" scope and will added another complexity to not ever call before a "where()" condition.

To set a default query we will need to make a lot of things, like a new ActiveQuery implementation or a base ActiveRecord that call another Base ActiveQuery to overwrite "createCommand()" and add a "beforeFind()" method to force the query to be added e etc. There are a lot of definitions can be added but none is a good thing.

For all this, wont be a good implementation that can be easy done by framework.

Now, the question is, what is better to do? Default Scope and never use method "where()" (complexity), add a Scope to be used but not use before a "where()" method (added complexity)? Create a new ActiveQuery to be used for all models and change the behavior that was did by framework?

André,

This is exactly my question:

  • Overwrite many classes does not seem a good idea. Looks like I’m doing the framework’s job.

  • Without overwriting the classes, which would be another approach?

Note: I still do not understand why "beforeFind" method was removed, his behavior was always helpful.

You are right, it produces two different queries with different results. But you are not limited to where(), use andWhere() instead.

Modelis::find()->active()->andWhere([‘user_id’=>1])->all(); // produces SELECT * FROM modelis WHERE (active=1) AND (user_id=1)

Modelis::find()->andWhere([‘user_id’=>1])->active()->all(); // produces SELECT * FROM modelis WHERE (user_id=1) AND (active=1)

Two different queries with the same result and the order in your SQL condition as you wish.

Use where() when you need to override default scope, or use andWhere() when you want to add condition to your default scope. Very flexible, IMHO.

Not sure, but it maybe duplicates init().

When you think just with a developer, is easy. Just tell "use Scope and andWhere() condition", forget "where()" unless you need this.

But when you are in a company that has more than 5 developer and this system can has more than that at a time, we’ll just say “dont use where() just andWhere() conditions” or always look for his codes to avoid this human error.

Resuming all, I think with the behaviors of Yii2 framework today we cant do what we want better.

The init() is called as a constructor class but only for a respective class without overwrite constructor, right? so, beforeFind() is just called before make query… If in Yii2 create a beforeQuery() method or something like this, will perfect make sense and resolve a lot of problems like ours ones.

We are thinkin to override all Models and ActiveQuery to just to put "beforeCommand()" or a "beforeQuery()" in a "createCommand()" method of db classes, this method will can puts any query before get the results.

This is not a good practice.

Yii2 documentation suggests that I extend the ActiveQuery to do this (using scopes).

Extending ActiveQuery not seem like a good idea since we would have to do the work of the framework.

I’m confused.

Look at my article here about before find / query :

Yii 2.0: Before Query Example : Soft Delete