Update Composer, update everything

This commit is contained in:
Oliver Davies 2018-11-23 12:29:20 +00:00
parent ea3e94409f
commit dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions

View file

@ -5,4 +5,4 @@ package: Core
version: VERSION
core: 8.x
dependencies:
- link
- drupal:link

View file

@ -16,3 +16,29 @@ function menu_link_content_install() {
// https://www.drupal.org/node/1965074
module_set_weight('menu_link_content', 1);
}
/**
* Add the publishing status entity key to custom menu links.
*/
function menu_link_content_update_8601() {
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$entity_type = $definition_update_manager->getEntityType('menu_link_content');
// Add the published entity key to the menu_link_content entity type.
$entity_keys = $entity_type->getKeys();
$entity_keys['published'] = 'enabled';
$entity_type->set('entity_keys', $entity_keys);
$definition_update_manager->updateEntityType($entity_type);
// @todo The above should be enough, since that is the only definition that
// changed. But \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema varies
// field schema by whether a field is an entity key, so invoke
// EntityDefinitionUpdateManagerInterface::updateFieldStorageDefinition()
// with an unmodified field storage definition to trigger the necessary
// changes. SqlContentEntityStorageSchema::onEntityTypeUpdate() should be
// fixed to automatically handle this.
// @see https://www.drupal.org/node/2554245
$definition_update_manager->updateFieldStorageDefinition($definition_update_manager->getFieldStorageDefinition('enabled', 'menu_link_content'));
return t('The publishing status entity key has been added to custom menu links.');
}

View file

