Blog: Propel 1.6 Gets Versionable Behavior - With A Twist
Propel 1.6 ships with a great new behavior. Once enabled on a table, the versionable
behavior stores a copy of the ActiveRecord object in a separate table each time it is saved. This allows to keep track of the changes made on an object, whether to review modifications, or revert to a previous state.
The classic Wiki example is a good illustration:
<table name="wiki_page"> <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" /> <column name="title" type="VARCHAR" required="true" /> <column name="body" type="LONGVARCHAR" /> <behavior name="versionable" /> </table>
After rebuild, the WikiPage
model has versioning abilities:
$page = new WikiPage(); // automatic version increment $page->setTitle('Propel'); $page->setBody('Propel is a CRM built in PHP'); $page->save(); echo $page->getVersion(); // 1 $page->setBody('Propel is an ORM built in PHP5'); $page->save(); echo $page->getVersion(); // 2 // reverting to a previous version $page->toVersion(1); echo $page->getBody(); // 'Propel is a CRM built in PHP' // saving a previous version creates a new one $page->save(); echo $page->getVersion(); // 3 // checking differences between versions print_r($page->compareVersions(1, 2)); // array( // 'Body' => array( // 1 => 'Propel is a CRM built in PHP', // 2 => 'Propel is an ORM built in PHP5' // ), // ); // deleting an object also deletes all its versions $page->delete();
The versionable
behavior offers audit log functionality, so you can track who made a modification, when, and why:
$page = new WikiPage(); $page->setTitle('PEAR'); $page->setBody('PEAR is a framework and distribution system for reusable PHP components'); $page->setVersionCreatedBy('John Doe'); $page->setVersionComment('First draft'); $page->save(); // do more modifications... // list all modifications foreach ($page->getAllVersions() as $pageVersion) { echo sprintf("'%s', Version %d, updated by %s on %s (%s)\n", $pageVersion->getTitle(), $pageVersion->getVersion(), $pageVersion->getVersionCreatedBy(), $pageVersion->getVersionCreatedAt(), $pageVersion->getVersionComment(), ); } // 'PEAR', Version 1, updated by John Doe on 2010-12-21 22:53:02 (First draft) // 'PEAR', Version 2, updated by ...
If it was just for that, the versionable
behavior would already be awesome. Versioning is a very common feature, and there is no doubt that this behavior will replace lots of boilerplate code. Consider the fact that it’s very configurable, fully documented, and unit tested, and there is no reason to develop your own versioning layer.
But there is more.
The versionable
behavior also works on relationships.
If the WikiPage
has one Category
, and if the Category
model also uses the versionable
behavior, then each time a WikiPage
is saved, it saves the version of the related Category
it is related to, and it is able to restore it:
$category = new Category(); $category->setName('Libraries'); $page = new WikiPage(); $page->setTitle('PEAR'); $page->setBody('PEAR is a framework and distribution system for reusable PHP components'); $page->setCategory($category); $page->save(); // version 1 $page->setTitle('PEAR - PHP Extension and Application Repository'); $page->save(); // version 2 $category->setName('PHP Libraries'); $page->save(); // version 3 $page->toVersion(1); echo $page->getTitle(); // 'PEAR' echo $page->getCategory()->getName(); // 'Libraries' $page->toVersion(3); echo $page->getTitle(); // 'PEAR - PHP Extension and Application Repository' echo $page->getCategory()->getName(); // 'PHP Libraries'
Now the versioning is not limited to a single class anymore. You can even design a fully versionable "application" - it all depends on your imagination.
This feature is unique to Propel, and that’s our very Christmas gift to you.