Quantcast
Channel: Live News for Yii Framework
Viewing all articles
Browse latest Browse all 3375

[Wiki] defaultScope

$
0
0

This example includes a composite condition as well as an empty condition (as if you bypass or disable defaultScope).

If you want to apply constant filter(s) to all your tables - even to related tables when using Relational Query - then currently (Yii 1.1.12) defaultScope() is more or less your best option.

First, create your own base model which will hold the defaultscope. Lets call it myBaseModel.

All your other models that should use defaultScope should extend from myBaseModel. (Note that we can temporarily skip defaultScope for these models if needed.)

Models that should never use defaultScope can still extend from CActiveRecord.

Your individual models that should be subjected to defaultScope():

class tbl1_model extends myBaseModel
{
    public $modelName           = __CLASS__;
    public $rstatus_fieldname   = 'tbl1_rstatus_nr';
    ...
}
 
class tbl2_model extends myBaseModel
{
    public $modelName           = __CLASS__;
    public $rstatus_fieldname   = 'tbl2_rstatus_nr';
    ...
}

Your individual models that should NOT be subjected to defaultScope():

class tbl32_model extends CActiveRecord
{
    ...
}

I added two variables to each model that extends myBaseModel. Both these variables are used by defaultScope(). $modelName is used to include the model's name as alias in the defaultScope's condition. $rstatus_fieldname is used to filter the records.

Record filtering: Each table has a field that indicates a record's status:

Record Status = 1 : record is inactive.

Record Status = 2 : record is active.

The defaultScope must be able to access these record status fields and that is why we store their names in $rstatus_fieldname. So this field's name in tbl1 is tbl1_rstatus_nr. In tbl2 it is called tbl2_rstatus_nr.

Obviously you could give these fields the same name in all tables, but my experience is that defaultScope then sometimes have trouble disambiguating the fields if you tunnel through tables via Relational Query. So I prefer disambiguating them in the db with tbl1_rstatus_nr, tbl2..., tbl3... etc.

Here is the base class with the defaultScope():

class myBaseModel extends CActiveRecord 
{
    public function defaultScope()
    {
        $condition = $this->testStatus();
 
        return array(
            'alias' => $this->modelName,
            'condition' => $condition,
        );      
 
    }
 
    public function testStatus()
    {
        /* Default condition: tblX_rstatus_nr = 0
           (return no records unless further tests in this function are
            successful)
           (0 is an invalid option, thus no records are returned) */
        $condition = $this->modelName . "." . $this->rstatus_fieldname . " = 0";
 
        /*  Bypass defaultScope().
            At the start of code sections in your controller where you
            do not want to apply defaultScope, do this: 
            Yii::app()->user->setState('skipDefaultScope', True);. 
            REMEMBER to unset(Yii::app()->user->skipDefaultScope) at
            the end of these sections, AND before any 'return'
            statement in these sections. */
        if(isset(Yii::app()->user->skipDefaultScope))
        {
            if(Yii::app()->user->skipDefaultScope === TRUE)
            {   //Return all records
                $condition = "";
            }
        }
 
        /*  If user is GUEST: 
            In some controllers, the user might not be login yet, so
            you can't use Yii::app()->user->skipDefaultScope.
            You therefor have to stipulate these conditions, under
            which defaultScope must not be applied and then simply
            return only active records. */
        elseif(Yii::app()->user->isGuest)
        {
            /* Test if the defaultScope should not be applied to
            the current controller.action.model combination */
            $controller =   Yii::app()->controller->id;
            $action     =   Yii::app()->controller->action->id;
            if(in_array($controller . '/' . $action . '/' . $this->modelName,
                array(
                    'site/login/tbl7_users',
                    'site/login/tbl8_user_roles',
                )
            ))
            {   //Return all active records.
                $condition = 
                $this->modelName . "." . $this->rstatus_fieldname . " = 2";
            }
        }
 
        /* Logged in Users. */
        else
        {
            if(user may view only active records)
            {   //Return all active records.
                $condition = 
                $this->modelName . "." . $this->rstatus_fieldname . " = 2";
            }
            elseif(user may view active and inactive records)
            {   //Return all active and inactive records.
                $condition = 
                $this->modelName . "." . $this->rstatus_fieldname . " > 0";
 
                /* You can also build a composite condition:
                $condition = $this->modelName . "." . $this->field1 . " <= 8"
                    . " AND " .
                    $this->modelName . "." . $this->field2 . " = " . $this->field3
                    . " AND " .
                    $this->modelName . "." . $this->field4 . " = 1";*/
            }
        }
        return $condition;
    }   
?>

Tip: defaultScope() only checks records read from the db. If you want similar control over records being written to db, then do something similar in beforeValidate() or beforeSave() and beforeDelete().


Viewing all articles
Browse latest Browse all 3375

Trending Articles