ExtraPropertiesBehavior
The ExtraPropertiesBehavior helps key/value extension for an object.
Basic example
Given a product, ExtraPropertiesBehavior add key/value extension.
{% highlight xml %}
{% highlight php %} setName('My big TV'); $tvSet->setProperty('size', '12 inches'); $tvSet->setProperty('frequency', '11 Hz'); $tvSet->save();?>
$tvSet->getProperty(‘size’); // will result in ‘12 inches’ $tvSet->getProperty(‘frequency’); // will result in ‘frequency’ {% endhighlight %}
Installation
First clone the behavior in your vendor directory
{% endhighlight %} git clone git://github.com/Carpe-Hora/ExtraPropertiesBehavior.git {% endhighlight %}
then register behavior in your propel.ini or buid.properties configuration files :
{% highlight ini %} propel.behavior.extra_properties.class = path.to.ExtraPropertiesBehavior {% endhighlight %}
Usage
Just declare the behavior in your table definition :
{% highlight xml %}
At this point behavior will add an extra table to store properties and a set of methods in the active record object :
Common methods
- hasProperty(‘property_name’)
- countPropertiesByName(‘property_name’)
- initializeProperties()
- deletePropertiesByName(‘property_name’)
Single instance properties
- setProperty(‘property_name’, ‘value’)
- getProperty(‘property_name’, ‘default value’)
multiple instance properties
- addProperty(‘property_name’, ‘value’)
- getPropertiesByName(‘property_name’)
This is nice, but usualy, what a developper want is direct access through getters and setters. To do so, declare the extra property list using following :
- registerProperty
- registerMultipleProperty
property extraction methods
- getExtraProperties: returns an array of properties
Configuration
First declare the behavior in the schema.xml :
{% highlight xml %}
REXML could not parse this XML/HTML:
<database name="user">
<table name="user_preference">
<column name="id" type="INTEGER" primaryKey="true" autoincrement="true" />
<column name="key" type="VARCHAR" size="50" />
<column name="value" type="LONGVARCHAR" />
<column name="user_id" type="integer" required="true" />
<foreign-key foreignTable="user" onDelete="cascade" refPhpName="Preference">
<reference local="user_id" foreign="id" />
</foreign-key>
</table>
REXML could not parse this XML/HTML: </database>
{% endhighlight %}
To enable humanized getters, you can declare properties during your initilization boot or anywhere else…
{% highlight php %} registerExtraProperty('MY_MODULE_PREFERENCE', 'default_value'); } } {% endhighlight %}?>
Then, anywhere just access preferences as follow :
{% highlight php %} getMyModulePreference(); // or call $user->getProperty('my_module_preference'); $user->setMyModulePreference('preference'); // or call $user->setProperty('my_module_preference', 'preference');?>
// extend dynamicly $user->registerExtraProperty(‘MY_OTHER_PREFERENCE’, ‘default_value’); $user->getMyOtherPreference(); // or call $user->getProperty(‘my_other_preference’); $user->setMyOtherPreference(‘preference’); // or call $user->setProperty(‘my_other_preference’, ‘preference’);
// simply deal with multiple occurences $user->registerExtraProperty(‘MY_MULTIPLE_PREFERENCE’); $user->addMyMultiplePreference(‘pref1’); $user->addMyMultiplePreference(‘pref2’); $user->save();
// extract properties $user->getExtraProperties(); // will result in // array( // ‘MY_MODULE_PREFERENCE’ => ‘preference’, // ‘MY_OTHER_PREFERENCE’ => ‘preference’, // ‘MY_MULTIPLE_PREFERENCE’ => array(‘pref1’, ‘pref2’), // )
$user->getMyMultiplePreferences(); // will result in array(‘id_pref1’ => ‘pref1’, ‘id_pref2’ => ‘pref2’) $user->clearMyMultiplePreferences(); // remove all MY_MULTIPLE_PREFERENCE preferences $user->save(); {% endhighlight %}
Use with single inheritance
It sometimes is useful to be able to extend the model depending on the inheritance classkey. ExtraPropertiesBehavior can do that for you.
Imagine a CMS with several content types :
{% highlight xml %} <database name=”content”> <table name=”content”>
Given the default content structure, just define your contents by defining your possible key/values in the initializeProperties method:
{% highlight php %} registerExtraProperty('CONTENT'); $this->registerExtraProperty('AUTHOR'); }?>
public function getOMClass() { return ‘Article’; } } {% endhighlight %}
and
{% highlight php %} registerExtraProperty('URL'); $this->registerExtraProperty('LENGTH'); }?>
public function getOMClass() { return ‘Video’; } } {% endhighlight %}
Then, just use extra properties as if it where built in fields :
{% highlight php %} setTitle('Propel, greatest php ORM ever'); $article->setContent('Try it you\'ll see'); $article->save();?>
$video = new Video(); $video->setTitle(‘Propel + phpsh’); $video->setUrl(‘http://vimeo.com/15140218’); $video->setLength(‘2:01’); $video->save(); {% endhighlight %}
Todo
- implement default properties (generate methods and register in initialize)
- parameter to chose setters and getters name.
- add a calback to convert property value
- add namespace
