I want my AR to have automatically generated properties.
I'll draw an example. Imagine we have an AR 'User'. User has properties 'firstName' and 'lastName'. In some cases (not always) I want my User instance to have third attribute 'fullName' that would be a concatenation of 'firstName' and 'lastName'.
<?php
class User extends arbase
{
...
public function getFullName()
{
if(this is an inappropriate case)
return null;
return $this->firstName.' '.$this->lastName;
}
...
}
echo $user->fullName;
Note that if you want not only read but write fullName, you have to set up a setter method as well.
<?php
public function setFullName($full)
{
if(inappropriate case)
return;
list($this->firstName, $this->lastName) = explode(' ', $full);
}
$user->fullName='Bill Gates'; // both first and last name are in place by now.
But this way doesn't fit into my application structure.
I thought about using scopes. I tried something like this:
<?php
class User extends CActiveRecord
{
public function scopes()
{
return array(
'witFullName'=>array(
'select'=>'concat(firstName, " ", lastName) as fullName',
),
);
}
}
The main reason why I don't want to use getters is that I want to be able to throw a list of users over RemoteObject interface into flex frontend. I.e. I want to be able to do something like:
Why not? I haven’t used Flex so far, but to external usage, it’d make no difference whether it calls model->firstName or fullName, as both are handled via getter magic method.
My extension (Pogostick Yii Extensions) adds this capability. Extend my CPSComponent and use the addOption() method to add propertiexs. They can then be retrieved like obj->propName.
The object comes into flex in serialized way. In flex it appears as a Flex Object similar to JavaScript dictionary: {'firstName':'Angelina', 'lastName':'Jolie'}. Object methods are not available.
Only standard attributes are available. It is so because they are in $user->attributes dictionary i guess. So since my new attribute exists only as getter method it will not be available in flex.
I already thought about using afterFind. It's not that good either. AfterFind triggers every time find() is called. I need my new attributes to appear only in some case (e.g. upon transfer into flex). Of course I can try to limit afterFind() functionality by If statement. But it's really ugly.
My extension (Pogostick Yii Extensions) adds this capability. Extend my CPSComponent and use the addOption() method to add propertiexs. They can then be retrieved like obj->propName.
I looked at your extension. It looks solid. But I think it's not efficient to use yet another framework just to add some minor functionality…
I guess I went in wrong direction. I solved my problem. Though not as beautiful as it could be. But it's efficient. I've made a class with static functions
<?php
class MyLib {
public static function userForComboBox($user)
{
return array('label'=>$user->firstName.' '.$user->lastName, 'data'=>$user->id);
}
}
Then I just call array_map() over my list of users: