diff --git a/core/core.libraries.yml b/core/core.libraries.yml index ce12db5..c4ca44c 100644 --- a/core/core.libraries.yml +++ b/core/core.libraries.yml @@ -203,6 +203,15 @@ drupal.dropbutton: - core/drupalSettings - core/jquery.once +drupal.entity-form: + version: VERSION + js: + misc/entity-form.js: {} + dependencies: + - core/jquery + - core/drupal + - core/drupal.form + drupal.form: version: VERSION js: diff --git a/core/lib/Drupal/Core/Entity/ContentEntityForm.php b/core/lib/Drupal/Core/Entity/ContentEntityForm.php index 29b0a9b..ff07277 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityForm.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityForm.php @@ -2,6 +2,7 @@ namespace Drupal\Core\Entity; +use Drupal\Component\Datetime\TimeInterface; use Drupal\Core\Entity\Display\EntityFormDisplayInterface; use Drupal\Core\Entity\Entity\EntityFormDisplay; use Drupal\Core\Form\FormStateInterface; @@ -22,13 +23,41 @@ class ContentEntityForm extends EntityForm implements ContentEntityFormInterface protected $entityManager; /** + * The entity being used by this form. + * + * @var \Drupal\Core\Entity\ContentEntityInterface|\Drupal\Core\Entity\RevisionLogInterface + */ + protected $entity; + + /** + * The entity type bundle info service. + * + * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface + */ + protected $entityTypeBundleInfo; + + /** + * The time service. + * + * @var \Drupal\Component\Datetime\TimeInterface + */ + protected $time; + + /** * Constructs a ContentEntityForm object. * * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager * The entity manager. + * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info + * The entity type bundle service. + * @param \Drupal\Component\Datetime\TimeInterface $time + * The time service. */ - public function __construct(EntityManagerInterface $entity_manager) { + public function __construct(EntityManagerInterface $entity_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL) { $this->entityManager = $entity_manager; + + $this->entityTypeBundleInfo = $entity_type_bundle_info ?: \Drupal::service('entity_type.bundle.info'); + $this->time = $time ?: \Drupal::service('datetime.time'); } /** @@ -36,15 +65,54 @@ public function __construct(EntityManagerInterface $entity_manager) { */ public static function create(ContainerInterface $container) { return new static( - $container->get('entity.manager') + $container->get('entity.manager'), + $container->get('entity_type.bundle.info'), + $container->get('datetime.time') ); } /** * {@inheritdoc} */ + protected function prepareEntity() { + parent::prepareEntity(); + + // Hide the current revision log message in UI. + if ($this->showRevisionUi() && !$this->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 + * The bundle entity. + */ + 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) { + + if ($this->showRevisionUi()) { + // Advanced tab must be the first, because other fields rely on that. + if (!isset($form['advanced'])) { + $form['advanced'] = [ + '#type' => 'vertical_tabs', + '#weight' => 99, + ]; + } + } + $form = parent::form($form, $form_state); + // Content entity forms do not use the parent's #after_build callback // because they only need to rebuild the entity in the validation and the // submit handler because Field API uses its own #after_build callback for @@ -54,6 +122,11 @@ public function form(array $form, FormStateInterface $form_state) { $this->getFormDisplay($form_state)->buildForm($this->entity, $form, $form_state); // Allow modules to act before and after form language is updated. $form['#entity_builders']['update_form_langcode'] = '::updateFormLangcode'; + + if ($this->showRevisionUi()) { + $this->addRevisionableFormFields($form); + } + return $form; } @@ -76,6 +149,17 @@ public function buildEntity(array $form, FormStateInterface $form_state) { // Mark the entity as requiring validation. $entity->setValidationRequired(!$form_state->getTemporaryValue('entity_validated')); + // Save as a new revision if requested to do so. + if ($this->showRevisionUi() && !$form_state->isValueEmpty('revision')) { + $entity->setNewRevision(); + if ($entity instanceof RevisionLogInterface) { + // If a new revision is created, save the current user as + // revision author. + $entity->setRevisionUserId($this->currentUser()->id()); + $entity->setRevisionCreationTime($this->time->getRequestTime()); + } + } + return $entity; } @@ -283,8 +367,84 @@ public function updateFormLangcode($entity_type_id, EntityInterface $entity, arr */ public function updateChangedTime(EntityInterface $entity) { if ($entity->getEntityType()->isSubclassOf(EntityChangedInterface::class)) { - $entity->setChangedTime(REQUEST_TIME); + $entity->setChangedTime($this->time->getRequestTime()); } } + /** + * Add revision form fields if the entity enabled the UI. + * + * @param array $form + * An associative array containing the structure of the form. + */ + protected function addRevisionableFormFields(&$form) { + $entity_type = $this->entity->getEntityType(); + + $new_revision_default = $this->getNewRevisionDefault(); + + // 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'] = [ + '#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 || $this->entity->get($entity_type->getKey('revision'))->access('update'), + '#optional' => TRUE, + '#attributes' => [ + 'class' => ['entity-content-form-revision-information'], + ], + '#attached' => [ + 'library' => ['core/drupal.entity-form'], + ], + ]; + + $form['revision'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Create new revision'), + '#default_value' => $new_revision_default, + '#access' => !$this->entity->isNew() && $this->entity->get($entity_type->getKey('revision'))->access('update'), + '#group' => 'revision_information', + ]; + + if (isset($form['revision_log'])) { + $form['revision_log'] += [ + '#group' => 'revision_information', + '#states' => [ + 'visible' => [ + ':input[name="revision"]' => ['checked' => TRUE], + ], + ], + ]; + } + } + + /** + * Should new revisions created on default. + * + * @return bool + * New revision on default. + */ + protected function getNewRevisionDefault() { + $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(); + } + return $new_revision_default; + } + + /** + * Checks whether the revision form fields should be added to the form. + * + * @return bool + * TRUE if the form field should be added, FALSE otherwise. + */ + protected function showRevisionUi() { + return $this->entity->getEntityType()->showRevisionUi(); + } + } diff --git a/core/lib/Drupal/Core/Entity/EntityType.php b/core/lib/Drupal/Core/Entity/EntityType.php index 89b83cf..78fb2ff 100644 --- a/core/lib/Drupal/Core/Entity/EntityType.php +++ b/core/lib/Drupal/Core/Entity/EntityType.php @@ -175,6 +175,13 @@ class EntityType implements EntityTypeInterface { protected $translatable = FALSE; /** + * Indicates whether the revision form fields should be added to the form. + * + * @var bool + */ + protected $show_revision_ui = FALSE; + + /** * The human-readable name of the type. * * @var string @@ -692,6 +699,13 @@ public function getBaseTable() { /** * {@inheritdoc} */ + public function showRevisionUi() { + return $this->isRevisionable() && $this->show_revision_ui; + } + + /** + * {@inheritdoc} + */ public function isTranslatable() { return !empty($this->translatable); } diff --git a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php index c6336c9..60d60b5 100644 --- a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php @@ -574,6 +574,14 @@ public function getBaseTable(); public function isTranslatable(); /** + * Indicates whether the revision form fields should be added to the form. + * + * @return bool + * TRUE if the form field should be added, FALSE otherwise. + */ + public function showRevisionUi(); + + /** * Indicates whether entities of this type have revision support. * * @return bool diff --git a/core/lib/Drupal/Core/Entity/RevisionableEntityBundleInterface.php b/core/lib/Drupal/Core/Entity/RevisionableEntityBundleInterface.php new file mode 100644 index 0000000..caf44f2 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/RevisionableEntityBundleInterface.php @@ -0,0 +1,20 @@ +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,7 @@ 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']['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; } /** @@ -167,19 +43,11 @@ 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()); + $block_type = $this->getBundleEntity(); $t_args = array('@type' => $block_type->label(), '%info' => $block->label()); if ($insert) { diff --git a/core/modules/block_content/src/BlockContentTranslationHandler.php b/core/modules/block_content/src/BlockContentTranslationHandler.php index 781ba1b..b446cde 100644 --- a/core/modules/block_content/src/BlockContentTranslationHandler.php +++ b/core/modules/block_content/src/BlockContentTranslationHandler.php @@ -5,7 +5,6 @@ use Drupal\block_content\Entity\BlockContentType; use Drupal\Core\Entity\EntityInterface; use Drupal\content_translation\ContentTranslationHandler; -use Drupal\Core\Form\FormStateInterface; /** * Defines the translation handler for custom blocks. @@ -15,23 +14,6 @@ class BlockContentTranslationHandler extends ContentTranslationHandler { /** * {@inheritdoc} */ - public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity) { - parent::entityFormAlter($form, $form_state, $entity); - // Move the translation fieldset to a vertical tab. - if (isset($form['translation'])) { - $form['translation'] += array( - '#group' => 'additional_settings', - '#weight' => 100, - '#attributes' => array( - 'class' => array('block-content-translation-options'), - ), - ); - } - } - - /** - * {@inheritdoc} - */ protected function entityFormTitle(EntityInterface $entity) { $block_type = BlockContentType::load($entity->bundle()); return t('Edit @type @title', array('@type' => $block_type->label(), '@title' => $entity->label())); diff --git a/core/modules/block_content/src/BlockContentTypeInterface.php b/core/modules/block_content/src/BlockContentTypeInterface.php index 9229dab..da3864e 100644 --- a/core/modules/block_content/src/BlockContentTypeInterface.php +++ b/core/modules/block_content/src/BlockContentTypeInterface.php @@ -3,11 +3,12 @@ namespace Drupal\block_content; use Drupal\Core\Config\Entity\ConfigEntityInterface; +use Drupal\Core\Entity\RevisionableEntityBundleInterface; /** * Provides an interface defining a custom block type entity. */ -interface BlockContentTypeInterface extends ConfigEntityInterface { +interface BlockContentTypeInterface extends ConfigEntityInterface, RevisionableEntityBundleInterface { /** * Returns the description of the block type. @@ -17,12 +18,4 @@ */ public function getDescription(); - /** - * Returns whether a new revision should be created by default. - * - * @return bool - * TRUE if a new revision should be created by default. - */ - public function shouldCreateNewRevision(); - } diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php index 13af342..51ae6f6 100644 --- a/core/modules/block_content/src/Entity/BlockContent.php +++ b/core/modules/block_content/src/Entity/BlockContent.php @@ -35,6 +35,7 @@ * base_table = "block_content", * revision_table = "block_content_revision", * data_table = "block_content_field_data", + * show_revision_ui = TRUE, * links = { * "canonical" = "/block/{block_content}", * "delete-form" = "/block/{block_content}/delete", @@ -182,7 +183,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/content_translation/src/ContentTranslationHandler.php b/core/modules/content_translation/src/ContentTranslationHandler.php index 6fd2254..7995125 100644 --- a/core/modules/content_translation/src/ContentTranslationHandler.php +++ b/core/modules/content_translation/src/ContentTranslationHandler.php @@ -384,6 +384,16 @@ public function entityFormAlter(array &$form, FormStateInterface $form_state, En '#multilingual' => TRUE, ); + if (isset($form['advanced'])) { + $form['content_translation'] += array( + '#group' => 'advanced', + '#weight' => 100, + '#attributes' => array( + 'class' => array('entity-translation-options'), + ), + ); + } + // A new translation is enabled by default. $metadata = $this->manager->getTranslationMetadata($entity); $status = $new_translation || $metadata->isPublished(); diff --git a/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php b/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php index ed372a9..029ca49 100644 --- a/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php +++ b/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php @@ -49,7 +49,7 @@ class MenuLinkContentForm extends ContentEntityForm { * The path validator. */ public function __construct(EntityManagerInterface $entity_manager, MenuParentFormSelectorInterface $menu_parent_selector, LanguageManagerInterface $language_manager, PathValidatorInterface $path_validator) { - parent::__construct($entity_manager, $language_manager); + parent::__construct($entity_manager); $this->menuParentSelector = $menu_parent_selector; $this->pathValidator = $path_validator; } diff --git a/core/modules/node/node.js b/core/modules/node/node.js index 98af6fd..086263d 100644 --- a/core/modules/node/node.js +++ b/core/modules/node/node.js @@ -18,21 +18,6 @@ Drupal.behaviors.nodeDetailsSummaries = { attach: function (context) { var $context = $(context); - $context.find('.node-form-revision-information').drupalSetSummary(function (context) { - var $revisionContext = $(context); - var revisionCheckbox = $revisionContext.find('.js-form-item-revision input'); - - // Return 'New revision' if the 'Create new revision' checkbox is - // checked, or if the checkbox doesn't exist, but the revision log does. - // For users without the "Administer content" permission the checkbox - // won't appear, but the revision log will if the content type is set to - // auto-revision. - if (revisionCheckbox.is(':checked') || (!revisionCheckbox.length && $revisionContext.find('.js-form-item-revision-log textarea').length)) { - return Drupal.t('New revision'); - } - - return Drupal.t('No revision'); - }); $context.find('.node-form-author').drupalSetSummary(function (context) { var $authorContext = $(context); @@ -64,22 +49,6 @@ return Drupal.t('Not promoted'); } }); - - $context.find('fieldset.node-translation-options').drupalSetSummary(function (context) { - var $translationContext = $(context); - var translate; - var $checkbox = $translationContext.find('.js-form-item-translation-translate input'); - - if ($checkbox.size()) { - translate = $checkbox.is(':checked') ? Drupal.t('Needs to be updated') : Drupal.t('Does not need to be updated'); - } - else { - $checkbox = $translationContext.find('.js-form-item-translation-retranslate input'); - translate = $checkbox.is(':checked') ? Drupal.t('Flag other translations as outdated') : Drupal.t('Do not flag other translations as outdated'); - } - - return translate; - }); } }; diff --git a/core/modules/node/node.libraries.yml b/core/modules/node/node.libraries.yml index 22c93ac..59947a2 100644 --- a/core/modules/node/node.libraries.yml +++ b/core/modules/node/node.libraries.yml @@ -6,10 +6,8 @@ drupal.node: js: node.js: {} dependencies: - - core/jquery - - core/drupal + - core/drupal.entity-form - core/drupalSettings - - core/drupal.form drupal.node.preview: version: VERSION diff --git a/core/modules/node/src/Entity/Node.php b/core/modules/node/src/Entity/Node.php index f034957..68afc83 100644 --- a/core/modules/node/src/Entity/Node.php +++ b/core/modules/node/src/Entity/Node.php @@ -46,6 +46,7 @@ * data_table = "node_field_data", * revision_table = "node_revision", * revision_data_table = "node_field_revision", + * show_revision_ui = TRUE, * translatable = TRUE, * list_cache_contexts = { "user.node_grants:view" }, * entity_keys = { 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..4193923 100644 --- a/core/modules/node/src/NodeForm.php +++ b/core/modules/node/src/NodeForm.php @@ -26,7 +26,7 @@ class NodeForm extends ContentEntityForm { protected $hasBeenPreviewed = FALSE; /** - * Constructs a ContentEntityForm object. + * Constructs a NodeForm object. * * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager * The entity manager. @@ -51,19 +51,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(). @@ -102,55 +89,15 @@ public function form(array $form, FormStateInterface $form_state) { $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. $form['changed'] = array( '#type' => 'hidden', '#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, - ); - - $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_log'] += array( - '#states' => array( - 'visible' => array( - ':input[name="revision"]' => array('checked' => TRUE), - ), - ), - '#group' => 'revision_information', - ); + $form['advanced']['#attributes']['class'][] = 'entity-meta'; // Node author information for administrators. $form['author'] = array( @@ -304,32 +251,6 @@ protected function actions(array $form, FormStateInterface $form_state) { } /** - * {@inheritdoc} - * - * Updates the node object by processing the submitted values. - * - * This function can be called by a "Next" button of a wizard to update the - * form state's entity with the current step's values before proceeding to the - * next step. - */ - public function submitForm(array &$form, FormStateInterface $form_state) { - // Build the node object from the submitted values. - parent::submitForm($form, $form_state); - $node = $this->entity; - - // Save as a new revision if requested to do so. - if (!$form_state->isValueEmpty('revision') && $form_state->getValue('revision') != FALSE) { - $node->setNewRevision(); - // If a new revision is created, save the current user as revision author. - $node->setRevisionCreationTime(REQUEST_TIME); - $node->setRevisionUserId(\Drupal::currentUser()->id()); - } - else { - $node->setNewRevision(FALSE); - } - } - - /** * Form submission handler for the 'preview' action. * * @param $form diff --git a/core/modules/node/src/NodeTranslationHandler.php b/core/modules/node/src/NodeTranslationHandler.php index 9c9741e..2f6d2ab 100644 --- a/core/modules/node/src/NodeTranslationHandler.php +++ b/core/modules/node/src/NodeTranslationHandler.php @@ -17,17 +17,7 @@ class NodeTranslationHandler extends ContentTranslationHandler { public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity) { parent::entityFormAlter($form, $form_state, $entity); - // Move the translation fieldset to a vertical tab. if (isset($form['content_translation'])) { - $form['content_translation'] += array( - '#group' => 'advanced', - '#attributes' => array( - 'class' => array('node-translation-options'), - ), - ); - - $form['content_translation']['#weight'] = 100; - // We do not need to show these values on node forms: they inherit the // basic node property values. $form['content_translation']['status']['#access'] = FALSE; diff --git a/core/modules/node/src/NodeTypeInterface.php b/core/modules/node/src/NodeTypeInterface.php index c034ffb..df4831e 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. @@ -22,13 +23,17 @@ public function isLocked(); * * @return bool * TRUE if a new revision should be created by default. + * + * @deprecated in Drupal 8.3.0 and will be removed before Drupal 9.0.0. Use + * Drupal\Core\Entity\RevisionableEntityBundleInterface::shouldCreateNewRevision() + * instead. */ public function isNewRevision(); /** * Sets whether a new revision should be created by default. * - * @param bool $new_revision_ + * @param bool $new_revision * TRUE if a new revision should be created by default. */ public function setNewRevision($new_revision); diff --git a/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php b/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php index 0f84d3d..2f5c20a 100644 --- a/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php +++ b/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php @@ -29,7 +29,7 @@ class EntitySerializationTest extends NormalizerTestBase { /** * The test entity. * - * @var \Drupal\Core\Entity\ContentEntityBase + * @var \Drupal\Core\Entity\ContentEntityInterface|\Drupal\Core\Entity\RevisionLogInterface */ protected $entity; @@ -76,6 +76,10 @@ protected function setUp() { 'value' => $this->randomMachineName(), 'format' => 'full_html', ), + 'revision_log_message' => array( + 'value' => 'Serialization revision message', + ), + 'revision_user' => $this->user->id(), ); $this->entity = EntityTestMulRev::create($this->values); $this->entity->save(); @@ -123,6 +127,20 @@ public function testNormalize() { array('value' => TRUE), ), 'non_rev_field' => array(), + 'revision_created' => array( + array('value' => $this->entity->getRevisionCreationTime()), + ), + 'revision_user' => array( + array( + 'target_id' => $this->user->id(), + 'target_type' => $this->user->getEntityTypeId(), + 'target_uuid' => $this->user->uuid(), + 'url' => $this->user->url(), + ), + ), + 'revision_log_message' => array( + array('value' => $this->values['revision_log_message']['value']), + ), 'field_test_text' => array( array( 'value' => $this->values['field_test_text']['value'], @@ -192,6 +210,9 @@ public function testSerialize() { 'revision_id' => '' . $this->entity->getRevisionId() . '', 'default_langcode' => '1', 'non_rev_field' => '', + 'revision_created' => '' . $this->entity->getRevisionCreationTime() . '', + 'revision_user' => '' . $this->user->id() . '' . $this->user->getEntityTypeId() . '' . $this->user->uuid() . '' . $this->user->url() . '', + 'revision_log_message' => '' . $this->values['revision_log_message']['value'] . '', 'field_test_text' => '' . $this->values['field_test_text']['value'] . '' . $this->values['field_test_text']['format'] . '', ); // Sort it in the same order as normalised. diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php index 0ee28bf..f01675f 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php @@ -27,6 +27,7 @@ * revision_data_table = "entity_test_mulrev_property_revision", * admin_permission = "administer entity_test content", * translatable = TRUE, + * show_revision_ui = TRUE, * entity_keys = { * "id" = "id", * "uuid" = "uuid", 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..49c5aca 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 @@ -3,6 +3,8 @@ namespace Drupal\entity_test\Entity; use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Entity\RevisionLogEntityTrait; +use Drupal\Core\Entity\RevisionLogInterface; use Drupal\Core\Field\BaseFieldDefinition; /** @@ -28,6 +30,7 @@ * base_table = "entity_test_rev", * revision_table = "entity_test_rev_revision", * admin_permission = "administer entity_test content", + * show_revision_ui = TRUE, * entity_keys = { * "id" = "id", * "uuid" = "uuid", @@ -45,7 +48,9 @@ * } * ) */ -class EntityTestRev extends EntityTest { +class EntityTestRev extends EntityTest implements RevisionLogInterface { + + use RevisionLogEntityTrait; /** * {@inheritdoc} @@ -53,13 +58,8 @@ 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 += static::revisionLogBaseFieldDefinitions($entity_type); - $fields['langcode']->setRevisionable(TRUE); $fields['name']->setRevisionable(TRUE); $fields['user_id']->setRevisionable(TRUE); diff --git a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php index 60ba8e5..acb84e5 100644 --- a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php +++ b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php @@ -89,6 +89,12 @@ protected function setUp() { $typed_data_manager->expects($this->any()) ->method('createDataDefinition') ->willReturn($this->getMock('Drupal\Core\TypedData\DataDefinitionInterface')); + + $typed_data_manager->expects($this->any()) + ->method('getDefinition') + ->with($this->equalTo('field_item:string_long')) + ->willReturn(array('class' => '\Drupal\Core\Field\Plugin\Field\FieldType\StringLongItem')); + $this->baseEntityType = new TestEntityType([ 'base_table' => 'entity_test', 'id' => 'entity_test', @@ -1107,3 +1113,12 @@ function t($string, array $args = []) { return strtr($string, $args); } } + + +namespace Drupal\Core\Entity; + +if (!function_exists('t')) { + function t($string, array $args = []) { + return strtr($string, $args); + } +} 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.'); diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityFieldTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityFieldTest.php index 56af888..5dc1a94 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/EntityFieldTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityFieldTest.php @@ -3,6 +3,7 @@ namespace Drupal\KernelTests\Core\Entity; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\RevisionLogInterface; use Drupal\Core\Entity\TypedData\EntityDataDefinition; use Drupal\Core\Entity\TypedData\EntityDataDefinitionInterface; use Drupal\Core\Field\BaseFieldDefinition; @@ -572,6 +573,12 @@ protected function doTestDataStructureInterfaces($entity_type) { // Field format. NULL, ); + + if ($entity instanceof RevisionLogInterface) { + // Adding empty string for revision message. + $target_strings[] = ''; + } + asort($strings); asort($target_strings); $this->assertEqual(array_values($strings), array_values($target_strings), format_string('%entity_type: All contained strings found.', array('%entity_type' => $entity_type)));