@ -5,6 +5,7 @@
* Allows administrators to create custom menu links.
*/
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\system\MenuInterface;
@ -81,3 +82,31 @@ function menu_link_content_path_update($path) {
function menu_link_content_path_delete($path) {
_menu_link_content_update_path_alias($path['alias']);
}
/**
* Implements hook_entity_predelete().
*/
function menu_link_content_entity_predelete(EntityInterface $entity) {
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
$entity_type_id = $entity->getEntityTypeId();
foreach ($entity->uriRelationships() as $rel) {
$url = $entity->toUrl($rel);
$route_parameters = $url->getRouteParameters();
if (!isset($route_parameters[$entity_type_id])) {
// Do not delete links which do not relate to this exact entity. For
// example, "collection", "add-form", etc.
continue;
}
// Delete all MenuLinkContent links that point to this entity route.
$result = $menu_link_manager->loadLinksByRoute($url->getRouteName(), $route_parameters);
if ($result) {
foreach ($result as $id => $instance) {
if ($instance->isDeletable() && strpos($id, 'menu_link_content:') === 0) {
$instance->deleteLink();
}
}
}
}
}

View file

@ -1,7 +1,9 @@
id: d6_menu_links
label: Menu links
audit: true
migration_tags:
- Drupal 6
- Content
source:
plugin: menu_link
process:
@ -54,3 +56,5 @@ destination:
migration_dependencies:
required:
- d6_menu
optional:
- d6_node

View file

@ -1,7 +1,9 @@
id: d7_menu_links
label: Menu links
audit: true
migration_tags:
- Drupal 7
- Content
source:
plugin: menu_link
constants:
@ -50,3 +52,5 @@ destination:
migration_dependencies:
required:
- d7_menu
optional:
- d7_node

View file

@ -4,6 +4,7 @@ namespace Drupal\menu_link_content\Entity;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityPublishedTrait;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
@ -19,6 +20,13 @@ use Drupal\menu_link_content\MenuLinkContentInterface;
* @ContentEntityType(
* id = "menu_link_content",
* label = @Translation("Custom menu link"),
* label_collection = @Translation("Custom menu links"),
* label_singular = @Translation("custom menu link"),
* label_plural = @Translation("custom menu links"),
* label_count = @PluralTranslation(
* singular = "@count custom menu link",
* plural = "@count custom menu links",
* ),
* handlers = {
* "storage" = "Drupal\Core\Entity\Sql\SqlContentEntityStorage",
* "storage_schema" = "Drupal\menu_link_content\MenuLinkContentStorageSchema",
@ -37,7 +45,8 @@ use Drupal\menu_link_content\MenuLinkContentInterface;
* "label" = "title",
* "langcode" = "langcode",
* "uuid" = "uuid",
* "bundle" = "bundle"
* "bundle" = "bundle",
* "published" = "enabled",
* },
* links = {
* "canonical" = "/admin/structure/menu/item/{menu_link_content}/edit",
@ -49,6 +58,7 @@ use Drupal\menu_link_content\MenuLinkContentInterface;
class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterface {
use EntityChangedTrait;
use EntityPublishedTrait;
/**
* A flag for whether this entity is wrapped in a plugin instance.
@ -186,6 +196,7 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf
$this->setRequiresRediscovery(FALSE);
}
}
/**
* {@inheritdoc}
*/
@ -228,6 +239,14 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf
foreach ($entities as $menu_link) {
/** @var \Drupal\menu_link_content\Entity\MenuLinkContent $menu_link */
$menu_link_manager->removeDefinition($menu_link->getPluginId(), FALSE);
// Children get re-attached to the menu link's parent.
$parent_plugin_id = $menu_link->getParentId();
$children = $storage->loadByProperties(['parent' => $menu_link->getPluginId()]);
foreach ($children as $child) {
/** @var \Drupal\menu_link_content\Entity\MenuLinkContent $child */
$child->set('parent', $parent_plugin_id)->save();
}
}
}
@ -238,6 +257,9 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf
/** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
$fields = parent::baseFieldDefinitions($entity_type);
// Add the publishing status field.
$fields += static::publishedBaseFieldDefinitions($entity_type);
$fields['id']->setLabel(t('Entity ID'))
->setDescription(t('The entity ID for this menu link content entity.'));
@ -316,7 +338,7 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf
->setDefaultValue(0)
->setDisplayOptions('view', [
'label' => 'hidden',
'type' => 'integer',
'type' => 'number_integer',
'weight' => 0,
])
->setDisplayOptions('form', [
@ -338,19 +360,21 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf
'weight' => 0,
]);
$fields['enabled'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Enabled'))
->setDescription(t('A flag for whether the link should be enabled in menus or hidden.'))
->setDefaultValue(TRUE)
->setDisplayOptions('view', [
'label' => 'hidden',
'type' => 'boolean',
'weight' => 0,
])
->setDisplayOptions('form', [
'settings' => ['display_label' => TRUE],
'weight' => -1,
]);
// Override some properties of the published field added by
// \Drupal\Core\Entity\EntityPublishedTrait::publishedBaseFieldDefinitions().
$fields['enabled']->setLabel(t('Enabled'));
$fields['enabled']->setDescription(t('A flag for whether the link should be enabled in menus or hidden.'));
$fields['enabled']->setTranslatable(FALSE);
$fields['enabled']->setRevisionable(FALSE);
$fields['enabled']->setDisplayOptions('view', [
'label' => 'hidden',
'type' => 'boolean',
'weight' => 0,
]);
$fields['enabled']->setDisplayOptions('form', [
'settings' => ['display_label' => TRUE],
'weight' => -1,
]);
$fields['parent'] = BaseFieldDefinition::create('string')
->setLabel(t('Parent plugin ID'))

View file

@ -7,6 +7,8 @@ use Drupal\Core\Url;
/**
* Provides a delete form for content menu links.
*
* @internal
*/
class MenuLinkContentDeleteForm extends ContentEntityDeleteForm {

View file

@ -4,7 +4,7 @@ namespace Drupal\menu_link_content\Form;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
@ -14,6 +14,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a form to add/update content menu links.
*
* @internal
*/
class MenuLinkContentForm extends ContentEntityForm {
@ -41,8 +43,8 @@ class MenuLinkContentForm extends ContentEntityForm {
/**
* Constructs a MenuLinkContentForm object.
*
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository.
* @param \Drupal\Core\Menu\MenuParentFormSelectorInterface $menu_parent_selector
* The menu parent form selector service.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
@ -54,8 +56,8 @@ class MenuLinkContentForm extends ContentEntityForm {
* @param \Drupal\Component\Datetime\TimeInterface $time
* The time service.
*/
public function __construct(EntityManagerInterface $entity_manager, MenuParentFormSelectorInterface $menu_parent_selector, LanguageManagerInterface $language_manager, PathValidatorInterface $path_validator, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL) {
parent::__construct($entity_manager, $entity_type_bundle_info, $time);
public function __construct(EntityRepositoryInterface $entity_repository, MenuParentFormSelectorInterface $menu_parent_selector, LanguageManagerInterface $language_manager, PathValidatorInterface $path_validator, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL) {
parent::__construct($entity_repository, $entity_type_bundle_info, $time);
$this->menuParentSelector = $menu_parent_selector;
$this->pathValidator = $path_validator;
}
@ -65,7 +67,7 @@ class MenuLinkContentForm extends ContentEntityForm {
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.manager'),
$container->get('entity.repository'),
$container->get('menu.parent_form_selector'),
$container->get('language_manager'),
$container->get('path.validator'),
@ -128,14 +130,14 @@ class MenuLinkContentForm extends ContentEntityForm {
$saved = $menu_link->save();
if ($saved) {
drupal_set_message($this->t('The menu link has been saved.'));
$this->messenger()->addStatus($this->t('The menu link has been saved.'));
$form_state->setRedirect(
'entity.menu_link_content.canonical',
['menu_link_content' => $menu_link->id()]
);
}
else {
drupal_set_message($this->t('There was an error saving the menu link.'), 'error');
$this->messenger()->addError($this->t('There was an error saving the menu link.'));
$form_state->setRebuild();
}
}

View file

@ -4,11 +4,12 @@ namespace Drupal\menu_link_content;
use Drupal\Core\Entity\EntityChangedInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityPublishedInterface;
/**
* Defines an interface for custom menu links.
*/
interface MenuLinkContentInterface extends ContentEntityInterface, EntityChangedInterface {
interface MenuLinkContentInterface extends ContentEntityInterface, EntityChangedInterface, EntityPublishedInterface {
/**
* Flags this instance as being wrapped in a menu link plugin instance.

View file

@ -17,7 +17,7 @@ class MenuLinkContentStorageSchema extends SqlContentEntityStorageSchema {
$schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping);
$field_name = $storage_definition->getName();
if ($table_name == 'menu_link_content') {
if ($table_name == $this->storage->getBaseTable()) {
switch ($field_name) {
case 'rediscover':
$this->addSharedTableFieldIndex($storage_definition, $schema, TRUE);

View file

@ -5,6 +5,7 @@ namespace Drupal\menu_link_content\Plugin\migrate\process;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Url;
use Drupal\migrate\MigrateException;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
@ -13,6 +14,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Processes a link path into an 'internal:' or 'entity:' URI.
*
* @todo: Add documentation in https://www.drupal.org/node/2954908
*
* @MigrateProcessPlugin(
* id = "link_uri"
* )
@ -39,6 +42,9 @@ class LinkUri extends ProcessPluginBase implements ContainerFactoryPluginInterfa
* The entity type manager, used to fetch entity link templates.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) {
$configuration += [
'validate_route' => TRUE,
];
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
}
@ -80,6 +86,17 @@ class LinkUri extends ProcessPluginBase implements ContainerFactoryPluginInterfa
}
}
}
else {
// If the URL is not routed, we might want to get something back to do
// other processing. If this is the case, the "validate_route"
// configuration option can be set to FALSE to return the URI.
if (!$this->configuration['validate_route']) {
return $url->getUri();
}
else {
throw new MigrateException(sprintf('The path "%s" failed validation.', $path));
}
}
}
return $path;
}

View file

@ -2,7 +2,7 @@
namespace Drupal\menu_link_content\Plugin\migrate\process\d6;
use \Drupal\menu_link_content\Plugin\migrate\process\LinkUri as RealLinkUri;
use Drupal\menu_link_content\Plugin\migrate\process\LinkUri as RealLinkUri;
/**
* Processes a link path into an 'internal:' or 'entity:' URI.

View file

@ -11,6 +11,7 @@ use Drupal\migrate\Row;
*
* @MigrateSource(
* id = "menu_link",
* source_module = "menu"
* )
*/
class MenuLink extends DrupalSqlBase {

View file

@ -0,0 +1,92 @@
<?php
namespace Drupal\menu_link_content\Plugin\migrate\source\d6;
use Drupal\content_translation\Plugin\migrate\source\I18nQueryTrait;
use Drupal\migrate\Row;
use Drupal\menu_link_content\Plugin\migrate\source\MenuLink;
/**
* Gets Menu link translations from source database.
*
* @MigrateSource(
* id = "d6_menu_link_translation",
* source_module = "i18nmenu"
* )
*/
class MenuLinkTranslation extends MenuLink {
use I18nQueryTrait;
/**
* Drupal 6 table names.
*/
const I18N_STRING_TABLE = 'i18n_strings';
/**
* {@inheritdoc}
*/
public function query() {
// Ideally, the query would return rows for each language for each menu link
// with the translations for both the title and description or just the
// title translation or just the description translation. That query quickly
// became complex and would be difficult to maintain.
// Therefore, build a query based on i18nstrings table where each row has
// the translation for only one property, either title or description. The
// method prepareRow() is then used to obtain the translation for the other
// property.
// The query starts with the same query as menu_link.
$query = parent::query();
// Add in the property, which is either title or description. Cast the mlid
// to text so PostgreSQL can make the join.
$query->leftJoin(static::I18N_STRING_TABLE, 'i18n', 'CAST(ml.mlid as CHAR(255)) = i18n.objectid');
$query->isNotNull('i18n.lid');
$query->addField('i18n', 'lid');
$query->addField('i18n', 'property');
// Add in the translation for the property.
$query->innerJoin('locales_target', 'lt', 'i18n.lid = lt.lid');
$query->addField('lt', 'language');
$query->addField('lt', 'translation');
return $query;
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
parent::prepareRow($row);
// Save the translation for this property.
$property_in_row = $row->getSourceProperty('property');
// Set the i18n string table for use in I18nQueryTrait.
$this->i18nStringTable = static::I18N_STRING_TABLE;
// Get the translation for the property not already in the row and save it
// in the row.
$property_not_in_row = ($property_in_row == 'title') ? 'description' : 'title';
return $this->getPropertyNotInRowTranslation($row, $property_not_in_row, 'mlid', $this->idMap);
}
/**
* {@inheritdoc}
*/
public function fields() {
$fields = [
'language' => $this->t('Language for this menu.'),
'title_translated' => $this->t('Menu link title translation.'),
'description_translated' => $this->t('Menu link description translation.'),
];
return parent::fields() + $fields;
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['language']['type'] = 'string';
return parent::getIds() + $ids;
}
}

View file

@ -3,4 +3,4 @@ type: module
core: 8.x
hidden: true
dependencies:
- menu_link_content
- drupal:menu_link_content

View file

@ -0,0 +1,74 @@
<?php
namespace Drupal\Tests\menu_link_content\Functional\Hal;
use Drupal\Core\Cache\Cache;
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
use Drupal\Tests\menu_link_content\Functional\Rest\MenuLinkContentResourceTestBase;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group hal
*/
class MenuLinkContentHalJsonAnonTest extends MenuLinkContentResourceTestBase {
use HalEntityNormalizationTrait;
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
$default_normalization = parent::getExpectedNormalizedEntity();
$normalization = $this->applyHalFieldNormalization($default_normalization);
return $normalization + [
'_links' => [
'self' => [
'href' => $this->baseUrl . '/admin/structure/menu/item/1/edit?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/menu_link_content/menu_link_content',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return parent::getNormalizedPostEntity() + [
'_links' => [
'type' => [
'href' => $this->baseUrl . '/rest/type/menu_link_content/menu_link_content',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedCacheContexts() {
// The 'url.site' cache context is added for '_links' in the response.
return Cache::mergeTags(parent::getExpectedCacheContexts(), ['url.site']);
}
}

View file

@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\menu_link_content\Functional\Hal;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group hal
*/
class MenuLinkContentHalJsonBasicAuthTest extends MenuLinkContentHalJsonAnonTest {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,19 @@
<?php
namespace Drupal\Tests\menu_link_content\Functional\Hal;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group hal
*/
class MenuLinkContentHalJsonCookieTest extends MenuLinkContentHalJsonAnonTest {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -2,10 +2,12 @@
namespace Drupal\Tests\menu_link_content\Functional;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\Tests\BrowserTestBase;
use Drupal\system\Entity\Menu;
use Drupal\Tests\BrowserTestBase;
use Drupal\user\Entity\User;
/**
* Tests handling of menu links hierarchies.
@ -24,7 +26,7 @@ class LinksTest extends BrowserTestBase {
/**
* The menu link plugin manager.
*
* @var \Drupal\Core\Menu\MenuLinkManagerInterface $menuLinkManager
* @var \Drupal\Core\Menu\MenuLinkManagerInterface
*/
protected $menuLinkManager;
@ -113,7 +115,7 @@ class LinksTest extends BrowserTestBase {
$menu_link_plugin = $this->menuLinkManager->createInstance($links[$id]);
$expected_parent = isset($links[$parent]) ? $links[$parent] : '';
$this->assertEqual($menu_link_plugin->getParent(), $expected_parent, SafeMarkup::format('Menu link %id has parent of %parent, expected %expected_parent.', ['%id' => $id, '%parent' => $menu_link_plugin->getParent(), '%expected_parent' => $expected_parent]));
$this->assertEqual($menu_link_plugin->getParent(), $expected_parent, new FormattableMarkup('Menu link %id has parent of %parent, expected %expected_parent.', ['%id' => $id, '%parent' => $menu_link_plugin->getParent(), '%expected_parent' => $expected_parent]));
}
}
@ -125,6 +127,7 @@ class LinksTest extends BrowserTestBase {
'menu_name' => 'menu_test',
'bundle' => 'menu_link_content',
'link' => [['uri' => 'internal:/']],
'title' => 'Link test',
];
$link = MenuLinkContent::create($options);
$link->save();
@ -140,6 +143,49 @@ class LinksTest extends BrowserTestBase {
$this->assertEqual($link->getChangedTime(), REQUEST_TIME, 'Changing a menu link sets "changed" timestamp.');
}
/**
* Tests that menu link pointing to entities get removed on entity remove.
*/
public function testMenuLinkOnEntityDelete() {
// Create user.
$user = User::create(['name' => 'username']);
$user->save();
// Create "canonical" menu link pointing to the user.
$menu_link_content = MenuLinkContent::create([
'title' => 'username profile',
'menu_name' => 'menu_test',
'link' => [['uri' => 'entity:user/' . $user->id()]],
'bundle' => 'menu_test',
]);
$menu_link_content->save();
// Create "collection" menu link pointing to the user listing page.
$menu_link_content_collection = MenuLinkContent::create([
'title' => 'users listing',
'menu_name' => 'menu_test',
'link' => [['uri' => 'internal:/' . $user->toUrl('collection')->getInternalPath()]],
'bundle' => 'menu_test',
]);
$menu_link_content_collection->save();
// Check is menu links present in the menu.
$menu_tree_condition = (new MenuTreeParameters())->addCondition('route_name', 'entity.user.canonical');
$this->assertCount(1, \Drupal::menuTree()->load('menu_test', $menu_tree_condition));
$menu_tree_condition_collection = (new MenuTreeParameters())->addCondition('route_name', 'entity.user.collection');
$this->assertCount(1, \Drupal::menuTree()->load('menu_test', $menu_tree_condition_collection));
// Delete the user.
$user->delete();
// The "canonical" menu item has to be deleted.
$this->assertCount(0, \Drupal::menuTree()->load('menu_test', $menu_tree_condition));
// The "collection" menu item should still present in the menu.
$this->assertCount(1, \Drupal::menuTree()->load('menu_test', $menu_tree_condition_collection));
}
/**
* Test automatic reparenting of menu links.
*/

View file

@ -78,6 +78,8 @@ class MenuLinkContentFormTest extends BrowserTestBase {
$element = $this->xpath('//select[@id = :id]/option[@selected]', [':id' => 'edit-menu-parent']);
$this->assertTrue($element, 'A default menu parent was found.');
$this->assertEqual('admin:', $element[0]->getValue(), '<Administration> menu is the parent.');
// Test that the field description is present.
$this->assertRaw('The location this menu link points to.');
$this->drupalPostForm(
NULL,

View file

@ -70,7 +70,11 @@ class MenuLinkContentTranslationUITest extends ContentTranslationUITestBase {
$this->drupalGet('admin/structure/menu/manage/tools');
$this->assertNoLink(t('Translate'));
$menu_link_content = MenuLinkContent::create(['menu_name' => 'tools', 'link' => ['uri' => 'internal:/admin/structure/menu']]);
$menu_link_content = MenuLinkContent::create([
'menu_name' => 'tools',
'link' => ['uri' => 'internal:/admin/structure/menu'],
'title' => 'Link test',
]);
$menu_link_content->save();
$this->drupalGet('admin/structure/menu/manage/tools');
$this->assertLink(t('Translate'));

View file

@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\menu_link_content\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group rest
*/
class MenuLinkContentJsonAnonTest extends MenuLinkContentResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
}

View file

@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\menu_link_content\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group rest
*/
class MenuLinkContentJsonBasicAuthTest extends MenuLinkContentResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,29 @@
<?php
namespace Drupal\Tests\menu_link_content\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group rest
*/
class MenuLinkContentJsonCookieTest extends MenuLinkContentResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,213 @@
<?php
namespace Drupal\Tests\menu_link_content\Functional\Rest;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
/**
* ResourceTestBase for MenuLinkContent entity.
*/
abstract class MenuLinkContentResourceTestBase extends EntityResourceTestBase {
use BcTimestampNormalizerUnixTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['menu_link_content'];
/**
* {@inheritdoc}
*/
protected static $entityTypeId = 'menu_link_content';
/**
* {@inheritdoc}
*/
protected static $patchProtectedFieldNames = [
'changed' => NULL,
];
/**
* The MenuLinkContent entity.
*
* @var \Drupal\menu_link_content\MenuLinkContentInterface
*/
protected $entity;
/**
* {@inheritdoc}
*/
protected function setUpAuthorization($method) {
switch ($method) {
case 'GET':
case 'POST':
case 'PATCH':
case 'DELETE':
$this->grantPermissionsToTestedRole(['administer menu']);
break;
}
}
/**
* {@inheritdoc}
*/
protected function createEntity() {
$menu_link = MenuLinkContent::create([
'id' => 'llama',
'title' => 'Llama Gabilondo',
'description' => 'Llama Gabilondo',
'link' => [
'uri' => 'https://nl.wikipedia.org/wiki/Llama',
'options' => [
'fragment' => 'a-fragment',
'attributes' => [
'class' => ['example-class'],
],
],
],
'weight' => 0,
'menu_name' => 'main',
]);
$menu_link->save();
return $menu_link;
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return [
'title' => [
[
'value' => 'Dramallama',
],
],
'link' => [
[
'uri' => 'http://www.urbandictionary.com/define.php?term=drama%20llama',
'options' => [
'fragment' => 'a-fragment',
'attributes' => [
'class' => ['example-class'],
],
],
],
],
'bundle' => [
[
'value' => 'menu_link_content',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
return [
'uuid' => [
[
'value' => $this->entity->uuid(),
],
],
'id' => [
[
'value' => 1,
],
],
'title' => [
[
'value' => 'Llama Gabilondo',
],
],
'link' => [
[
'uri' => 'https://nl.wikipedia.org/wiki/Llama',
'title' => NULL,
'options' => [
'fragment' => 'a-fragment',
'attributes' => [
'class' => ['example-class'],
],
],
],
],
'weight' => [
[
'value' => 0,
],
],
'menu_name' => [
[
'value' => 'main',
],
],
'langcode' => [
[
'value' => 'en',
],
],
'bundle' => [
[
'value' => 'menu_link_content',
],
],
'description' => [
[
'value' => 'Llama Gabilondo',
],
],
'external' => [
[
'value' => FALSE,
],
],
'rediscover' => [
[
'value' => FALSE,
],
],
'expanded' => [
[
'value' => FALSE,
],
],
'enabled' => [
[
'value' => TRUE,
],
],
'changed' => [
$this->formatExpectedTimestampItemValues($this->entity->getChangedTime()),
],
'default_langcode' => [
[
'value' => TRUE,
],
],
'parent' => [],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessMessage($method) {
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
return parent::getExpectedUnauthorizedAccessMessage($method);
}
switch ($method) {
case 'DELETE':
return "You are not authorized to delete this menu_link_content entity.";
default:
return parent::getExpectedUnauthorizedAccessMessage($method);
}
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace Drupal\Tests\menu_link_content\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class MenuLinkContentXmlAnonTest extends MenuLinkContentResourceTestBase {
use AnonResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\Tests\menu_link_content\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class MenuLinkContentXmlBasicAuthTest extends MenuLinkContentResourceTestBase {
use BasicAuthResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,31 @@
<?php
namespace Drupal\Tests\menu_link_content\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class MenuLinkContentXmlCookieTest extends MenuLinkContentResourceTestBase {
use CookieResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,69 @@
<?php
namespace Drupal\Tests\menu_link_content\Functional\Update;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
use Drupal\user\Entity\User;
/**
* Tests the upgrade path for custom menu links.
*
* @group menu_link_content
* @group Update
* @group legacy
*/
class MenuLinkContentUpdateTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.filled.standard.php.gz',
];
}
/**
* Tests the addition of the publishing status entity key.
*
* @see menu_link_content_update_8601()
*/
public function testPublishedEntityKeyAddition() {
$this->runUpdates();
// 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();
$menu_link = $storage->loadUnchanged($menu_link->id());
$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}
*/
protected function replaceUser1() {
// Do not replace the user from our dump.
}
}

View file

@ -59,7 +59,6 @@ class MenuLinkContentCacheabilityBubblingTest extends KernelTestBase {
$menu_tree = \Drupal::menuTree();
$renderer = \Drupal::service('renderer');
$default_menu_cacheability = (new BubbleableMetadata())
->setCacheMaxAge(Cache::PERMANENT)
->setCacheTags(['config:system.menu.tools'])
@ -109,6 +108,7 @@ class MenuLinkContentCacheabilityBubblingTest extends KernelTestBase {
$menu_link_content = MenuLinkContent::create([
'link' => ['uri' => $expectation['uri']],
'menu_name' => 'tools',
'title' => 'Link test',
]);
$menu_link_content->save();
$tree = $menu_tree->load('tools', new MenuTreeParameters());
@ -129,6 +129,7 @@ class MenuLinkContentCacheabilityBubblingTest extends KernelTestBase {
$menu_link_content = MenuLinkContent::create([
'link' => ['uri' => $expectation['uri']],
'menu_name' => 'tools',
'title' => 'Link test',
]);
$menu_link_content->save();
$expected_cacheability = $expected_cacheability->merge($expectation['cacheability']);

View file

@ -0,0 +1,62 @@
<?php
namespace Drupal\Tests\menu_link_content\Kernel;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests the menu link content delete function.
*
* @group menu_link_content
*/
class MenuLinkContentDeleteTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['menu_link_content', 'link', 'system'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('menu_link_content');
}
/**
* Tests the MenuLinkContent::preDelete function.
*/
public function testMenuLinkContentDelete() {
// Add new menu items in a hierarchy.
$parent = MenuLinkContent::create([
'title' => $this->randomMachineName(8),
'link' => [['uri' => 'internal:/']],
'menu_name' => 'main',
]);
$parent->save();
$child1 = MenuLinkContent::create([
'title' => $this->randomMachineName(8),
'link' => [['uri' => 'internal:/']],
'menu_name' => 'main',
'parent' => 'menu_link_content:' . $parent->uuid(),
]);
$child1->save();
$child2 = MenuLinkContent::create([
'title' => $this->randomMachineName(8),
'link' => [['uri' => 'internal:/']],
'menu_name' => 'main',
'parent' => 'menu_link_content:' . $child1->uuid(),
]);
$child2->save();
// Delete the middle child.
$child1->delete();
// Refresh $child2.
$child2 = MenuLinkContent::load($child2->id());
// Test the reference in the child.
$this->assertSame('menu_link_content:' . $parent->uuid(), $child2->getParentId());
}
}

View file

@ -3,19 +3,27 @@
namespace Drupal\Tests\menu_link_content\Kernel\Migrate\d6;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
use Drupal\menu_link_content\MenuLinkContentInterface;
use Drupal\Tests\node\Kernel\Migrate\d6\MigrateNodeTestBase;
/**
* Menu link migration.
*
* @group migrate_drupal_6
*/
class MigrateMenuLinkTest extends MigrateDrupal6TestBase {
class MigrateMenuLinkTest extends MigrateNodeTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['menu_ui', 'menu_link_content'];
public static $modules = [
'content_translation',
'language',
'menu_link_content',
// Required for translation migrations.
'migrate_drupal_multilingual',
'menu_ui',
];
/**
* {@inheritdoc}
@ -23,53 +31,76 @@ class MigrateMenuLinkTest extends MigrateDrupal6TestBase {
protected function setUp() {
parent::setUp();
$this->installEntitySchema('menu_link_content');
$this->executeMigrations(['d6_menu', 'd6_menu_links']);
$this->executeMigrations([
'language',
'd6_language_content_settings',
'd6_node',
'd6_node_translation',
'd6_menu',
'd6_menu_links',
'node_translation_menu_links',
]);
}
/**
* Asserts various aspects of a menu link entity.
*
* @param string $id
* The link ID.
* @param string $title
* The expected title of the link.
* @param string $menu
* The expected ID of the menu to which the link will belong.
* @param string $description
* The link's expected description.
* @param bool $enabled
* Whether the link is enabled.
* @param bool $expanded
* Whether the link is expanded.
* @param array $attributes
* Additional attributes the link is expected to have.
* @param string $uri
* The expected URI of the link.
* @param int $weight
* The expected weight of the link.
*
* @return \Drupal\menu_link_content\MenuLinkContentInterface
* The menu link content.
*/
protected function assertEntity($id, $title, $menu, $description, $enabled, $expanded, array $attributes, $uri, $weight) {
/** @var \Drupal\menu_link_content\MenuLinkContentInterface $menu_link */
$menu_link = MenuLinkContent::load($id);
$this->assertInstanceOf(MenuLinkContentInterface::class, $menu_link);
$this->assertSame($title, $menu_link->getTitle());
$this->assertSame($menu, $menu_link->getMenuName());
$this->assertSame($description, $menu_link->getDescription());
$this->assertSame($enabled, $menu_link->isEnabled());
$this->assertSame($expanded, $menu_link->isExpanded());
$this->assertSame($attributes, $menu_link->link->options);
$this->assertSame($uri, $menu_link->link->uri);
$this->assertSame($weight, $menu_link->getWeight());
return $menu_link;
}
/**
* Tests migration of menu links.
*/
public function testMenuLinks() {
$menu_link = MenuLinkContent::load(138);
$this->assertIdentical('Test 1', $menu_link->getTitle());
$this->assertIdentical('secondary-links', $menu_link->getMenuName());
$this->assertIdentical('Test menu link 1', $menu_link->getDescription());
$this->assertIdentical(TRUE, $menu_link->isEnabled());
$this->assertIdentical(FALSE, $menu_link->isExpanded());
$this->assertIdentical(['attributes' => ['title' => 'Test menu link 1']], $menu_link->link->options);
$this->assertIdentical('internal:/user/login', $menu_link->link->uri);
$this->assertIdentical(-50, $menu_link->getWeight());
$this->assertEntity('138', 'Test 1', 'secondary-links', 'Test menu link 1', TRUE, FALSE, ['attributes' => ['title' => 'Test menu link 1'], 'langcode' => 'en'], 'internal:/user/login', -50);
$this->assertEntity('139', 'Test 2', 'secondary-links', 'Test menu link 2', TRUE, TRUE, ['query' => 'foo=bar', 'attributes' => ['title' => 'Test menu link 2']], 'internal:/admin', -49);
$this->assertEntity('140', 'Drupal.org', 'secondary-links', NULL, TRUE, FALSE, ['attributes' => ['title' => '']], 'https://www.drupal.org', -50);
$menu_link = MenuLinkContent::load(139);
$this->assertIdentical('Test 2', $menu_link->getTitle());
$this->assertIdentical('secondary-links', $menu_link->getMenuName());
$this->assertIdentical('Test menu link 2', $menu_link->getDescription());
$this->assertIdentical(TRUE, $menu_link->isEnabled());
$this->assertIdentical(TRUE, $menu_link->isExpanded());
$this->assertIdentical(['query' => 'foo=bar', 'attributes' => ['title' => 'Test menu link 2']], $menu_link->link->options);
$this->assertIdentical('internal:/admin', $menu_link->link->uri);
$this->assertIdentical(-49, $menu_link->getWeight());
// Assert that missing title attributes don't stop or break migration.
$this->assertEntity('393', 'Test 3', 'secondary-links', NULL, TRUE, FALSE, [], 'internal:/user/login', -47);
$menu_link = MenuLinkContent::load(140);
$this->assertIdentical('Drupal.org', $menu_link->getTitle());
$this->assertIdentical('secondary-links', $menu_link->getMenuName());
$this->assertIdentical(NULL, $menu_link->getDescription());
$this->assertIdentical(TRUE, $menu_link->isEnabled());
$this->assertIdentical(FALSE, $menu_link->isExpanded());
$this->assertIdentical(['attributes' => ['title' => '']], $menu_link->link->options);
$this->assertIdentical('https://www.drupal.org', $menu_link->link->uri);
$this->assertIdentical(-50, $menu_link->getWeight());
// Test the migration of menu links for translated nodes.
$this->assertEntity('459', 'The Real McCoy', 'primary-links', NULL, TRUE, FALSE, ['attributes' => ['title' => ''], 'alter' => TRUE], 'entity:node/10', 0);
$this->assertEntity('460', 'Le Vrai McCoy', 'primary-links', NULL, TRUE, FALSE, ['attributes' => ['title' => ''], 'alter' => TRUE], 'entity:node/10', 0);
$this->assertEntity('461', 'Abantu zulu', 'primary-links', NULL, TRUE, FALSE, ['attributes' => ['title' => ''], 'alter' => TRUE], 'entity:node/12', 0);
$this->assertEntity('462', 'The Zulu People', 'primary-links', NULL, TRUE, FALSE, ['attributes' => ['title' => ''], 'alter' => TRUE], 'entity:node/12', 0);
// assert that missing title attributes don't stop or break migration.
$menu_link = MenuLinkContent::load(393);
$this->assertIdentical('Test 3', $menu_link->getTitle());
$this->assertIdentical('secondary-links', $menu_link->getMenuName());
$this->assertIdentical(NULL, $menu_link->getDescription());
$this->assertIdentical(TRUE, $menu_link->isEnabled());
$this->assertIdentical(FALSE, $menu_link->isExpanded());
$this->assertIdentical([], $menu_link->link->options);
$this->assertIdentical('internal:/user/login', $menu_link->link->uri);
$this->assertIdentical(-47, $menu_link->getWeight());
// Test the migration of menu links translation.
$this->assertEntity('463', 'fr - Test 1', 'secondary-links', 'fr - Test menu link 1', TRUE, FALSE, ['attributes' => ['title' => 'fr - Test menu link 1'], 'langcode' => 'fr', 'alter' => TRUE], 'internal:/user/login', -49);
}
}

View file

@ -0,0 +1,100 @@
<?php
namespace Drupal\Tests\menu_link_content\Kernel\Migrate\d6;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Menu link migration.
*
* @group migrate_drupal_6
*/
class MigrateMenuLinkTranslationTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
public static $modules = [
'menu_ui',
'menu_link_content',
'language',
'content_translation',
// Required for translation migrations.
'migrate_drupal_multilingual',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->migrateContent();
$this->installSchema('system', ['router']);
$this->installEntitySchema('menu_link_content');
$this->executeMigrations([
'language',
'd6_menu',
'd6_menu_links',
'd6_menu_links_translation',
]);
}
/**
* Tests migration of menu links.
*/
public function testMenuLinks() {
/** @var \Drupal\menu_link_content\Entity\MenuLinkContent $menu_link */
$menu_link = MenuLinkContent::load(139)->getTranslation('fr');
$this->assertInstanceOf(MenuLinkContent::class, $menu_link);
$this->assertSame('fr - Test 2', $menu_link->getTitle());
$this->assertSame('fr - Test menu link 2', $menu_link->getDescription());
$this->assertSame('secondary-links', $menu_link->getMenuName());
$this->assertTrue($menu_link->isEnabled());
$this->assertTrue($menu_link->isExpanded());
$this->assertSame(['query' => 'foo=bar', 'attributes' => ['title' => 'Test menu link 2']], $menu_link->link->options);
$this->assertSame('internal:/admin', $menu_link->link->uri);
$this->assertSame(-49, $menu_link->getWeight());
$menu_link = MenuLinkContent::load(139)->getTranslation('zu');
$this->assertInstanceOf(MenuLinkContent::class, $menu_link);
$this->assertSame('Test 2', $menu_link->getTitle());
$this->assertSame('zu - Test menu link 2', $menu_link->getDescription());
$this->assertSame('secondary-links', $menu_link->getMenuName());
$this->assertTrue($menu_link->isEnabled());
$this->assertTrue($menu_link->isExpanded());
$this->assertSame(['query' => 'foo=bar', 'attributes' => ['title' => 'Test menu link 2']], $menu_link->link->options);
$this->assertSame('internal:/admin', $menu_link->link->uri);
$this->assertSame(-49, $menu_link->getWeight());
$menu_link = MenuLinkContent::load(140)->getTranslation('fr');
$this->assertInstanceOf(MenuLinkContent::class, $menu_link);
$this->assertSame('fr - Drupal.org', $menu_link->getTitle());
$this->assertSame('', $menu_link->getDescription());
$this->assertSame('secondary-links', $menu_link->getMenuName());
$this->assertTrue($menu_link->isEnabled());
$this->assertFalse($menu_link->isExpanded());
$this->assertSame(['attributes' => ['title' => '']], $menu_link->link->options);
$this->assertSame('https://www.drupal.org', $menu_link->link->uri);
$this->assertSame(-50, $menu_link->getWeight());
$menu_link = MenuLinkContent::load(463);
$this->assertInstanceOf(MenuLinkContent::class, $menu_link);
$this->assertSame('fr - Test 1', $menu_link->getTitle());
$this->assertSame('fr - Test menu link 1', $menu_link->getDescription());
$this->assertSame('secondary-links', $menu_link->getMenuName());
$this->assertTrue($menu_link->isEnabled());
$this->assertFalse($menu_link->isExpanded());
$attributes = [
'attributes' => [
'title' => 'fr - Test menu link 1',
],
'langcode' => 'fr',
'alter' => TRUE,
];
$this->assertSame($attributes, $menu_link->link->options);
$this->assertSame('internal:/user/login', $menu_link->link->uri);
$this->assertSame(-49, $menu_link->getWeight());
}
}

View file

@ -5,7 +5,6 @@ namespace Drupal\Tests\menu_link_content\Kernel\Migrate\d7;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\menu_link_content\MenuLinkContentInterface;
use Drupal\node\Entity\Node;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
/**
@ -19,7 +18,17 @@ class MigrateMenuLinkTest extends MigrateDrupal7TestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['link', 'menu_ui', 'menu_link_content', 'node'];
public static $modules = [
'content_translation',
'language',
'link',
'menu_ui',
'menu_link_content',
// Required for translation migrations.
'migrate_drupal_multilingual',
'node',
'text',
];
/**
* {@inheritdoc}
@ -28,13 +37,20 @@ class MigrateMenuLinkTest extends MigrateDrupal7TestBase {
parent::setUp();
$this->installEntitySchema('menu_link_content');
$this->installEntitySchema('node');
$node = Node::create([
'nid' => 3,
'title' => 'node link test',
'type' => 'article',
$this->installSchema('node', ['node_access']);
$this->installConfig(static::$modules);
$this->executeMigrations([
'language',
'd7_user_role',
'd7_user',
'd7_node_type',
'd7_language_content_settings',
'd7_node',
'd7_node_translation',
'd7_menu',
'd7_menu_links',
'node_translation_menu_links',
]);
$node->save();
$this->executeMigrations(['d7_menu', 'd7_menu_links']);
\Drupal::service('router.builder')->rebuild();
}
@ -52,7 +68,7 @@ class MigrateMenuLinkTest extends MigrateDrupal7TestBase {
* @param bool $enabled
* Whether the link is enabled.
* @param bool $expanded
* Whether the link is expanded
* Whether the link is expanded.
* @param array $attributes
* Additional attributes the link is expected to have.
* @param string $uri
@ -66,11 +82,9 @@ class MigrateMenuLinkTest extends MigrateDrupal7TestBase {
protected function assertEntity($id, $title, $menu, $description, $enabled, $expanded, array $attributes, $uri, $weight) {
/** @var \Drupal\menu_link_content\MenuLinkContentInterface $menu_link */
$menu_link = MenuLinkContent::load($id);
$this->assertTrue($menu_link instanceof MenuLinkContentInterface);
$this->assertInstanceOf(MenuLinkContentInterface::class, $menu_link);
$this->assertSame($title, $menu_link->getTitle());
$this->assertSame($menu, $menu_link->getMenuName());
// The migration sets the description of the link to the value of the
// 'title' attribute. Bit strange, but there you go.
$this->assertSame($description, $menu_link->getDescription());
$this->assertSame($enabled, $menu_link->isEnabled());
$this->assertSame($expanded, $menu_link->isExpanded());
@ -90,8 +104,8 @@ class MigrateMenuLinkTest extends MigrateDrupal7TestBase {
// Tests migrating an external link with an undefined title attribute.
$this->assertEntity(470, 'Ask', static::MENU_NAME, NULL, TRUE, FALSE, [], 'http://ask.com', 0);
$this->assertEntity(245, 'Home', 'main', NULL, TRUE, FALSE, [], 'internal:/', 0);
$this->assertEntity(478, 'custom link test', 'admin', NULL, TRUE, FALSE, ['attributes' => ['title' => '']], 'internal:/admin/content/book', 0);
$this->assertEntity(479, 'node link test', 'tools', 'node 3', TRUE, FALSE, ['attributes' => ['title' => 'node 3']], 'entity:node/3', 3);
$this->assertEntity(478, 'custom link test', 'admin', NULL, TRUE, FALSE, ['attributes' => ['title' => '']], 'internal:/admin/content', 0);
$this->assertEntity(479, 'node link test', 'tools', 'node 2', TRUE, FALSE, ['attributes' => ['title' => 'node 2']], 'entity:node/2', 3);
$menu_link_tree_service = \Drupal::service('menu.link_tree');
$parameters = new MenuTreeParameters();
@ -120,6 +134,12 @@ class MigrateMenuLinkTest extends MigrateDrupal7TestBase {
}
}
$this->assertTrue($found);
// Test the migration of menu links for translated nodes.
$this->assertEntity(484, 'The thing about Deep Space 9', 'tools', NULL, TRUE, FALSE, ['attributes' => ['title' => '']], 'entity:node/2', 9);
$this->assertEntity(485, 'is - The thing about Deep Space 9', 'tools', NULL, TRUE, FALSE, ['attributes' => ['title' => '']], 'entity:node/2', 10);
$this->assertEntity(486, 'is - The thing about Firefly', 'tools', NULL, TRUE, FALSE, ['attributes' => ['title' => '']], 'entity:node/4', 11);
$this->assertEntity(487, 'en - The thing about Firefly', 'tools', NULL, TRUE, FALSE, ['attributes' => ['title' => '']], 'entity:node/4', 12);
}
}

View file

@ -44,7 +44,6 @@ class PathAliasMenuLinkContentTest extends KernelTestBase {
->addTag('path_processor_inbound', ['priority' => 100]);
}
/**
* Tests the path aliasing changing.
*/

View file

@ -0,0 +1,187 @@
<?php
namespace Drupal\Tests\menu_link_content\Kernel\Plugin\migrate\process;
use Drupal\menu_link_content\Plugin\migrate\process\LinkUri;
use Drupal\migrate\MigrateException;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;
use Drupal\node\Entity\Node;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests \Drupal\menu_link_content\Plugin\migrate\process\LinkUri.
*
* @group menu_link_content
*
* @coversDefaultClass \Drupal\menu_link_content\Plugin\migrate\process\LinkUri
*/
class LinkUriTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'user'];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->installEntitySchema('node');
$this->installEntitySchema('user');
}
/**
* Tests LinkUri::transform().
*
* @param array $value
* The value to pass to LinkUri::transform().
* @param string $expected
* The expected return value of LinkUri::transform().
*
* @dataProvider providerTestRouted
*
* @covers ::transform
*/
public function testRouted(array $value, $expected) {
$actual = $this->doTransform($value);
$this->assertSame($expected, $actual);
}
/**
* Provides test cases for LinkUriTest::testTransform().
*
* @return array
* An array of test cases, each which the following values:
* - The value array to pass to LinkUri::transform().
* - The expected path returned by LinkUri::transform().
*/
public function providerTestRouted() {
$tests = [];
$value = ['http://example.com'];
$expected = 'http://example.com';
$tests['with_scheme'] = [$value, $expected];
$value = ['<front>'];
$expected = 'internal:/';
$tests['front'] = [$value, $expected];
return $tests;
}
/**
* Tests that Non routed URLs throws an exception.
*
* @param array $value
* The value to pass to LinkUri::transform().
* @param string $exception_message
* The expected exception message.
*
* @dataProvider providerTestNotRouted
*/
public function testNotRouted(array $value, $exception_message) {
$this->setExpectedException(MigrateException::class, $exception_message);
$this->doTransform($value);
}
/**
* Provides test cases for LinkUriTest::testNotRouted().
*
* @return array
* An array of test cases, each which the following values:
* - The value array to pass to LinkUri::transform().
* - The expected path returned by LinkUri::transform().
* - (optional) A URL object that the path validator prophecy will return.
*/
public function providerTestNotRouted() {
$tests = [];
$message = 'The path "%s" failed validation.';
$value = ['/test'];
$expected = 'internal:/test';
$exception_message = sprintf($message, $expected);
$tests['leading_slash'] = [$value, $exception_message];
$value = ['test'];
$expected = 'internal:/test';
$exception_message = sprintf($message, $expected);
$tests['without_scheme'] = [$value, $exception_message];
return $tests;
}
/**
* Tests disabling route validation in LinkUri::transform().
*
* @param array $value
* The value to pass to LinkUri::transform().
* @param string $expected
* The expected return value of LinkUri::transform().
*
* @dataProvider providerTestDisablingRouteValidation
*
* @covers ::transform
*/
public function testDisablingRouteValidation(array $value, $expected) {
// Create a node so we have a valid route.
Node::create([
'nid' => 1,
'title' => 'test',
'type' => 'page',
])->save();
$actual = $this->doTransform($value, ['validate_route' => FALSE]);
$this->assertSame($expected, $actual);
}
/**
* Provides test cases for LinkUriTest::testDisablingRouteValidation().
*
* @return array
* An array of test cases, each which the following values:
* - The value array to pass to LinkUri::transform().
* - The expected path returned by LinkUri::transform().
*/
public function providerTestDisablingRouteValidation() {
$tests = [];
$value = ['node/1'];
$expected = 'entity:node/1';
$tests['routed'] = [$value, $expected];
$value = ['node/2'];
$expected = 'base:node/2';
$tests['unrouted'] = [$value, $expected];
return $tests;
}
/**
* Transforms a link path into an 'internal:' or 'entity:' URI.
*
* @param array $value
* The value to pass to LinkUri::transform().
* @param array $configuration
* The plugin configuration.
*
* @return string
* The transformed link.
*/
public function doTransform(array $value, $configuration = []) {
$entityTypeManager = $this->container->get('entity_type.manager');
$routeBuilder = $this->container->get('router.builder');
$row = new Row();
$executable = $this->prophesize(MigrateExecutableInterface::class)->reveal();
$plugin = new LinkUri($configuration, 'link_uri', [], $entityTypeManager, $routeBuilder);
$actual = $plugin->transform($value, $executable, $row, 'destinationproperty');
return $actual;
}
}

View file

@ -0,0 +1,250 @@
<?php
namespace Drupal\Tests\menu_link_content\Kernel\Plugin\migrate\source\d6;
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
/**
* Tests menu link translation source plugin.
*
* @covers \Drupal\menu_link_content\Plugin\migrate\source\d6\MenuLinkTranslation
* @group menu_link_content
*/
class MenuLinkTranslationTest extends MigrateSqlSourceTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['menu_link_content', 'migrate_drupal'];
/**
* {@inheritdoc}
*/
public function providerSource() {
$test = [];
$test[0]['source_data']['menu_links'] = [
[
'menu_name' => 'menu-test-menu',
'mlid' => 138,
'plid' => 0,
'link_path' => 'admin',
'router_path' => 'admin',
'link_title' => 'Test 1',
'options' => 'a:1:{s:10:"attributes";a:1:{s:5:"title";s:16:"Test menu link 1";}}',
'module' => 'menu',
'hidden' => 0,
'external' => 0,
'has_children' => 1,
'expanded' => 0,
'weight' => 15,
'depth' => 1,
'customized' => 1,
'p1' => '138',
'p2' => '0',
'p3' => '0',
'p4' => '0',
'p5' => '0',
'p6' => '0',
'p7' => '0',
'p8' => '0',
'p9' => '0',
'updated' => '0',
],
[
'menu_name' => 'menu-test-menu',
'mlid' => 139,
'plid' => 138,
'link_path' => 'admin/modules',
'router_path' => 'admin/modules',
'link_title' => 'Test 2',
'options' => 'a:1:{s:10:"attributes";a:1:{s:5:"title";s:16:"Test menu link 2";}}',
'module' => 'menu',
'hidden' => 0,
'external' => 0,
'has_children' => 0,
'expanded' => 0,
'weight' => 12,
'depth' => 2,
'customized' => 1,
'p1' => '138',
'p2' => '139',
'p3' => '0',
'p4' => '0',
'p5' => '0',
'p6' => '0',
'p7' => '0',
'p8' => '0',
'p9' => '0',
'updated' => '0',
],
[
'menu_name' => 'menu-test-menu',
'mlid' => 140,
'plid' => 0,
'link_path' => 'https://www.drupal.org',
'router_path' => 'admin/modules',
'link_title' => 'Test 2',
'options' => 'a:1:{s:10:"attributes";a:1:{s:5:"title";s:16:"Test menu link 2";}}',
'module' => 'menu',
'hidden' => 0,
'external' => 0,
'has_children' => 0,
'expanded' => 0,
'weight' => 12,
'depth' => 2,
'customized' => 1,
'p1' => '0',
'p2' => '0',
'p3' => '0',
'p4' => '0',
'p5' => '0',
'p6' => '0',
'p7' => '0',
'p8' => '0',
'p9' => '0',
'updated' => '0',
],
[
'menu_name' => 'menu-test-menu',
'mlid' => 141,
'plid' => 0,
'link_path' => 'https://api.drupal.org/api/drupal/8.3.x',
'router_path' => 'admin/modules',
'link_title' => 'Test 3',
'options' => 'a:1:{s:10:"attributes";a:1:{s:5:"title";s:16:"Test menu link 3";}}',
'module' => 'menu',
'hidden' => 0,
'external' => 0,
'has_children' => 0,
'expanded' => 0,
'weight' => 12,
'depth' => 2,
'customized' => 1,
'p1' => '0',
'p2' => '0',
'p3' => '0',
'p4' => '0',
'p5' => '0',
'p6' => '0',
'p7' => '0',
'p8' => '0',
'p9' => '0',
'updated' => '0',
],
];
$test[0]['source_data']['i18n_strings'] = [
[
'lid' => 1,
'objectid' => 139,
'type' => 'item',
'property' => 'title',
'objectindex' => 0,
'format' => 0,
],
[
'lid' => 2,
'objectid' => 139,
'type' => 'item',
'property' => 'description',
'objectindex' => 0,
'format' => 0,
],
[
'lid' => 3,
'objectid' => 140,
'type' => 'item',
'property' => 'description',
'objectindex' => 0,
'format' => 0,
],
[
'lid' => 4,
'objectid' => 141,
'type' => 'item',
'property' => 'title',
'objectindex' => 0,
'format' => 0,
],
];
$test[0]['source_data']['locales_target'] = [
[
'lid' => 1,
'language' => 'fr',
'translation' => 'fr - title translation',
'plid' => 0,
'plural' => 0,
'i18n_status' => 0,
],
[
'lid' => 2,
'language' => 'fr',
'translation' => 'fr - description translation',
'plid' => 0,
'plural' => 0,
'i18n_status' => 0,
],
[
'lid' => 3,
'language' => 'zu',
'translation' => 'zu - description translation',
'plid' => 0,
'plural' => 0,
'i18n_status' => 0,
],
[
'lid' => 4,
'language' => 'zu',
'translation' => 'zu - title translation',
'plid' => 0,
'plural' => 0,
'i18n_status' => 0,
],
];
$test[0]['expected_results'] = [
[
'menu_name' => 'menu-test-menu',
'mlid' => 139,
'property' => 'title',
'language' => 'fr',
'link_title' => 'Test 2',
'description' => 'Test menu link 2',
'title_translated' => 'fr - title translation',
'description_translated' => 'fr - description translation',
],
[
'menu_name' => 'menu-test-menu',
'mlid' => 139,
'property' => 'description',
'language' => 'fr',
'link_title' => 'Test 2',
'description' => 'Test menu link 2',
'title_translated' => 'fr - title translation',
'description_translated' => 'fr - description translation',
],
[
'menu_name' => 'menu-test-menu',
'mlid' => 140,
'property' => 'description',
'language' => 'zu',
'link_title' => 'Test 2',
'description' => 'Test menu link 2',
'title_translated' => NULL,
'description_translated' => 'zu - description translation',
],
[
'menu_name' => 'menu-test-menu',
'mlid' => 141,
'property' => 'title',
'language' => 'zu',
'link_title' => 'Test 3',
'description' => 'Test menu link 3',
'title_translated' => 'zu - title translation',
'description_translated' => NULL,
],
];
return $test;
}
}

View file

@ -1,140 +0,0 @@
<?php
namespace Drupal\Tests\menu_link_content\Unit\Plugin\migrate\process;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Url;
use Drupal\menu_link_content\Plugin\migrate\process\LinkUri;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;
use Drupal\Tests\UnitTestCase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Path\PathValidator;
/**
* Tests \Drupal\menu_link_content\Plugin\migrate\process\LinkUri.
*
* @group menu_link_content
*
* @coversDefaultClass \Drupal\menu_link_content\Plugin\migrate\process\LinkUri
*/
class LinkUriTest extends UnitTestCase {
/**
* The entity type manager prophecy used in the test.
*
* @var \Prophecy\Prophecy\ProphecyInterface|\Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The 'link_uri' process plugin being tested.
*
* @var \Drupal\menu_link_content\Plugin\migrate\process\LinkUri
*/
protected $processPlugin;
/**
* The path validator prophecy used in the test.
*
* @var \Drupal\Core\Path\PathValidator
*/
protected $pathValidator;
/**
* The fake entity type ID used in the test.
*
* @var string
*/
protected $entityTypeId = 'the_entity_type_id';
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
$this->entityTypeManager->getDefinitions()->willReturn([$this->entityTypeId => '']);
$this->processPlugin = new LinkUri([], 'link_uri', [], $this->entityTypeManager->reveal());
// Url::fromInternalUri() accesses the path validator from the global
// container.
// @see \Drupal\Core\Url::fromInternalUri()
$this->pathValidator = $this->prophesize(PathValidator::class);
$container = new ContainerBuilder();
$container->set('path.validator', $this->pathValidator->reveal());
\Drupal::setContainer($container);
}
/**
* Tests LinkUri::transform().
*
* @param array $value
* The value to pass to LinkUri::transform().
* @param string $expected
* The expected return value of LinkUri::transform().
* @param \Drupal\Core\Url $url
* (optional) The URL that the path validator prophecy will return.
*
* @dataProvider providerTestTransform
*
* @covers ::transform
*/
public function testTransform(array $value, $expected, Url $url = NULL) {
$migrate_executable = $this->prophesize(MigrateExecutableInterface::class);
$row = $this->prophesize(Row::class);
if ($url) {
$this->pathValidator->getUrlIfValidWithoutAccessCheck(reset($value))->willReturn($url);
}
$actual = $this->processPlugin->transform($value, $migrate_executable->reveal(), $row->reveal(), 'link/uri');
$this->assertEquals($expected, $actual);
}
/**
* Provides test cases for LinkUriTest::testTransform().
*
* @return array
* An array of test cases, each which the following values:
* - The value array to pass to LinkUri::transform().
* - The expected path returned by LinkUri::transform().
* - (optional) A URL object that the path validator prophecy will return.
*/
public function providerTestTransform() {
$tests = [];
$value = ['http://example.com'];
$expected = 'http://example.com';
$tests['with_scheme'] = [$value, $expected];
$value = ['/test'];
$expected = 'internal:/test';
$tests['leading_slash'] = [$value, $expected];
$value = ['test'];
$expected = 'internal:/test';
$tests['without_scheme'] = [$value, $expected];
$value = ['<front>'];
$expected = 'internal:/';
$tests['front'] = [$value, $expected];
$url = Url::fromRoute('route_name');
$tests['with_route'] = [$value, $expected, $url];
$url = Url::fromRoute('entity.not_an_entity_type_id.canonical');
$tests['without_entity_type'] = [$value, $expected, $url];
$url = Url::fromRoute('entity.the_entity_type_id.canonical');
$tests['without_route_parameter'] = [$value, $expected, $url];
$url = Url::fromRoute('entity.the_entity_type_id.canonical', ['the_entity_type_id' => 'the_entity_id']);
$expected = 'entity:the_entity_type_id/the_entity_id';
$tests['entity_path'] = [$value, $expected, $url];
return $tests;
}
}