Commit e203b73b authored by webchick's avatar webchick

Issue #218755 by jstoller, Gábor Hojtsy, stevector, mradcliffe, agentrickard,...

Issue #218755 by jstoller, Gábor Hojtsy, stevector, mradcliffe, agentrickard, catch, Crell: Added Support revisions in different states.
parent 5f4440fa
......@@ -4,6 +4,9 @@ Drupal 8.0, xxxx-xx-xx (development version)
- Improved entity system.
* Added support for saving and deleting entities through the controller.
* Entities are now classed objects, implementing EntityInterface.
* Drupal now understands the concept of a "default" revision, tracked
independently from the latest revision, allowing for the creation of
drafts while the current revision stays published.
- Replaced the core routing system with one built on the Symfony2 framework.
- Configuration:
* Added a centralized file-based configuration system.
......
......@@ -318,8 +318,8 @@ protected function buildQuery($ids, $revision_id = FALSE) {
$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);
......
......@@ -42,11 +42,11 @@ class Entity implements EntityInterface {
protected $enforceIsNew;
/**
* Indicates whether this is the current revision.
* Indicates whether this is the default revision.
*
* @var bool
*/
protected $isCurrentRevision = TRUE;
protected $isDefaultRevision = TRUE;
/**
* Constructs a new entity object.
......@@ -277,12 +277,12 @@ public function getRevisionId() {
}
/**
* Implements Drupal\entity\EntityInterface::isCurrentRevision().
* Implements Drupal\entity\EntityInterface::isDefaultRevision().
*/
public function isCurrentRevision($new_value = NULL) {
$return = $this->isCurrentRevision;
public function isDefaultRevision($new_value = NULL) {
$return = $this->isDefaultRevision;
if (isset($new_value)) {
$this->isCurrentRevision = (bool) $new_value;
$this->isDefaultRevision = (bool) $new_value;
}
return $return;
}
......
......@@ -209,14 +209,14 @@ public function entityInfo();
public function getRevisionId();
/**
* Checks if this entity is the current revision.
* Checks if this entity is the default revision.
*
* @param bool $new_value
* (optional) A Boolean to (re)set the isCurrentRevision flag.
* (optional) A Boolean to (re)set the isDefaultRevision flag.
*
* @return bool
* TRUE if the entity is the current revision, FALSE otherwise. If
* TRUE if the entity is the default revision, FALSE otherwise. If
* $new_value was passed, the previous value is returned.
*/
public function isCurrentRevision($new_value = NULL);
public function isDefaultRevision($new_value = NULL);
}
......@@ -400,11 +400,15 @@ 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.
if ($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 +457,11 @@ 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.
if ($entity->isDefaultRevision()) {
$query->execute();
}
$revision_query->execute();
}
}
......
......@@ -29,6 +29,16 @@ class Node extends Entity implements ContentEntityInterface {
*/
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.
*
......
......@@ -100,7 +100,16 @@ public function save(EntityInterface $entity) {
}
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 @@ protected function saveRevision(EntityInterface $entity) {
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,9 +272,13 @@ protected function preSave(EntityInterface $node) {
* Overrides Drupal\entity\DatabaseStorageController::postSave().
*/
function postSave(EntityInterface $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);
}
}
/**
* Overrides Drupal\entity\DatabaseStorageController::preDelete().
*/
......
......@@ -24,13 +24,14 @@ function setUp() {
// 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.
$node = $this->drupalCreateNode();
$settings = get_object_vars($node);
$settings['revision'] = 1;
$settings['isDefaultRevision'] = TRUE;
$nodes = array();
$logs = array();
......@@ -47,6 +48,7 @@ function setUp() {
$this->drupalCreateNode($settings);
$node = node_load($node->nid); // Make sure we get revision information.
$settings = get_object_vars($node);
$settings['isDefaultRevision'] = TRUE;
$nodes[] = $node;
}
......@@ -75,8 +77,8 @@ function testRevisions() {
$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 +88,9 @@ function testRevisions() {
$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 +114,33 @@ function testRevisions() {
'%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 new revision that is not "front facing".
$new_node_revision = clone $node;
$new_body = $this->randomName();
$new_node_revision->body[LANGUAGE_NOT_SPECIFIED][0]['value'] = $new_body;
// Save this as a non-default revision.
$new_node_revision->revision = TRUE;
$new_node_revision->isDefaultRevision = FALSE;
node_save($new_node_revision);
$this->drupalGet("node/$node->nid");
$this->assertNoText($new_body, t('Revision body text is not present on default version of node.'));
// Verify that the new body text is present on the revision.
$this->drupalGet("node/$node->nid/revisions/" . $new_node_revision->vid . "/view");
$this->assertText($new_body, t('Revision body text is present when loading specific revision.'));
// Verify that the non-default 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($new_node_revision->vid > $default_revision_vid, 'Revision vid is greater than default revision vid.');
}
/**
......
......@@ -1129,8 +1129,8 @@ function node_delete_multiple($nids) {
*/
function node_revision_delete($revision_id) {
if ($revision = node_revision_load($revision_id)) {
// Prevent deleting the current revision.
if ($revision->isCurrentRevision()) {
// Prevent deleting the default revision.
if ($revision->isDefaultRevision()) {
return FALSE;
}
......@@ -1795,20 +1795,20 @@ function _node_revision_access(Node $node, $op = 'view', $account = NULL, $langc
}
// There should be at least two revisions. If the vid of the given node
// and the vid of the current revision differ, then we already have two
// and the vid of the default revision differ, then we already have two
// different revisions so there is no need for a separate database check.
// Also, if you try to revert to or delete the current revision, that's
// Also, if you try to revert to or delete the default revision, that's
// not good.
if ($node->isCurrentRevision() && (db_query('SELECT COUNT(vid) FROM {node_revision} WHERE nid = :nid', array(':nid' => $node->nid))->fetchField() == 1 || $op == 'update' || $op == 'delete')) {
if ($node->isDefaultRevision() && (db_query('SELECT COUNT(vid) FROM {node_revision} WHERE nid = :nid', array(':nid' => $node->nid))->fetchField() == 1 || $op == 'update' || $op == 'delete')) {
$access[$cid] = FALSE;
}
elseif (user_access('administer nodes', $account)) {
$access[$cid] = TRUE;
}
else {
// First check the access to the current revision and finally, if the
// node passed in is not the current revision then access to that, too.
$access[$cid] = node_access($op, node_load($node->nid), $account, $langcode) && ($node->isCurrentRevision() || node_access($op, $node, $account, $langcode));
// First check the access to the default revision and finally, if the
// node passed in is not the default revision then access to that, too.
$access[$cid] = node_access($op, node_load($node->nid), $account, $langcode) && ($node->isDefaultRevision() || node_access($op, $node, $account, $langcode));
}
}
......
......@@ -291,6 +291,8 @@ function node_revision_revert_confirm($form, $form_state, $node_revision) {
function node_revision_revert_confirm_submit($form, &$form_state) {
$node_revision = $form['#node_revision'];
$node_revision->revision = 1;
// Make this the new default revision for the node.
$node_revision->isDefaultRevision = TRUE;
// The revision timestamp will be updated when the revision is saved. Keep the
// original one for the confirmation message.
......
......@@ -1665,7 +1665,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) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment