Issue #218755 by jstoller, Gábor Hojtsy, stevector, mradcliffe, agentrickard, catch, Crell: Added Support revisions in different states.
parent
5f4440fa7d
commit
e203b73b62
|
@ -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 @@ 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);
|
||||
|
|
|
@ -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 @@ class Entity implements EntityInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* 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 @@ interface EntityInterface {
|
|||
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 @@ 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,9 +272,13 @@ class NodeStorageController extends DatabaseStorageController {
|
|||
* 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 @@ 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.
|
||||
$node = $this->drupalCreateNode();
|
||||
$settings = get_object_vars($node);
|
||||
$settings['revision'] = 1;
|
||||
$settings['isDefaultRevision'] = TRUE;
|
||||
|
||||
$nodes = array();
|
||||
$logs = array();
|
||||
|
@ -47,6 +48,7 @@ class NodeRevisionsTest extends NodeTestBase {
|
|||
$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 @@ 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 +88,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 +114,33 @@ 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 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) {
|
||||
|
|
Loading…
Reference in New Issue