Saturday, January 22, 2011

Yii's Activerecord subclass model() method

I've recently gotten into the Yii PHP framework. It's a really great MVC framework that makes good use of OOP. Like many MVC frameworks out there, Yii has its own Activerecord implementation that works great for what I need it do: callbacks, relations, validation, named scopes etc. There is a bit of a quirk that I noticed with the version of Yii that I am currently using (yii-1.1.6.r2877). Yii comes with generator to generate the model class for the db table you want to hook into. Unfortunately the file that the generator creates is the same class where you would add your business logic. If you want regenerate your model class when you have schema, changes you wind up overwriting your business rules (unless you carefully diff the process). You could also use the generator to make a base class and then subclass off of that. Example: UserBase -> User.
Here is an example of how you would use this User subclass.
1. $record=new User;
2. $record=User::model()->findByPk((int)$id);

If you use example 1, all your custom methods in User along with rules, etc work just fine. However if you use example 2 what you get back from model() appears to be an instance of UserBase so you're losing the benefits of subclassing off of UserBase. Here's what I did to get around this issue. Add the following to your subclass.


/**
* @return object of current class instead of reverting to parent class
*/
public static function model($className=__CLASS__)
{
$model=new $className(null);
$model->_md=new CActiveRecordMetaData($model);
$model->attachBehaviors($model->behaviors());
return $model;
}


I'm using PHP version 5.2 on Windows. I don't know if this will addressed in future versions of Yii. The code in my method came from Yii's source so I can't even explain it in full detail at the moment. All I can say is that the rules and methods in my subclass work like they are supposed to. Please feel free to share any comments/concerns about this.