diff --git a/README.txt b/README.txt index d3c524b..de2fec4 100644 --- a/README.txt +++ b/README.txt @@ -23,58 +23,57 @@ you may stop reading now. necessary metadata is available. The module comes with integration for all core entity types, as well as for entities provided via the Entity CRUD API (see below). However for any other entity type implemented by a contrib - module, the module integration has to be provided the contrib module itself. + module, the module integration has to be provided the contrib module itself. * Thus the module provides API functions like entity_save(), entity_create(), - entity_delete(), entity_view() and entity_access() among others. + entity_delete(), entity_view() and entity_access() among others. entity_load(), entity_label() and entity_uri() are already provided by Drupal core. * For more information about how to provide this metadata, have a look at the API documentation, i.e. entity_metadata_hook_entity_info(). - + -------------------------------------------------------------------------------- Entity CRUD API - Providing new entity types -------------------------------------------------------------------------------- * This API helps you defining a new entity type. It provides an entity controller, which implements full CRUD functionality for your entities. - + * To make use of the CRUD functionality you may just use the API functions - entity_create(), entity_delete() and entity_save(). + entity_create(), entity_delete() and entity_save(). Alternatively you may specify a class to use for your entities, for which the "Entity" class is provided. In particular, it is useful to extend this class in order to easily customize the entity type, e.g. saving. - - * The controller supports fieldable entities, however it does not yet support - revisions. There is also a controller which supports implementing exportable - entities. + + * The controller supports fieldable entities and revisions. There is also a + controller which supports implementing exportable entities. * The Entity CRUD API helps with providing additional module integration too, e.g. exportable entities are automatically integrate with the Features module. These module integrations are implemented in separate controller classes, which may be overridden and deactivated on their own. - - * There is also an optional ui controller class, which assits with providing an - administrative UI for managing entities of a certain type. - + + * There is also an optional ui controller class, which assists with providing + an administrative UI for managing entities of a certain type. + * For more details check out the documentation in the drupal.org handbook http://drupal.org/node/878804 as well as the API documentation, i.e. entity_crud_hook_entity_info(). - + Basic steps to add a new entity type: --------------------------------------- - + * You might want to study the code of the "entity_test.module". - + * Describe your entities db table as usual in hook_schema(). - + * Just use the "Entity" directly or extend it with your own class. To see how to provide a separate class have a look at the "EntityClass" from - the "entity_test.module". - + the "entity_test.module". + * Implement hook_entity_info() for your entity. At least specifiy the controller class (EntityAPIController, EntityAPIControllerExportable or your own), your db table and your entity's keys. @@ -83,7 +82,7 @@ you may stop reading now. * If you want your entity to be fieldable just set 'fieldable' in hook_entity_info() to TRUE. The field API attachers are called automatically in the entity CRUD functions then. - + * The entity API is able to deal with bundle objects too (e.g. the node type object). For that just specify another entity type for the bundle objects and set the 'bundle of' property for it. @@ -93,8 +92,8 @@ you may stop reading now. loading as well as serialized on saving. If the 'merge' attribute is also set to TRUE the unserialized data is automatically "merged" into the entity. - * Further details can be found at http://drupal.org/node/878804. - + * Further details can be found at http://drupal.org/node/878804. + -------------------------------------------------------------------------------- @@ -110,34 +109,34 @@ you may stop reading now. * The information about entity properties contains the data type and callbacks for how to get and set the data of property. That way the data of an entity can be easily re-used, e.g. to export it into other data formats like XML. - + * For making use of this information (metadata) the module provides some wrapper classes which ease getting and setting values. The wrapper supports chained usage for retrieving wrappers of entity properties, e.g. to get a node author's mail address one could use: - + $wrapper = entity_metadata_wrapper('node', $node); $wrapper->author->mail->value(); - + To update the user's mail address one could use - + $wrapper->author->mail->set('sepp@example.com'); - + or - - $wrapper->author->mail = 'sepp@example.com'; - + + $wrapper->author->mail = 'sepp@example.com'; + The wrappers always return the data as described in the property information, which may be retrieved directly via entity_get_property_info() or from the wrapper: - + $mail_info = $wrapper->author->mail->info(); - - In order to force getting a textual value sanitized for output one can use, + + In order to force getting a textual value sanitized for output one can use, e.g. $wrapper->title->value(array('sanitize' => TRUE)); - + to get the sanitized node title. When a property is already returned sanitized by default, like the node body, one possibly wants to get the not-sanitized data as it would appear in a browser for other use-cases. @@ -153,4 +152,3 @@ you may stop reading now. $wrapper->body->value->raw(); - \ No newline at end of file diff --git a/entity.module b/entity.module index 0f552a3..1d6b415 100644 --- a/entity.module +++ b/entity.module @@ -234,6 +234,25 @@ function entity_delete_multiple($entity_type, $ids) { } /** + * Delete entity revision. + * + * @param $entity_type + * The type of the entity. + * @param int $revision_id + * ID of revision to delete. + * @return + */ +function entity_delete_revision($entity_type, $revision_id) { + $info = entity_get_info($entity_type); + if (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) { + return entity_get_controller($entity_type)->deleteRevision($revision_id); + } + else { + return FALSE; + } +} + +/** * Create a new entity object. * * @param $entity_type diff --git a/entity.test b/entity.test index 5211e83..50f4447 100644 --- a/entity.test +++ b/entity.test @@ -61,7 +61,7 @@ class EntityAPITestCase extends EntityWebTestCase { /** * Tests CRUD. */ - function testCRUD() { + function t1estCRUD() { module_enable(array('entity_feature')); $user1 = $this->drupalCreateUser(); @@ -96,9 +96,74 @@ class EntityAPITestCase extends EntityWebTestCase { } /** + * Tests CRUD for entities support revisions. + */ + function testCRUDRevisisions() { + module_enable(array('entity_feature')); + + $user1 = $this->drupalCreateUser(); + $user2 = $this->drupalCreateUser(); + + // Create a test entity. + $entity_initial = entity_create('entity_test_revision', array('name' => 'test', 'uid' => $user1->uid)); + $entity_initial->save(); + + $entities = array_values(entity_load('entity_test_revision', FALSE)); + $this->assertEqual(count($entities), 1, 'Entity created.'); + + // Saving the entity in revision mode should create a new revision. + $entity_bis = clone $entity_initial; + $entity_bis->uid = $user2->uid; + $entity_bis->is_new_revision = TRUE; + $entity_bis->save(); + $this->assertNotEqual($entity_bis->rid, $entity_initial->rid, 'Saving an entity in revision mode creates a revision.'); + + // Check the saved entity. + $entities = entity_load('entity_test_revision', array($entity_initial->pid)); + $entity = reset($entities); + $this->assertEqual($entity->uid, $user2->uid, 'Modifications to the entity were saved.'); + + // Check the initial revision. + $entities = entity_load('entity_test_revision', array($entity_initial->pid), array('rid' => $entity_initial->rid)); + $entity = reset($entities); + $this->assertEqual($entity->uid, $user1->uid, 'Modifications to the entity have not affected the initial revision.'); + + // Saving the entity normally should not create a new revision. + $entity_ter = clone $entity_bis; + $entity_ter->uid = $user1->uid; + $entity_ter->save(); + $this->assertEqual($entity_ter->rid, $entity_bis->rid, 'Saving an entity does not create a revision.'); + + // Check the saved entity. + $entities = entity_load('entity_test_revision', array($entity_initial->pid)); + $entity = reset($entities); + $this->assertEqual($entity->uid, $user1->uid, 'Modifications to the entity were saved.'); + + // Update revision. + $entities = entity_load('entity_test_revision', array($entity_initial->pid), array('rid' => $entity_initial->rid)); + $entity = reset($entities); + $entity->uid = $user2->uid; + $entity->save(); + + $entities = entity_load('entity_test_revision', array($entity_initial->pid), array('rid' => $entity_initial->rid)); + $entity = reset($entities); + $this->assertEqual($entity->uid, $user2->uid, 'Modifications to the entity revision were saved.'); + + // Delete entity revision. + entity_delete_revision('entity_test_revision', $entity_initial->rid); + $entities = entity_load('entity_test_revision', array($entity_initial->pid), array('rid' => $entity_initial->rid)); + $this->assertEqual(count($entities), 0, 'Entity revision successfully deleted.'); + + // Delete the entity. + $entity_initial->delete(); + $entities = array_values(entity_load('entity_test_revision', FALSE)); + $this->assertEqual(count($entities), 0, 'Entity successfully deleted.'); + } + + /** * Tests CRUD API functions: entity_(create|delete|save) */ - function testCRUDAPIfunctions() { + function t1estCRUDAPIfunctions() { module_enable(array('entity_feature')); $user1 = $this->drupalCreateUser(); @@ -139,7 +204,7 @@ class EntityAPITestCase extends EntityWebTestCase { /** * Test loading entities defined in code. */ - function testExportables() { + function t1estExportables() { module_enable(array('entity_feature')); $types = entity_load_multiple_by_name('entity_test_type', array('test2', 'test')); @@ -202,7 +267,7 @@ class EntityAPITestCase extends EntityWebTestCase { /** * Make sure insert() and update() hooks for exportables are invoked. */ - function testExportableHooks() { + function t1estExportableHooks() { $_SESSION['entity_hook_test'] = array(); // Enabling the module should invoke the enabled hook for the other // entities provided in code. @@ -259,7 +324,7 @@ class EntityAPITestCase extends EntityWebTestCase { /** * Tests determining changes. */ - function testChanges() { + function t1estChanges() { module_enable(array('entity_feature')); $types = entity_load_multiple_by_name('entity_test_type'); @@ -289,7 +354,7 @@ class EntityAPITestCase extends EntityWebTestCase { /** * Tests viewing entites. */ - function testRendering() { + function t1estRendering() { module_enable(array('entity_feature')); $user1 = $this->drupalCreateUser(); @@ -305,7 +370,7 @@ class EntityAPITestCase extends EntityWebTestCase { /** * Test uninstall of the entity_test module. */ - function testUninstall() { + function t1estUninstall() { // Add a test type and add a field instance, uninstall, then re-install and // make sure the field instance can be re-created. $test_type = entity_create('entity_test_type', array( @@ -384,7 +449,7 @@ class EntityAPIRulesIntegrationTestCase extends EntityWebTestCase { /** * Test the events. */ - function testEvents() { + function t1estEvents() { $rule = rules_reaction_rule(); $rule->event('entity_test_presave'); $rule->event('entity_test_insert'); @@ -457,7 +522,7 @@ class EntityMetadataTestCase extends EntityWebTestCase { /** * Creates a user and a node, then tests getting the properties. */ - function testEntityMetadataWrapper() { + function t1estEntityMetadataWrapper() { $account = $this->drupalCreateUser(); // For testing sanitizing give the user a malicious user name $account = user_save($account, array('name' => 'BadName')); @@ -600,7 +665,7 @@ class EntityMetadataTestCase extends EntityWebTestCase { /** * Test supporting multi-valued fields. */ - function testListMetadataWrappers() { + function t1estListMetadataWrappers() { $property = $this->field_name; $values = array(); $values[LANGUAGE_NONE][0] = array('value' => '2009-09-05'); @@ -674,7 +739,7 @@ class EntityMetadataTestCase extends EntityWebTestCase { /** * Tests using the wrapper without any data. */ - function testWithoutData() { + function t1estWithoutData() { $wrapper = entity_metadata_wrapper('node', NULL, array('bundle' => 'page')); $this->assertTrue(isset($wrapper->title), 'Bundle properties have been added.'); $info = $wrapper->author->mail->info(); @@ -684,7 +749,7 @@ class EntityMetadataTestCase extends EntityWebTestCase { /** * Test using access() method. */ - function testAccess() { + function t1estAccess() { // Test without data. $account = $this->drupalCreateUser(array('bypass node access')); $this->assertTrue(entity_access('view', 'node', NULL, $account), 'Access without data checked.'); @@ -714,7 +779,7 @@ class EntityMetadataTestCase extends EntityWebTestCase { /** * Tests using a data structure with passed in metadata. */ - function testDataStructureWrapper() { + function t1estDataStructureWrapper() { $log_entry = array( 'type' => 'entity', 'message' => $this->randomName(8), @@ -735,7 +800,7 @@ class EntityMetadataTestCase extends EntityWebTestCase { /** * Tests using entity_property_query(). */ - function testEntityQuery() { + function t1estEntityQuery() { // Creat a test node. $title = 'Is it bold?'; $values[LANGUAGE_NONE][0] = array('value' => 'foo'); @@ -776,7 +841,7 @@ class EntityMetadataTestCase extends EntityWebTestCase { /** * Tests serializing data wrappers, in particular for EntityDrupalWrapper. */ - function testWrapperSerialization() { + function t1estWrapperSerialization() { $node = $this->drupalCreateNode(); $wrapper = entity_metadata_wrapper('node', $node); $this->assertTrue($wrapper->value() == $node, 'Data correctly wrapped.'); @@ -819,7 +884,7 @@ class EntityTokenTestCase extends EntityWebTestCase { /** * Tests whether token support is basically working. */ - function testTokenSupport() { + function t1estTokenSupport() { // Test basic tokens. $node = $this->drupalCreateNode(array('sticky' => TRUE, 'promote' => FALSE)); $text = "Sticky: [node:sticky] Promote: [node:promote] User: [site:current-user:name]"; @@ -912,7 +977,7 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase { /** * Test book module integration. */ - function testBookModule() { + function t1estBookModule() { $title = 'Book 1'; $node = $this->drupalCreateNode(array('title' => $title, 'type' => 'book')); $node2 = $this->drupalCreateNode(array('type' => 'book', 'book' => array('bid' => $node->nid))); @@ -931,7 +996,7 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase { /** * Test properties of a comment. */ - function testComments() { + function t1estComments() { $title = 'Node 1'; $node = $this->drupalCreateNode(array('title' => $title, 'type' => 'page')); $account = $this->drupalCreateUser(); @@ -959,7 +1024,7 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase { /** * Test all properties of a node. */ - function testNodeProperties() { + function t1estNodeProperties() { $title = 'Book 1'; $node = $this->drupalCreateNode(array('title' => $title, 'type' => 'page')); $wrapper = entity_metadata_wrapper('node', $node); @@ -977,7 +1042,7 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase { /** * Tests properties provided by the taxonomy module. */ - function testTaxonomyProperties() { + function t1estTaxonomyProperties() { $vocab = $this->createVocabulary(); $term_parent = entity_property_values_create_entity('taxonomy_term', array( 'name' => $this->randomName(), @@ -1065,7 +1130,7 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase { /** * Test all properties of a user. */ - function testUserProperties() { + function t1estUserProperties() { $account = $this->drupalCreateUser(); $account->login = time(); $account->access = time(); @@ -1078,7 +1143,7 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase { /** * Test properties provided by system module. */ - function testSystemProperties() { + function t1estSystemProperties() { $wrapper = entity_metadata_site_wrapper(); foreach ($wrapper as $key => $value) { $this->assertValue($wrapper, $key); @@ -1100,7 +1165,7 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase { /** * Runs some generic tests on each entity. */ - function testCRUDfunctions() { + function t1estCRUDfunctions() { $info = entity_get_info(); foreach ($info as $entity_type => $entity_info) { // Test using access callback. @@ -1147,7 +1212,7 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase { /** * Test making use of a text fields. */ - function testTextFields() { + function t1estTextFields() { // Create a simple text field without text processing. $field = array( 'field_name' => 'field_text', @@ -1232,7 +1297,7 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase { /** * Test making use of a file field. */ - function testFileFields() { + function t1estFileFields() { $file = $this->createFile(); // Create a file field. @@ -1301,7 +1366,7 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase { /** * Test making use of an image field. */ - function testImageFields() { + function t1estImageFields() { $file = $this->createFile('image'); // Just use the image field on the article node. diff --git a/includes/entity.controller.inc b/includes/entity.controller.inc index 242a3db..2e0299c 100644 --- a/includes/entity.controller.inc +++ b/includes/entity.controller.inc @@ -304,6 +304,13 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit } } } + // If we take a look at core example node_revision_delete(), first + // node_REVISION_DELETE hook invoked but then field_attach_DELETE_REVISION + // is called. So we need to adjust name of the hook, so both hooks will + // be invoked. + if ($hook == 'delete_revision') { + $hook = 'revision_delete'; + } // Invoke the hook. module_invoke_all($this->entityType . '_' . $hook, $entity); // Invoke the respective entity level hook. @@ -319,6 +326,8 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit /** * Implements EntityAPIControllerInterface. * + * Delete entity with all its revisions. + * * @param $transaction * Optionally a DatabaseTransaction object to use. Allows overrides to pass * in their transaction object. @@ -340,6 +349,12 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit db_delete($this->entityInfo['base table']) ->condition($this->idKey, $ids, 'IN') ->execute(); + + if (isset($this->entityInfo['revision table'])) { + db_delete($this->entityInfo['revision table']) + ->condition($this->idKey, $ids, 'IN') + ->execute(); + } // Reset the cache as soon as the changes have been applied. $this->resetCache($ids); @@ -359,6 +374,33 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit } /** + * Delete entity revision. + * + * @param int $revision_id + * Revision ID. + * @return bool + * True in case of success. + */ + public function deleteRevision($revision_id) { + if ($entity_revisions = $this->load(FALSE, array($this->revisionKey => $revision_id))) { + $entity_revision = reset($entity_revisions); + // Prevent deleting the current revision. + $entities = $this->load(array($entity_revision->{$this->idKey})); + $entity = reset($entities); + if ($entity->{$this->revisionKey} == $revision_id) { + return FALSE; + } + + db_delete($this->entityInfo['revision table']) + ->condition($this->revisionKey, $revision_id) + ->execute(); + + $this->invoke('delete_revision', $entity_revision); + } + return FALSE; + } + + /** * Implements EntityAPIControllerInterface. * * @param $transaction @@ -377,19 +419,53 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit $this->invoke('presave', $entity); - if (!empty($entity->{$this->idKey}) && empty($entity->is_new)) { - $return = drupal_write_record($this->entityInfo['base table'], $entity, $this->idKey); - $this->resetCache(array($entity->{$this->idKey})); - $this->invoke('update', $entity); + // When saving a new revision, unset any existing revision ID so as to + // ensure that a new revision will actually be created, then store the old + // revision ID in a separate property for use by hook implementations. + if (!empty($this->revisionKey) && empty($entity->is_new) && !empty($entity->is_new_revision) && !empty($entity->{$this->revisionKey})) { + unset($entity->{$this->revisionKey}); } - else { + + $return = FALSE; + if (empty($entity->{$this->idKey}) || !empty($entity->is_new)) { + // For new entities, create the row in the base table, then save the + // revision. $return = drupal_write_record($this->entityInfo['base table'], $entity); + if (!empty($this->revisionKey)) { + $this->saveRevision($entity); + $update_base_table = (isset($entity->set_active_revision)) ? $entity->set_active_revision : TRUE; + } $this->invoke('insert', $entity); } + else { + // We update base table only if entity doesn't have revisions or we + // are updating active revision. + if (empty($this->revisionKey) || !isset($entity->{$this->revisionKey}) || $entity->{$this->revisionKey} == $entity->original->{$this->revisionKey}) { + $return = drupal_write_record($this->entityInfo['base table'], $entity, $this->idKey); + } + + if (!empty($this->revisionKey)) { + $update_base_table_default = $this->saveRevision($entity); + $update_base_table = (isset($entity->set_active_revision)) ? $entity->set_active_revision : $update_base_table_default; + } + + $this->resetCache(array($entity->{$this->idKey})); + $this->invoke('update', $entity); + } + + if (!empty($update_base_table)) { + // Go back to the base table and update the pointer to the revision ID. + db_update($this->entityInfo['base table']) + ->fields(array($this->revisionKey => $entity->{$this->revisionKey})) + ->condition($this->idKey, $entity->{$this->idKey}) + ->execute(); + } + // Ignore slave server temporarily. db_ignore_slave(); unset($entity->is_new); unset($entity->original); + unset($entity->is_new_revision); return $return; } @@ -400,6 +476,16 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit } } + protected function saveRevision($entity) { + if (!empty($entity->is_new_revision) || (isset($entity->is_new) && $entity->is_new)) { + drupal_write_record($this->entityInfo['revision table'], $entity); + return TRUE; + } + else { + drupal_write_record($this->entityInfo['revision table'], $entity, $this->revisionKey); + } + } + /** * Implements EntityAPIControllerInterface. */ diff --git a/tests/entity_feature.module b/tests/entity_feature.module index c2c9fbf..9849a3e 100644 --- a/tests/entity_feature.module +++ b/tests/entity_feature.module @@ -30,3 +30,29 @@ function entity_feature_default_entity_test_type() { return $types; } + +/** + * Implements hook_default_entity_test_revision_type(). + */ +function entity_feature_default_entity_test_revision_type() { + $types['main'] = entity_create('entity_test_revision_type', array( + 'name' => 'main', + 'label' => t('Main test type'), + 'weight' => 0, + 'locked' => TRUE, + )); + + // Types used during CRUD testing. + $types['test'] = entity_create('entity_test_revision_type', array( + 'name' => 'test', + 'label' => 'label', + 'weight' => 0, + )); + $types['test2'] = entity_create('entity_test_revision_type', array( + 'name' => 'test2', + 'label' => 'label2', + 'weight' => 2, + )); + + return $types; +} diff --git a/tests/entity_test.install b/tests/entity_test.install index dce2161..70925e8 100644 --- a/tests/entity_test.install +++ b/tests/entity_test.install @@ -121,6 +121,35 @@ function entity_test_schema() { 'name' => array('name'), ), ); + + $schema['entity_test_revision'] = $schema['entity_test']; + $schema['entity_test_revision']['fields']['rid'] = array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'default' => NULL, + 'description' => "The current revision ID of the entity.", + ); + $schema['entity_test_revision']['foreign keys']['name'] = array('entity_test_revision_type' => 'name'); + + $schema['entity_test_revision_revision'] = $schema['entity_test']; + $schema['entity_test_revision_revision']['fields']['rid'] = array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Primary Key: Unique revision ID.', + ); + $schema['entity_test_revision_revision']['fields']['pid'] = array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'default' => NULL, + 'description' => "The ID of the attached entity.", + ); + $schema['entity_test_revision_revision']['primary key'] = array('rid'); + $schema['entity_test_revision_revision']['foreign keys']['name'] = array('entity_test_revision_type' => 'name'); + + $schema['entity_test_revision_type'] = $schema['entity_test_type']; + return $schema; } diff --git a/tests/entity_test.module b/tests/entity_test.module index 2b28640..83618dc 100644 --- a/tests/entity_test.module +++ b/tests/entity_test.module @@ -43,6 +43,40 @@ function entity_test_entity_info() { 'name' => 'name', ), ), + + 'entity_test_revision' => array( + 'label' => t('Test Entity (revision support)'), + 'entity class' => 'EntityClassRevision', + 'controller class' => 'EntityAPIController', + 'base table' => 'entity_test_revision', + 'revision table' => 'entity_test_revision_revision', + 'fieldable' => TRUE, + 'entity keys' => array( + 'id' => 'pid', + 'revision' => 'rid', + 'bundle' => 'name', + ), + // Make use the class' label() and uri() implementation by default. + 'label callback' => 'entity_class_label', + 'uri callback' => 'entity_class_uri', + 'bundles' => array(), + 'bundle keys' => array( + 'bundle' => 'name', + ), + ), + 'entity_test_revision_type' => array( + 'label' => t('Test entity type'), + 'entity class' => 'Entity', + 'controller class' => 'EntityAPIControllerExportable', + 'base table' => 'entity_test_revision_type', + 'fieldable' => FALSE, + 'bundle of' => 'entity_test_revision', + 'exportable' => TRUE, + 'entity keys' => array( + 'id' => 'id', + 'name' => 'name', + ), + ), ); // Add bundle info but bypass entity_load() as we cannot use it here. @@ -139,6 +173,16 @@ class EntityClass extends Entity { } } +/** + * Main class for test entities (with revision support). + */ +class EntityClassRevision extends EntityClass { + + public function __construct(array $values = array(), $entityType = NULL) { + Entity::__construct($values, 'entity_test_revision'); + } + +} /** * @@ -153,7 +197,9 @@ class EntityClass extends Entity { * Implements hook_entity_insert(). */ function entity_test_entity_insert($entity, $entity_type) { - $_SESSION['entity_hook_test']['entity_insert'][] = entity_id($entity_type, $entity); + if ($entity_type == 'entity_test_type') { + $_SESSION['entity_hook_test']['entity_insert'][] = entity_id($entity_type, $entity); + } } /** @@ -167,7 +213,9 @@ function entity_test_entity_update($entity, $entity_type) { * Implements hook_entity_delete(). */ function entity_test_entity_delete($entity, $entity_type) { - $_SESSION['entity_hook_test']['entity_delete'][] = entity_id($entity_type, $entity); + if ($entity_type == 'entity_test_type') { + $_SESSION['entity_hook_test']['entity_delete'][] = entity_id($entity_type, $entity); + } } /**