Yii 2.0 ActiveRecord inverseOf

Yii 2.0 introduced a new feature to its ActiveRecord class, the inverse relation.  The documentation does a decent job at explaining its purpose – to prevent an unneeded SQL call from being executed and the instantiation of a new object, when in reality, the current object that is performing the lookup is the same object that would be found with that unneeded SQL call.  The optimization is much appreciated and in one project, this new relation has cut down on the SQL being executed and potential errors being introduced.

However, what the documentation does not make clear, as referenced in issue 7316, is that, in most cases, the inverse relation should only be defined for one side of the relationship.  For example, let’s take the documentation’s example of an order having exactly one customer, and customers having many orders.  In this example, the inverseOf should only be defined within the Customer class’ order relation.  This is because the order can only have one customer, so no SQL is required to determine what the correct customer will be.

What if we had an inverseOf relation defined in the opposite direction from the Order class’ customer relation?  The inverseOf relation would tell the customer class that this one order is the only order the customer has!  Obviously, not correct.

To determine if you should use the inverseOf relation, just ask yourself when writing the relation, does the other class have a ‘hasOne’ relation to this class?  If it does, you should be OK to use the inverseOf relation.

Read More

Yii 2.0 – Where did ActiveRecord Scopes go?

The Yii Framework team recently released their second major version, 2.0.  The version is still a little rough around the edges, but my first impression is that it is a solid replacement for their last major version, 1.1.

ActiveRecord has been given a facelift in 2.0, and one of the 1.1 features – scopes – isn’t mentioned until the very end of the ActiveRecord guide page.  While it was convenient to declare scopes in 1.1 to filter results down to the ones that matter to you at the moment, it also mixed much query logic inside the model.  The developers made the decision to require the use of a separate ActiveQuery class if you want to use a scope-style pattern.

In practice, there isn’t much new work here – just another class that you need to create and an override of your model’s find function.  Check out the pattern below, as detailed in the Yii documentation.

namespace app\models;

use yii\db\ActiveRecord;
use yii\db\ActiveQuery;

class Comment extends ActiveRecord
{
    public static function find()
    {
        return new CommentQuery(get_called_class());
    }
}

class CommentQuery extends ActiveQuery
{
    public function active($state = true)
    {
        return $this->andWhere(['active' => $state]);
    }
}

Read More