diff --git a/core/lib/Drupal/Core/Entity/Form/RevisionableContentEntityForm.php b/core/lib/Drupal/Core/Entity/Form/RevisionableContentEntityForm.php
new file mode 100644
index 0000000..33ae55b
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Form/RevisionableContentEntityForm.php
@@ -0,0 +1,150 @@
+entity->isNew()) {
+ $this->entity->setRevisionLogMessage(NULL);
+ }
+ }
+
+ /**
+ * Returns the bundle entity of the entity, or NULL if there is none.
+ *
+ * @return \Drupal\Core\Entity\EntityInterface|null
+ */
+ protected function getBundleEntity() {
+ if ($bundle_entity_type = $this->entity->getEntityType()->getBundleEntityType()) {
+ return $this->entityTypeManager->getStorage($bundle_entity_type)->load($this->entity->bundle());
+ }
+ return NULL;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function form(array $form, FormStateInterface $form_state) {
+ $entity_type = $this->entity->getEntityType();
+ $bundle_entity = $this->getBundleEntity();
+ $account = $this->currentUser();
+ if ($this->operation == 'edit') {
+ $form['#title'] = $this->t('Edit %bundle_label @label', [
+ '%bundle_label' => $bundle_entity ? $bundle_entity->label() : '',
+ '@label' => $this->entity->label(),
+ ]);
+ }
+ $form['advanced'] = [
+ '#type' => 'vertical_tabs',
+ '#attributes' => array('class' => array('entity-meta')),
+ '#weight' => 99,
+ ];
+
+ $new_revision_default = FALSE;
+ $bundle_entity = $this->getBundleEntity();
+ if ($bundle_entity instanceof RevisionableEntityBundleInterface) {
+ // Always use the default revision setting.
+ $new_revision_default = $bundle_entity->shouldCreateNewRevision();
+ }
+
+ // Add a log field if the "Create new revision" option is checked, or if the
+ // current user has the ability to check that option.
+ // @todo Could we autogenerate this form by using some widget on the
+ // revision info field.
+ $form['revision_information'] = [
+ '#type' => 'details',
+ '#title' => $this->t('Revision information'),
+ // Open by default when "Create new revision" is checked.
+ '#open' => $new_revision_default,
+ '#group' => 'advanced',
+ '#weight' => 20,
+ '#access' => $new_revision_default || ($entity_type->get('admin_permission')) && $account->hasPermission($entity_type->get('admin_permission')),
+ '#optional' => TRUE,
+ ];
+ $form['revision'] = [
+ '#type' => 'checkbox',
+ '#title' => $this->t('Create new revision'),
+ '#default_value' => $new_revision_default,
+ '#access' => !$this->entity->isNew() && ($entity_type->get('admin_permission') || $account->hasPermission($entity_type->get('admin_permission'))),
+ '#group' => 'revision_information',
+ ];
+
+ // Check the revision log checkbox when the log textarea is filled in.
+ // This must not happen if "Create new revision" is enabled by default,
+ // since the state would auto-disable the checkbox otherwise.
+ if (!$this->entity->isNewRevision()) {
+ $form['revision']['#states'] = [
+ 'checked' => [
+ 'textarea[name="revision_log"]' => ['empty' => FALSE],
+ ],
+ ];
+ }
+
+ if (isset($form['revision_log'])) {
+ $form['revision_log']['#group'] = 'revision_information';
+ }
+
+ return parent::form($form, $form_state);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function save(array $form, FormStateInterface $form_state) {
+ // Save as a new revision if requested to do so.
+ if (!$form_state->isValueEmpty('revision')) {
+ $this->entity->setNewRevision();
+ }
+
+ $insert = $this->entity->isNew();
+ $this->entity->save();
+
+ $context = ['@type' => $this->entity->bundle(), '%info' => $this->entity->label()];
+ $logger = $this->logger($this->entity->getEntityTypeId());
+ $bundle_entity = $this->getBundleEntity();
+ $t_args = ['@type' => $bundle_entity ? $bundle_entity->label() : $this->entity->getEntityType()->getLabel(), '%label' => $this->entity->label()];
+
+ if ($insert) {
+ $logger->notice('@type: added %info.', $context);
+ drupal_set_message($this->t('@type %label has been created.', $t_args));
+ }
+ else {
+ $logger->notice('@type: updated %info.', $context);
+ drupal_set_message($this->t('@type %label has been updated.', $t_args));
+ }
+
+ if ($this->entity->getEntityType()->hasLinkTemplate('collection')) {
+ $form_state->setRedirectUrl($this->entity->toUrl('collection'));
+ }
+ else {
+ $form_state->setRedirectUrl($this->entity->toUrl('canonical'));
+ }
+ }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/RevisionableEntityBundleInterface.php b/core/lib/Drupal/Core/Entity/RevisionableEntityBundleInterface.php
new file mode 100644
index 0000000..9d7ef07
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/RevisionableEntityBundleInterface.php
@@ -0,0 +1,22 @@
+blockContentStorage = $block_content_storage;
- $this->blockContentTypeStorage = $block_content_type_storage;
- $this->languageManager = $language_manager;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container) {
- $entity_manager = $container->get('entity.manager');
- return new static(
- $entity_manager,
- $entity_manager->getStorage('block_content'),
- $entity_manager->getStorage('block_content_type'),
- $container->get('language_manager')
- );
- }
-
- /**
- * Overrides \Drupal\Core\Entity\EntityForm::prepareEntity().
- *
- * Prepares the custom block object.
- *
- * Fills in a few default values, and then invokes
- * hook_block_content_prepare() on all modules.
- */
- protected function prepareEntity() {
- $block = $this->entity;
- // Set up default values, if required.
- $block_type = $this->blockContentTypeStorage->load($block->bundle());
- if (!$block->isNew()) {
- $block->setRevisionLogMessage(NULL);
- }
- // Always use the default revision setting.
- $block->setNewRevision($block_type->shouldCreateNewRevision());
- }
-
- /**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
$block = $this->entity;
- $account = $this->currentUser();
+
+ $form = parent::form($form, $form_state);
if ($this->operation == 'edit') {
$form['#title'] = $this->t('Edit custom block %label', array('%label' => $block->label()));
@@ -109,56 +34,12 @@ public function form(array $form, FormStateInterface $form_state) {
// names.
$form['#attributes']['class'][0] = 'block-' . Html::getClass($block->bundle()) . '-form';
- $form['advanced'] = array(
- '#type' => 'vertical_tabs',
- '#weight' => 99,
- );
-
// Add a log field if the "Create new revision" option is checked, or if the
// current user has the ability to check that option.
- $form['revision_information'] = array(
- '#type' => 'details',
- '#title' => $this->t('Revision information'),
- // Open by default when "Create new revision" is checked.
- '#open' => $block->isNewRevision(),
- '#group' => 'advanced',
- '#attributes' => array(
- 'class' => array('block-content-form-revision-information'),
- ),
- '#attached' => array(
- 'library' => array('block_content/drupal.block_content'),
- ),
- '#weight' => 20,
- '#access' => $block->isNewRevision() || $account->hasPermission('administer blocks'),
- );
+ $form['revision_information']['#attributes']['class'][] = 'block-content-form-revision-information';
+ $form['revision_information']['#attached']['library'][] = 'block_content/drupal.block_content';
- $form['revision_information']['revision'] = array(
- '#type' => 'checkbox',
- '#title' => $this->t('Create new revision'),
- '#default_value' => $block->isNewRevision(),
- '#access' => $account->hasPermission('administer blocks'),
- );
-
- // Check the revision log checkbox when the log textarea is filled in.
- // This must not happen if "Create new revision" is enabled by default,
- // since the state would auto-disable the checkbox otherwise.
- if (!$block->isNewRevision()) {
- $form['revision_information']['revision']['#states'] = array(
- 'checked' => array(
- 'textarea[name="revision_log"]' => array('empty' => FALSE),
- ),
- );
- }
-
- $form['revision_information']['revision_log'] = array(
- '#type' => 'textarea',
- '#title' => $this->t('Revision log message'),
- '#rows' => 4,
- '#default_value' => $block->getRevisionLog(),
- '#description' => $this->t('Briefly describe the changes you have made.'),
- );
-
- return parent::form($form, $form_state, $block);
+ return $form;
}
/**
@@ -166,55 +47,21 @@ public function form(array $form, FormStateInterface $form_state) {
*/
public function save(array $form, FormStateInterface $form_state) {
$block = $this->entity;
-
- // Save as a new revision if requested to do so.
- if (!$form_state->isValueEmpty('revision')) {
- $block->setNewRevision();
- // If a new revision is created, save the current user as revision author.
- $block->setRevisionCreationTime(REQUEST_TIME);
- $block->setRevisionUserId(\Drupal::currentUser()->id());
- }
-
$insert = $block->isNew();
- $block->save();
- $context = array('@type' => $block->bundle(), '%info' => $block->label());
- $logger = $this->logger('block_content');
- $block_type = $this->blockContentTypeStorage->load($block->bundle());
- $t_args = array('@type' => $block_type->label(), '%info' => $block->label());
+
+ parent::save($form, $form_state);
if ($insert) {
- $logger->notice('@type: added %info.', $context);
- drupal_set_message($this->t('@type %info has been created.', $t_args));
- }
- else {
- $logger->notice('@type: updated %info.', $context);
- drupal_set_message($this->t('@type %info has been updated.', $t_args));
- }
-
- if ($block->id()) {
- $form_state->setValue('id', $block->id());
- $form_state->set('id', $block->id());
- if ($insert) {
- if (!$theme = $block->getTheme()) {
- $theme = $this->config('system.theme')->get('default');
- }
- $form_state->setRedirect(
- 'block.admin_add',
- array(
- 'plugin_id' => 'block_content:' . $block->uuid(),
- 'theme' => $theme,
- )
- );
+ if (!$theme = $block->getTheme()) {
+ $theme = $this->config('system.theme')->get('default');
}
- else {
- $form_state->setRedirectUrl($block->urlInfo('collection'));
- }
- }
- else {
- // In the unlikely case something went wrong on save, the block will be
- // rebuilt and block form redisplayed.
- drupal_set_message($this->t('The block could not be saved.'), 'error');
- $form_state->setRebuild();
+ $form_state->setRedirect(
+ 'block.admin_add',
+ array(
+ 'plugin_id' => 'block_content:' . $block->uuid(),
+ 'theme' => $theme,
+ )
+ );
}
}
diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php
index 13af342..0f50fbc 100644
--- a/core/modules/block_content/src/Entity/BlockContent.php
+++ b/core/modules/block_content/src/Entity/BlockContent.php
@@ -182,7 +182,14 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields['revision_log'] = BaseFieldDefinition::create('string_long')
->setLabel(t('Revision log message'))
->setDescription(t('The log entry explaining the changes in this revision.'))
- ->setRevisionable(TRUE);
+ ->setRevisionable(TRUE)
+ ->setDisplayOptions('form', array(
+ 'type' => 'string_textarea',
+ 'weight' => 25,
+ 'settings' => array(
+ 'rows' => 4,
+ ),
+ ));
$fields['changed'] = BaseFieldDefinition::create('changed')
->setLabel(t('Changed'))
diff --git a/core/modules/field/src/Tests/FormTest.php b/core/modules/field/src/Tests/FormTest.php
index 16625a9..f16886e 100644
--- a/core/modules/field/src/Tests/FormTest.php
+++ b/core/modules/field/src/Tests/FormTest.php
@@ -609,11 +609,11 @@ function testHiddenField() {
$this->drupalPostForm(NULL, array(), t('Save'));
preg_match('|' . $entity_type . '/manage/(\d+)|', $this->url, $match);
$id = $match[1];
- $this->assertText(t('entity_test_rev @id has been created.', array('@id' => $id)), 'Entity was created');
$storage = $this->container->get('entity_type.manager')
->getStorage($entity_type);
$entity = $storage->load($id);
+ $this->assertRaw(t('@type %label has been created.', ['@type' => 'Test entity - revisions', '%label' => $entity->label()]));
$this->assertEqual($entity->{$field_name}->value, 99, 'Default value was saved');
// Update the field to remove the default value, and switch to the default
@@ -634,7 +634,7 @@ function testHiddenField() {
$value = mt_rand(1, 127);
$edit = array("{$field_name}[0][value]" => $value);
$this->drupalPostForm(NULL, $edit, t('Save'));
- $this->assertText(t('entity_test_rev @id has been updated.', array('@id' => $id)), 'Entity was updated');
+ $this->assertRaw(t('@type %label has been updated.', ['@type' => 'Test entity - revisions', '%label' => $entity->label()]));
$storage->resetCache([$id]);
$entity = $storage->load($id);
$this->assertEqual($entity->{$field_name}->value, $value, 'Field value was updated');
diff --git a/core/modules/node/src/Entity/NodeType.php b/core/modules/node/src/Entity/NodeType.php
index 91d8a90..23f24a4 100644
--- a/core/modules/node/src/Entity/NodeType.php
+++ b/core/modules/node/src/Entity/NodeType.php
@@ -205,4 +205,11 @@ public static function postDelete(EntityStorageInterface $storage, array $entiti
$storage->resetCache(array_keys($entities));
}
+ /**
+ * {@inheritdoc}
+ */
+ public function shouldCreateNewRevision() {
+ return $this->isNewRevision();
+ }
+
}
diff --git a/core/modules/node/src/NodeForm.php b/core/modules/node/src/NodeForm.php
index 2828030..c76172c 100644
--- a/core/modules/node/src/NodeForm.php
+++ b/core/modules/node/src/NodeForm.php
@@ -4,6 +4,7 @@
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\Form\RevisionableContentEntityForm;
use Drupal\Core\Form\FormStateInterface;
use Drupal\user\PrivateTempStoreFactory;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -11,7 +12,7 @@
/**
* Form handler for the node edit forms.
*/
-class NodeForm extends ContentEntityForm {
+class NodeForm extends RevisionableContentEntityForm {
/**
* The tempstore factory.
@@ -51,19 +52,6 @@ public static function create(ContainerInterface $container) {
/**
* {@inheritdoc}
*/
- protected function prepareEntity() {
- /** @var \Drupal\node\NodeInterface $node */
- $node = $this->entity;
-
- if (!$node->isNew()) {
- // Remove the revision log message from the original node entity.
- $node->revision_log = NULL;
- }
- }
-
- /**
- * {@inheritdoc}
- */
public function form(array $form, FormStateInterface $form_state) {
// Try to restore from temp store, this must be done before calling
// parent::form().
@@ -98,10 +86,6 @@ public function form(array $form, FormStateInterface $form_state) {
/** @var \Drupal\node\NodeInterface $node */
$node = $this->entity;
- if ($this->operation == 'edit') {
- $form['#title'] = $this->t('Edit @type @title', array('@type' => node_get_type_label($node), '@title' => $node->label()));
- }
-
$current_user = $this->currentUser();
// Changed must be sent to the client, for later overwrite error checking.
@@ -110,38 +94,16 @@ public function form(array $form, FormStateInterface $form_state) {
'#default_value' => $node->getChangedTime(),
);
- $form['advanced'] = array(
- '#type' => 'vertical_tabs',
- '#attributes' => array('class' => array('entity-meta')),
- '#weight' => 99,
- );
$form = parent::form($form, $form_state);
- // Add a revision_log field if the "Create new revision" option is checked,
- // or if the current user has the ability to check that option.
- $form['revision_information'] = array(
- '#type' => 'details',
- '#group' => 'advanced',
- '#title' => t('Revision information'),
- // Open by default when "Create new revision" is checked.
- '#open' => $node->isNewRevision(),
- '#attributes' => array(
- 'class' => array('node-form-revision-information'),
- ),
- '#attached' => array(
- 'library' => array('node/drupal.node'),
- ),
- '#weight' => 20,
- '#optional' => TRUE,
- );
+ if ($this->operation == 'edit') {
+ $form['#title'] = $this->t('Edit @type @title', array('@type' => node_get_type_label($node), '@title' => $node->label()));
+ }
- $form['revision'] = array(
- '#type' => 'checkbox',
- '#title' => t('Create new revision'),
- '#default_value' => $node->type->entity->isNewRevision(),
- '#access' => $current_user->hasPermission('administer nodes') && !$node->isNew(),
- '#group' => 'revision_information',
- );
+ $form['revision_information']['#attributes']['class'][] = 'node-form-revision-information';
+ $form['revision_information']['#attached']['library'][] = 'node/drupal.node';
+
+ $form['revision']['#access'] = $current_user->hasPermission('administer nodes') && !$node->isNew();
$form['revision_log'] += array(
'#states' => array(
@@ -149,7 +111,6 @@ public function form(array $form, FormStateInterface $form_state) {
':input[name="revision"]' => array('checked' => TRUE),
),
),
- '#group' => 'revision_information',
);
// Node author information for administrators.
diff --git a/core/modules/node/src/NodeTypeInterface.php b/core/modules/node/src/NodeTypeInterface.php
index c034ffb..882c080 100644
--- a/core/modules/node/src/NodeTypeInterface.php
+++ b/core/modules/node/src/NodeTypeInterface.php
@@ -3,11 +3,12 @@
namespace Drupal\node;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\Core\Entity\RevisionableEntityBundleInterface;
/**
* Provides an interface defining a node type entity.
*/
-interface NodeTypeInterface extends ConfigEntityInterface {
+interface NodeTypeInterface extends ConfigEntityInterface, RevisionableEntityBundleInterface {
/**
* Determines whether the node type is locked.
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php
index 47035ea..4291ce6 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php
@@ -15,7 +15,7 @@
* "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
* "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
* "form" = {
- * "default" = "Drupal\entity_test\EntityTestForm",
+ * "default" = "\Drupal\entity_test\EntityTestRevisionForm",
* "delete" = "Drupal\entity_test\EntityTestDeleteForm"
* },
* "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
@@ -53,13 +53,6 @@ class EntityTestRev extends EntityTest {
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields = parent::baseFieldDefinitions($entity_type);
- $fields['revision_id'] = BaseFieldDefinition::create('integer')
- ->setLabel(t('Revision ID'))
- ->setDescription(t('The version id of the test entity.'))
- ->setReadOnly(TRUE)
- ->setSetting('unsigned', TRUE);
-
- $fields['langcode']->setRevisionable(TRUE);
$fields['name']->setRevisionable(TRUE);
$fields['user_id']->setRevisionable(TRUE);
diff --git a/core/modules/system/tests/modules/entity_test/src/EntityTestRevisionForm.php b/core/modules/system/tests/modules/entity_test/src/EntityTestRevisionForm.php
new file mode 100644
index 0000000..180f137
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/src/EntityTestRevisionForm.php
@@ -0,0 +1,40 @@
+entity->name->value)) {
+ // Assign a random name to new EntityTest entities, to avoid repetition in
+ // tests.
+ $random = new Random();
+ $this->entity->name->value = $random->name();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function save(array $form, FormStateInterface $form_state) {
+ try {
+ parent::save($form, $form_state);
+ }
+ catch (\Exception $e) {
+ \Drupal::state()->set('entity_test.form.save.exception', get_class($e) . ': ' . $e->getMessage());
+ }
+ }
+
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php
index 23cf034..befa0f0 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php
@@ -102,6 +102,9 @@ public function testEntityTypeUpdateWithoutData() {
$expected = array(
'entity_test_update' => array(
t('The %entity_type entity type needs to be updated.', ['%entity_type' => $this->entityManager->getDefinition('entity_test_update')->getLabel()]),
+ // The revision key is now defined, so the revision field needs to be
+ // created.
+ t('The %field_name field needs to be installed.', ['%field_name' => 'Revision ID']),
),
);
$this->assertEqual($this->entityDefinitionUpdateManager->getChangeSummary(), $expected); //, 'EntityDefinitionUpdateManager reports the expected change summary.');