diff --git a/core/modules/entity/lib/Drupal/entity/DatabaseStorageController.php b/core/modules/entity/lib/Drupal/entity/DatabaseStorageController.php index 2634041178170544db51dbf96ae7a0511ceca5fe..ff82234110a40a000a2f97c3b3c3c21c70817014 100644 --- a/core/modules/entity/lib/Drupal/entity/DatabaseStorageController.php +++ b/core/modules/entity/lib/Drupal/entity/DatabaseStorageController.php @@ -317,8 +317,8 @@ class DatabaseStorageController implements EntityStorageControllerInterface { $query->fields('revision', $entity_revision_fields); // Compare revision id of the base and revision table, if equal then this - // is the current revision. - $query->addExpression('base.' . $this->revisionKey . ' = revision.' . $this->revisionKey, 'isCurrentRevision'); + // is the default revision. + $query->addExpression('base.' . $this->revisionKey . ' = revision.' . $this->revisionKey, 'isDefaultRevision'); } $query->fields('base', $entity_fields); diff --git a/core/modules/entity/lib/Drupal/entity/StorableBase.php b/core/modules/entity/lib/Drupal/entity/StorableBase.php index 57bf352b93882ea8e4666b51ebb23192348d6694..d959146378c534c5af3e37a492259c3f33aef92d 100644 --- a/core/modules/entity/lib/Drupal/entity/StorableBase.php +++ b/core/modules/entity/lib/Drupal/entity/StorableBase.php @@ -41,11 +41,11 @@ abstract class StorableBase implements StorableInterface { protected $enforceIsNew; /** - * Indicates whether this is the current revision. + * Indicates whether this is the default revision. * * @var bool */ - public $isCurrentRevision = TRUE; + public $isDefaultRevision = TRUE; /** * Constructs a new entity object. @@ -278,9 +278,9 @@ abstract class StorableBase implements StorableInterface { } /** - * Implements Drupal\entity\StorableInterface::isCurrentRevision(). + * Implements Drupal\entity\StorableInterface::isDefaultRevision(). */ - public function isCurrentRevision() { - return $this->isCurrentRevision; + public function isDefaultRevision() { + return $this->isDefaultRevision; } } diff --git a/core/modules/entity/lib/Drupal/entity/StorableInterface.php b/core/modules/entity/lib/Drupal/entity/StorableInterface.php index 820fdc752288a239785af21b5085229684843532..c0935c70288ffc6f082e9e6b8bd203bfb1dcfda9 100644 --- a/core/modules/entity/lib/Drupal/entity/StorableInterface.php +++ b/core/modules/entity/lib/Drupal/entity/StorableInterface.php @@ -209,10 +209,10 @@ interface StorableInterface { public function getRevisionId(); /** - * Checks if this entity is the current revision. + * Checks if this entity is the default revision. * * @return bool - * TRUE if the entity is the current revision, FALSE otherwise. + * TRUE if the entity is the default revision, FALSE otherwise. */ - public function isCurrentRevision(); + public function isDefaultRevision(); } diff --git a/core/modules/field/modules/field_sql_storage/field_sql_storage.module b/core/modules/field/modules/field_sql_storage/field_sql_storage.module index 69e8bda6e000ca3ccf14e9f09bcc58aa1f691d8e..f6f86890a38b1aca3f296b5e9eff2d6bf0b8e41a 100644 --- a/core/modules/field/modules/field_sql_storage/field_sql_storage.module +++ b/core/modules/field/modules/field_sql_storage/field_sql_storage.module @@ -400,11 +400,18 @@ function field_sql_storage_field_storage_write($entity_type, $entity, $op, $fiel // Delete all language codes if $entity->$field_name is empty. $langcodes = !empty($entity->$field_name) ? $field_langcodes : $all_langcodes; if ($langcodes) { - db_delete($table_name) - ->condition('entity_type', $entity_type) - ->condition('entity_id', $id) - ->condition('langcode', $langcodes, 'IN') - ->execute(); + // Only overwrite the field's base table if saving the default revision + // of an entity. + // @todo: Remove the method_exists() check from this 'if' statement + // once issue #1616930 has been resolved. This is currently needed to + // prevent errors in the Field module tests. + if (!method_exists($entity, 'isDefaultRevision') || $entity->isDefaultRevision()) { + db_delete($table_name) + ->condition('entity_type', $entity_type) + ->condition('entity_id', $id) + ->condition('langcode', $langcodes, 'IN') + ->execute(); + } db_delete($revision_name) ->condition('entity_type', $entity_type) ->condition('entity_id', $id) @@ -453,7 +460,14 @@ function field_sql_storage_field_storage_write($entity_type, $entity, $op, $fiel // Execute the query if we have values to insert. if ($do_insert) { - $query->execute(); + // Only overwrite the field's base table if saving the default revision + // of an entity. + // @todo: Remove the method_exists() check from this 'if' statement + // once issue #1616930 has been resolved. This is currently needed to + // prevent errors in the Field module tests. + if (!method_exists($entity, 'isDefaultRevision') || $entity->isDefaultRevision()) { + $query->execute(); + } $revision_query->execute(); } } diff --git a/core/modules/node/lib/Drupal/node/Node.php b/core/modules/node/lib/Drupal/node/Node.php index fd3454e94c51a1270fbcdae95a76f887f3ba27b7..70086424a2bbfddbe6663f46612321d73f423cda 100644 --- a/core/modules/node/lib/Drupal/node/Node.php +++ b/core/modules/node/lib/Drupal/node/Node.php @@ -29,6 +29,16 @@ class Node extends Entity { public $vid; /** + * Indicates whether this is the default node revision. + * + * The default revision of a node is the one loaded when no specific revision + * has been specified. Only default revisions are saved to the node table. + * + * @var boolean + */ + public $isDefaultRevision = TRUE; + + /** * The node UUID. * * @var string diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php index c5763e8ec479dc3629f5248fdd48a13201e0a346..f43988b3e48527593c8b3d633834212b3eb8efb9 100644 --- a/core/modules/node/lib/Drupal/node/NodeFormController.php +++ b/core/modules/node/lib/Drupal/node/NodeFormController.php @@ -147,6 +147,18 @@ class NodeFormController extends EntityFormController { ); } + $form['revision_information']['isDefaultRevision'] = array( + '#type' => 'checkbox', + '#title' => t('Set as default revision'), + '#default_value' => 1, + '#access' => user_access('administer nodes'), + '#states' => array( + 'visible' => array( + ':input[name="revision"]' => array('checked' => TRUE), + ), + ), + ); + $form['revision_information']['log'] = array( '#type' => 'textarea', '#title' => t('Revision log message'), diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php index ee475465ba93c2f8c3bdb9724d01de973f032b35..4e17d418837845b4153c4cca1da0f7e3c91906fc 100644 --- a/core/modules/node/lib/Drupal/node/NodeStorageController.php +++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php @@ -100,7 +100,16 @@ class NodeStorageController extends DatabaseStorageController { } else { $op = 'update'; - $return = drupal_write_record($this->entityInfo['base table'], $entity, $this->idKey); + // Update the base node table, but only if this revision is marked as + // the default. + if ($entity->isDefaultRevision()) { + $return = drupal_write_record($this->entityInfo['base table'], $entity, $this->idKey); + } + else { + // @todo, should a different value be returned when saving an entity + // with $isDefaultRevision = FALSE? + $return = FALSE; + } } if ($this->revisionKey) { @@ -139,19 +148,19 @@ class NodeStorageController extends DatabaseStorageController { if (empty($entity->{$this->revisionKey}) || !empty($entity->revision)) { drupal_write_record($this->revisionTable, $record); - db_update($this->entityInfo['base table']) - ->fields(array($this->revisionKey => $record->{$this->revisionKey})) - ->condition($this->idKey, $entity->{$this->idKey}) - ->execute(); + // Only update the base node table if this revision is the default. + if ($entity->isDefaultRevision()) { + db_update($this->entityInfo['base table']) + ->fields(array($this->revisionKey => $record->{$this->revisionKey})) + ->condition($this->idKey, $entity->{$this->idKey}) + ->execute(); + } } else { drupal_write_record($this->revisionTable, $record, $this->revisionKey); } // Make sure to update the new revision key for the entity. $entity->{$this->revisionKey} = $record->{$this->revisionKey}; - - // Mark this revision as the current one. - $entity->isCurrentRevision(TRUE); } /** @@ -263,7 +272,12 @@ class NodeStorageController extends DatabaseStorageController { * Overrides Drupal\entity\DatabaseStorageController::postSave(). */ function postSave(StorableInterface $node, $update) { - node_access_acquire_grants($node, $update); + // Update the node access table for this node, but only if it is the + // default revision. There's no need to delete existing records if the node + // is new. + if ($node->isDefaultRevision()) { + node_access_acquire_grants($node, $update); + } } /** diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php index 6b1b14112353eb071880419a3b1fb8c2966dd8e3..cf0970aa215b7aa5ae74d0ecf520d0141b4079b0 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php @@ -24,7 +24,7 @@ class NodeRevisionsTest extends NodeTestBase { // Create and login user. $web_user = $this->drupalCreateUser(array('view revisions', 'revert revisions', 'edit any page content', - 'delete revisions', 'delete any page content')); + 'delete revisions', 'delete any page content', 'administer nodes')); $this->drupalLogin($web_user); // Create initial node. @@ -75,8 +75,8 @@ class NodeRevisionsTest extends NodeTestBase { $this->assertText($log, t('Log message found.')); } - // Confirm that this is the current revision. - $this->assertTrue($node->isCurrentRevision(), 'Third node revision is the current one.'); + // Confirm that this is the default revision. + $this->assertTrue($node->isDefaultRevision(), 'Third node revision is the default one.'); // Confirm that revisions revert properly. $this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/revert", array(), t('Revert')); @@ -86,9 +86,9 @@ class NodeRevisionsTest extends NodeTestBase { $reverted_node = node_load($node->nid); $this->assertTrue(($nodes[1]->body[LANGUAGE_NOT_SPECIFIED][0]['value'] == $reverted_node->body[LANGUAGE_NOT_SPECIFIED][0]['value']), t('Node reverted correctly.')); - // Confirm that this is not the current version. + // Confirm that this is not the default version. $node = node_revision_load($node->vid); - $this->assertFalse($node->isCurrentRevision(), 'Third node revision is not the current one.'); + $this->assertFalse($node->isDefaultRevision(), 'Third node revision is not the default one.'); // Confirm revisions delete properly. $this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/delete", array(), t('Delete')); @@ -112,6 +112,44 @@ class NodeRevisionsTest extends NodeTestBase { '%title' => $nodes[2]->label(), '%revision-date' => format_date($old_revision_date), ))); + + // Make a new revision and set it to not be default. + // This will create a "forward revision." + $edit = array(); + $langcode = LANGUAGE_NOT_SPECIFIED; + $new_body = $this->randomName(); + $edit["body[$langcode][0][value]"] = $new_body; + // Save this as a forward revision. + $edit["revision"] = TRUE; + $edit["isDefaultRevision"] = FALSE; + $this->drupalPost("node/$node->nid/edit", $edit, t('Save')); + $this->drupalGet("node/$node->nid"); + $this->assertNoText($new_body, t('Forward revision body text is not present on default version of node.')); + + // Get the highest vid for this node. + $versions = db_select('node_revision', 'nr') + ->fields('nr', array('vid')) + ->condition('nid', $node->nid) + ->orderBy('nr.vid', 'DESC') + ->range(0,1) + ->execute() + ->fetchCol(); + + $forward_revision_vid = $versions[0]; + + // Verify that the new body text is present on the forward revision. + $this->drupalGet("node/$node->nid/revisions/" . $forward_revision_vid . "/view"); + $this->assertText($new_body, t('Forward revision body text is present on forward version of node.')); + + // Verify that the forward revision vid is greater than the default + // revision vid. + $default_revision = db_select('node', 'n') + ->fields('n', array('vid')) + ->condition('nid', $node->nid) + ->execute() + ->fetchCol(); + $default_revision_vid = $default_revision[0]; + $this->assertTrue($forward_revision_vid > $default_revision_vid, 'Forward revision vid is greater than default revision vid.'); } /** diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index a772e0259be4a3d410a46958bc178e9694f1ae49..2582acbb706c21ad38a84b8e599dee96b69fd5f9 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -1580,7 +1580,7 @@ function taxonomy_build_node_index($node) { } } // We only maintain the taxonomy index for published nodes. - if ($status) { + if ($status && $node->isDefaultRevision()) { // Collect a unique list of all the term IDs from all node fields. $tid_all = array(); foreach (field_info_instances('node', $node->type) as $instance) {