Issue #2880152 by amateescu, blazey, plach, larowlan, vijaycs85: Convert custom menu links to be revisionable
							parent
							
								
									1e0ad95a0b
								
							
						
					
					
						commit
						5ad8f598e5
					
				| 
						 | 
					@ -29,6 +29,16 @@ function menu_link_content_help($route_name, RouteMatchInterface $route_match) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Implements hook_entity_type_alter().
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function menu_link_content_entity_type_alter(array &$entity_types) {
 | 
				
			||||||
 | 
					  // @todo Moderation is disabled for custom menu links until when we have an UI
 | 
				
			||||||
 | 
					  //   for them.
 | 
				
			||||||
 | 
					  //   @see https://www.drupal.org/project/drupal/issues/2350939
 | 
				
			||||||
 | 
					  $entity_types['menu_link_content']->setHandlerClass('moderation', '');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Implements hook_menu_delete().
 | 
					 * Implements hook_menu_delete().
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,103 @@
 | 
				
			||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @file
 | 
				
			||||||
 | 
					 * Post update functions for the Menu link content module.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Drupal\Core\Field\BaseFieldDefinition;
 | 
				
			||||||
 | 
					use Drupal\Core\StringTranslation\TranslatableMarkup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Update custom menu links to be revisionable.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function menu_link_content_post_update_make_menu_link_content_revisionable(&$sandbox) {
 | 
				
			||||||
 | 
					  $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
 | 
				
			||||||
 | 
					  /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $last_installed_schema_repository */
 | 
				
			||||||
 | 
					  $last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $entity_type = $definition_update_manager->getEntityType('menu_link_content');
 | 
				
			||||||
 | 
					  $field_storage_definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions('menu_link_content');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Update the entity type definition.
 | 
				
			||||||
 | 
					  $entity_keys = $entity_type->getKeys();
 | 
				
			||||||
 | 
					  $entity_keys['revision'] = 'revision_id';
 | 
				
			||||||
 | 
					  $entity_keys['revision_translation_affected'] = 'revision_translation_affected';
 | 
				
			||||||
 | 
					  $entity_type->set('entity_keys', $entity_keys);
 | 
				
			||||||
 | 
					  $entity_type->set('revision_table', 'menu_link_content_revision');
 | 
				
			||||||
 | 
					  $entity_type->set('revision_data_table', 'menu_link_content_field_revision');
 | 
				
			||||||
 | 
					  $revision_metadata_keys = [
 | 
				
			||||||
 | 
					    'revision_default' => 'revision_default',
 | 
				
			||||||
 | 
					    'revision_user' => 'revision_user',
 | 
				
			||||||
 | 
					    'revision_created' => 'revision_created',
 | 
				
			||||||
 | 
					    'revision_log_message' => 'revision_log_message',
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					  $entity_type->set('revision_metadata_keys', $revision_metadata_keys);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Update the field storage definitions and add the new ones required by a
 | 
				
			||||||
 | 
					  // revisionable entity type.
 | 
				
			||||||
 | 
					  $field_storage_definitions['langcode']->setRevisionable(TRUE);
 | 
				
			||||||
 | 
					  $field_storage_definitions['title']->setRevisionable(TRUE);
 | 
				
			||||||
 | 
					  $field_storage_definitions['description']->setRevisionable(TRUE);
 | 
				
			||||||
 | 
					  $field_storage_definitions['link']->setRevisionable(TRUE);
 | 
				
			||||||
 | 
					  $field_storage_definitions['external']->setRevisionable(TRUE);
 | 
				
			||||||
 | 
					  $field_storage_definitions['enabled']->setRevisionable(TRUE);
 | 
				
			||||||
 | 
					  $field_storage_definitions['changed']->setRevisionable(TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $field_storage_definitions['revision_id'] = BaseFieldDefinition::create('integer')
 | 
				
			||||||
 | 
					    ->setName('revision_id')
 | 
				
			||||||
 | 
					    ->setTargetEntityTypeId('menu_link_content')
 | 
				
			||||||
 | 
					    ->setTargetBundle(NULL)
 | 
				
			||||||
 | 
					    ->setLabel(new TranslatableMarkup('Revision ID'))
 | 
				
			||||||
 | 
					    ->setReadOnly(TRUE)
 | 
				
			||||||
 | 
					    ->setSetting('unsigned', TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $field_storage_definitions['revision_default'] = BaseFieldDefinition::create('boolean')
 | 
				
			||||||
 | 
					    ->setName('revision_default')
 | 
				
			||||||
 | 
					    ->setTargetEntityTypeId('menu_link_content')
 | 
				
			||||||
 | 
					    ->setTargetBundle(NULL)
 | 
				
			||||||
 | 
					    ->setLabel(new TranslatableMarkup('Default revision'))
 | 
				
			||||||
 | 
					    ->setDescription(new TranslatableMarkup('A flag indicating whether this was a default revision when it was saved.'))
 | 
				
			||||||
 | 
					    ->setStorageRequired(TRUE)
 | 
				
			||||||
 | 
					    ->setInternal(TRUE)
 | 
				
			||||||
 | 
					    ->setTranslatable(FALSE)
 | 
				
			||||||
 | 
					    ->setRevisionable(TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $field_storage_definitions['revision_translation_affected'] = BaseFieldDefinition::create('boolean')
 | 
				
			||||||
 | 
					    ->setName('revision_translation_affected')
 | 
				
			||||||
 | 
					    ->setTargetEntityTypeId('menu_link_content')
 | 
				
			||||||
 | 
					    ->setTargetBundle(NULL)
 | 
				
			||||||
 | 
					    ->setLabel(new TranslatableMarkup('Revision translation affected'))
 | 
				
			||||||
 | 
					    ->setDescription(new TranslatableMarkup('Indicates if the last edit of a translation belongs to current revision.'))
 | 
				
			||||||
 | 
					    ->setReadOnly(TRUE)
 | 
				
			||||||
 | 
					    ->setRevisionable(TRUE)
 | 
				
			||||||
 | 
					    ->setTranslatable(TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $field_storage_definitions['revision_created'] = BaseFieldDefinition::create('created')
 | 
				
			||||||
 | 
					    ->setName('revision_created')
 | 
				
			||||||
 | 
					    ->setTargetEntityTypeId('menu_link_content')
 | 
				
			||||||
 | 
					    ->setTargetBundle(NULL)
 | 
				
			||||||
 | 
					    ->setLabel(new TranslatableMarkup('Revision create time'))
 | 
				
			||||||
 | 
					    ->setDescription(new TranslatableMarkup('The time that the current revision was created.'))
 | 
				
			||||||
 | 
					    ->setRevisionable(TRUE);
 | 
				
			||||||
 | 
					  $field_storage_definitions['revision_user'] = BaseFieldDefinition::create('entity_reference')
 | 
				
			||||||
 | 
					    ->setName('revision_user')
 | 
				
			||||||
 | 
					    ->setTargetEntityTypeId('menu_link_content')
 | 
				
			||||||
 | 
					    ->setTargetBundle(NULL)
 | 
				
			||||||
 | 
					    ->setLabel(new TranslatableMarkup('Revision user'))
 | 
				
			||||||
 | 
					    ->setDescription(new TranslatableMarkup('The user ID of the author of the current revision.'))
 | 
				
			||||||
 | 
					    ->setSetting('target_type', 'user')
 | 
				
			||||||
 | 
					    ->setRevisionable(TRUE);
 | 
				
			||||||
 | 
					  $field_storage_definitions['revision_log_message'] = BaseFieldDefinition::create('string_long')
 | 
				
			||||||
 | 
					    ->setName('revision_log_message')
 | 
				
			||||||
 | 
					    ->setTargetEntityTypeId('menu_link_content')
 | 
				
			||||||
 | 
					    ->setTargetBundle(NULL)
 | 
				
			||||||
 | 
					    ->setLabel(new TranslatableMarkup('Revision log message'))
 | 
				
			||||||
 | 
					    ->setDescription(new TranslatableMarkup('Briefly describe the changes you have made.'))
 | 
				
			||||||
 | 
					    ->setRevisionable(TRUE)
 | 
				
			||||||
 | 
					    ->setDefaultValue('');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $definition_update_manager->updateFieldableEntityType($entity_type, $field_storage_definitions, $sandbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return t('Custom menu links have been converted to be revisionable.');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2,9 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Drupal\menu_link_content\Entity;
 | 
					namespace Drupal\menu_link_content\Entity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Drupal\Core\Entity\ContentEntityBase;
 | 
					use Drupal\Core\Entity\EditorialContentEntityBase;
 | 
				
			||||||
use Drupal\Core\Entity\EntityChangedTrait;
 | 
					 | 
				
			||||||
use Drupal\Core\Entity\EntityPublishedTrait;
 | 
					 | 
				
			||||||
use Drupal\Core\Entity\EntityStorageInterface;
 | 
					use Drupal\Core\Entity\EntityStorageInterface;
 | 
				
			||||||
use Drupal\Core\Entity\EntityTypeInterface;
 | 
					use Drupal\Core\Entity\EntityTypeInterface;
 | 
				
			||||||
use Drupal\Core\Field\BaseFieldDefinition;
 | 
					use Drupal\Core\Field\BaseFieldDefinition;
 | 
				
			||||||
| 
						 | 
					@ -28,7 +26,7 @@ use Drupal\menu_link_content\MenuLinkContentInterface;
 | 
				
			||||||
 *     plural = "@count custom menu links",
 | 
					 *     plural = "@count custom menu links",
 | 
				
			||||||
 *   ),
 | 
					 *   ),
 | 
				
			||||||
 *   handlers = {
 | 
					 *   handlers = {
 | 
				
			||||||
 *     "storage" = "Drupal\Core\Entity\Sql\SqlContentEntityStorage",
 | 
					 *     "storage" = "\Drupal\menu_link_content\MenuLinkContentStorage",
 | 
				
			||||||
 *     "storage_schema" = "Drupal\menu_link_content\MenuLinkContentStorageSchema",
 | 
					 *     "storage_schema" = "Drupal\menu_link_content\MenuLinkContentStorageSchema",
 | 
				
			||||||
 *     "access" = "Drupal\menu_link_content\MenuLinkContentAccessControlHandler",
 | 
					 *     "access" = "Drupal\menu_link_content\MenuLinkContentAccessControlHandler",
 | 
				
			||||||
 *     "form" = {
 | 
					 *     "form" = {
 | 
				
			||||||
| 
						 | 
					@ -39,26 +37,34 @@ use Drupal\menu_link_content\MenuLinkContentInterface;
 | 
				
			||||||
 *   admin_permission = "administer menu",
 | 
					 *   admin_permission = "administer menu",
 | 
				
			||||||
 *   base_table = "menu_link_content",
 | 
					 *   base_table = "menu_link_content",
 | 
				
			||||||
 *   data_table = "menu_link_content_data",
 | 
					 *   data_table = "menu_link_content_data",
 | 
				
			||||||
 | 
					 *   revision_table = "menu_link_content_revision",
 | 
				
			||||||
 | 
					 *   revision_data_table = "menu_link_content_field_revision",
 | 
				
			||||||
 *   translatable = TRUE,
 | 
					 *   translatable = TRUE,
 | 
				
			||||||
 *   entity_keys = {
 | 
					 *   entity_keys = {
 | 
				
			||||||
 *     "id" = "id",
 | 
					 *     "id" = "id",
 | 
				
			||||||
 | 
					 *     "revision" = "revision_id",
 | 
				
			||||||
 *     "label" = "title",
 | 
					 *     "label" = "title",
 | 
				
			||||||
 *     "langcode" = "langcode",
 | 
					 *     "langcode" = "langcode",
 | 
				
			||||||
 *     "uuid" = "uuid",
 | 
					 *     "uuid" = "uuid",
 | 
				
			||||||
 *     "bundle" = "bundle",
 | 
					 *     "bundle" = "bundle",
 | 
				
			||||||
 *     "published" = "enabled",
 | 
					 *     "published" = "enabled",
 | 
				
			||||||
 *   },
 | 
					 *   },
 | 
				
			||||||
 | 
					 *   revision_metadata_keys = {
 | 
				
			||||||
 | 
					 *     "revision_user" = "revision_user",
 | 
				
			||||||
 | 
					 *     "revision_created" = "revision_created",
 | 
				
			||||||
 | 
					 *     "revision_log_message" = "revision_log_message",
 | 
				
			||||||
 | 
					 *   },
 | 
				
			||||||
 *   links = {
 | 
					 *   links = {
 | 
				
			||||||
 *     "canonical" = "/admin/structure/menu/item/{menu_link_content}/edit",
 | 
					 *     "canonical" = "/admin/structure/menu/item/{menu_link_content}/edit",
 | 
				
			||||||
 *     "edit-form" = "/admin/structure/menu/item/{menu_link_content}/edit",
 | 
					 *     "edit-form" = "/admin/structure/menu/item/{menu_link_content}/edit",
 | 
				
			||||||
 *     "delete-form" = "/admin/structure/menu/item/{menu_link_content}/delete",
 | 
					 *     "delete-form" = "/admin/structure/menu/item/{menu_link_content}/delete",
 | 
				
			||||||
 *   }
 | 
					 *   },
 | 
				
			||||||
 | 
					 *   constraints = {
 | 
				
			||||||
 | 
					 *     "MenuTreeHierarchy" = {}
 | 
				
			||||||
 | 
					 *   },
 | 
				
			||||||
 * )
 | 
					 * )
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterface {
 | 
					class MenuLinkContent extends EditorialContentEntityBase implements MenuLinkContentInterface {
 | 
				
			||||||
 | 
					 | 
				
			||||||
  use EntityChangedTrait;
 | 
					 | 
				
			||||||
  use EntityPublishedTrait;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * A flag for whether this entity is wrapped in a plugin instance.
 | 
					   * A flag for whether this entity is wrapped in a plugin instance.
 | 
				
			||||||
| 
						 | 
					@ -203,6 +209,11 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf
 | 
				
			||||||
  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
 | 
					  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
 | 
				
			||||||
    parent::postSave($storage, $update);
 | 
					    parent::postSave($storage, $update);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Don't update the menu tree if a pending revision was saved.
 | 
				
			||||||
 | 
					    if (!$this->isDefaultRevision()) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
 | 
					    /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
 | 
				
			||||||
    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
 | 
					    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -277,6 +288,7 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf
 | 
				
			||||||
      ->setDescription(t('The text to be used for this link in the menu.'))
 | 
					      ->setDescription(t('The text to be used for this link in the menu.'))
 | 
				
			||||||
      ->setRequired(TRUE)
 | 
					      ->setRequired(TRUE)
 | 
				
			||||||
      ->setTranslatable(TRUE)
 | 
					      ->setTranslatable(TRUE)
 | 
				
			||||||
 | 
					      ->setRevisionable(TRUE)
 | 
				
			||||||
      ->setSetting('max_length', 255)
 | 
					      ->setSetting('max_length', 255)
 | 
				
			||||||
      ->setDisplayOptions('view', [
 | 
					      ->setDisplayOptions('view', [
 | 
				
			||||||
        'label' => 'hidden',
 | 
					        'label' => 'hidden',
 | 
				
			||||||
| 
						 | 
					@ -293,6 +305,7 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf
 | 
				
			||||||
      ->setLabel(t('Description'))
 | 
					      ->setLabel(t('Description'))
 | 
				
			||||||
      ->setDescription(t('Shown when hovering over the menu link.'))
 | 
					      ->setDescription(t('Shown when hovering over the menu link.'))
 | 
				
			||||||
      ->setTranslatable(TRUE)
 | 
					      ->setTranslatable(TRUE)
 | 
				
			||||||
 | 
					      ->setRevisionable(TRUE)
 | 
				
			||||||
      ->setSetting('max_length', 255)
 | 
					      ->setSetting('max_length', 255)
 | 
				
			||||||
      ->setDisplayOptions('view', [
 | 
					      ->setDisplayOptions('view', [
 | 
				
			||||||
        'label' => 'hidden',
 | 
					        'label' => 'hidden',
 | 
				
			||||||
| 
						 | 
					@ -313,6 +326,7 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf
 | 
				
			||||||
    $fields['link'] = BaseFieldDefinition::create('link')
 | 
					    $fields['link'] = BaseFieldDefinition::create('link')
 | 
				
			||||||
      ->setLabel(t('Link'))
 | 
					      ->setLabel(t('Link'))
 | 
				
			||||||
      ->setDescription(t('The location this menu link points to.'))
 | 
					      ->setDescription(t('The location this menu link points to.'))
 | 
				
			||||||
 | 
					      ->setRevisionable(TRUE)
 | 
				
			||||||
      ->setRequired(TRUE)
 | 
					      ->setRequired(TRUE)
 | 
				
			||||||
      ->setSettings([
 | 
					      ->setSettings([
 | 
				
			||||||
        'link_type' => LinkItemInterface::LINK_GENERIC,
 | 
					        'link_type' => LinkItemInterface::LINK_GENERIC,
 | 
				
			||||||
| 
						 | 
					@ -326,7 +340,8 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf
 | 
				
			||||||
    $fields['external'] = BaseFieldDefinition::create('boolean')
 | 
					    $fields['external'] = BaseFieldDefinition::create('boolean')
 | 
				
			||||||
      ->setLabel(t('External'))
 | 
					      ->setLabel(t('External'))
 | 
				
			||||||
      ->setDescription(t('A flag to indicate if the link points to a full URL starting with a protocol, like http:// (1 = external, 0 = internal).'))
 | 
					      ->setDescription(t('A flag to indicate if the link points to a full URL starting with a protocol, like http:// (1 = external, 0 = internal).'))
 | 
				
			||||||
      ->setDefaultValue(FALSE);
 | 
					      ->setDefaultValue(FALSE)
 | 
				
			||||||
 | 
					      ->setRevisionable(TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $fields['rediscover'] = BaseFieldDefinition::create('boolean')
 | 
					    $fields['rediscover'] = BaseFieldDefinition::create('boolean')
 | 
				
			||||||
      ->setLabel(t('Indicates whether the menu link should be rediscovered'))
 | 
					      ->setLabel(t('Indicates whether the menu link should be rediscovered'))
 | 
				
			||||||
| 
						 | 
					@ -365,7 +380,6 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf
 | 
				
			||||||
    $fields['enabled']->setLabel(t('Enabled'));
 | 
					    $fields['enabled']->setLabel(t('Enabled'));
 | 
				
			||||||
    $fields['enabled']->setDescription(t('A flag for whether the link should be enabled in menus or hidden.'));
 | 
					    $fields['enabled']->setDescription(t('A flag for whether the link should be enabled in menus or hidden.'));
 | 
				
			||||||
    $fields['enabled']->setTranslatable(FALSE);
 | 
					    $fields['enabled']->setTranslatable(FALSE);
 | 
				
			||||||
    $fields['enabled']->setRevisionable(FALSE);
 | 
					 | 
				
			||||||
    $fields['enabled']->setDisplayOptions('view', [
 | 
					    $fields['enabled']->setDisplayOptions('view', [
 | 
				
			||||||
      'label' => 'hidden',
 | 
					      'label' => 'hidden',
 | 
				
			||||||
      'type' => 'boolean',
 | 
					      'type' => 'boolean',
 | 
				
			||||||
| 
						 | 
					@ -383,7 +397,14 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf
 | 
				
			||||||
    $fields['changed'] = BaseFieldDefinition::create('changed')
 | 
					    $fields['changed'] = BaseFieldDefinition::create('changed')
 | 
				
			||||||
      ->setLabel(t('Changed'))
 | 
					      ->setLabel(t('Changed'))
 | 
				
			||||||
      ->setDescription(t('The time that the menu link was last edited.'))
 | 
					      ->setDescription(t('The time that the menu link was last edited.'))
 | 
				
			||||||
      ->setTranslatable(TRUE);
 | 
					      ->setTranslatable(TRUE)
 | 
				
			||||||
 | 
					      ->setRevisionable(TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // @todo Keep this field hidden until we have a revision UI for menu links.
 | 
				
			||||||
 | 
					    //   @see https://www.drupal.org/project/drupal/issues/2350939
 | 
				
			||||||
 | 
					    $fields['revision_log_message']->setDisplayOptions('form', [
 | 
				
			||||||
 | 
					      'region' => 'hidden',
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return $fields;
 | 
					    return $fields;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -127,19 +127,11 @@ class MenuLinkContentForm extends ContentEntityForm {
 | 
				
			||||||
  public function save(array $form, FormStateInterface $form_state) {
 | 
					  public function save(array $form, FormStateInterface $form_state) {
 | 
				
			||||||
    // The entity is rebuilt in parent::submit().
 | 
					    // The entity is rebuilt in parent::submit().
 | 
				
			||||||
    $menu_link = $this->entity;
 | 
					    $menu_link = $this->entity;
 | 
				
			||||||
    $saved = $menu_link->save();
 | 
					    $menu_link->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ($saved) {
 | 
					    $this->messenger()->addStatus($this->t('The menu link has been saved.'));
 | 
				
			||||||
      $this->messenger()->addStatus($this->t('The menu link has been saved.'));
 | 
					
 | 
				
			||||||
      $form_state->setRedirect(
 | 
					    $form_state->setRedirectUrl($menu_link->toUrl('canonical'));
 | 
				
			||||||
        'entity.menu_link_content.canonical',
 | 
					 | 
				
			||||||
        ['menu_link_content' => $menu_link->id()]
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
      $this->messenger()->addError($this->t('There was an error saving the menu link.'));
 | 
					 | 
				
			||||||
      $form_state->setRebuild();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,11 +5,12 @@ namespace Drupal\menu_link_content;
 | 
				
			||||||
use Drupal\Core\Entity\EntityChangedInterface;
 | 
					use Drupal\Core\Entity\EntityChangedInterface;
 | 
				
			||||||
use Drupal\Core\Entity\ContentEntityInterface;
 | 
					use Drupal\Core\Entity\ContentEntityInterface;
 | 
				
			||||||
use Drupal\Core\Entity\EntityPublishedInterface;
 | 
					use Drupal\Core\Entity\EntityPublishedInterface;
 | 
				
			||||||
 | 
					use Drupal\Core\Entity\RevisionLogInterface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Defines an interface for custom menu links.
 | 
					 * Defines an interface for custom menu links.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
interface MenuLinkContentInterface extends ContentEntityInterface, EntityChangedInterface, EntityPublishedInterface {
 | 
					interface MenuLinkContentInterface extends ContentEntityInterface, EntityChangedInterface, EntityPublishedInterface, RevisionLogInterface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Flags this instance as being wrapped in a menu link plugin instance.
 | 
					   * Flags this instance as being wrapped in a menu link plugin instance.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,44 @@
 | 
				
			||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Drupal\menu_link_content;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Storage handler for menu_link_content entities.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class MenuLinkContentStorage extends SqlContentEntityStorage implements MenuLinkContentStorageInterface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * {@inheritdoc}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public function getMenuLinkIdsWithPendingRevisions() {
 | 
				
			||||||
 | 
					    $table_mapping = $this->getTableMapping();
 | 
				
			||||||
 | 
					    $id_field = $table_mapping->getColumnNames($this->entityType->getKey('id'))['value'];
 | 
				
			||||||
 | 
					    $revision_field = $table_mapping->getColumnNames($this->entityType->getKey('revision'))['value'];
 | 
				
			||||||
 | 
					    $rta_field = $table_mapping->getColumnNames($this->entityType->getKey('revision_translation_affected'))['value'];
 | 
				
			||||||
 | 
					    $langcode_field = $table_mapping->getColumnNames($this->entityType->getKey('langcode'))['value'];
 | 
				
			||||||
 | 
					    $revision_default_field = $table_mapping->getColumnNames($this->entityType->getRevisionMetadataKey('revision_default'))['value'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $query = $this->database->select($this->getRevisionDataTable(), 'mlfr');
 | 
				
			||||||
 | 
					    $query->fields('mlfr', [$id_field]);
 | 
				
			||||||
 | 
					    $query->addExpression("MAX(mlfr.$revision_field)", $revision_field);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $query->join($this->getRevisionTable(), 'mlr', "mlfr.$revision_field = mlr.$revision_field AND mlr.$revision_default_field = 0");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $inner_select = $this->database->select($this->getRevisionDataTable(), 't');
 | 
				
			||||||
 | 
					    $inner_select->condition("t.$rta_field", '1');
 | 
				
			||||||
 | 
					    $inner_select->fields('t', [$id_field, $langcode_field]);
 | 
				
			||||||
 | 
					    $inner_select->addExpression("MAX(t.$revision_field)", $revision_field);
 | 
				
			||||||
 | 
					    $inner_select
 | 
				
			||||||
 | 
					      ->groupBy("t.$id_field")
 | 
				
			||||||
 | 
					      ->groupBy("t.$langcode_field");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $query->join($inner_select, 'mr', "mlfr.$revision_field = mr.$revision_field AND mlfr.$langcode_field = mr.$langcode_field");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $query->groupBy("mlfr.$id_field");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return $query->execute()->fetchAllKeyed(1, 0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Drupal\menu_link_content;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Drupal\Core\Entity\ContentEntityStorageInterface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Defines an interface for menu_link_content entity storage classes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					interface MenuLinkContentStorageInterface extends ContentEntityStorageInterface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Gets a list of menu link IDs with pending revisions.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @return int[]
 | 
				
			||||||
 | 
					   *   An array of menu link IDs which have pending revisions, keyed by their
 | 
				
			||||||
 | 
					   *   revision IDs.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @internal
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public function getMenuLinkIdsWithPendingRevisions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Drupal\menu_link_content\Plugin\Validation\Constraint;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Drupal\Core\Entity\Plugin\Validation\Constraint\CompositeConstraintBase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Validation constraint for changing the menu hierarchy in pending revisions.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @Constraint(
 | 
				
			||||||
 | 
					 *   id = "MenuTreeHierarchy",
 | 
				
			||||||
 | 
					 *   label = @Translation("Menu tree hierarchy.", context = "Validation"),
 | 
				
			||||||
 | 
					 * )
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class MenuTreeHierarchyConstraint extends CompositeConstraintBase {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * The default violation message.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @var string
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public $message = 'You can only change the hierarchy for the <em>published</em> version of this menu link.';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * {@inheritdoc}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public function coversFields() {
 | 
				
			||||||
 | 
					    return ['parent', 'weight'];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,66 @@
 | 
				
			||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Drupal\menu_link_content\Plugin\Validation\Constraint;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 | 
				
			||||||
 | 
					use Drupal\Core\Entity\EntityTypeManagerInterface;
 | 
				
			||||||
 | 
					use Symfony\Component\DependencyInjection\ContainerInterface;
 | 
				
			||||||
 | 
					use Symfony\Component\Validator\Constraint;
 | 
				
			||||||
 | 
					use Symfony\Component\Validator\ConstraintValidator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Constraint validator for changing menu link parents in pending revisions.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class MenuTreeHierarchyConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * The entity type manager.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  private $entityTypeManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Creates a new MenuTreeHierarchyConstraintValidator instance.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
 | 
				
			||||||
 | 
					   *   The entity type manager.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
 | 
				
			||||||
 | 
					    $this->entityTypeManager = $entity_type_manager;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * {@inheritdoc}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public static function create(ContainerInterface $container) {
 | 
				
			||||||
 | 
					    return new static(
 | 
				
			||||||
 | 
					      $container->get('entity_type.manager')
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * {@inheritdoc}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public function validate($entity, Constraint $constraint) {
 | 
				
			||||||
 | 
					    if ($entity && !$entity->isNew() && !$entity->isDefaultRevision()) {
 | 
				
			||||||
 | 
					      $original = $this->entityTypeManager->getStorage($entity->getEntityTypeId())->loadUnchanged($entity->id());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Ensure that empty items do not affect the comparison checks below.
 | 
				
			||||||
 | 
					      // @todo Remove this filtering when
 | 
				
			||||||
 | 
					      //   https://www.drupal.org/project/drupal/issues/3039031 is fixed.
 | 
				
			||||||
 | 
					      $entity->parent->filterEmptyItems();
 | 
				
			||||||
 | 
					      if (($entity->parent->isEmpty() !== $original->parent->isEmpty()) || !$entity->parent->equals($original->parent)) {
 | 
				
			||||||
 | 
					        $this->context->buildViolation($constraint->message)
 | 
				
			||||||
 | 
					          ->atPath('menu_parent')
 | 
				
			||||||
 | 
					          ->addViolation();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (!$entity->weight->equals($original->weight)) {
 | 
				
			||||||
 | 
					        $this->context->buildViolation($constraint->message)
 | 
				
			||||||
 | 
					          ->atPath('weight')
 | 
				
			||||||
 | 
					          ->addViolation();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -120,6 +120,11 @@ abstract class MenuLinkContentResourceTestBase extends EntityResourceTestBase {
 | 
				
			||||||
          'value' => 1,
 | 
					          'value' => 1,
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
 | 
					      'revision_id' => [
 | 
				
			||||||
 | 
					        [
 | 
				
			||||||
 | 
					          'value' => 1,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
      'title' => [
 | 
					      'title' => [
 | 
				
			||||||
        [
 | 
					        [
 | 
				
			||||||
          'value' => 'Llama Gabilondo',
 | 
					          'value' => 'Llama Gabilondo',
 | 
				
			||||||
| 
						 | 
					@ -191,6 +196,16 @@ abstract class MenuLinkContentResourceTestBase extends EntityResourceTestBase {
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
      'parent' => [],
 | 
					      'parent' => [],
 | 
				
			||||||
 | 
					      'revision_created' => [
 | 
				
			||||||
 | 
					        $this->formatExpectedTimestampItemValues((int) $this->entity->getRevisionCreationTime()),
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      'revision_user' => [],
 | 
				
			||||||
 | 
					      'revision_log_message' => [],
 | 
				
			||||||
 | 
					      'revision_translation_affected' => [
 | 
				
			||||||
 | 
					        [
 | 
				
			||||||
 | 
					          'value' => TRUE,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,6 +59,49 @@ class MenuLinkContentUpdateTest extends UpdatePathTestBase {
 | 
				
			||||||
    $this->assertTrue($menu_link->isPublished());
 | 
					    $this->assertTrue($menu_link->isPublished());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Tests the conversion of custom menu links to be revisionable.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @see menu_link_content_post_update_make_menu_link_content_revisionable()
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public function testConversionToRevisionable() {
 | 
				
			||||||
 | 
					    $entity_type = \Drupal::entityDefinitionUpdateManager()->getEntityType('menu_link_content');
 | 
				
			||||||
 | 
					    $this->assertFalse($entity_type->isRevisionable());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $this->runUpdates();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $entity_type = \Drupal::entityDefinitionUpdateManager()->getEntityType('menu_link_content');
 | 
				
			||||||
 | 
					    $this->assertTrue($entity_type->isRevisionable());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Log in as user 1.
 | 
				
			||||||
 | 
					    $account = User::load(1);
 | 
				
			||||||
 | 
					    $account->passRaw = 'drupal';
 | 
				
			||||||
 | 
					    $this->drupalLogin($account);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Make sure our custom menu link exists.
 | 
				
			||||||
 | 
					    $assert_session = $this->assertSession();
 | 
				
			||||||
 | 
					    $this->drupalGet('admin/structure/menu/item/1/edit');
 | 
				
			||||||
 | 
					    $assert_session->checkboxChecked('edit-enabled-value');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check that custom menu links can be created, saved and then loaded.
 | 
				
			||||||
 | 
					    $storage = \Drupal::entityTypeManager()->getStorage('menu_link_content');
 | 
				
			||||||
 | 
					    /** @var \Drupal\menu_link_content\Entity\MenuLinkContent $menu_link */
 | 
				
			||||||
 | 
					    $menu_link = $storage->create([
 | 
				
			||||||
 | 
					      'menu_name' => 'main',
 | 
				
			||||||
 | 
					      'link' => 'route:user.page',
 | 
				
			||||||
 | 
					      'title' => 'Pineapple',
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					    $menu_link->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $storage->resetCache();
 | 
				
			||||||
 | 
					    $menu_link = $storage->loadRevision($menu_link->getRevisionId());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $this->assertEquals('main', $menu_link->getMenuName());
 | 
				
			||||||
 | 
					    $this->assertEquals('Pineapple', $menu_link->label());
 | 
				
			||||||
 | 
					    $this->assertEquals('route:user.page', $menu_link->link->uri);
 | 
				
			||||||
 | 
					    $this->assertTrue($menu_link->isPublished());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * {@inheritdoc}
 | 
					   * {@inheritdoc}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@ class MenuLinkContentDeriverTest extends KernelTestBase {
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * {@inheritdoc}
 | 
					   * {@inheritdoc}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  public static $modules = ['menu_link_content', 'link', 'system', 'menu_link_content_dynamic_route'];
 | 
					  public static $modules = ['menu_link_content', 'link', 'system', 'menu_link_content_dynamic_route', 'user'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * {@inheritdoc}
 | 
					   * {@inheritdoc}
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@ class MenuLinkContentDeriverTest extends KernelTestBase {
 | 
				
			||||||
  protected function setUp() {
 | 
					  protected function setUp() {
 | 
				
			||||||
    parent::setUp();
 | 
					    parent::setUp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $this->installEntitySchema('user');
 | 
				
			||||||
    $this->installEntitySchema('menu_link_content');
 | 
					    $this->installEntitySchema('menu_link_content');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -310,4 +310,114 @@ class MenuLinksTest extends KernelTestBase {
 | 
				
			||||||
    $this->assertEqual(count($menu_links), 0);
 | 
					    $this->assertEqual(count($menu_links), 0);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Tests handling of pending revisions.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @coversDefaultClass \Drupal\menu_link_content\Plugin\Validation\Constraint\MenuTreeHierarchyConstraintValidator
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public function testPendingRevisions() {
 | 
				
			||||||
 | 
					    /** @var \Drupal\Core\Entity\RevisionableStorageInterface $storage */
 | 
				
			||||||
 | 
					    $storage = \Drupal::entityTypeManager()->getStorage('menu_link_content');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add new menu items in a hierarchy.
 | 
				
			||||||
 | 
					    $default_root_1_title = $this->randomMachineName(8);
 | 
				
			||||||
 | 
					    $root_1 = $storage->create([
 | 
				
			||||||
 | 
					      'title' => $default_root_1_title,
 | 
				
			||||||
 | 
					      'link' => [['uri' => 'internal:/#root_1']],
 | 
				
			||||||
 | 
					      'menu_name' => 'menu_test',
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					    $root_1->save();
 | 
				
			||||||
 | 
					    $default_child1_title = $this->randomMachineName(8);
 | 
				
			||||||
 | 
					    $child1 = $storage->create([
 | 
				
			||||||
 | 
					      'title' => $default_child1_title,
 | 
				
			||||||
 | 
					      'link' => [['uri' => 'internal:/#child1']],
 | 
				
			||||||
 | 
					      'menu_name' => 'menu_test',
 | 
				
			||||||
 | 
					      'parent' => 'menu_link_content:' . $root_1->uuid(),
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					    $child1->save();
 | 
				
			||||||
 | 
					    $default_child2_title = $this->randomMachineName(8);
 | 
				
			||||||
 | 
					    $child2 = $storage->create([
 | 
				
			||||||
 | 
					      'title' => $default_child2_title,
 | 
				
			||||||
 | 
					      'link' => [['uri' => 'internal:/#child2']],
 | 
				
			||||||
 | 
					      'menu_name' => 'menu_test',
 | 
				
			||||||
 | 
					      'parent' => 'menu_link_content:' . $child1->uuid(),
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					    $child2->save();
 | 
				
			||||||
 | 
					    $default_root_2_title = $this->randomMachineName(8);
 | 
				
			||||||
 | 
					    $root_2 = $storage->create([
 | 
				
			||||||
 | 
					      'title' => $default_root_2_title,
 | 
				
			||||||
 | 
					      'link' => [['uri' => 'internal:/#root_2']],
 | 
				
			||||||
 | 
					      'menu_name' => 'menu_test',
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					    $root_2->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check that changing the title and the link in a pending revision is
 | 
				
			||||||
 | 
					    // allowed.
 | 
				
			||||||
 | 
					    $pending_child1_title = $this->randomMachineName(8);
 | 
				
			||||||
 | 
					    $child1_pending_revision = $storage->createRevision($child1, FALSE);
 | 
				
			||||||
 | 
					    $child1_pending_revision->set('title', $pending_child1_title);
 | 
				
			||||||
 | 
					    $child1_pending_revision->set('link', [['uri' => 'internal:/#test']]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $violations = $child1_pending_revision->validate();
 | 
				
			||||||
 | 
					    $this->assertEmpty($violations);
 | 
				
			||||||
 | 
					    $child1_pending_revision->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $storage->resetCache();
 | 
				
			||||||
 | 
					    $child1_pending_revision = $storage->loadRevision($child1_pending_revision->getRevisionId());
 | 
				
			||||||
 | 
					    $this->assertFalse($child1_pending_revision->isDefaultRevision());
 | 
				
			||||||
 | 
					    $this->assertEquals($pending_child1_title, $child1_pending_revision->getTitle());
 | 
				
			||||||
 | 
					    $this->assertEquals('/#test', $child1_pending_revision->getUrlObject()->toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check that saving a pending revision does not affect the menu tree.
 | 
				
			||||||
 | 
					    $menu_tree = \Drupal::menuTree()->load('menu_test', new MenuTreeParameters());
 | 
				
			||||||
 | 
					    $parent_link = reset($menu_tree);
 | 
				
			||||||
 | 
					    $this->assertEquals($default_root_1_title, $parent_link->link->getTitle());
 | 
				
			||||||
 | 
					    $this->assertEquals('/#root_1', $parent_link->link->getUrlObject()->toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $child1_link = reset($parent_link->subtree);
 | 
				
			||||||
 | 
					    $this->assertEquals($default_child1_title, $child1_link->link->getTitle());
 | 
				
			||||||
 | 
					    $this->assertEquals('/#child1', $child1_link->link->getUrlObject()->toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $child2_link = reset($child1_link->subtree);
 | 
				
			||||||
 | 
					    $this->assertEquals($default_child2_title, $child2_link->link->getTitle());
 | 
				
			||||||
 | 
					    $this->assertEquals('/#child2', $child2_link->link->getUrlObject()->toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check that changing the parent in a pending revision is not allowed.
 | 
				
			||||||
 | 
					    $child2_pending_revision = $storage->createRevision($child2, FALSE);
 | 
				
			||||||
 | 
					    $child2_pending_revision->set('parent', $child1->id());
 | 
				
			||||||
 | 
					    $violations = $child2_pending_revision->validate();
 | 
				
			||||||
 | 
					    $this->assertCount(1, $violations);
 | 
				
			||||||
 | 
					    $this->assertEquals('You can only change the hierarchy for the <em>published</em> version of this menu link.', $violations[0]->getMessage());
 | 
				
			||||||
 | 
					    $this->assertEquals('menu_parent', $violations[0]->getPropertyPath());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check that changing the weight in a pending revision is not allowed.
 | 
				
			||||||
 | 
					    $child2_pending_revision = $storage->createRevision($child2, FALSE);
 | 
				
			||||||
 | 
					    $child2_pending_revision->set('weight', 500);
 | 
				
			||||||
 | 
					    $violations = $child2_pending_revision->validate();
 | 
				
			||||||
 | 
					    $this->assertCount(1, $violations);
 | 
				
			||||||
 | 
					    $this->assertEquals('You can only change the hierarchy for the <em>published</em> version of this menu link.', $violations[0]->getMessage());
 | 
				
			||||||
 | 
					    $this->assertEquals('weight', $violations[0]->getPropertyPath());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check that changing both the parent and the weight in a pending revision
 | 
				
			||||||
 | 
					    // is not allowed.
 | 
				
			||||||
 | 
					    $child2_pending_revision = $storage->createRevision($child2, FALSE);
 | 
				
			||||||
 | 
					    $child2_pending_revision->set('parent', $child1->id());
 | 
				
			||||||
 | 
					    $child2_pending_revision->set('weight', 500);
 | 
				
			||||||
 | 
					    $violations = $child2_pending_revision->validate();
 | 
				
			||||||
 | 
					    $this->assertCount(2, $violations);
 | 
				
			||||||
 | 
					    $this->assertEquals('You can only change the hierarchy for the <em>published</em> version of this menu link.', $violations[0]->getMessage());
 | 
				
			||||||
 | 
					    $this->assertEquals('You can only change the hierarchy for the <em>published</em> version of this menu link.', $violations[1]->getMessage());
 | 
				
			||||||
 | 
					    $this->assertEquals('menu_parent', $violations[0]->getPropertyPath());
 | 
				
			||||||
 | 
					    $this->assertEquals('weight', $violations[1]->getPropertyPath());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check that changing the parent of a term which didn't have a parent
 | 
				
			||||||
 | 
					    // initially is not allowed in a pending revision.
 | 
				
			||||||
 | 
					    $root_2_pending_revision = $storage->createRevision($root_2, FALSE);
 | 
				
			||||||
 | 
					    $root_2_pending_revision->set('parent', $root_1->id());
 | 
				
			||||||
 | 
					    $violations = $root_2_pending_revision->validate();
 | 
				
			||||||
 | 
					    $this->assertCount(1, $violations);
 | 
				
			||||||
 | 
					    $this->assertEquals('You can only change the hierarchy for the <em>published</em> version of this menu link.', $violations[0]->getMessage());
 | 
				
			||||||
 | 
					    $this->assertEquals('menu_parent', $violations[0]->getPropertyPath());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@ class PathAliasMenuLinkContentTest extends KernelTestBase {
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * {@inheritdoc}
 | 
					   * {@inheritdoc}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  public static $modules = ['menu_link_content', 'system', 'link', 'test_page_test'];
 | 
					  public static $modules = ['menu_link_content', 'system', 'link', 'test_page_test', 'user'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * {@inheritdoc}
 | 
					   * {@inheritdoc}
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@ class PathAliasMenuLinkContentTest extends KernelTestBase {
 | 
				
			||||||
  protected function setUp() {
 | 
					  protected function setUp() {
 | 
				
			||||||
    parent::setUp();
 | 
					    parent::setUp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $this->installEntitySchema('user');
 | 
				
			||||||
    $this->installEntitySchema('menu_link_content');
 | 
					    $this->installEntitySchema('menu_link_content');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Ensure that the weight of module_link_content is higher than system.
 | 
					    // Ensure that the weight of module_link_content is higher than system.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,8 @@ use Drupal\Core\Menu\MenuTreeParameters;
 | 
				
			||||||
use Drupal\Core\Render\Element;
 | 
					use Drupal\Core\Render\Element;
 | 
				
			||||||
use Drupal\Core\Url;
 | 
					use Drupal\Core\Url;
 | 
				
			||||||
use Drupal\Core\Utility\LinkGeneratorInterface;
 | 
					use Drupal\Core\Utility\LinkGeneratorInterface;
 | 
				
			||||||
 | 
					use Drupal\menu_link_content\MenuLinkContentStorageInterface;
 | 
				
			||||||
 | 
					use Drupal\menu_link_content\Plugin\Menu\MenuLinkContent;
 | 
				
			||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
 | 
					use Symfony\Component\DependencyInjection\ContainerInterface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -45,6 +47,13 @@ class MenuForm extends EntityForm {
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  protected $linkGenerator;
 | 
					  protected $linkGenerator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * The menu_link_content storage handler.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @var \Drupal\menu_link_content\MenuLinkContentStorageInterface
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  protected $menuLinkContentStorage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * The overview tree form.
 | 
					   * The overview tree form.
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
| 
						 | 
					@ -61,11 +70,14 @@ class MenuForm extends EntityForm {
 | 
				
			||||||
   *   The menu tree service.
 | 
					   *   The menu tree service.
 | 
				
			||||||
   * @param \Drupal\Core\Utility\LinkGeneratorInterface $link_generator
 | 
					   * @param \Drupal\Core\Utility\LinkGeneratorInterface $link_generator
 | 
				
			||||||
   *   The link generator.
 | 
					   *   The link generator.
 | 
				
			||||||
 | 
					   * @param \Drupal\menu_link_content\MenuLinkContentStorageInterface $menu_link_content_storage
 | 
				
			||||||
 | 
					   *   The menu link content storage handler.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  public function __construct(MenuLinkManagerInterface $menu_link_manager, MenuLinkTreeInterface $menu_tree, LinkGeneratorInterface $link_generator) {
 | 
					  public function __construct(MenuLinkManagerInterface $menu_link_manager, MenuLinkTreeInterface $menu_tree, LinkGeneratorInterface $link_generator, MenuLinkContentStorageInterface $menu_link_content_storage) {
 | 
				
			||||||
    $this->menuLinkManager = $menu_link_manager;
 | 
					    $this->menuLinkManager = $menu_link_manager;
 | 
				
			||||||
    $this->menuTree = $menu_tree;
 | 
					    $this->menuTree = $menu_tree;
 | 
				
			||||||
    $this->linkGenerator = $link_generator;
 | 
					    $this->linkGenerator = $link_generator;
 | 
				
			||||||
 | 
					    $this->menuLinkContentStorage = $menu_link_content_storage;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
| 
						 | 
					@ -75,7 +87,8 @@ class MenuForm extends EntityForm {
 | 
				
			||||||
    return new static(
 | 
					    return new static(
 | 
				
			||||||
      $container->get('plugin.manager.menu.link'),
 | 
					      $container->get('plugin.manager.menu.link'),
 | 
				
			||||||
      $container->get('menu.link_tree'),
 | 
					      $container->get('menu.link_tree'),
 | 
				
			||||||
      $container->get('link_generator')
 | 
					      $container->get('link_generator'),
 | 
				
			||||||
 | 
					      $container->get('entity_type.manager')->getStorage('menu_link_content')
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -273,16 +286,52 @@ class MenuForm extends EntityForm {
 | 
				
			||||||
      ]),
 | 
					      ]),
 | 
				
			||||||
    ]);
 | 
					    ]);
 | 
				
			||||||
    $links = $this->buildOverviewTreeForm($tree, $delta);
 | 
					    $links = $this->buildOverviewTreeForm($tree, $delta);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Get the menu links which have pending revisions, and disable the
 | 
				
			||||||
 | 
					    // tabledrag if there are any.
 | 
				
			||||||
 | 
					    $edited_ids = array_filter(array_map(function ($element) {
 | 
				
			||||||
 | 
					      return is_array($element) && isset($element['#item']) && $element['#item']->link instanceof MenuLinkContent ? $element['#item']->link->getMetaData()['entity_id'] : NULL;
 | 
				
			||||||
 | 
					    }, $links));
 | 
				
			||||||
 | 
					    $pending_menu_link_ids = array_intersect($this->menuLinkContentStorage->getMenuLinkIdsWithPendingRevisions(), $edited_ids);
 | 
				
			||||||
 | 
					    if ($pending_menu_link_ids) {
 | 
				
			||||||
 | 
					      $form['help'] = [
 | 
				
			||||||
 | 
					        '#type' => 'container',
 | 
				
			||||||
 | 
					        'message' => [
 | 
				
			||||||
 | 
					          '#markup' => $this->formatPlural(
 | 
				
			||||||
 | 
					            count($pending_menu_link_ids),
 | 
				
			||||||
 | 
					            '%capital_name contains 1 menu link with pending revisions. Manipulation of a menu tree having links with pending revisions is not supported, but you can re-enable manipulation by getting each menu link to a published state.',
 | 
				
			||||||
 | 
					            '%capital_name contains @count menu links with pending revisions. Manipulation of a menu tree having links with pending revisions is not supported, but you can re-enable manipulation by getting each menu link to a published state.',
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					              '%capital_name' => $this->entity->label(),
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        '#attributes' => ['class' => ['messages', 'messages--warning']],
 | 
				
			||||||
 | 
					        '#weight' => -10,
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      unset($form['links']['#tabledrag']);
 | 
				
			||||||
 | 
					      unset($form['links']['#header'][2]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    foreach (Element::children($links) as $id) {
 | 
					    foreach (Element::children($links) as $id) {
 | 
				
			||||||
      if (isset($links[$id]['#item'])) {
 | 
					      if (isset($links[$id]['#item'])) {
 | 
				
			||||||
        $element = $links[$id];
 | 
					        $element = $links[$id];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $is_pending_menu_link = isset($element['#item']->link->getMetaData()['entity_id'])
 | 
				
			||||||
 | 
					          && in_array($element['#item']->link->getMetaData()['entity_id'], $pending_menu_link_ids);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $form['links'][$id]['#item'] = $element['#item'];
 | 
					        $form['links'][$id]['#item'] = $element['#item'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // TableDrag: Mark the table row as draggable.
 | 
					        // TableDrag: Mark the table row as draggable.
 | 
				
			||||||
        $form['links'][$id]['#attributes'] = $element['#attributes'];
 | 
					        $form['links'][$id]['#attributes'] = $element['#attributes'];
 | 
				
			||||||
        $form['links'][$id]['#attributes']['class'][] = 'draggable';
 | 
					        $form['links'][$id]['#attributes']['class'][] = 'draggable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($is_pending_menu_link) {
 | 
				
			||||||
 | 
					          $form['links'][$id]['#attributes']['class'][] = 'color-warning';
 | 
				
			||||||
 | 
					          $form['links'][$id]['#attributes']['class'][] = 'menu-link-content--pending-revision';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // TableDrag: Sort the table row according to its existing/configured weight.
 | 
					        // TableDrag: Sort the table row according to its existing/configured weight.
 | 
				
			||||||
        $form['links'][$id]['#weight'] = $element['#item']->link->getWeight();
 | 
					        $form['links'][$id]['#weight'] = $element['#item']->link->getWeight();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -301,7 +350,14 @@ class MenuForm extends EntityForm {
 | 
				
			||||||
        $form['links'][$id]['enabled'] = $element['enabled'];
 | 
					        $form['links'][$id]['enabled'] = $element['enabled'];
 | 
				
			||||||
        $form['links'][$id]['enabled']['#wrapper_attributes']['class'] = ['checkbox', 'menu-enabled'];
 | 
					        $form['links'][$id]['enabled']['#wrapper_attributes']['class'] = ['checkbox', 'menu-enabled'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $form['links'][$id]['weight'] = $element['weight'];
 | 
					        // Disallow changing the publishing status of a pending revision.
 | 
				
			||||||
 | 
					        if ($is_pending_menu_link) {
 | 
				
			||||||
 | 
					          $form['links'][$id]['enabled']['#access'] = FALSE;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!$pending_menu_link_ids) {
 | 
				
			||||||
 | 
					          $form['links'][$id]['weight'] = $element['weight'];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Operations (dropbutton) column.
 | 
					        // Operations (dropbutton) column.
 | 
				
			||||||
        $form['links'][$id]['operations'] = $element['operations'];
 | 
					        $form['links'][$id]['operations'] = $element['operations'];
 | 
				
			||||||
| 
						 | 
					@ -463,7 +519,7 @@ class MenuForm extends EntityForm {
 | 
				
			||||||
        $updated_values = [];
 | 
					        $updated_values = [];
 | 
				
			||||||
        // Update any fields that have changed in this menu item.
 | 
					        // Update any fields that have changed in this menu item.
 | 
				
			||||||
        foreach ($fields as $field) {
 | 
					        foreach ($fields as $field) {
 | 
				
			||||||
          if ($element[$field]['#value'] != $element[$field]['#default_value']) {
 | 
					          if (isset($element[$field]['#value']) && $element[$field]['#value'] != $element[$field]['#default_value']) {
 | 
				
			||||||
            $updated_values[$field] = $element[$field]['#value'];
 | 
					            $updated_values[$field] = $element[$field]['#value'];
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -987,4 +987,48 @@ class MenuUiTest extends BrowserTestBase {
 | 
				
			||||||
    $block->save();
 | 
					    $block->save();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Test that menu links with pending revisions can not be re-parented.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public function testMenuUiWithPendingRevisions() {
 | 
				
			||||||
 | 
					    $this->drupalLogin($this->adminUser);
 | 
				
			||||||
 | 
					    $assert_session = $this->assertSession();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add four menu links in two separate menus.
 | 
				
			||||||
 | 
					    $menu_1 = $this->addCustomMenu();
 | 
				
			||||||
 | 
					    $root_1 = $this->addMenuLink('', '/', $menu_1->id());
 | 
				
			||||||
 | 
					    $this->addMenuLink($root_1->getPluginId(), '/', $menu_1->id());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $menu_2 = $this->addCustomMenu();
 | 
				
			||||||
 | 
					    $root_2 = $this->addMenuLink('', '/', $menu_2->id());
 | 
				
			||||||
 | 
					    $child_2 = $this->addMenuLink($root_2->getPluginId(), '/', $menu_2->id());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $this->drupalGet('admin/structure/menu/manage/' . $menu_2->id());
 | 
				
			||||||
 | 
					    $assert_session->pageTextNotContains($menu_2->label() . ' contains 1 menu link with pending revisions. Manipulation of a menu tree having links with pending revisions is not supported, but you can re-enable manipulation by getting each menu link to a published state.');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $this->drupalGet('admin/structure/menu/manage/' . $menu_1->id());
 | 
				
			||||||
 | 
					    $assert_session->pageTextNotContains($menu_1->label() . ' contains 1 menu link with pending revisions. Manipulation of a menu tree having links with pending revisions is not supported, but you can re-enable manipulation by getting each menu link to a published state.');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Create a pending revision for one of the menu links and check that it can
 | 
				
			||||||
 | 
					    // no longer be re-parented in the UI. We can not create pending revisions
 | 
				
			||||||
 | 
					    // through the UI yet so we have to use API calls.
 | 
				
			||||||
 | 
					    \Drupal::entityTypeManager()->getStorage('menu_link_content')->createRevision($child_2, FALSE)->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $this->drupalGet('admin/structure/menu/manage/' . $menu_2->id());
 | 
				
			||||||
 | 
					    $assert_session->pageTextContains($menu_2->label() . ' contains 1 menu link with pending revisions. Manipulation of a menu tree having links with pending revisions is not supported, but you can re-enable manipulation by getting each menu link to a published state.');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check that the 'Enabled' checkbox is hidden for a pending revision.
 | 
				
			||||||
 | 
					    $this->assertNotEmpty($this->cssSelect('input[name="links[menu_plugin_id:' . $root_2->getPluginId() . '][enabled]"]'), 'The publishing status of a default revision can be changed.');
 | 
				
			||||||
 | 
					    $this->assertEmpty($this->cssSelect('input[name="links[menu_plugin_id:' . $child_2->getPluginId() . '][enabled]"]'), 'The publishing status of a pending revision can not be changed.');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $this->drupalGet('admin/structure/menu/manage/' . $menu_1->id());
 | 
				
			||||||
 | 
					    $assert_session->pageTextNotContains($menu_1->label() . ' contains 1 menu link with pending revisions. Manipulation of a menu tree having links with pending revisions is not supported, but you can re-enable manipulation by getting each menu link to a published state.');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check that the menu overview form can be saved without errors when there
 | 
				
			||||||
 | 
					    // are pending revisions.
 | 
				
			||||||
 | 
					    $this->drupalPostForm('admin/structure/menu/manage/' . $menu_2->id(), [], 'Save');
 | 
				
			||||||
 | 
					    $errors = $this->xpath('//div[contains(@class, "messages--error")]');
 | 
				
			||||||
 | 
					    $this->assertFalse($errors, 'Menu overview form saved without errors.');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -239,7 +239,7 @@ EOS;
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  public function testEnableModulesFixedList() {
 | 
					  public function testEnableModulesFixedList() {
 | 
				
			||||||
    // Install system module.
 | 
					    // Install system module.
 | 
				
			||||||
    $this->container->get('module_installer')->install(['system', 'menu_link_content']);
 | 
					    $this->container->get('module_installer')->install(['system', 'user', 'menu_link_content']);
 | 
				
			||||||
    $entity_manager = \Drupal::entityManager();
 | 
					    $entity_manager = \Drupal::entityManager();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // entity_test is loaded via $modules; its entity type should exist.
 | 
					    // entity_test is loaded via $modules; its entity type should exist.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -130,6 +130,8 @@ class DbDumpTest extends KernelTestBase {
 | 
				
			||||||
      'key_value_expire',
 | 
					      'key_value_expire',
 | 
				
			||||||
      'menu_link_content',
 | 
					      'menu_link_content',
 | 
				
			||||||
      'menu_link_content_data',
 | 
					      'menu_link_content_data',
 | 
				
			||||||
 | 
					      'menu_link_content_revision',
 | 
				
			||||||
 | 
					      'menu_link_content_field_revision',
 | 
				
			||||||
      'sequences',
 | 
					      'sequences',
 | 
				
			||||||
      'sessions',
 | 
					      'sessions',
 | 
				
			||||||
      'url_alias',
 | 
					      'url_alias',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,6 +41,7 @@ class MenuLinkTreeTest extends KernelTestBase {
 | 
				
			||||||
    'menu_link_content',
 | 
					    'menu_link_content',
 | 
				
			||||||
    'field',
 | 
					    'field',
 | 
				
			||||||
    'link',
 | 
					    'link',
 | 
				
			||||||
 | 
					    'user',
 | 
				
			||||||
  ];
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
| 
						 | 
					@ -49,6 +50,7 @@ class MenuLinkTreeTest extends KernelTestBase {
 | 
				
			||||||
  protected function setUp() {
 | 
					  protected function setUp() {
 | 
				
			||||||
    parent::setUp();
 | 
					    parent::setUp();
 | 
				
			||||||
    \Drupal::service('router.builder')->rebuild();
 | 
					    \Drupal::service('router.builder')->rebuild();
 | 
				
			||||||
 | 
					    $this->installEntitySchema('user');
 | 
				
			||||||
    $this->installEntitySchema('menu_link_content');
 | 
					    $this->installEntitySchema('menu_link_content');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $this->linkTree = $this->container->get('menu.link_tree');
 | 
					    $this->linkTree = $this->container->get('menu.link_tree');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue