diff --git includes/common.inc includes/common.inc index f1b1537..1d1437e 100644 --- includes/common.inc +++ includes/common.inc @@ -7329,6 +7329,28 @@ function entity_get_controller($entity_type) { } /** + * Loads the unchanged, i.e. not modified, entity from the database. + * + * Unlike entity_load() this function ensures the entity is directly loaded from + * the database, thus bypassing any static cache. In particular, this function + * is useful in 'presave' hooks to determine changes by comparing the entity + * being saved and the unchanged version. + * + * @param $entity_type + * The entity type to load, e.g. node or user. + * @param $id + * The id of the entity to load. + * + * @return + * The unchanged entity, or FALSE if the entity cannot be loaded. + */ +function entity_load_unchanged($entity_type, $id) { + entity_get_controller($entity_type)->resetCache($id); + $result = entity_get_controller($entity_type)->load(array($id)); + return reset($result); +} + +/** * Invoke hook_entity_prepare_view(). * * If adding a new entity similar to nodes, comments or users, you should diff --git includes/entity.inc includes/entity.inc index 1c3e749..9ea0084 100644 --- includes/entity.inc +++ includes/entity.inc @@ -24,8 +24,12 @@ interface DrupalEntityControllerInterface { /** * Resets the internal, static entity cache. + * + * @param $id + * (optional) If specified, the cache is only reset for the entity with + * the given id. */ - public function resetCache(); + public function resetCache($id = NULL); /** * Loads one or more entities. @@ -139,8 +143,13 @@ class DrupalDefaultEntityController implements DrupalEntityControllerInterface { /** * Implements DrupalEntityControllerInterface::resetCache(). */ - public function resetCache() { - $this->entityCache = array(); + public function resetCache($id = NULL) { + if (isset($id)) { + unset($this->entityCache[$id]); + } + else { + $this->entityCache = array(); + } } /** diff --git modules/node/node.test modules/node/node.test index df189bc..9f2702f 100644 --- modules/node/node.test +++ modules/node/node.test @@ -997,14 +997,14 @@ class NodeSaveTestCase extends DrupalWebTestCase { $changed = $node->changed; node_save($node); - $node = $this->drupalGetNodeByTitle($edit['title']); + $node = $this->drupalGetNodeByTitle($edit['title'], TRUE); $this->assertEqual($node->created, $created, t('Updating a node preserves "created" timestamp.')); // Programmatically set the timestamps using hook_node_presave. $node->title = 'testing_node_presave'; node_save($node); - $node = $this->drupalGetNodeByTitle('testing_node_presave'); + $node = $this->drupalGetNodeByTitle('testing_node_presave', TRUE); $this->assertEqual($node->created, 280299600, t('Saving a node uses "created" timestamp set in presave hook.')); $this->assertEqual($node->changed, 979534800, t('Saving a node uses "changed" timestamp set in presave hook.')); @@ -1027,10 +1027,35 @@ class NodeSaveTestCase extends DrupalWebTestCase { $node->changed = 280299600; node_save($node); - $node = $this->drupalGetNodeByTitle($edit['title']); + $node = $this->drupalGetNodeByTitle($edit['title'], TRUE); $this->assertEqual($node->created, 979534800, t('Updating a node uses user-set "created" timestamp.')); $this->assertNotEqual($node->changed, 280299600, t('Updating a node doesn\'t use user-set "changed" timestamp.')); } + + /** + * Tests determing changes in hook_node_presave(). + */ + function testDeterminingChanges() { + // Initial creation. + $node = (object) array( + 'uid' => $this->web_user->uid, + 'type' => 'article', + 'title' => 'test_changes', + ); + node_save($node); + + // Update the node without applying changes. + node_save($node); + $this->assertEqual($node->title, 'test_changes', 'No changes have been determined.'); + + // Apply changes. + $node->title = 'updated'; + node_save($node); + + // The hook implementation node_test_node_presave() has to determine the + // changes and set the title to 'changed'. + $this->assertEqual($node->title, 'changed', 'Changes have been determined.'); + } } /** diff --git modules/node/tests/node_test.module modules/node/tests/node_test.module index cfc503d..fc0c8a5 100644 --- modules/node/tests/node_test.module +++ modules/node/tests/node_test.module @@ -115,4 +115,10 @@ function node_test_node_presave($node) { // Drupal 1.0 release. $node->changed = 979534800; } + // Determine changes. + if (!empty($node->nid) && $unchanged_node = entity_load_unchanged('node', $node->nid)) { + if ($unchanged_node->title == 'test_changes' && $unchanged_node->title != $node->title) { + $node->title = 'changed'; + } + } } diff --git modules/simpletest/drupal_web_test_case.php modules/simpletest/drupal_web_test_case.php index 1949b99..1f47ade 100644 --- modules/simpletest/drupal_web_test_case.php +++ modules/simpletest/drupal_web_test_case.php @@ -787,12 +787,14 @@ class DrupalWebTestCase extends DrupalTestCase { * * @param title * A node title, usually generated by $this->randomName(). + * @param $reset + * (optional) Whether to reset the internal node_load() cache. * * @return * A node object matching $title. */ - function drupalGetNodeByTitle($title) { - $nodes = node_load_multiple(array(), array('title' => $title)); + function drupalGetNodeByTitle($title, $reset = FALSE) { + $nodes = node_load_multiple(array(), array('title' => $title), $reset); // Load the first node returned from the database. $returned_node = reset($nodes); return $returned_node;