Community Documentation

Implementing entity revisioning

Last updated April 16, 2011. Created by naught101 on April 16, 2011.
Log in to edit this page.

Entity revisioning is fairly simple - most of it is handled by field API, so you just need to implement a revision table, and appropriate load and save functions, and add an {example_revision} table with the appropriate columns.

hook_schema implementation

<?php
/**
* Implements hook_schema().
*/
function example_schema() {
 
$schema['example'] = array(
   
'description' => 'Keeps track of example entities.',
   
'fields' => array(
     
'example_id' => array(
       
'type' => 'serial',
       
'unsigned' => TRUE,
       
'not null' => TRUE,
       
'description' => 'Unique example id.',
      ),
     
'vid' => array(
       
'description' => 'The current {example_revision}.vid version identifier.',
       
'type' => 'int',
       
'unsigned' => TRUE,
       
'not null' => TRUE,
       
'default' => 0,
      ),
     
'created' => array(
       
'description' => 'The Unix timestamp when the example was created.',
       
'type' => 'int',
       
'not null' => TRUE,
       
'default' => 0,
      ),
     
'changed' => array(
       
'description' => 'The Unix timestamp when the example was most recently saved.',
       
'type' => 'int',
       
'not null' => TRUE,
       
'default' => 0,
      ),
     
// .. Any other columns you need in for your entity
   
),
   
'primary key' => array('example_id'),
  );
 
$schema['example_revision'] = array(
   
'description' => 'Keeps track of example entities.',
   
'fields' => array(
     
'example_id' => array(
       
'type' => 'int',
       
'unsigned' => TRUE,
       
'not null' => TRUE,
       
'default' => 0,
       
'description' => 'Unique example id (entity id).',
      ),
     
'vid' => array(
       
'description' => 'The current {example_revision}.vid version identifier.',
       
'type' => 'serial',
       
'unsigned' => TRUE,
       
'not null' => TRUE,
      ),
     
'changed' => array(
       
'description' => 'The Unix timestamp when the example was most recently saved.',
       
'type' => 'int',
       
'not null' => TRUE,
       
'default' => 0,
      ),
     
// Any other columns that you have in the example entity table that you
      // want to store in revisions.
   
),
   
'primary key' => array('example_id', 'vid'),
  );
}
?>

Add a _save function

This assumes your entites being saved are stdClass objects, with an entity ID, a created date, and any other data that you want to push into the database. New entities to be saved should also have a property called "is_new" set to TRUE.

<?php
function example_save($example) {
  if (
$example->is_new) {
   
// Adds the data to the entity table, and returns the new $example_id:
   
$example_id = db_insert('example')
      ->
useDefaults(array('example_id'))
      ->
fields(array(
       
'created'   => REQUEST_TIME,
       
'changed'   => REQUEST_TIME,
       
// Any other DB columns that you want to provide defaults for.
       
))
      ->
execute();
   
// Add the new entity ID back into the entity object
   
$example->example_id = $example_id;
   
// Add a revision for all new nodes.
   
$example->revision = TRUE;
  }
  if (!empty(
$example->revision)) {
   
// Add the entity data to the revision table, and return the unique revision id.
   
$vid = db_insert('example_revision')
      ->
useDefaults(array('vid'))
      ->
fields(array(
       
'example_id' => $example->example_id,
       
// We don't need to store the creation time
       
'changed'     => REQUEST_TIME,
       
// Any other DB columns that you want to store, and for which you
        // need revisioning.
       
))
      ->
execute();
     
// Add the revision ID back to the entity
     
$example->vid = $vid;
     
   
// Update the revision ID on the entity table.
   
db_update('example')
      ->
condition('example_id', $example->example_id)
      ->
fields(array(
       
'vid'     => $example->vid,
        ))
      ->
execute();
  }
 
 
// let Field UI deal with the fields.
 
if ($example->is_new) {
   
field_attach_insert('example', $example);
  }
  else {
   
field_attach_update('example', $example);
  }
     
  return
$example->example_id;
}
?>

Comments

hook_entity_presave, _insert, and _update?

Who invokes the hooks?

Drupal doesn't invoke the hooks, so you have to invoke the hooks.

Entity API provide them by default

http://drupal.org/node/878804

Or you can create your custom Entity Controller.

The Simple Module Example

If you want a practical module as a reference, you won't regret to checkout one of productions of the Drupal Genius(merlinofchaos): http://drupal.org/project/fieldable_panels_panes