Yii 1.1: eactsasversioned

EActsAsVersioned provides versioning behavior for active record models

EActsAsVersioned provides versioning for ActiveRecord models.


This extension requires a column for versioning and one to reference the parent/original record. Each new version is a new record but they all share the same parent_id, which is the primary key value of the initial record. Below is an example table definition:

   $this->createTable('email', array(
            'id'            => 'int(11) NOT NULL AUTO_INCREMENT',
            'parent_id'     => 'int(11),
            'version'       => 'int(11) DEFAULT 1',
            'title'         => 'string NOT NULL',
            'body'          => 'string NOT NULL',
            'created_time'  => 'timestamp DEFAULT \'0000-00-00 00:00:00\'',

This extension is built/tested with Yii 1.1.6


To use this extension, just copy this file to your extensions/ directory, add 'import' => 'application.extensions.EActsAsVersioned', [...] to your config/main.php and add this behavior to each model you would like to inherit the new functionalities:

public function behaviors(){
      return array( 'EActsAsVersioned' => array(
            'class' => 'application.extensions.EActsAsVersioned'));

If you decide to use different column names you can define them as follows (Note that the values shown here are default!)

public function behaviors(){
      return array( 'EActsAsVersioned' => array(
            'class'              => 'application.extensions.EActsAsVersioned')
            'parentIdColumnName' => 'parent_id' ;
            'versionColumnName'  => 'version' ;

The examples below assume the versioning behavior is added to an Email model


Load all current models or just one:

$emails = Email::model()->getCurrent() ;   // all current models
$email  = Email::model()->getCurrent(10) ; // load current model with parent_id = 10

it returns an array of Emails or one Email object

getVersions( $criteria=array(), $params=null ) ;

This method is called on an Email instance and loads all related versions or a subset depending on the $criteria

$versionList = $email->getVersions() ; // returns an array with version numbers
/* output:
        [0] => 1
        [1] => 2
        [2] => 3
$emails = $email->getVersions(
    array(   // criteria
       'toModels'  => true,
       'condition' =>'created_time >:created'
    ),array( // params

With the toModels criteria set to TRUE the returned array contains Email objects instead of version numbers


Load a specific version:

$email = Email::model()->getCurrent(1)->getVersion(8) ;
$email = $email->getVersion(21) ;
$current = $email->getCurrent() ; // load current version of $email


If you plan to use the same instance multiple times to create different versions, like:

$email->title = 'barfoo' ;
$email->save() ;
$email->title = 'foobar' ;
$email->save(false) ;

without validation, it will not work. To fix this call reuse() before save(), like:

$email->reuse() ;
$email->save(false) ;

Other functionalities

$nextEmail = $someEmail->getNextVersion() ; // returns null if not exist
$prevEmail = $someEmail->getPreviousVersion() ; 
if ( $someEmail->isCurrent() ) { ... }

Total 6 comments

#4893 report it
jacmoe at 2011/08/25 06:04pm
Great extension

Thanks! Truly useful extension. Thumbs up!

#3142 report it
horizons at 2011/03/21 08:42am

i thought the Parent_id would be the autoincrement id of the version before and not the first version id.

#3085 report it
tronga at 2011/03/15 05:16am
Select all version

I don´t really understand what you mean: select * from email where parent_id = '1'; // with the id --> you get all versions from an email

select * from email where parent_id IS NOT NULL; --> you get all versions from all mails

select * from email; --> you get all mail including versions

Greetings Jan

#3084 report it
horizons at 2011/03/15 05:06am

I guess Parent_id would be not that good. Because if you have to select "all version" at once you would then have to select each parent id from each entry one by one.

#3081 report it
jeanluca at 2011/03/15 03:54am

good point, especially when considering relations! I'll implement this in the next release!

thanks a lot

#3078 report it
tronga at 2011/03/14 05:43pm

Great extension, this is very good for a manual version control. But I´d like to make a proposal.

Why don´t use a parent_id? With the auto_increment the "'PRIMARY KEY (id, version)'" is not necessary. The Extension with a id+version+parent_id would be much better imho. Espacially if you want to use it with other tables. (No foreign keys with id+version)

Example: Post -> id, parent_id, version

Comment -> id, post_id

Now the Comment table must have a primary key (id+version) which is now not really understandable.

Greetings tronga

Leave a comment

Please to leave your comment.

Create extension