magic AR functions proposal

I found that in my models I can have such the following:


public function setEmail_confirmed($value) {}

Then when I call $model->email_confirmed = value; it will actually nicely call the method setEmail_confirmed().  I like this a lot.  But I found that it will actually not do this if the email_confirmed attribute is actually also an attribute in the mysql table.

I propose that if the attribute is in the mysql table, it will both function as normal (put the key/value in _attributes) AND call the set<attribute> function.

The reason this would be useful in my case is that I would like my app to set a flag whenever I set email_confirmed to false.  This flag would be checked in afterSave, and if the flag is up, it will send the verification email to the user.

What do you think?

The fix should be as easy as removing line 401 from CActiveRecord.php in the SVN if i'm not mistaken…

Maybe you can use the other way around? Rename your setter to be "setEmailConfirmed"; Inside the setter you set 'email_confirmed'; Then in other application code, you set 'emailConfirmed' property instead of 'email_confirmed'.

Although your proposed change is easy, it may be unwanted in some cases. For example, CActiveRecord has setAttributes(), which would mean 'attributes' cannot be a table column with your proposed change, because otherwise it would cause trouble when you attempt to set 'attributes' column.

Ok, I see why that would not be optimal… I will probably use your solution then or another one I am thinking of…  Thanks

I've come across another scenario where this feature would be nice.

For instance, when the user password gets changed, it would be nice if it could set a flag so that it knows to hash the password in beforeSave() (otherwise you might be hashing it for a second time).  This would easily be possible if it called a corresponding getter/setter method even though it is in the DB.

I know I could still have a getter/setter but under a different name, but it's harder to extend your app that way as you have to go through all your controllers to perform some name changes.

So I thought about it some more and thought of a solution to get around the problem you stated:

What if it only calls the corresponding getter/setter if it is NOT already defined in CModel or CActiveRecord?  In other words give it the ability to differentiate core methods from application ones.  For instance:


if (!method_exists('CModel', 'set'.$attribute) && !method_exists('CActiveRecord', 'set'.$attribute))

then call setter method in model if it exists

And another solution would be to add a method to CActiveRecord called magicMethods() that returned a list of attributes that are in the DB but should also call magic setter/getter methods when changed.

And another solution even would be to have some sort of prefix or something to the magic methods that should be called even though they are attributes in the DB.  Possible examples:


public function setMagicPassword()

public function _setPassword()

public function magicSetPassword()

public function DBSetPassword()  //DB for database

Just a bunch of ideas.  What do you think?