-
Notifications
You must be signed in to change notification settings - Fork 35
DevGuide PerlObjectsRevisionable
Revisionable objects are objects that Melody will automatically track previous versions of that object for you. The class is primarily used for entries and templates, but could conceivable be used to track previous versions of any object, including custom objects a developer might create, which is why we are providing this documentation.
Furthermore, Melody's revision framework is customizable so that you can control, through the creation of custom drivers, how and where revisions are stored. For example, by default Melody stores revisions in the database, but someone might want revisions tracked through a source code control system like subversion or git. While, Melody does not yet support those revisioning systems, a developer could if they wanted to.
Let's get started.
To be versioned, an MT::Object subclass must first inherit MT::Revisable:
package MT::Foo;
use base qw( MT::Object MT::Revisable );
When a revision is saved, the entire object is taken and serialized. However, in order to curb bloat, the saving of a revision is only triggered when a designated column has changed. To flag a column as one to trigger a revision to be saved, simply add the keyword revisioned
to the column definition like so:
__PACKAGE__->install_properties({
column_defs => {
some_string => 'string(255) not null revisioned'
}
});
If at least one versioned column is changed then a copy of the entire object is saved so that one can easily revert back to it later.
Classes that inherit from MT::Revisionable
automatically inherit the following methods or subroutines:
-
$class->revision_pkg
Returned byMT->model($class->datasource . ':revision')
- the namespace of the class that stores revisions for the class. -
$class->revision_props
- Returns a hashref of the install properties for therevision_pkg
-
$class->init_revisioning
- Called by the baseMT::Object
class to initialize the revisioning framework for the particular class. This may involve creating therevision_pkg
. -
$class->revisioned_columns
- Returns an arrayref of column names that are marked as being revisioned. -
$class->is_revisioned_column($col)
- Checks whether the passed column name has been marked as being revisioned. -
$obj->gather_changed_cols($orig, $app)
- Compares the revisioned columns of$orig
with$obj
and stores an arrayref of changed columns in$obj->{changed_revisioned_columns}
-
$obj->pack_revision()
- Creates the hashref that will be stored as a particular revision of the object. By default, this hashref contains the values of the object's normal and meta columns. The<package>::pack_revision
callback can be used to add further values to be stored with the revision. -
$obj->unpack_revision($packed_obj)
- The opposite ofpack_revision
, takes the$packed_obj
hashref and unpacks it, setting the values of$obj
as needed. The<package>::unpack_revision
callback can be used for any other keys added to$packged_obj
that are not part of the normal or meta columns. -
$obj->save_revision()
- Called automatically when an object is saved from the MT web interface or posted via a 3rd party client (on a low priority api/cms_post_save callback). Saves a revision only if at least one revisioned column has changed. -
$obj->object_from_revision($revision)
- -
$obj->load_revision(\%terms, \%args)
- Loads revisions for the$obj
. Arguments work similarly toMT::Object->load
. Thus, one can simply do$obj->load_revision($rev_numer)
or pass terms and args. Terms can be any of the following:- id
- label
- description
- rev_number
- changed
load_revision
should return an/array of arrayref(s) of:- The object stored at the revision
- An array ref of the changed columns that triggered the revision
- The revision number
-
$obj->apply_revision(\%terms, \%args)
- Rolls back to the state of the object at$obj->load_revision(\%terms, \%args)
and saves this action as a revision. -
$obj->diff_object($obj_b)
- Returns a hashref of column names with the values being an arrayref representation of the diff:[<flag>, <left>, <right>]
with the flag being
'u', '+', '-', 'c'
. See the HTML::Diff POD for more information. -
$obj->diff_revision(\%terms, \%diff_args)
- Loads the first object at$obj->load_revision(\%terms, \%args)
and returns a hashref of column names with the values being an arrayref representation of the diff:[<flag>, <left>, <right>]
with the flag being
'u', '+', '-', 'c'
. See the HTML::Diff POD for more information.
-
::pack_revision
sub pack_revision { my ($cb, $obj, $values) = @_; }
This callback is run after
$values
is initially populated by$obj->pack-revision()
and is a hashref of the normal and meta column values and allows you to modify$values
before it is saved with the revision. Thus, you can use this callback to augment what is stored with every revision. -
<package>::unpack_revision
sub unpack_revision { my ($cb, $obj, $packed_obj) = @_; }
This callback is the complement of
pack_revision
and allows you to restore values that are within$packed_obj
. -
<package>::save_revision_filter
sub save_revision_filter { my ($cb, $obj) = @_; }
Similar to the
cms_save_filter
callbacks, this filter will allow you to prevent the saving of a particular revision. -
<package>::pre_save_revision
sub pre_save_revision { my ($cb, $obj) = @_; }
This callback is called just before the revision is saved.
-
<package>::post_save_revision
sub post_save_revision { my ($cb, $obj, $rev_number) = @_; }
This callback is called immediately after a revision is saved.
-
<package>::gather_changed_cols
sub post_save_revision { my ($cb, $obj, $rev_number) = @_; }
This callback is called when MT gathered changed columns from object columns. Plugins can use the callback to add more column such as the ones added by plugins themselves that may not be detected by the default handler.
The majority of the methods MT::Revisable
provides are implemented by driver modules. These driver modules specify how versions of an object are saved and retrieved from a data store. By default, MT::Revisable
uses the MT::Revisable::Local
driver which saves versions within the Melody database. To change this, you would first need to create a driver that implements the following methods:
revision_pkg
revision_props
init_revisioning
save_revision
load_revision
If some of the above methods are not applicable to your driver, simply return undef.
Questions, comments, can't find something? Let us know at our community outpost on Get Satisfaction.
- Author: Arvind Satyanarayan
- Editor: Byrne Reese
- Special Thanks to Ezra Cooper, author of HTML::Diff and one of Movable Type's first engineers, like ever. Props to him.