Update to Drupal 8.2.4. For more information, see https://www.drupal.org/project/drupal/releases/8.2.4
This commit is contained in:
parent
0a95b8440e
commit
8544b60b39
284 changed files with 12980 additions and 3199 deletions
|
|
@ -151,7 +151,7 @@ function hook_block_view_BASE_BLOCK_ID_alter(array &$build, \Drupal\Core\Block\B
|
|||
function hook_block_build_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block) {
|
||||
// Add the 'user' cache context to some blocks.
|
||||
if ($some_condition) {
|
||||
$build['#contexts'][] = 'user';
|
||||
$build['#cache']['contexts'][] = 'user';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class BookJavascriptTest extends JavascriptTestBase {
|
|||
$dragged->dragTo($target);
|
||||
|
||||
// Give javascript some time to manipulate the DOM.
|
||||
$this->getSession()->wait(1000, 'jQuery(".tabledrag-changed-warning").is(":visible")');
|
||||
$this->assertJsCondition('jQuery(".tabledrag-changed-warning").is(":visible")');
|
||||
|
||||
// Check that the 'unsaved changes' text appeared in the message area.
|
||||
$this->assertSession()->pageTextContains('You have unsaved changes.');
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ use Drupal\ckeditor\CKEditorPluginCssInterface;
|
|||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageManager;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\editor\Entity\Editor;
|
||||
|
||||
/**
|
||||
|
|
@ -115,7 +114,7 @@ class Language extends CKEditorPluginBase implements CKEditorPluginConfigurableI
|
|||
],
|
||||
'#default_value' => $config['language_list'],
|
||||
'#description' => $this->t('The list of languages to show in the language dropdown. The basic list will only show the <a href=":url">six official languages of the UN</a>. The extended list will show all @count languages that are available in Drupal.', [
|
||||
':url' => Url::fromUri('http://www.un.org/en/aboutun/languages.shtml/')->toString(),
|
||||
':url' => 'https://www.un.org/en/sections/about-un/official-languages',
|
||||
'@count' => count($predefined_languages),
|
||||
]),
|
||||
'#attached' => ['library' => ['ckeditor/drupal.ckeditor.language.admin']],
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ source:
|
|||
constants:
|
||||
entity_type: node
|
||||
process:
|
||||
# If you are using this file to build a custom migration consider removing
|
||||
# the cid field to allow incremental migrations.
|
||||
cid: cid
|
||||
pid:
|
||||
plugin: migration
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ process:
|
|||
type: 'constants/type'
|
||||
'settings/comment_type': comment_type
|
||||
destination:
|
||||
plugin: md_entity:field_storage_config
|
||||
plugin: entity:field_storage_config
|
||||
dependencies:
|
||||
module:
|
||||
- comment
|
||||
migration_dependencies:
|
||||
required:
|
||||
- d6_comment_type
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ source:
|
|||
constants:
|
||||
entity_type: node
|
||||
process:
|
||||
# If you are using this file to build a custom migration consider removing
|
||||
# the cid field to allow incremental migrations.
|
||||
cid: cid
|
||||
pid:
|
||||
plugin: migration
|
||||
|
|
|
|||
|
|
@ -110,12 +110,13 @@ class CommentAccessControlHandler extends EntityAccessControlHandler {
|
|||
// access.
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
$is_name = $field_definition->getName() === 'name';
|
||||
/** @var \Drupal\comment\CommentInterface $entity */
|
||||
$entity = $items->getEntity();
|
||||
$commented_entity = $entity->getCommentedEntity();
|
||||
$anonymous_contact = $commented_entity->get($entity->getFieldName())->getFieldDefinition()->getSetting('anonymous');
|
||||
$admin_access = AccessResult::allowedIfHasPermission($account, 'administer comments');
|
||||
$anonymous_access = AccessResult::allowedIf($entity->isNew() && $account->isAnonymous() && $anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT && $account->hasPermission('post comments'))
|
||||
$anonymous_access = AccessResult::allowedIf($entity->isNew() && $account->isAnonymous() && ($anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT || $is_name) && $account->hasPermission('post comments'))
|
||||
->cachePerPermissions()
|
||||
->addCacheableDependency($entity)
|
||||
->addCacheableDependency($field_definition->getConfig($commented_entity->bundle()))
|
||||
|
|
|
|||
|
|
@ -65,6 +65,16 @@ class CommentAnonymousTest extends CommentTestBase {
|
|||
$anonymous_comment1 = $this->postComment($this->node, $this->randomMachineName(), $this->randomMachineName());
|
||||
$this->assertTrue($this->commentExists($anonymous_comment1), 'Anonymous comment without contact info found.');
|
||||
|
||||
// Ensure anonymous users cannot post in the name of registered users.
|
||||
$edit = array(
|
||||
'name' => $this->adminUser->getUsername(),
|
||||
'comment_body[0][value]' => $this->randomMachineName(),
|
||||
);
|
||||
$this->drupalPostForm('comment/reply/node/' . $this->node->id() . '/comment', $edit, t('Save'));
|
||||
$this->assertRaw(t('The name you used (%name) belongs to a registered user.', [
|
||||
'%name' => $this->adminUser->getUsername(),
|
||||
]));
|
||||
|
||||
// Allow contact info.
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->setCommentAnonymous(COMMENT_ANONYMOUS_MAY_CONTACT);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\config\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\user\Entity\Role;
|
||||
|
||||
/**
|
||||
* Tests draggable list builder.
|
||||
*
|
||||
* @group config
|
||||
*/
|
||||
class ConfigDraggableListBuilderTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = array('config_test');
|
||||
|
||||
/**
|
||||
* Test draggable lists.
|
||||
*/
|
||||
public function testDraggableList() {
|
||||
$this->drupalLogin($this->drupalCreateUser(array('administer permissions')));
|
||||
|
||||
// Create more than 50 roles.
|
||||
for ($i = 0; $i < 51; $i++) {
|
||||
$role = Role::create([
|
||||
'id' => 'role_' . $i,
|
||||
'label' => "Role $i",
|
||||
]);
|
||||
$role->save();
|
||||
}
|
||||
|
||||
// Navigate to Roles page
|
||||
$this->drupalGet('admin/people/roles');
|
||||
|
||||
// Test for the page title.
|
||||
$this->assertSession()->titleEquals(t('Roles') . ' | Drupal');
|
||||
|
||||
// Count the number of rows in table.
|
||||
$rows = $this->xpath('//form[@class="user-admin-roles-form"]/table/tbody/tr');
|
||||
$this->assertGreaterThan(50, count($rows));
|
||||
for ($i = 0; $i < 51; $i++) {
|
||||
$this->assertSession()->pageTextContains("Role $i");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -152,7 +152,6 @@ class EntityOperations implements ContainerInjectionInterface {
|
|||
$entity_type_id = $entity->getEntityTypeId();
|
||||
$entity_id = $entity->id();
|
||||
$entity_revision_id = $entity->getRevisionId();
|
||||
$entity_langcode = $entity->language()->getId();
|
||||
|
||||
$storage = $this->entityTypeManager->getStorage('content_moderation_state');
|
||||
$entities = $storage->loadByProperties([
|
||||
|
|
@ -174,11 +173,14 @@ class EntityOperations implements ContainerInjectionInterface {
|
|||
}
|
||||
|
||||
// Sync translations.
|
||||
if (!$content_moderation_state->hasTranslation($entity_langcode)) {
|
||||
$content_moderation_state->addTranslation($entity_langcode);
|
||||
}
|
||||
if ($content_moderation_state->language()->getId() !== $entity_langcode) {
|
||||
$content_moderation_state = $content_moderation_state->getTranslation($entity_langcode);
|
||||
if ($entity->getEntityType()->hasKey('langcode')) {
|
||||
$entity_langcode = $entity->language()->getId();
|
||||
if (!$content_moderation_state->hasTranslation($entity_langcode)) {
|
||||
$content_moderation_state->addTranslation($entity_langcode);
|
||||
}
|
||||
if ($content_moderation_state->language()->getId() !== $entity_langcode) {
|
||||
$content_moderation_state = $content_moderation_state->getTranslation($entity_langcode);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the ContentModerationState entity for the inserted entity.
|
||||
|
|
|
|||
|
|
@ -292,8 +292,8 @@ class EntityTypeInfo implements ContainerInjectionInterface {
|
|||
|
||||
$fields = [];
|
||||
$fields['moderation_state'] = BaseFieldDefinition::create('entity_reference')
|
||||
->setLabel(t('Moderation state'))
|
||||
->setDescription(t('The moderation state of this piece of content.'))
|
||||
->setLabel($this->t('Moderation state'))
|
||||
->setDescription($this->t('The moderation state of this piece of content.'))
|
||||
->setComputed(TRUE)
|
||||
->setClass(ModerationStateFieldItemList::class)
|
||||
->setSetting('target_type', 'moderation_state')
|
||||
|
|
@ -310,6 +310,7 @@ class EntityTypeInfo implements ContainerInjectionInterface {
|
|||
->addConstraint('ModerationState', [])
|
||||
->setDisplayConfigurable('form', FALSE)
|
||||
->setDisplayConfigurable('view', FALSE)
|
||||
->setReadOnly(FALSE)
|
||||
->setTranslatable(TRUE);
|
||||
|
||||
return $fields;
|
||||
|
|
|
|||
|
|
@ -43,12 +43,14 @@ class ModerationStateFieldItemList extends EntityReferenceFieldItemList {
|
|||
->loadRevision($revision_to_load);
|
||||
|
||||
// Return the correct translation.
|
||||
$langcode = $entity->language()->getId();
|
||||
if (!$content_moderation_state->hasTranslation($langcode)) {
|
||||
$content_moderation_state->addTranslation($langcode);
|
||||
}
|
||||
if ($content_moderation_state->language()->getId() !== $langcode) {
|
||||
$content_moderation_state = $content_moderation_state->getTranslation($langcode);
|
||||
if ($entity->getEntityType()->hasKey('langcode')) {
|
||||
$langcode = $entity->language()->getId();
|
||||
if (!$content_moderation_state->hasTranslation($langcode)) {
|
||||
$content_moderation_state->addTranslation($langcode);
|
||||
}
|
||||
if ($content_moderation_state->language()->getId() !== $langcode) {
|
||||
$content_moderation_state = $content_moderation_state->getTranslation($langcode);
|
||||
}
|
||||
}
|
||||
|
||||
return $content_moderation_state->get('moderation_state')->entity;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ namespace Drupal\Tests\content_moderation\Kernel;
|
|||
|
||||
use Drupal\content_moderation\Entity\ContentModerationState;
|
||||
use Drupal\content_moderation\Entity\ModerationState;
|
||||
use Drupal\entity_test\Entity\EntityTestBundle;
|
||||
use Drupal\entity_test\Entity\EntityTestWithBundle;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\Entity\Node;
|
||||
|
|
@ -21,12 +23,14 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'entity_test',
|
||||
'node',
|
||||
'content_moderation',
|
||||
'user',
|
||||
'system',
|
||||
'language',
|
||||
'content_translation',
|
||||
'text',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -38,6 +42,7 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
$this->installSchema('node', 'node_access');
|
||||
$this->installEntitySchema('node');
|
||||
$this->installEntitySchema('user');
|
||||
$this->installEntitySchema('entity_test_with_bundle');
|
||||
$this->installEntitySchema('content_moderation_state');
|
||||
$this->installConfig('content_moderation');
|
||||
}
|
||||
|
|
@ -210,6 +215,91 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
$this->assertEquals(6, $english_node->getRevisionId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a non-translatable entity type with a langcode can be moderated.
|
||||
*/
|
||||
public function testNonTranslatableEntityTypeModeration() {
|
||||
// Make the 'entity_test_with_bundle' entity type revisionable.
|
||||
$entity_type = clone \Drupal::entityTypeManager()->getDefinition('entity_test_with_bundle');
|
||||
$keys = $entity_type->getKeys();
|
||||
$keys['revision'] = 'revision_id';
|
||||
$entity_type->set('entity_keys', $keys);
|
||||
\Drupal::state()->set('entity_test_with_bundle.entity_type', $entity_type);
|
||||
\Drupal::entityDefinitionUpdateManager()->applyUpdates();
|
||||
|
||||
// Create a test bundle.
|
||||
$entity_test_bundle = EntityTestBundle::create([
|
||||
'id' => 'example',
|
||||
]);
|
||||
$entity_test_bundle->setThirdPartySetting('content_moderation', 'enabled', TRUE);
|
||||
$entity_test_bundle->setThirdPartySetting('content_moderation', 'allowed_moderation_states', [
|
||||
'draft',
|
||||
'published'
|
||||
]);
|
||||
$entity_test_bundle->setThirdPartySetting('content_moderation', 'default_moderation_state', 'draft');
|
||||
$entity_test_bundle->save();
|
||||
|
||||
// Check that the tested entity type is not translatable.
|
||||
$entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_with_bundle');
|
||||
$this->assertFalse($entity_type->isTranslatable(), 'The test entity type is not translatable.');
|
||||
|
||||
// Create a test entity.
|
||||
$entity_test_with_bundle = EntityTestWithBundle::create([
|
||||
'type' => 'example'
|
||||
]);
|
||||
$entity_test_with_bundle->save();
|
||||
$this->assertEquals('draft', $entity_test_with_bundle->moderation_state->entity->id());
|
||||
|
||||
$entity_test_with_bundle->moderation_state->target_id = 'published';
|
||||
$entity_test_with_bundle->save();
|
||||
|
||||
$this->assertEquals('published', EntityTestWithBundle::load($entity_test_with_bundle->id())->moderation_state->entity->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a non-translatable entity type without a langcode can be
|
||||
* moderated.
|
||||
*/
|
||||
public function testNonLangcodeEntityTypeModeration() {
|
||||
// Make the 'entity_test_with_bundle' entity type revisionable and unset
|
||||
// the langcode entity key.
|
||||
$entity_type = clone \Drupal::entityTypeManager()->getDefinition('entity_test_with_bundle');
|
||||
$keys = $entity_type->getKeys();
|
||||
$keys['revision'] = 'revision_id';
|
||||
unset($keys['langcode']);
|
||||
$entity_type->set('entity_keys', $keys);
|
||||
\Drupal::state()->set('entity_test_with_bundle.entity_type', $entity_type);
|
||||
\Drupal::entityDefinitionUpdateManager()->applyUpdates();
|
||||
|
||||
// Create a test bundle.
|
||||
$entity_test_bundle = EntityTestBundle::create([
|
||||
'id' => 'example',
|
||||
]);
|
||||
$entity_test_bundle->setThirdPartySetting('content_moderation', 'enabled', TRUE);
|
||||
$entity_test_bundle->setThirdPartySetting('content_moderation', 'allowed_moderation_states', [
|
||||
'draft',
|
||||
'published'
|
||||
]);
|
||||
$entity_test_bundle->setThirdPartySetting('content_moderation', 'default_moderation_state', 'draft');
|
||||
$entity_test_bundle->save();
|
||||
|
||||
// Check that the tested entity type is not translatable.
|
||||
$entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_with_bundle');
|
||||
$this->assertFalse($entity_type->isTranslatable(), 'The test entity type is not translatable.');
|
||||
|
||||
// Create a test entity.
|
||||
$entity_test_with_bundle = EntityTestWithBundle::create([
|
||||
'type' => 'example'
|
||||
]);
|
||||
$entity_test_with_bundle->save();
|
||||
$this->assertEquals('draft', $entity_test_with_bundle->moderation_state->entity->id());
|
||||
|
||||
$entity_test_with_bundle->moderation_state->target_id = 'published';
|
||||
$entity_test_with_bundle->save();
|
||||
|
||||
$this->assertEquals('published', EntityTestWithBundle::load($entity_test_with_bundle->id())->moderation_state->entity->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the node after clearing the static cache.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_moderation\Kernel;
|
||||
|
||||
use Drupal\content_moderation\Entity\Handler\ModerationHandler;
|
||||
use Drupal\content_moderation\EntityTypeInfo;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\content_moderation\EntityTypeInfo
|
||||
*
|
||||
* @group content_moderation
|
||||
*/
|
||||
class EntityTypeInfoTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = [
|
||||
'content_moderation',
|
||||
'entity_test',
|
||||
];
|
||||
|
||||
/**
|
||||
* The entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The entity type info class.
|
||||
*
|
||||
* @var \Drupal\content_moderation\EntityTypeInfo
|
||||
*/
|
||||
protected $entityTypeInfo;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->entityTypeInfo = $this->container->get('class_resolver')->getInstanceFromDefinition(EntityTypeInfo::class);
|
||||
$this->entityTypeManager = $this->container->get('entity_type.manager');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::entityBaseFieldInfo
|
||||
*/
|
||||
public function testEntityBaseFieldInfo() {
|
||||
$definition = $this->entityTypeManager->getDefinition('entity_test');
|
||||
$definition->setHandlerClass('moderation', ModerationHandler::class);
|
||||
|
||||
$base_fields = $this->entityTypeInfo->entityBaseFieldInfo($definition);
|
||||
|
||||
$this->assertFalse($base_fields['moderation_state']->isReadOnly());
|
||||
$this->assertTrue($base_fields['moderation_state']->isComputed());
|
||||
$this->assertTrue($base_fields['moderation_state']->isTranslatable());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\datetime\Kernel;
|
||||
|
||||
use Drupal\Core\Datetime\DrupalDateTime;
|
||||
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
|
||||
use Drupal\Core\Form\FormInterface;
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests serializing a form with an injected datetime instance.
|
||||
*
|
||||
* @group datetime
|
||||
*/
|
||||
class DateTimeFormInjectionTest extends KernelTestBase implements FormInterface {
|
||||
|
||||
use DependencySerializationTrait;
|
||||
|
||||
/**
|
||||
* A Dblog logger instance.
|
||||
*
|
||||
* @var \Psr\Log\LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['system', 'datetime'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installSchema('system', ['key_value_expire', 'sequences']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'datetime_test_injection_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* Process callback.
|
||||
*
|
||||
* @param array $element
|
||||
* Form element.
|
||||
*
|
||||
* @return array
|
||||
* Processed element.
|
||||
*/
|
||||
public function process($element) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form['datelist_element'] = [
|
||||
'#title' => 'datelist test',
|
||||
'#type' => 'datelist',
|
||||
'#default_value' => new DrupalDateTime('2000-01-01 00:00:00'),
|
||||
'#date_part_order' => [
|
||||
'month',
|
||||
'day',
|
||||
'year',
|
||||
'hour',
|
||||
'minute', 'ampm',
|
||||
],
|
||||
'#date_text_parts' => ['year'],
|
||||
'#date_year_range' => '2010:2020',
|
||||
'#date_increment' => 15,
|
||||
];
|
||||
$form['#process'][] = [$this, 'process'];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->assertTrue(TRUE);
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests custom string injection serialization.
|
||||
*/
|
||||
public function testDatetimeSerialization() {
|
||||
$form_state = new FormState();
|
||||
$form_state->setRequestMethod('POST');
|
||||
$form_state->setCached();
|
||||
$form_builder = $this->container->get('form_builder');
|
||||
$form_id = $form_builder->getFormId($this, $form_state);
|
||||
$form = $form_builder->retrieveForm($form_id, $form_state);
|
||||
$form_builder->prepareForm($form_id, $form, $form_state);
|
||||
$form_builder->processForm($form_id, $form, $form_state);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -123,4 +123,4 @@ process:
|
|||
- '@type'
|
||||
- global_settings
|
||||
destination:
|
||||
plugin: md_entity:field_storage_config
|
||||
plugin: entity:field_storage_config
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ process:
|
|||
datestamp: datetime
|
||||
datetime: datetime
|
||||
email: email
|
||||
entityreference: entity_reference
|
||||
file: file
|
||||
image: image
|
||||
link_field: link
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ process:
|
|||
-
|
||||
plugin: static_map
|
||||
bypass: true
|
||||
source: type
|
||||
source: formatter_type
|
||||
map:
|
||||
date_default: datetime_default
|
||||
email_default: email_mailto
|
||||
|
|
@ -61,6 +61,9 @@ process:
|
|||
link_default: link
|
||||
phone: basic_string
|
||||
taxonomy_term_reference_link: entity_reference_label
|
||||
entityreference_label: entity_reference_label
|
||||
entityreference_entity_id: entity_reference_entity_id
|
||||
entityreference_entity_view: entity_reference_entity_view
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ process:
|
|||
source:
|
||||
- instance_settings
|
||||
- widget_settings
|
||||
- field_settings
|
||||
default_value_function: ''
|
||||
default_value:
|
||||
plugin: d7_field_instance_defaults
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ process:
|
|||
phone_textfield: telephone_default
|
||||
options_onoff: boolean_checkbox
|
||||
entityreference_autocomplete: entity_reference_autocomplete
|
||||
entityreference_autocomplete_tags: entity_reference_autocomplete_tags
|
||||
taxonomy_autocomplete: entity_reference_autocomplete
|
||||
'options/settings':
|
||||
plugin: field_instance_widget_settings
|
||||
|
|
|
|||
|
|
@ -17,9 +17,38 @@ class FieldInstanceSettings extends ProcessPluginBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($instance_settings, $widget_settings) = $value;
|
||||
list($instance_settings, $widget_settings, $field_settings) = $value;
|
||||
$widget_type = $widget_settings['type'];
|
||||
|
||||
// Get entityreference handler settings from source field configuration.
|
||||
if ($row->getSourceProperty('type') == "entityreference") {
|
||||
$instance_settings['handler'] = 'default:' . $field_settings['target_type'];
|
||||
// Transform the sort settings to D8 structure.
|
||||
$sort = [
|
||||
'field' => '_none',
|
||||
'direction' => 'ASC',
|
||||
];
|
||||
if (!empty(array_filter($field_settings['handler_settings']['sort']))) {
|
||||
if ($field_settings['handler_settings']['sort']['type'] == "property") {
|
||||
$sort = [
|
||||
'field' => $field_settings['handler_settings']['sort']['property'],
|
||||
'direction' => $field_settings['handler_settings']['sort']['direction'],
|
||||
];
|
||||
}
|
||||
elseif ($field_settings['handler_settings']['sort']['type'] == "field") {
|
||||
$sort = [
|
||||
'field' => $field_settings['handler_settings']['sort']['field'],
|
||||
'direction' => $field_settings['handler_settings']['sort']['direction'],
|
||||
];
|
||||
}
|
||||
}
|
||||
if (empty($field_settings['handler_settings']['target_bundles'])) {
|
||||
$field_settings['handler_settings']['target_bundles'] = NULL;
|
||||
}
|
||||
$field_settings['handler_settings']['sort'] = $sort;
|
||||
$instance_settings['handler_settings'] = $field_settings['handler_settings'];
|
||||
}
|
||||
|
||||
switch ($widget_type) {
|
||||
case 'image_image':
|
||||
$settings = $instance_settings;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ class FieldInstance extends DrupalSqlBase {
|
|||
->fields('fc', array('type'));
|
||||
|
||||
$query->innerJoin('field_config', 'fc', 'fci.field_id = fc.id');
|
||||
$query->addField('fc', 'data', 'field_data');
|
||||
|
||||
// Optionally filter by entity type and bundle.
|
||||
if (isset($this->configuration['entity_type'])) {
|
||||
|
|
@ -53,6 +54,7 @@ class FieldInstance extends DrupalSqlBase {
|
|||
'instance_settings' => $this->t('Field instance settings.'),
|
||||
'widget_settings' => $this->t('Widget settings.'),
|
||||
'display_settings' => $this->t('Display settings.'),
|
||||
'field_settings' => $this->t('Field settings.'),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +83,9 @@ class FieldInstance extends DrupalSqlBase {
|
|||
// This is for parity with the d6_field_instance plugin.
|
||||
$row->setSourceProperty('widget_type', $data['widget']['type']);
|
||||
|
||||
$field_data = unserialize($row->getSourceProperty('field_data'));
|
||||
$row->setSourceProperty('field_settings', $field_data['settings']);
|
||||
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,15 @@ class FieldInstancePerViewMode extends DrupalSqlBase {
|
|||
$data = unserialize($field_instance['data']);
|
||||
// We don't need to include the serialized data in the returned rows.
|
||||
unset($field_instance['data']);
|
||||
|
||||
foreach ($data['display'] as $view_mode => $info) {
|
||||
$rows[] = array_merge($field_instance, $info, array('view_mode' => $view_mode));
|
||||
// Rename type to formatter_type in the info array.
|
||||
$info['formatter_type'] = $info['type'];
|
||||
unset($info['type']);
|
||||
|
||||
$rows[] = array_merge($field_instance, $info, [
|
||||
'view_mode' => $view_mode,
|
||||
]);
|
||||
}
|
||||
}
|
||||
return new \ArrayIterator($rows);
|
||||
|
|
@ -35,8 +42,11 @@ class FieldInstancePerViewMode extends DrupalSqlBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
return $this->select('field_config_instance', 'fci')
|
||||
->fields('fci', array('entity_type', 'bundle', 'field_name', 'data'));
|
||||
$query = $this->select('field_config_instance', 'fci')
|
||||
->fields('fci', ['entity_type', 'bundle', 'field_name', 'data'])
|
||||
->fields('fc', ['type']);
|
||||
$query->join('field_config', 'fc', 'fc.field_name = fci.field_name');
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -49,7 +59,8 @@ class FieldInstancePerViewMode extends DrupalSqlBase {
|
|||
'field_name' => $this->t('Machine name of the field.'),
|
||||
'view_mode' => $this->t('The original machine name of the view mode.'),
|
||||
'label' => $this->t('The display label of the field.'),
|
||||
'type' => $this->t('The formatter ID.'),
|
||||
'type' => $this->t('The field ID.'),
|
||||
'formatter_type' => $this->t('The formatter ID.'),
|
||||
'settings' => $this->t('Array of formatter-specific settings.'),
|
||||
'module' => $this->t('The module providing the formatter.'),
|
||||
'weight' => $this->t('Display weight of the field.'),
|
||||
|
|
|
|||
|
|
@ -20,7 +20,12 @@ class BooleanFieldTest extends WebTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('entity_test', 'field_ui', 'options');
|
||||
public static $modules = [
|
||||
'entity_test',
|
||||
'field_ui',
|
||||
'options',
|
||||
'field_test_boolean_access_denied',
|
||||
];
|
||||
|
||||
/**
|
||||
* A field to use in this test class.
|
||||
|
|
@ -179,4 +184,66 @@ class BooleanFieldTest extends WebTestBase {
|
|||
$this->assertFieldById('edit-settings-off-label', $off);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test field access.
|
||||
*/
|
||||
public function testFormAccess() {
|
||||
$on = 'boolean_on';
|
||||
$off = 'boolean_off';
|
||||
$label = 'boolean_label';
|
||||
$field_name = 'boolean_name';
|
||||
$this->fieldStorage = FieldStorageConfig::create([
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => 'boolean',
|
||||
]);
|
||||
$this->fieldStorage->save();
|
||||
$this->field = FieldConfig::create([
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'label' => $label,
|
||||
'settings' => [
|
||||
'on_label' => $on,
|
||||
'off_label' => $off,
|
||||
],
|
||||
]);
|
||||
$this->field->save();
|
||||
|
||||
// Create a form display for the default form mode.
|
||||
entity_get_form_display('entity_test', 'entity_test', 'default')
|
||||
->setComponent($field_name, [
|
||||
'type' => 'boolean_checkbox',
|
||||
])
|
||||
->save();
|
||||
|
||||
// Create a display for the full view mode.
|
||||
entity_get_display('entity_test', 'entity_test', 'full')
|
||||
->setComponent($field_name, [
|
||||
'type' => 'boolean',
|
||||
])
|
||||
->save();
|
||||
|
||||
// Display creation form.
|
||||
$this->drupalGet('entity_test/add');
|
||||
$this->assertFieldByName("{$field_name}[value]");
|
||||
|
||||
// Should be posted OK.
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
preg_match('|entity_test/manage/(\d+)|', $this->url, $match);
|
||||
$id = $match[1];
|
||||
$this->assertText(t('entity_test @id has been created.', ['@id' => $id]));
|
||||
|
||||
// Tell the test module to disable access to the field.
|
||||
\Drupal::state()->set('field.test_boolean_field_access_field', $field_name);
|
||||
$this->drupalGet('entity_test/add');
|
||||
// Field should not be there anymore.
|
||||
$this->assertNoFieldByName("{$field_name}[value]");
|
||||
// Should still be able to post the form.
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
preg_match('|entity_test/manage/(\d+)|', $this->url, $match);
|
||||
$id = $match[1];
|
||||
$this->assertText(t('entity_test @id has been created.', ['@id' => $id]));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field_test\Plugin\Field\FieldType;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\TypedData\DataDefinition;
|
||||
use Drupal\Core\Field\FieldItemBase;
|
||||
|
||||
/**
|
||||
* Defines the 'test_object_field' entity field item.
|
||||
*
|
||||
* @FieldType(
|
||||
* id = "test_object_field",
|
||||
* label = @Translation("Test object field"),
|
||||
* description = @Translation("Test field type that has an object to test serialization"),
|
||||
* default_widget = "test_object_field_widget",
|
||||
* default_formatter = "object_field_test_default"
|
||||
* )
|
||||
*/
|
||||
class TestObjectItem extends FieldItemBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
|
||||
$properties['value'] = DataDefinition::create('any')
|
||||
->setLabel(t('Value'))
|
||||
->setRequired(TRUE);
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function schema(FieldStorageDefinitionInterface $field_definition) {
|
||||
return [
|
||||
'columns' => [
|
||||
'value' => [
|
||||
'description' => 'The object item value.',
|
||||
'type' => 'blob',
|
||||
'not null' => TRUE,
|
||||
'serialize' => TRUE,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setValue($values, $notify = TRUE) {
|
||||
if (isset($values['value'])) {
|
||||
// @todo Remove this in https://www.drupal.org/node/2788637.
|
||||
if (is_string($values['value'])) {
|
||||
$values['value'] = unserialize($values['value']);
|
||||
}
|
||||
}
|
||||
parent::setValue($values, $notify);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
name: 'Boolean field Test'
|
||||
type: module
|
||||
description: 'Support module for the field and entity display tests.'
|
||||
core: 8.x
|
||||
package: Testing
|
||||
version: VERSION
|
||||
dependencies:
|
||||
- field
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Module for testing denying access to boolean fields.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_entity_field_access().
|
||||
*/
|
||||
function field_test_boolean_access_denied_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
|
||||
return AccessResult::forbiddenIf($field_definition->getName() === \Drupal::state()->get('field.test_boolean_field_access_field'));
|
||||
}
|
||||
|
|
@ -277,6 +277,49 @@ class EntityReferenceFormatterTest extends EntityKernelTestBase {
|
|||
$this->assertEqual($actual_occurrences, $expected_occurrences);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the same entity referenced from different places.
|
||||
*/
|
||||
public function testEntityReferenceRecursiveProtectionWithManyRenderedEntities() {
|
||||
$formatter = 'entity_reference_entity_view';
|
||||
$view_builder = $this->entityManager->getViewBuilder($this->entityType);
|
||||
|
||||
// Set the default view mode to use the 'entity_reference_entity_view'
|
||||
// formatter.
|
||||
entity_get_display($this->entityType, $this->bundle, 'default')
|
||||
->setComponent($this->fieldName, [
|
||||
'type' => $formatter,
|
||||
])
|
||||
->save();
|
||||
|
||||
$storage = $this->entityManager->getStorage($this->entityType);
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $referenced_entity */
|
||||
$referenced_entity = $storage->create(['name' => $this->randomMachineName()]);
|
||||
|
||||
$range = range(0, 30);
|
||||
$referencing_entities = array_map(function () use ($storage, $referenced_entity) {
|
||||
$referencing_entity = $storage->create([
|
||||
'name' => $this->randomMachineName(),
|
||||
$this->fieldName => $referenced_entity,
|
||||
]);
|
||||
$referencing_entity->save();
|
||||
return $referencing_entity;
|
||||
}, $range);
|
||||
|
||||
$build = $view_builder->viewMultiple($referencing_entities, 'default');
|
||||
$output = $this->render($build);
|
||||
|
||||
// The title of entity_test entities is printed twice by default, so we have
|
||||
// to multiply the formatter's recursive rendering protection limit by 2.
|
||||
// Additionally, we have to take into account 2 additional occurrences of
|
||||
// the entity title because we're rendering the full entity, not just the
|
||||
// reference field.
|
||||
$expected_occurrences = 30 * 2 + 2;
|
||||
$actual_occurrences = substr_count($output, $referenced_entity->get('name')->value);
|
||||
$this->assertEquals($expected_occurrences, $actual_occurrences);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests the label formatter.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -276,6 +276,9 @@ class MigrateFieldFormatterSettingsTest extends MigrateDrupal7TestBase {
|
|||
$this->assertComponent('node.test_content_type.default', 'field_text_list', 'list_default', 'above', 10);
|
||||
$this->assertComponent('node.test_content_type.default', 'field_integer_list', 'list_default', 'above', 11);
|
||||
$this->assertComponent('node.test_content_type.default', 'field_long_text', 'text_default', 'above', 12);
|
||||
$this->assertComponent('node.test_content_type.default', 'field_node_entityreference', 'entity_reference_label', 'above', 15);
|
||||
$this->assertComponent('node.test_content_type.default', 'field_user_entityreference', 'entity_reference_label', 'above', 16);
|
||||
$this->assertComponent('node.test_content_type.default', 'field_term_entityreference', 'entity_reference_label', 'above', 17);
|
||||
$this->assertComponentNotExists('node.test_content_type.default', 'field_term_reference');
|
||||
$this->assertComponentNotExists('node.test_content_type.default', 'field_text');
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,9 @@ class MigrateFieldInstanceTest extends MigrateDrupal7TestBase {
|
|||
$this->assertEntity('node.test_content_type.field_integer_list', 'Integer List', 'list_integer', FALSE);
|
||||
$this->assertEntity('node.test_content_type.field_long_text', 'Long text', 'text_with_summary', FALSE);
|
||||
$this->assertEntity('node.test_content_type.field_term_reference', 'Term Reference', 'entity_reference', FALSE);
|
||||
$this->assertEntity('node.test_content_type.field_node_entityreference', 'Node Entity Reference', 'entity_reference', FALSE);
|
||||
$this->assertEntity('node.test_content_type.field_user_entityreference', 'User Entity Reference', 'entity_reference', FALSE);
|
||||
$this->assertEntity('node.test_content_type.field_term_entityreference', 'Term Entity Reference', 'entity_reference', FALSE);
|
||||
$this->assertEntity('node.test_content_type.field_text', 'Text', 'text', FALSE);
|
||||
$this->assertEntity('comment.comment_node_test_content_type.field_integer', 'Integer', 'integer', FALSE);
|
||||
$this->assertEntity('user.user.field_file', 'File', 'file', FALSE);
|
||||
|
|
|
|||
|
|
@ -125,6 +125,9 @@ class MigrateFieldInstanceWidgetSettingsTest extends MigrateDrupal7TestBase {
|
|||
$this->assertComponent('node.test_content_type.default', 'field_long_text', 'text_textarea_with_summary', 13);
|
||||
$this->assertComponent('node.test_content_type.default', 'field_phone', 'telephone_default', 6);
|
||||
$this->assertComponent('node.test_content_type.default', 'field_term_reference', 'entity_reference_autocomplete', 14);
|
||||
$this->assertComponent('node.test_content_type.default', 'field_node_entityreference', 'entity_reference_autocomplete', 16);
|
||||
$this->assertComponent('node.test_content_type.default', 'field_user_entityreference', 'options_buttons', 17);
|
||||
$this->assertComponent('node.test_content_type.default', 'field_term_entityreference', 'entity_reference_autocomplete_tags', 18);
|
||||
$this->assertComponent('node.test_content_type.default', 'field_text', 'text_textfield', 15);
|
||||
$this->assertComponent('node.test_content_type.default', 'field_text_list', 'options_select', 11);
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,9 @@ class MigrateFieldTest extends MigrateDrupal7TestBase {
|
|||
$this->assertEntity('node.field_phone', 'telephone', FALSE, 1);
|
||||
$this->assertEntity('node.field_date', 'datetime', FALSE, 1);
|
||||
$this->assertEntity('node.field_date_with_end_time', 'datetime', FALSE, 1);
|
||||
$this->assertEntity('node.field_node_entityreference', 'entity_reference', FALSE, -1);
|
||||
$this->assertEntity('node.field_user_entityreference', 'entity_reference', FALSE, 1);
|
||||
$this->assertEntity('node.field_term_entityreference', 'entity_reference', FALSE, -1);
|
||||
|
||||
// Assert that the taxonomy term reference fields are referencing the
|
||||
// correct entity type.
|
||||
|
|
@ -108,6 +111,15 @@ class MigrateFieldTest extends MigrateDrupal7TestBase {
|
|||
$field = FieldStorageConfig::load('node.taxonomy_forums');
|
||||
$this->assertIdentical('taxonomy_term', $field->getSetting('target_type'));
|
||||
|
||||
// Assert that the entityreference fields are referencing the correct
|
||||
// entity type.
|
||||
$field = FieldStorageConfig::load('node.field_node_entityreference');
|
||||
$this->assertIdentical('node', $field->getSetting('target_type'));
|
||||
$field = FieldStorageConfig::load('node.field_user_entityreference');
|
||||
$this->assertIdentical('user', $field->getSetting('target_type'));
|
||||
$field = FieldStorageConfig::load('node.field_term_entityreference');
|
||||
$this->assertIdentical('taxonomy_term', $field->getSetting('target_type'));
|
||||
|
||||
// Validate that the source count and processed count match up.
|
||||
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
|
||||
$migration = $this->getMigration('d7_field');
|
||||
|
|
|
|||
|
|
@ -41,6 +41,24 @@ class FieldInstancePerViewModeTest extends MigrateSqlSourceTestBase {
|
|||
],
|
||||
];
|
||||
|
||||
$tests[0]['source_data']['field_config'] = [
|
||||
[
|
||||
'id' => '2',
|
||||
'field_name' => 'body',
|
||||
'type' => 'text_with_summary',
|
||||
'module' => 'text',
|
||||
'active' => '1',
|
||||
'storage_type' => 'field_sql_storage',
|
||||
'storage_module' => 'field_sql_storage',
|
||||
'storage_active' => '1',
|
||||
'locked' => '0',
|
||||
'data' => 'a:7:{s:12:"entity_types";a:1:{i:0;s:4:"node";}s:7:"indexes";a:1:{s:6:"format";a:1:{i:0;s:6:"format";}}s:8:"settings";a:0:{}s:12:"translatable";i:0;s:12:"foreign keys";a:1:{s:6:"format";a:2:{s:5:"table";s:13:"filter_format";s:7:"columns";a:1:{s:6:"format";s:6:"format";}}}s:7:"storage";a:4:{s:4:"type";s:17:"field_sql_storage";s:8:"settings";a:0:{}s:6:"module";s:17:"field_sql_storage";s:6:"active";s:1:"1";}s:2:"id";s:2:"25";}',
|
||||
'cardinality' => '1',
|
||||
'translatable' => '0',
|
||||
'deleted' => '0',
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
|
|
@ -48,7 +66,8 @@ class FieldInstancePerViewModeTest extends MigrateSqlSourceTestBase {
|
|||
'bundle' => 'page',
|
||||
'field_name' => 'body',
|
||||
'label' => 'hidden',
|
||||
'type' => 'text_default',
|
||||
'type' => 'text_with_summary',
|
||||
'formatter_type' => 'text_default',
|
||||
'settings' => [],
|
||||
'module' => 'text',
|
||||
'weight' => 0,
|
||||
|
|
@ -59,7 +78,8 @@ class FieldInstancePerViewModeTest extends MigrateSqlSourceTestBase {
|
|||
'bundle' => 'page',
|
||||
'field_name' => 'body',
|
||||
'label' => 'hidden',
|
||||
'type' => 'text_summary_or_trimmed',
|
||||
'type' => 'text_with_summary',
|
||||
'formatter_type' => 'text_summary_or_trimmed',
|
||||
'settings' => [
|
||||
'trim_length' => 600,
|
||||
],
|
||||
|
|
|
|||
30
core/modules/field/tests/src/Kernel/String/UuidItemTest.php
Normal file
30
core/modules/field/tests/src/Kernel/String/UuidItemTest.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\field\Kernel\String;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\Tests\field\Kernel\FieldKernelTestBase;
|
||||
use Drupal\Component\Uuid\Uuid;
|
||||
|
||||
/**
|
||||
* Tests the UUID field.
|
||||
*
|
||||
* @group field
|
||||
*/
|
||||
class UuidItemTest extends FieldKernelTestBase {
|
||||
|
||||
/**
|
||||
* Tests 'uuid' random values.
|
||||
*/
|
||||
public function testSampleValue() {
|
||||
$entity = EntityTest::create([]);
|
||||
$entity->save();
|
||||
|
||||
$uuid_field = $entity->get('uuid');
|
||||
|
||||
// Test the generateSampleValue() method.
|
||||
$uuid_field->generateSampleItems();
|
||||
$this->assertTrue(Uuid::isValid($uuid_field->value));
|
||||
}
|
||||
|
||||
}
|
||||
59
core/modules/field/tests/src/Kernel/TestObjectItemTest.php
Normal file
59
core/modules/field/tests/src/Kernel/TestObjectItemTest.php
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\field\Kernel;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests the serialization of an object.
|
||||
*
|
||||
* @group field
|
||||
*/
|
||||
class TestObjectItemTest extends FieldKernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('field_test');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create a 'test_field' field and storage for validation.
|
||||
FieldStorageConfig::create(array(
|
||||
'field_name' => 'field_test',
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => 'test_object_field',
|
||||
))->save();
|
||||
FieldConfig::create([
|
||||
'entity_type' => 'entity_test',
|
||||
'field_name' => 'field_test',
|
||||
'bundle' => 'entity_test',
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the serialization of a field type that has an object.
|
||||
*/
|
||||
public function testTestObjectItem() {
|
||||
$object = new \stdClass();
|
||||
$object->foo = 'bar';
|
||||
$entity = EntityTest::create();
|
||||
$entity->field_test->value = $object;
|
||||
$entity->save();
|
||||
|
||||
// Verify that the entity has been created properly.
|
||||
$id = $entity->id();
|
||||
$entity = EntityTest::load($id);
|
||||
$this->assertTrue($entity->field_test->value instanceof \stdClass);
|
||||
$this->assertEquals($object, $entity->field_test->value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ class FieldInstanceSettingsTest extends MigrateTestCase {
|
|||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$value = $plugin->transform([[], ['type' => 'image_image']], $executable, $row, 'foo');
|
||||
$value = $plugin->transform([[], ['type' => 'image_image'], []], $executable, $row, 'foo');
|
||||
$this->assertInternalType('array', $value['default_image']);
|
||||
$this->assertSame('', $value['default_image']['alt']);
|
||||
$this->assertSame('', $value['default_image']['title']);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ source:
|
|||
# configuration in this migration's process pipeline as an example.
|
||||
source_base_path: ''
|
||||
process:
|
||||
# If you are using both this migration and d6_user_picture_file in a custom
|
||||
# migration and executing migrations incrementally, it is recommended that
|
||||
# you remove the fid mapping here to avoid potential ID conflicts.
|
||||
fid: fid
|
||||
filename: filename
|
||||
source_full_path:
|
||||
|
|
|
|||
|
|
@ -20,4 +20,7 @@ process:
|
|||
cardinality: 'constants/cardinality'
|
||||
'settings/display_field': 'constants/display_field'
|
||||
destination:
|
||||
plugin: md_entity:field_storage_config
|
||||
plugin: entity:field_storage_config
|
||||
dependencies:
|
||||
module:
|
||||
- file
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ source:
|
|||
# configuration in this migration's process pipeline as an example.
|
||||
source_base_path: ''
|
||||
process:
|
||||
# If you are using this file to build a custom migration consider removing
|
||||
# the fid field to allow incremental migrations.
|
||||
fid: fid
|
||||
filename: filename
|
||||
source_full_path:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ namespace Drupal\file\Plugin\migrate\process\d6;
|
|||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\MigrateSkipRowException;
|
||||
use Drupal\migrate\Plugin\MigrateProcessInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
|
@ -76,18 +75,7 @@ class CckFile extends ProcessPluginBase implements ContainerFactoryPluginInterfa
|
|||
// some reason -- file migration is notoriously brittle -- and we do NOT
|
||||
// want to send invalid file references into the field system (it causes
|
||||
// fatals), so return an empty item instead.
|
||||
try {
|
||||
$fid = $this->migrationPlugin->transform($value['fid'], $migrate_executable, $row, $destination_property);
|
||||
}
|
||||
// If the migration plugin completely fails its lookup process, it will
|
||||
// throw a MigrateSkipRowException. It shouldn't, but that is being dealt
|
||||
// with at https://www.drupal.org/node/2487568. Until that lands, return
|
||||
// an empty item.
|
||||
catch (MigrateSkipRowException $e) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($fid) {
|
||||
if ($fid = $this->migrationPlugin->transform($value['fid'], $migrate_executable, $row, $destination_property)) {
|
||||
return [
|
||||
'target_id' => $fid,
|
||||
'display' => $value['list'],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Block;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\Block\BlockResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class BlockHalJsonAnonTest extends BlockResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Block;
|
||||
|
||||
use Drupal\Tests\hal\Functional\HalJsonBasicAuthWorkaroundFor2805281Trait;
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\Block\BlockResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class BlockHalJsonBasicAuthTest extends BlockResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal', 'basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use HalJsonBasicAuthWorkaroundFor2805281Trait {
|
||||
HalJsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Block;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\Block\BlockResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class BlockHalJsonCookieTest extends BlockResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Comment;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class CommentHalJsonAnonTest extends CommentHalJsonTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Anononymous users cannot edit their own comments.
|
||||
*
|
||||
* @see \Drupal\comment\CommentAccessControlHandler::checkAccess
|
||||
*
|
||||
* Therefore we grant them the 'administer comments' permission for the
|
||||
* purpose of this test. Then they are able to edit their own comments, but
|
||||
* some fields are still not editable, even with that permission.
|
||||
*
|
||||
* @see ::setUpAuthorization
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [
|
||||
'changed',
|
||||
'thread',
|
||||
'entity_type',
|
||||
'field_name',
|
||||
'entity_id',
|
||||
];
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Comment;
|
||||
|
||||
use Drupal\Tests\hal\Functional\HalJsonBasicAuthWorkaroundFor2805281Trait;
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class CommentHalJsonBasicAuthTest extends CommentHalJsonTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use HalJsonBasicAuthWorkaroundFor2805281Trait {
|
||||
HalJsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Comment;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class CommentHalJsonCookieTest extends CommentHalJsonTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Comment;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\Comment\CommentResourceTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
abstract class CommentHalJsonTestBase extends CommentResourceTestBase {
|
||||
|
||||
use HalEntityNormalizationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* The HAL+JSON format causes different PATCH-protected fields. For some
|
||||
* reason, the 'pid' and 'homepage' fields are NOT PATCH-protected, even
|
||||
* though they are for non-HAL+JSON serializations.
|
||||
*
|
||||
* @todo fix in https://www.drupal.org/node/2824271
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [
|
||||
'created',
|
||||
'changed',
|
||||
'status',
|
||||
'thread',
|
||||
'entity_type',
|
||||
'field_name',
|
||||
'entity_id',
|
||||
'uid',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
$default_normalization = parent::getExpectedNormalizedEntity();
|
||||
|
||||
$normalization = $this->applyHalFieldNormalization($default_normalization);
|
||||
|
||||
// Because \Drupal\comment\Entity\Comment::getOwner() generates an in-memory
|
||||
// User entity without a UUID, we cannot use it.
|
||||
$author = User::load($this->entity->getOwnerId());
|
||||
$commented_entity = EntityTest::load(1);
|
||||
return $normalization + [
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/comment/1?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/comment/comment',
|
||||
],
|
||||
$this->baseUrl . '/rest/relation/comment/comment/entity_id' => [
|
||||
[
|
||||
'href' => $this->baseUrl . '/entity_test/1?_format=hal_json',
|
||||
],
|
||||
],
|
||||
$this->baseUrl . '/rest/relation/comment/comment/uid' => [
|
||||
[
|
||||
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
|
||||
'lang' => 'en',
|
||||
],
|
||||
],
|
||||
],
|
||||
'_embedded' => [
|
||||
$this->baseUrl . '/rest/relation/comment/comment/entity_id' => [
|
||||
[
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/entity_test/1?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/entity_test/bar',
|
||||
],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => $commented_entity->uuid()]
|
||||
],
|
||||
],
|
||||
],
|
||||
$this->baseUrl . '/rest/relation/comment/comment/uid' => [
|
||||
[
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/user/user',
|
||||
],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => $author->uuid()]
|
||||
],
|
||||
'lang' => 'en',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return parent::getNormalizedPostEntity() + [
|
||||
'_links' => [
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/comment/comment',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
// The 'url.site' cache context is added for '_links' in the response.
|
||||
return Cache::mergeTags(parent::getExpectedCacheContexts(), ['url.site']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\ConfigTest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\ConfigTest\ConfigTestResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class ConfigTestHalJsonAnonTest extends ConfigTestResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\ConfigTest;
|
||||
|
||||
use Drupal\Tests\hal\Functional\HalJsonBasicAuthWorkaroundFor2805281Trait;
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\ConfigTest\ConfigTestResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class ConfigTestHalJsonBasicAuthTest extends ConfigTestResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal', 'basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use HalJsonBasicAuthWorkaroundFor2805281Trait {
|
||||
HalJsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\ConfigTest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\ConfigTest\ConfigTestResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class ConfigTestHalJsonCookieTest extends ConfigTestResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\EntityTest;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityTest\EntityTestResourceTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class EntityTestHalJsonAnonTest extends EntityTestResourceTestBase {
|
||||
|
||||
use HalEntityNormalizationTrait;
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
$default_normalization = parent::getExpectedNormalizedEntity();
|
||||
|
||||
$normalization = $this->applyHalFieldNormalization($default_normalization);
|
||||
|
||||
$author = User::load(0);
|
||||
return $normalization + [
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/entity_test/1?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/entity_test/entity_test',
|
||||
],
|
||||
$this->baseUrl . '/rest/relation/entity_test/entity_test/user_id' => [
|
||||
[
|
||||
'href' => $this->baseUrl . '/user/0?_format=hal_json',
|
||||
'lang' => 'en',
|
||||
],
|
||||
],
|
||||
],
|
||||
'_embedded' => [
|
||||
$this->baseUrl . '/rest/relation/entity_test/entity_test/user_id' => [
|
||||
[
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/user/0?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/user/user',
|
||||
],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => $author->uuid()]
|
||||
],
|
||||
'lang' => 'en',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return parent::getNormalizedPostEntity() + [
|
||||
'_links' => [
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/entity_test/entity_test',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
// The 'url.site' cache context is added for '_links' in the response.
|
||||
return Cache::mergeTags(parent::getExpectedCacheContexts(), ['url.site']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\EntityTest;
|
||||
|
||||
use Drupal\Tests\hal\Functional\HalJsonBasicAuthWorkaroundFor2805281Trait;
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class EntityTestHalJsonBasicAuthTest extends EntityTestHalJsonAnonTest {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use HalJsonBasicAuthWorkaroundFor2805281Trait {
|
||||
HalJsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\EntityTest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class EntityTestHalJsonCookieTest extends EntityTestHalJsonAnonTest {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource;
|
||||
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Url;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
|
||||
/**
|
||||
* Trait for EntityResourceTestBase subclasses testing formats using HAL.
|
||||
*/
|
||||
trait HalEntityNormalizationTrait {
|
||||
|
||||
/**
|
||||
* Applies the HAL entity field normalization to an entity normalization.
|
||||
*
|
||||
* The HAL normalization:
|
||||
* - adds a 'lang' attribute to every translatable field
|
||||
* - omits reference fields, since references are stored in _links & _embedded
|
||||
* - omits empty fields (fields without value)
|
||||
*
|
||||
* @param array $normalization
|
||||
* An entity normalization.
|
||||
*
|
||||
* @return array
|
||||
* The updated entity normalization.
|
||||
*/
|
||||
protected function applyHalFieldNormalization(array $normalization) {
|
||||
if (!$this->entity instanceof FieldableEntityInterface) {
|
||||
throw new \LogicException('This trait should only be used for fieldable entity types.');
|
||||
}
|
||||
|
||||
// In the HAL normalization, all translatable fields get a 'lang' attribute.
|
||||
$translatable_non_reference_fields = array_keys(array_filter($this->entity->getTranslatableFields(), function (FieldItemListInterface $field) {
|
||||
return !$field instanceof EntityReferenceFieldItemListInterface;
|
||||
}));
|
||||
foreach ($translatable_non_reference_fields as $field_name) {
|
||||
if (isset($normalization[$field_name])) {
|
||||
$normalization[$field_name][0]['lang'] = 'en';
|
||||
}
|
||||
}
|
||||
|
||||
// In the HAL normalization, reference fields are omitted, except for the
|
||||
// bundle field.
|
||||
$bundle_key = $this->entity->getEntityType()->getKey('bundle');
|
||||
$reference_fields = array_keys(array_filter($this->entity->getFields(), function (FieldItemListInterface $field) use ($bundle_key) {
|
||||
return $field instanceof EntityReferenceFieldItemListInterface && $field->getName() !== $bundle_key;
|
||||
}));
|
||||
foreach ($reference_fields as $field_name) {
|
||||
unset($normalization[$field_name]);
|
||||
}
|
||||
|
||||
// In the HAL normalization, the bundle field omits the 'target_type' and
|
||||
// 'target_uuid' properties, because it's encoded in the '_links' section.
|
||||
if ($bundle_key) {
|
||||
unset($normalization[$bundle_key][0]['target_type']);
|
||||
unset($normalization[$bundle_key][0]['target_uuid']);
|
||||
}
|
||||
|
||||
// In the HAL normalization, empty fields are omitted.
|
||||
$empty_fields = array_keys(array_filter($this->entity->getFields(), function (FieldItemListInterface $field) {
|
||||
return $field->isEmpty();
|
||||
}));
|
||||
foreach ($empty_fields as $field_name) {
|
||||
unset($normalization[$field_name]);
|
||||
}
|
||||
|
||||
return $normalization;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function removeFieldsFromNormalization(array $normalization, $field_names) {
|
||||
$normalization = parent::removeFieldsFromNormalization($normalization, $field_names);
|
||||
foreach ($field_names as $field_name) {
|
||||
$relation_url = Url::fromUri('base:rest/relation/' . static::$entityTypeId . '/' . $this->entity->bundle() . '/' . $field_name)
|
||||
->setAbsolute(TRUE)
|
||||
->toString();
|
||||
$normalization['_links'] = array_diff_key($normalization['_links'], [$relation_url => TRUE]);
|
||||
if (isset($normalization['_embedded'])) {
|
||||
$normalization['_embedded'] = array_diff_key($normalization['_embedded'], [$relation_url => TRUE]);
|
||||
}
|
||||
}
|
||||
|
||||
return array_diff_key($normalization, array_flip($field_names));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function assertNormalizationEdgeCases($method, Url $url, array $request_options) {
|
||||
// \Drupal\serialization\Normalizer\EntityNormalizer::denormalize(): entity
|
||||
// types with bundles MUST send their bundle field to be denormalizable.
|
||||
if ($this->entity->getEntityType()->hasKey('bundle')) {
|
||||
$normalization = $this->getNormalizedPostEntity();
|
||||
|
||||
// @todo Uncomment this in https://www.drupal.org/node/2824827.
|
||||
// @codingStandardsIgnoreStart
|
||||
/*
|
||||
$normalization['_links']['type'] = Url::fromUri('base:rest/type/' . static::$entityTypeId . '/bad_bundle_name');
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// DX: 400 when incorrect entity type bundle is specified.
|
||||
$response = $this->request($method, $url, $request_options);
|
||||
// @todo Uncomment, remove next 3 in https://www.drupal.org/node/2813853.
|
||||
// $this->assertResourceErrorResponse(400, 'The type link relation must be specified.', $response);
|
||||
$this->assertSame(400, $response->getStatusCode());
|
||||
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame($this->serializer->encode(['error' => 'The type link relation must be specified.'], static::$format), (string) $response->getBody());
|
||||
*/
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
unset($normalization['_links']['type']);
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
|
||||
// DX: 400 when no entity type bundle is specified.
|
||||
$response = $this->request($method, $url, $request_options);
|
||||
// @todo Uncomment, remove next 3 in https://www.drupal.org/node/2813853.
|
||||
// $this->assertResourceErrorResponse(400, 'The type link relation must be specified.', $response);
|
||||
$this->assertSame(400, $response->getStatusCode());
|
||||
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame($this->serializer->encode(['error' => 'The type link relation must be specified.'], static::$format), (string) $response->getBody());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Node;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\Node\NodeResourceTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class NodeHalJsonAnonTest extends NodeResourceTestBase {
|
||||
|
||||
use HalEntityNormalizationTrait;
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [
|
||||
'created',
|
||||
'changed',
|
||||
'promote',
|
||||
'sticky',
|
||||
'revision_timestamp',
|
||||
'revision_uid',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
$default_normalization = parent::getExpectedNormalizedEntity();
|
||||
|
||||
$normalization = $this->applyHalFieldNormalization($default_normalization);
|
||||
|
||||
$author = User::load($this->entity->getOwnerId());
|
||||
return $normalization + [
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/node/1?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/node/camelids',
|
||||
],
|
||||
$this->baseUrl . '/rest/relation/node/camelids/uid' => [
|
||||
[
|
||||
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
|
||||
'lang' => 'en',
|
||||
],
|
||||
],
|
||||
$this->baseUrl . '/rest/relation/node/camelids/revision_uid' => [
|
||||
[
|
||||
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
|
||||
],
|
||||
],
|
||||
],
|
||||
'_embedded' => [
|
||||
$this->baseUrl . '/rest/relation/node/camelids/uid' => [
|
||||
[
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/user/user',
|
||||
],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => $author->uuid()]
|
||||
],
|
||||
'lang' => 'en',
|
||||
],
|
||||
],
|
||||
$this->baseUrl . '/rest/relation/node/camelids/revision_uid' => [
|
||||
[
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/user/user',
|
||||
],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => $author->uuid()]
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return parent::getNormalizedPostEntity() + [
|
||||
'_links' => [
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/node/camelids',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
// The 'url.site' cache context is added for '_links' in the response.
|
||||
return Cache::mergeContexts(parent::getExpectedCacheContexts(), ['url.site']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Node;
|
||||
|
||||
use Drupal\Tests\hal\Functional\HalJsonBasicAuthWorkaroundFor2805281Trait;
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class NodeHalJsonBasicAuthTest extends NodeHalJsonAnonTest {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use HalJsonBasicAuthWorkaroundFor2805281Trait {
|
||||
HalJsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Node;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class NodeHalJsonCookieTest extends NodeHalJsonAnonTest {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Role;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\Role\RoleResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class RoleHalJsonAnonTest extends RoleResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Role;
|
||||
|
||||
use Drupal\Tests\hal\Functional\HalJsonBasicAuthWorkaroundFor2805281Trait;
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\Role\RoleResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class RoleHalJsonBasicAuthTest extends RoleResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal', 'basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use HalJsonBasicAuthWorkaroundFor2805281Trait {
|
||||
HalJsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Role;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\Role\RoleResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class RoleHalJsonCookieTest extends RoleResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Term;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\Term\TermResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class TermHalJsonAnonTest extends TermResourceTestBase {
|
||||
|
||||
use HalEntityNormalizationTrait;
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
$default_normalization = parent::getExpectedNormalizedEntity();
|
||||
|
||||
$normalization = $this->applyHalFieldNormalization($default_normalization);
|
||||
|
||||
return $normalization + [
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/taxonomy/term/1?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return parent::getNormalizedPostEntity() + [
|
||||
'_links' => [
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
// The 'url.site' cache context is added for '_links' in the response.
|
||||
return Cache::mergeContexts(parent::getExpectedCacheContexts(), ['url.site']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Term;
|
||||
|
||||
use Drupal\Tests\hal\Functional\HalJsonBasicAuthWorkaroundFor2805281Trait;
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class TermHalJsonBasicAuthTest extends TermHalJsonAnonTest {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use HalJsonBasicAuthWorkaroundFor2805281Trait {
|
||||
HalJsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Term;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class TermHalJsonCookieTest extends TermHalJsonAnonTest {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\User;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\User\UserResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class UserHalJsonAnonTest extends UserResourceTestBase {
|
||||
|
||||
use HalEntityNormalizationTrait;
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
$default_normalization = parent::getExpectedNormalizedEntity();
|
||||
|
||||
$normalization = $this->applyHalFieldNormalization($default_normalization);
|
||||
|
||||
return $normalization + [
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/user/3?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/user/user',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return parent::getNormalizedPostEntity() + [
|
||||
'_links' => [
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/user/user',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
// The 'url.site' cache context is added for '_links' in the response.
|
||||
return Cache::mergeContexts(parent::getExpectedCacheContexts(), ['url.site']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\User;
|
||||
|
||||
use Drupal\Tests\hal\Functional\HalJsonBasicAuthWorkaroundFor2805281Trait;
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class UserHalJsonBasicAuthTest extends UserHalJsonAnonTest {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use HalJsonBasicAuthWorkaroundFor2805281Trait {
|
||||
HalJsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\User;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class UserHalJsonCookieTest extends UserHalJsonAnonTest {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Vocabulary;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\Vocabulary\VocabularyResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class VocabularyHalJsonAnonTest extends VocabularyResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* @todo Remove this override in https://www.drupal.org/node/2805281.
|
||||
*/
|
||||
public function testGet() {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Vocabulary;
|
||||
|
||||
use Drupal\Tests\hal\Functional\HalJsonBasicAuthWorkaroundFor2805281Trait;
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\Vocabulary\VocabularyResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class VocabularyHalJsonBasicAuthTest extends VocabularyResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal', 'basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use HalJsonBasicAuthWorkaroundFor2805281Trait {
|
||||
HalJsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\Vocabulary;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\Vocabulary\VocabularyResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class VocabularyHalJsonCookieTest extends VocabularyResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Functional;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
trait HalJsonBasicAuthWorkaroundFor2805281Trait {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Note how the response claims it contains a application/hal+json body, but
|
||||
* in reality it contains a text/plain body! Also, the correct error MIME type
|
||||
* is application/json.
|
||||
*
|
||||
* @todo Fix in https://www.drupal.org/node/2805281: remove this trait.
|
||||
*/
|
||||
protected function assertResponseWhenMissingAuthentication(ResponseInterface $response) {
|
||||
$this->assertSame(401, $response->getStatusCode());
|
||||
// @todo this works fine locally, but on testbot it comes back with
|
||||
// 'text/plain; charset=UTF-8'. WTF.
|
||||
// $this->assertSame(['application/hal+json'], $response->getHeader('Content-Type'));
|
||||
$this->assertSame('No authentication credentials provided.', (string) $response->getBody());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ use Drupal\field\Entity\FieldConfig;
|
|||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Tests that entities can be denormalized from HAL.
|
||||
* Tests HAL denormalization edge cases for EntityResource.
|
||||
*
|
||||
* @group hal
|
||||
*/
|
||||
|
|
@ -110,98 +110,4 @@ class DenormalizeTest extends NormalizerTestBase {
|
|||
$this->assertEqual($entity->field_test_text->count(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that non-reference fields can be denormalized.
|
||||
*/
|
||||
public function testBasicFieldDenormalization() {
|
||||
$data = array(
|
||||
'_links' => array(
|
||||
'type' => array(
|
||||
'href' => Url::fromUri('base:rest/type/entity_test/entity_test', array('absolute' => TRUE))->toString(),
|
||||
),
|
||||
),
|
||||
'uuid' => array(
|
||||
array(
|
||||
'value' => 'e5c9fb96-3acf-4a8d-9417-23de1b6c3311',
|
||||
),
|
||||
),
|
||||
'field_test_text' => array(
|
||||
array(
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => 'full_html',
|
||||
),
|
||||
),
|
||||
'field_test_translatable_text' => array(
|
||||
array(
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => 'full_html',
|
||||
),
|
||||
array(
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => 'filtered_html',
|
||||
),
|
||||
array(
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => 'filtered_html',
|
||||
'lang' => 'de',
|
||||
),
|
||||
array(
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => 'full_html',
|
||||
'lang' => 'de',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$expected_value_default = array(
|
||||
array (
|
||||
'value' => $data['field_test_translatable_text'][0]['value'],
|
||||
'format' => 'full_html',
|
||||
),
|
||||
array (
|
||||
'value' => $data['field_test_translatable_text'][1]['value'],
|
||||
'format' => 'filtered_html',
|
||||
),
|
||||
);
|
||||
$expected_value_de = array(
|
||||
array (
|
||||
'value' => $data['field_test_translatable_text'][2]['value'],
|
||||
'format' => 'filtered_html',
|
||||
),
|
||||
array (
|
||||
'value' => $data['field_test_translatable_text'][3]['value'],
|
||||
'format' => 'full_html',
|
||||
),
|
||||
);
|
||||
$denormalized = $this->serializer->denormalize($data, $this->entityClass, $this->format);
|
||||
$this->assertEqual($data['uuid'], $denormalized->get('uuid')->getValue(), 'A preset value (e.g. UUID) is overridden by incoming data.');
|
||||
$this->assertEqual($data['field_test_text'], $denormalized->get('field_test_text')->getValue(), 'A basic text field is denormalized.');
|
||||
$this->assertEqual($expected_value_default, $denormalized->get('field_test_translatable_text')->getValue(), 'Values in the default language are properly handled for a translatable field.');
|
||||
$this->assertEqual($expected_value_de, $denormalized->getTranslation('de')->get('field_test_translatable_text')->getValue(), 'Values in a translation language are properly handled for a translatable field.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the denormalized entity is correct in the PATCH context.
|
||||
*/
|
||||
public function testPatchDenormalization() {
|
||||
$data = array(
|
||||
'_links' => array(
|
||||
'type' => array(
|
||||
'href' => Url::fromUri('base:rest/type/entity_test/entity_test', array('absolute' => TRUE))->toString(),
|
||||
),
|
||||
),
|
||||
'field_test_text' => array(
|
||||
array(
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => 'full_html',
|
||||
),
|
||||
),
|
||||
);
|
||||
$denormalized = $this->serializer->denormalize($data, $this->entityClass, $this->format, array('request_method' => 'patch'));
|
||||
// Check that the one field got populated as expected.
|
||||
$this->assertEqual($data['field_test_text'], $denormalized->get('field_test_text')->getValue());
|
||||
// Check the custom property that contains the list of fields to merge.
|
||||
$this->assertEqual($denormalized->_restSubmittedFields, ['field_test_text']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,206 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\hal\Kernel;
|
||||
|
||||
use Drupal\comment\Tests\CommentTestTrait;
|
||||
use Drupal\comment\Entity\Comment;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\user\Entity\User;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Tests that nodes and terms are correctly normalized and denormalized.
|
||||
*
|
||||
* @group hal
|
||||
*/
|
||||
class EntityNormalizeTest extends NormalizerTestBase {
|
||||
|
||||
use CommentTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'taxonomy', 'comment');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
$this->installSchema('system', array('sequences'));
|
||||
$this->installSchema('comment', array('comment_entity_statistics'));
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->installConfig(['node', 'comment']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the normalization of nodes.
|
||||
*/
|
||||
public function testNode() {
|
||||
$node_type = NodeType::create(['type' => 'example_type']);
|
||||
$node_type->save();
|
||||
|
||||
$user = User::create(['name' => $this->randomMachineName()]);
|
||||
$user->save();
|
||||
|
||||
// Add comment type.
|
||||
$this->container->get('entity.manager')->getStorage('comment_type')->create(array(
|
||||
'id' => 'comment',
|
||||
'label' => 'comment',
|
||||
'target_entity_type_id' => 'node',
|
||||
))->save();
|
||||
|
||||
$this->addDefaultCommentField('node', 'example_type');
|
||||
|
||||
$node = Node::create([
|
||||
'title' => $this->randomMachineName(),
|
||||
'uid' => $user->id(),
|
||||
'type' => $node_type->id(),
|
||||
'status' => NODE_PUBLISHED,
|
||||
'promote' => 1,
|
||||
'sticky' => 0,
|
||||
'body' => [
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => $this->randomMachineName()
|
||||
],
|
||||
'revision_log' => $this->randomString(),
|
||||
]);
|
||||
$node->save();
|
||||
|
||||
$original_values = $node->toArray();
|
||||
|
||||
$normalized = $this->serializer->normalize($node, $this->format);
|
||||
|
||||
/** @var \Drupal\node\NodeInterface $denormalized_node */
|
||||
$denormalized_node = $this->serializer->denormalize($normalized, 'Drupal\node\Entity\Node', $this->format);
|
||||
|
||||
$this->assertEqual($original_values, $denormalized_node->toArray(), 'Node values are restored after normalizing and denormalizing.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the normalization of terms.
|
||||
*/
|
||||
public function testTerm() {
|
||||
$vocabulary = Vocabulary::create(['vid' => 'example_vocabulary']);
|
||||
$vocabulary->save();
|
||||
|
||||
$account = User::create(['name' => $this->randomMachineName()]);
|
||||
$account->save();
|
||||
|
||||
// @todo Until https://www.drupal.org/node/2327935 is fixed, if no parent is
|
||||
// set, the test fails because target_id => 0 is reserialized to NULL.
|
||||
$term_parent = Term::create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'vid' => $vocabulary->id(),
|
||||
]);
|
||||
$term_parent->save();
|
||||
$term = Term::create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'vid' => $vocabulary->id(),
|
||||
'description' => array(
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => $this->randomMachineName(),
|
||||
),
|
||||
'parent' => $term_parent->id(),
|
||||
]);
|
||||
$term->save();
|
||||
|
||||
$original_values = $term->toArray();
|
||||
|
||||
$normalized = $this->serializer->normalize($term, $this->format, ['account' => $account]);
|
||||
|
||||
/** @var \Drupal\taxonomy\TermInterface $denormalized_term */
|
||||
$denormalized_term = $this->serializer->denormalize($normalized, 'Drupal\taxonomy\Entity\Term', $this->format, ['account' => $account]);
|
||||
|
||||
$this->assertEqual($original_values, $denormalized_term->toArray(), 'Term values are restored after normalizing and denormalizing.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the normalization of comments.
|
||||
*/
|
||||
public function testComment() {
|
||||
$node_type = NodeType::create(['type' => 'example_type']);
|
||||
$node_type->save();
|
||||
|
||||
$account = User::create(['name' => $this->randomMachineName()]);
|
||||
$account->save();
|
||||
|
||||
// Add comment type.
|
||||
$this->container->get('entity.manager')->getStorage('comment_type')->create(array(
|
||||
'id' => 'comment',
|
||||
'label' => 'comment',
|
||||
'target_entity_type_id' => 'node',
|
||||
))->save();
|
||||
|
||||
$this->addDefaultCommentField('node', 'example_type');
|
||||
|
||||
$node = Node::create([
|
||||
'title' => $this->randomMachineName(),
|
||||
'uid' => $account->id(),
|
||||
'type' => $node_type->id(),
|
||||
'status' => NODE_PUBLISHED,
|
||||
'promote' => 1,
|
||||
'sticky' => 0,
|
||||
'body' => [[
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => $this->randomMachineName()
|
||||
]],
|
||||
]);
|
||||
$node->save();
|
||||
|
||||
$parent_comment = Comment::create(array(
|
||||
'uid' => $account->id(),
|
||||
'subject' => $this->randomMachineName(),
|
||||
'comment_body' => [
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => NULL,
|
||||
],
|
||||
'entity_id' => $node->id(),
|
||||
'entity_type' => 'node',
|
||||
'field_name' => 'comment',
|
||||
));
|
||||
$parent_comment->save();
|
||||
|
||||
$comment = Comment::create(array(
|
||||
'uid' => $account->id(),
|
||||
'subject' => $this->randomMachineName(),
|
||||
'comment_body' => [
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => NULL,
|
||||
],
|
||||
'entity_id' => $node->id(),
|
||||
'entity_type' => 'node',
|
||||
'field_name' => 'comment',
|
||||
'pid' => $parent_comment->id(),
|
||||
'mail' => 'dries@drupal.org',
|
||||
'homepage' => 'http://buytaert.net',
|
||||
));
|
||||
$comment->save();
|
||||
|
||||
$original_values = $comment->toArray();
|
||||
// Hostname will always be denied view access.
|
||||
// No value will exist for name as this is only for anonymous users.
|
||||
unset($original_values['hostname'], $original_values['name']);
|
||||
|
||||
$normalized = $this->serializer->normalize($comment, $this->format, ['account' => $account]);
|
||||
|
||||
// Assert that the hostname field does not appear at all in the normalized
|
||||
// data.
|
||||
$this->assertFalse(array_key_exists('hostname', $normalized), 'Hostname was not found in normalized comment data.');
|
||||
|
||||
/** @var \Drupal\comment\CommentInterface $denormalized_comment */
|
||||
$denormalized_comment = $this->serializer->denormalize($normalized, 'Drupal\comment\Entity\Comment', $this->format, ['account' => $account]);
|
||||
|
||||
// Before comparing, unset values that are expected to differ.
|
||||
$denormalized_comment_values = $denormalized_comment->toArray();
|
||||
unset($denormalized_comment_values['hostname'], $denormalized_comment_values['name']);
|
||||
$this->assertEqual($original_values, $denormalized_comment_values, 'The expected comment values are restored after normalizing and denormalizing.');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ use Drupal\Core\Url;
|
|||
use Drupal\entity_test\Entity\EntityTest;
|
||||
|
||||
/**
|
||||
* Tests that entities can be normalized in HAL.
|
||||
* Tests HAL normalization edge cases for EntityResource.
|
||||
*
|
||||
* @group hal
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
id: d6_language_negotiation_settings
|
||||
label: Language negotiation settings
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- language_negotiation
|
||||
process:
|
||||
session/parameter:
|
||||
plugin: default_value
|
||||
default_value: 'language'
|
||||
selected_langcode:
|
||||
plugin: default_value
|
||||
default_value: 'site_default'
|
||||
url/source:
|
||||
plugin: static_map
|
||||
source: language_negotiation
|
||||
default_value: path_prefix
|
||||
map:
|
||||
# LANGUAGE_NEGOTIATION_NONE = 0
|
||||
# LANGUAGE_NEGOTIATION_PATH_DEFAULT = 1
|
||||
# LANGUAGE_NEGOTIATION_PATH = 2
|
||||
# LANGUAGE_NEGOTIATION_DOMAIN = 3
|
||||
0: path_prefix
|
||||
1: path_prefix
|
||||
2: path_prefix
|
||||
3: domain
|
||||
destination:
|
||||
plugin: config
|
||||
config_name: language.negotiation
|
||||
migration_dependencies:
|
||||
required:
|
||||
- language
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
id: d6_language_types
|
||||
label: Language types
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- language_negotiation
|
||||
process:
|
||||
all:
|
||||
plugin: default_value
|
||||
default_value:
|
||||
- 'language_interface'
|
||||
- 'language_content'
|
||||
- 'language_url'
|
||||
configurable:
|
||||
plugin: default_value
|
||||
default_value:
|
||||
- 'language_interface'
|
||||
negotiation/language_content/enabled:
|
||||
plugin: default_value
|
||||
default_value:
|
||||
'language-interface': 0
|
||||
negotiation/language_url/enabled:
|
||||
plugin: default_value
|
||||
default_value:
|
||||
'language-url': 0
|
||||
'language-url-fallback': 1
|
||||
negotiation/language_interface/enabled:
|
||||
plugin: static_map
|
||||
source: language_negotiation
|
||||
map:
|
||||
# LANGUAGE_NEGOTIATION_NONE = 0
|
||||
# LANGUAGE_NEGOTIATION_PATH_DEFAULT = 1
|
||||
# LANGUAGE_NEGOTIATION_PATH = 2
|
||||
# LANGUAGE_NEGOTIATION_DOMAIN = 3
|
||||
0:
|
||||
'language-selected': 0
|
||||
1:
|
||||
'language-url': 0
|
||||
'language-selected': 1
|
||||
2:
|
||||
'language-url': 0
|
||||
'language-user': 1
|
||||
'language-browser': 2
|
||||
'language-selected': 3
|
||||
3:
|
||||
'language-url': 0
|
||||
'language-selected': 1
|
||||
destination:
|
||||
plugin: config
|
||||
config_name: language.types
|
||||
|
|
@ -8,8 +8,25 @@ source:
|
|||
- locale_language_negotiation_session_param
|
||||
- locale_language_negotiation_url_part
|
||||
process:
|
||||
'session/parameter': locale_language_negotiation_session_param
|
||||
'url/source': locale_language_negotiation_url_part
|
||||
session/parameter:
|
||||
plugin: default_value
|
||||
source: locale_language_negotiation_session_param
|
||||
default_value: 'language'
|
||||
selected_langcode:
|
||||
plugin: default_value
|
||||
default_value: 'site_default'
|
||||
url/source:
|
||||
plugin: static_map
|
||||
source: locale_language_negotiation_url_part
|
||||
default_value: path_prefix
|
||||
map:
|
||||
# LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX = 0
|
||||
# LOCALE_LANGUAGE_NEGOTIATION_URL_DOMAIN = 1
|
||||
0: path_prefix
|
||||
1: domain
|
||||
destination:
|
||||
plugin: config
|
||||
config_name: language.negotiation
|
||||
migration_dependencies:
|
||||
required:
|
||||
- language
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
id: d7_language_types
|
||||
label: Language types
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- language_types
|
||||
- language_negotiation_language
|
||||
- language_negotiation_language_content
|
||||
- language_negotiation_language_url
|
||||
- locale_language_providers_weight_language
|
||||
- locale_language_providers_weight_language_content
|
||||
- locale_language_providers_weight_language_url
|
||||
process:
|
||||
all:
|
||||
plugin: language_types
|
||||
source: language_types
|
||||
configurable:
|
||||
plugin: language_types
|
||||
source: language_types
|
||||
filter_configurable: true
|
||||
negotiation/language_content:
|
||||
plugin: language_negotiation
|
||||
source:
|
||||
- language_negotiation_language_content
|
||||
- locale_language_providers_weight_language_content
|
||||
negotiation/language_url:
|
||||
plugin: language_negotiation
|
||||
source:
|
||||
- language_negotiation_language_url
|
||||
- locale_language_providers_weight_language_url
|
||||
negotiation/language_interface:
|
||||
plugin: language_negotiation
|
||||
source:
|
||||
- language_negotiation_language
|
||||
- locale_language_providers_weight_language
|
||||
destination:
|
||||
plugin: config
|
||||
config_name: language.types
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
id: language_prefixes_and_domains
|
||||
label: Language prefixes and domains
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Drupal 7
|
||||
source:
|
||||
plugin: language
|
||||
fetch_all: true
|
||||
domain_negotiation: true
|
||||
process:
|
||||
url/prefixes:
|
||||
plugin: array_build
|
||||
source: languages
|
||||
key: language
|
||||
value: prefix
|
||||
url/domains:
|
||||
plugin: language_domains
|
||||
source: languages
|
||||
key: language
|
||||
value: domain
|
||||
destination:
|
||||
plugin: config
|
||||
config_name: language.negotiation
|
||||
migration_dependencies:
|
||||
required:
|
||||
- language
|
||||
|
|
@ -192,6 +192,7 @@ class LanguageNegotiationUrl extends LanguageNegotiationMethodBase implements In
|
|||
*/
|
||||
public function getLanguageSwitchLinks(Request $request, $type, Url $url) {
|
||||
$links = array();
|
||||
$query = $request->query->all();
|
||||
|
||||
foreach ($this->languageManager->getNativeLanguages() as $language) {
|
||||
$links[$language->getId()] = array(
|
||||
|
|
@ -202,6 +203,7 @@ class LanguageNegotiationUrl extends LanguageNegotiationMethodBase implements In
|
|||
'title' => $language->getName(),
|
||||
'language' => $language,
|
||||
'attributes' => array('class' => array('language-link')),
|
||||
'query' => $query,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\language\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Plugin\migrate\process\ArrayBuild;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* This plugin makes sure that no domain is empty if domain negotiation is used.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "language_domains",
|
||||
* handle_multiples = TRUE
|
||||
* )
|
||||
*/
|
||||
class LanguageDomains extends ArrayBuild {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if ($row->getSourceProperty('domain_negotiation')) {
|
||||
global $base_url;
|
||||
|
||||
foreach ($value as $old_key => $old_value) {
|
||||
if (empty($old_value['domain'])) {
|
||||
// The default language domain might be empty.
|
||||
// If it is, use the current domain.
|
||||
$value[$old_key]['domain'] = parse_url($base_url, PHP_URL_HOST);
|
||||
}
|
||||
else {
|
||||
// Ensure we have a protocol when checking for the hostname.
|
||||
$domain = 'http://' . str_replace(['http://', 'https://'], '', $old_value['domain']);
|
||||
// Only keep the host part of the domain.
|
||||
$value[$old_key]['domain'] = parse_url($domain, PHP_URL_HOST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::transform($value, $migrate_executable, $row, $destination_property);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\language\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Processes the arrays for the language types' negotiation methods and weights.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "language_negotiation",
|
||||
* handle_multiples = TRUE
|
||||
* )
|
||||
*/
|
||||
class LanguageNegotiation extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
$new_value = [
|
||||
'enabled' => [],
|
||||
'method_weights' => [],
|
||||
];
|
||||
|
||||
if (!is_array($value)) {
|
||||
throw new MigrateException('The input should be an array');
|
||||
}
|
||||
|
||||
// If no weights are provided, use the keys by flipping the array.
|
||||
if (empty($value[1])) {
|
||||
$new_value['enabled'] = array_flip(array_map([$this, 'mapNewMethods'], array_keys($value[0])));
|
||||
unset($new_value['method_weights']);
|
||||
}
|
||||
else {
|
||||
foreach ($value[1] as $method => $weight) {
|
||||
$new_method = $this->mapNewMethods($method);
|
||||
$new_value['method_weights'][$new_method] = $weight;
|
||||
if (in_array($method, array_keys($value[0]))) {
|
||||
$new_value['enabled'][$new_method] = $weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $new_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps old negotiation method names to the new ones.
|
||||
*
|
||||
* @param string $value
|
||||
* The old negotiation method name.
|
||||
*
|
||||
* @return string
|
||||
* The new negotiation method name.
|
||||
*/
|
||||
protected function mapNewMethods($value) {
|
||||
switch ($value) {
|
||||
case 'language-default':
|
||||
return 'language-selected';
|
||||
case 'locale-browser':
|
||||
return 'language-browser';
|
||||
case 'locale-interface':
|
||||
return 'language-interface';
|
||||
case 'locale-session':
|
||||
return 'language-session';
|
||||
case 'locale-url':
|
||||
return 'language-url';
|
||||
case 'locale-url-fallback':
|
||||
return 'language-url-fallback';
|
||||
case 'locale-user':
|
||||
return 'language-user';
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\language\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Processes the array for the language types.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "language_types",
|
||||
* handle_multiples = TRUE
|
||||
* )
|
||||
*/
|
||||
class LanguageTypes extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if (!is_array($value)) {
|
||||
throw new MigrateException('The input should be an array');
|
||||
}
|
||||
|
||||
if (array_key_exists('language', $value)) {
|
||||
$value['language_interface'] = $value['language'];
|
||||
unset($value['language']);
|
||||
}
|
||||
|
||||
if (!empty($this->configuration['filter_configurable'])) {
|
||||
$value = array_filter($value);
|
||||
}
|
||||
|
||||
return array_keys($value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\language\Plugin\migrate\source;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
|
|
@ -49,4 +50,27 @@ class Language extends DrupalSqlBase {
|
|||
return $this->select('languages')->fields('languages');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
if (!empty($this->configuration['fetch_all'])) {
|
||||
// Get an array of all languages.
|
||||
$languages = $this->query()->execute()->fetchAll();
|
||||
$row->setSourceProperty('languages', $languages);
|
||||
}
|
||||
|
||||
if (!empty($this->configuration['domain_negotiation'])) {
|
||||
// Check if domain negotiation is used to be able to fill in the default
|
||||
// language domain, which may be empty. In D6, domain negotiation is used
|
||||
// when the 'language_negotiation' variable is set to '3', and in D7, when
|
||||
// the 'locale_language_negotiation_url_part' variable is set to '1'.
|
||||
if ($this->variableGet('language_negotiation', 0) == 3 || $this->variableGet('locale_language_negotiation_url_part', 0) == 1) {
|
||||
$row->setSourceProperty('domain_negotiation', TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,8 +118,9 @@ class LanguageSwitchingTest extends WebTestBase {
|
|||
protected function doTestLanguageBlockAnonymous($block_label) {
|
||||
$this->drupalLogout();
|
||||
|
||||
// Assert that the language switching block is displayed on the frontpage.
|
||||
$this->drupalGet('');
|
||||
// Assert that the language switching block is displayed on the frontpage
|
||||
// and ensure that the active class is added when query params are present.
|
||||
$this->drupalGet('', ['query' => ['foo' => 'bar']]);
|
||||
$this->assertText($block_label, 'Language switcher block found.');
|
||||
|
||||
// Assert that only the current language is marked as active.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Tests the migration of language negotiation and language types.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateLanguageNegotiationSettingsTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* Tests the migration with LANGUAGE_NEGOTIATION_PATH_DEFAULT.
|
||||
*/
|
||||
public function testLanguageNegotiationWithDefaultPathPrefix() {
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
'd6_language_types',
|
||||
]);
|
||||
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertSame($config->get('session.parameter'), 'language');
|
||||
$this->assertSame($config->get('url.source'), LanguageNegotiationUrl::CONFIG_PATH_PREFIX);
|
||||
$this->assertSame($config->get('selected_langcode'), 'site_default');
|
||||
$expected_prefixes = [
|
||||
'en' => '',
|
||||
'fr' => 'fr',
|
||||
'zu' => 'zu',
|
||||
];
|
||||
$this->assertSame($config->get('url.prefixes'), $expected_prefixes);
|
||||
|
||||
$config = $this->config('language.types');
|
||||
$this->assertSame($config->get('all'), ['language_interface', 'language_content', 'language_url']);
|
||||
$this->assertSame($config->get('configurable'), ['language_interface']);
|
||||
$this->assertSame($config->get('negotiation.language_content.enabled'), ['language-interface' => 0]);
|
||||
$this->assertSame($config->get('negotiation.language_url.enabled'), ['language-url' => 0, 'language-url-fallback' => 1]);
|
||||
$expected_language_interface = [
|
||||
'language-url' => 0,
|
||||
'language-selected' => 1,
|
||||
];
|
||||
$this->assertSame($config->get('negotiation.language_interface.enabled'), $expected_language_interface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the migration with LANGUAGE_NEGOTIATION_NONE.
|
||||
*/
|
||||
public function testLanguageNegotiationWithNoNegotiation() {
|
||||
$this->sourceDatabase->update('variable')
|
||||
->fields(array('value' => serialize(0)))
|
||||
->condition('name', 'language_negotiation')
|
||||
->execute();
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
'd6_language_types',
|
||||
]);
|
||||
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertSame($config->get('session.parameter'), 'language');
|
||||
$this->assertSame($config->get('url.source'), LanguageNegotiationUrl::CONFIG_PATH_PREFIX);
|
||||
$this->assertSame($config->get('selected_langcode'), 'site_default');
|
||||
|
||||
$config = $this->config('language.types');
|
||||
$this->assertSame($config->get('all'), ['language_interface', 'language_content', 'language_url']);
|
||||
$this->assertSame($config->get('configurable'), ['language_interface']);
|
||||
$this->assertSame($config->get('negotiation.language_content.enabled'), ['language-interface' => 0]);
|
||||
$this->assertSame($config->get('negotiation.language_url.enabled'), ['language-url' => 0, 'language-url-fallback' => 1]);
|
||||
$expected_language_interface = [
|
||||
'language-selected' => 0,
|
||||
];
|
||||
$this->assertSame($config->get('negotiation.language_interface.enabled'), $expected_language_interface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the migration with LANGUAGE_NEGOTIATION_PATH.
|
||||
*/
|
||||
public function testLanguageNegotiationWithPathPrefix() {
|
||||
$this->sourceDatabase->update('variable')
|
||||
->fields(array('value' => serialize(2)))
|
||||
->condition('name', 'language_negotiation')
|
||||
->execute();
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
'd6_language_types',
|
||||
]);
|
||||
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertSame($config->get('session.parameter'), 'language');
|
||||
$this->assertSame($config->get('url.source'), LanguageNegotiationUrl::CONFIG_PATH_PREFIX);
|
||||
$this->assertSame($config->get('selected_langcode'), 'site_default');
|
||||
$expected_prefixes = [
|
||||
'en' => '',
|
||||
'fr' => 'fr',
|
||||
'zu' => 'zu',
|
||||
];
|
||||
$this->assertSame($config->get('url.prefixes'), $expected_prefixes);
|
||||
|
||||
$config = $this->config('language.types');
|
||||
$this->assertSame($config->get('all'), ['language_interface', 'language_content', 'language_url']);
|
||||
$this->assertSame($config->get('configurable'), ['language_interface']);
|
||||
$this->assertSame($config->get('negotiation.language_content.enabled'), ['language-interface' => 0]);
|
||||
$this->assertSame($config->get('negotiation.language_url.enabled'), ['language-url' => 0, 'language-url-fallback' => 1]);
|
||||
$expected_language_interface = [
|
||||
'language-url' => 0,
|
||||
'language-user' => 1,
|
||||
'language-browser' => 2,
|
||||
'language-selected' => 3,
|
||||
];
|
||||
$this->assertSame($config->get('negotiation.language_interface.enabled'), $expected_language_interface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the migration with LANGUAGE_NEGOTIATION_DOMAIN.
|
||||
*/
|
||||
public function testLanguageNegotiationWithDomain() {
|
||||
$this->sourceDatabase->update('variable')
|
||||
->fields(array('value' => serialize(3)))
|
||||
->condition('name', 'language_negotiation')
|
||||
->execute();
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
'd6_language_types',
|
||||
]);
|
||||
|
||||
global $base_url;
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertSame($config->get('session.parameter'), 'language');
|
||||
$this->assertSame($config->get('url.source'), LanguageNegotiationUrl::CONFIG_DOMAIN);
|
||||
$this->assertSame($config->get('selected_langcode'), 'site_default');
|
||||
$expected_domains = [
|
||||
'en' => parse_url($base_url, PHP_URL_HOST),
|
||||
'fr' => 'fr.drupal.org',
|
||||
'zu' => 'zu.drupal.org',
|
||||
];
|
||||
$this->assertSame($config->get('url.domains'), $expected_domains);
|
||||
|
||||
$config = $this->config('language.types');
|
||||
$this->assertSame($config->get('all'), ['language_interface', 'language_content', 'language_url']);
|
||||
$this->assertSame($config->get('configurable'), ['language_interface']);
|
||||
$this->assertSame($config->get('negotiation.language_content.enabled'), ['language-interface' => 0]);
|
||||
$this->assertSame($config->get('negotiation.language_url.enabled'), ['language-url' => 0, 'language-url-fallback' => 1]);
|
||||
$expected_language_interface = [
|
||||
'language-url' => 0,
|
||||
'language-selected' => 1,
|
||||
];
|
||||
$this->assertSame($config->get('negotiation.language_interface.enabled'), $expected_language_interface);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,37 +2,124 @@
|
|||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests migration of language negotiation variables.
|
||||
* Tests the migration of language negotiation.
|
||||
*
|
||||
* @group language
|
||||
* @group migrate_drupal_7
|
||||
*/
|
||||
class MigrateLanguageNegotiationSettingsTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Tests migration of language types variables to language.types.yml.
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->executeMigration('d7_language_negotiation_settings');
|
||||
public function testLanguageTypes() {
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_language_negotiation_settings',
|
||||
'd7_language_types',
|
||||
]);
|
||||
|
||||
$config = $this->config('language.types');
|
||||
$this->assertSame($config->get('all'), ['language_content', 'language_url', 'language_interface']);
|
||||
$this->assertSame($config->get('configurable'), ['language_interface']);
|
||||
$this->assertSame($config->get('negotiation.language_content'), ['enabled' => ['language-interface' => 0]]);
|
||||
$this->assertSame($config->get('negotiation.language_url'), ['enabled' => ['language-url' => 0, 'language-url-fallback' => 1]]);
|
||||
$expected_language_interface = [
|
||||
'enabled' => [
|
||||
'language-url' => -9,
|
||||
'language-user' => -10,
|
||||
'language-selected' => -6,
|
||||
],
|
||||
'method_weights' => [
|
||||
'language-url' => -9,
|
||||
'language-session' => -8,
|
||||
'language-user' => -10,
|
||||
'language-browser' => -7,
|
||||
'language-selected' => -6,
|
||||
],
|
||||
];
|
||||
$this->assertSame($config->get('negotiation.language_interface'), $expected_language_interface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of language negotiation variables to language.negotiation.yml.
|
||||
* Tests the migration with prefix negotiation.
|
||||
*/
|
||||
public function testLanguageNegotiation() {
|
||||
public function testLanguageNegotiationWithPrefix() {
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
]);
|
||||
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertIdentical($config->get('session.parameter'), 'language');
|
||||
$this->assertIdentical($config->get('url.source'), 'domain');
|
||||
$this->assertSame($config->get('session.parameter'), 'language');
|
||||
$this->assertSame($config->get('url.source'), LanguageNegotiationUrl::CONFIG_PATH_PREFIX);
|
||||
$this->assertSame($config->get('selected_langcode'), 'site_default');
|
||||
$expected_prefixes = [
|
||||
'en' => '',
|
||||
'is' => 'is',
|
||||
];
|
||||
$this->assertSame($config->get('url.prefixes'), $expected_prefixes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the migration with domain negotiation.
|
||||
*/
|
||||
public function testLanguageNegotiationWithDomain() {
|
||||
$this->sourceDatabase->update('variable')
|
||||
->fields(array('value' => serialize(1)))
|
||||
->condition('name', 'locale_language_negotiation_url_part')
|
||||
->execute();
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
]);
|
||||
|
||||
global $base_url;
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertSame($config->get('session.parameter'), 'language');
|
||||
$this->assertSame($config->get('url.source'), LanguageNegotiationUrl::CONFIG_DOMAIN);
|
||||
$this->assertSame($config->get('selected_langcode'), 'site_default');
|
||||
$expected_domains = [
|
||||
'en' => parse_url($base_url, PHP_URL_HOST),
|
||||
'is' => 'is.drupal.org',
|
||||
];
|
||||
$this->assertSame($config->get('url.domains'), $expected_domains);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the migration with non-existent variables.
|
||||
*/
|
||||
public function testLanguageNegotiationWithNonExistentVariables() {
|
||||
$this->sourceDatabase->delete('variable')
|
||||
->condition('name', ['local_language_negotiation_url_part', 'local_language_negotiation_session_param'], 'IN')
|
||||
->execute();
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
]);
|
||||
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertSame($config->get('session.parameter'), 'language');
|
||||
$this->assertSame($config->get('url.source'), LanguageNegotiationUrl::CONFIG_PATH_PREFIX);
|
||||
$this->assertSame($config->get('selected_langcode'), 'site_default');
|
||||
$expected_prefixes = [
|
||||
'en' => '',
|
||||
'is' => 'is',
|
||||
];
|
||||
$this->assertSame($config->get('url.prefixes'), $expected_prefixes);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\language\Unit\process;
|
||||
|
||||
use Drupal\language\Plugin\migrate\process\LanguageDomains;
|
||||
use Drupal\Tests\migrate\Unit\process\MigrateProcessTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\language\Plugin\migrate\process\LanguageDomains
|
||||
* @group language
|
||||
*/
|
||||
class LanguageDomainsTest extends MigrateProcessTestCase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $backupGlobalsBlacklist = ['base_url'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$configuration = [
|
||||
'key' => 'language',
|
||||
'value' => 'domain',
|
||||
];
|
||||
$this->plugin = new LanguageDomains($configuration, 'map', []);
|
||||
parent::setUp();
|
||||
|
||||
// The language_domains plugin calls getSourceProperty() to check if domain
|
||||
// negotiation is used. If it is the values will be processed so we need it
|
||||
// to return TRUE to be able to test the process.
|
||||
$this->row->expects($this->once())
|
||||
->method('getSourceProperty')
|
||||
->will($this->returnValue(TRUE));
|
||||
|
||||
// The language_domains plugin use $base_url to fill empty domains.
|
||||
global $base_url;
|
||||
$base_url = 'http://example.com';
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransform() {
|
||||
$source = [
|
||||
['language' => 'en', 'domain' => ''],
|
||||
['language' => 'fr', 'domain' => 'fr.example.com'],
|
||||
['language' => 'es', 'domain' => 'http://es.example.com'],
|
||||
['language' => 'hu', 'domain' => 'https://hu.example.com'],
|
||||
];
|
||||
$expected = [
|
||||
'en' => 'example.com',
|
||||
'fr' => 'fr.example.com',
|
||||
'es' => 'es.example.com',
|
||||
'hu' => 'hu.example.com',
|
||||
];
|
||||
$value = $this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$this->assertSame($value, $expected);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\language\Unit\process;
|
||||
|
||||
use Drupal\language\Plugin\migrate\process\LanguageNegotiation;
|
||||
use Drupal\Tests\migrate\Unit\process\MigrateProcessTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\language\Plugin\migrate\process\LanguageNegotiation
|
||||
* @group language
|
||||
*/
|
||||
class LanguageNegotiationTest extends MigrateProcessTestCase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->plugin = new LanguageNegotiation([], 'map', []);
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests successful transformation without weights.
|
||||
*/
|
||||
public function testTransformWithWeights() {
|
||||
$source = [
|
||||
[
|
||||
'locale-url' => [],
|
||||
'language-default' => [],
|
||||
],
|
||||
[
|
||||
'locale-url' => -10,
|
||||
'locale-session' => -9,
|
||||
'locale-user' => -8,
|
||||
'locale-browser' => -7,
|
||||
'language-default' => -6,
|
||||
],
|
||||
];
|
||||
$expected = [
|
||||
'enabled' => [
|
||||
'language-url' => -10,
|
||||
'language-selected' => -6,
|
||||
],
|
||||
'method_weights' => [
|
||||
'language-url' => -10,
|
||||
'language-session' => -9,
|
||||
'language-user' => -8,
|
||||
'language-browser' => -7,
|
||||
'language-selected' => -6,
|
||||
],
|
||||
];
|
||||
$value = $this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$this->assertSame($value, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests successful transformation without weights.
|
||||
*/
|
||||
public function testTransformWithoutWeights() {
|
||||
$source = [
|
||||
[
|
||||
'locale-url' => [],
|
||||
'locale-url-fallback' => [],
|
||||
],
|
||||
];
|
||||
$expected = [
|
||||
'enabled' => [
|
||||
'language-url' => 0,
|
||||
'language-url-fallback' => 1,
|
||||
],
|
||||
];
|
||||
$value = $this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$this->assertSame($value, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests string input.
|
||||
*
|
||||
* @expectedException \Drupal\migrate\MigrateException
|
||||
* @expectedExceptionMessage The input should be an array
|
||||
*/
|
||||
public function testStringInput() {
|
||||
$this->plugin = new LanguageNegotiation([], 'map', []);
|
||||
$this->plugin->transform('foo', $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\language\Unit\process;
|
||||
|
||||
use Drupal\language\Plugin\migrate\process\LanguageTypes;
|
||||
use Drupal\Tests\migrate\Unit\process\MigrateProcessTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\language\Plugin\migrate\process\LanguageTypes
|
||||
* @group language
|
||||
*/
|
||||
class LanguageTypesTest extends MigrateProcessTestCase {
|
||||
|
||||
/**
|
||||
* Tests successful transformation of all language types.
|
||||
*/
|
||||
public function testTransformAll() {
|
||||
$this->plugin = new LanguageTypes([], 'map', []);
|
||||
$source = [
|
||||
'language' => TRUE,
|
||||
'language_url' => FALSE,
|
||||
'language_content' => FALSE,
|
||||
];
|
||||
$expected = [
|
||||
0 => 'language_url',
|
||||
1 => 'language_content',
|
||||
2 => 'language_interface',
|
||||
];
|
||||
$value = $this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$this->assertSame($value, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests successful transformation of configurable language types.
|
||||
*/
|
||||
public function testTransformConfigurable() {
|
||||
$this->plugin = new LanguageTypes(['filter_configurable' => TRUE], 'map', []);
|
||||
$source = [
|
||||
'language' => TRUE,
|
||||
'language_url' => FALSE,
|
||||
'language_content' => FALSE,
|
||||
];
|
||||
$expected = [
|
||||
0 => 'language_interface',
|
||||
];
|
||||
$value = $this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$this->assertSame($value, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests string input.
|
||||
*
|
||||
* @expectedException \Drupal\migrate\MigrateException
|
||||
* @expectedExceptionMessage The input should be an array
|
||||
*/
|
||||
public function testStringInput() {
|
||||
$this->plugin = new LanguageTypes([], 'map', []);
|
||||
$this->plugin->transform('foo', $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
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\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Processes a link path into an 'internal:' or 'entity:' URI.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "link_uri"
|
||||
* )
|
||||
*/
|
||||
class LinkUri extends ProcessPluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The entity type manager, used to fetch entity link templates.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* Constructs a LinkUri object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager, used to fetch entity link templates.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity_type.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($path) = $value;
|
||||
$path = ltrim($path, '/');
|
||||
|
||||
if (parse_url($path, PHP_URL_SCHEME) === NULL) {
|
||||
$path = 'internal:/' . $path;
|
||||
|
||||
// Convert entity URIs to the entity scheme, if the path matches a route
|
||||
// of the form "entity.$entity_type_id.canonical".
|
||||
// @see \Drupal\Core\Url::fromEntityUri()
|
||||
$url = Url::fromUri($path);
|
||||
if ($url->isRouted()) {
|
||||
$route_name = $url->getRouteName();
|
||||
foreach (array_keys($this->entityTypeManager->getDefinitions()) as $entity_type_id) {
|
||||
if ($route_name == "entity.$entity_type_id.canonical" && isset($url->getRouteParameters()[$entity_type_id])) {
|
||||
return "entity:$entity_type_id/" . $url->getRouteParameters()[$entity_type_id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,83 +2,12 @@
|
|||
|
||||
namespace Drupal\menu_link_content\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use \Drupal\menu_link_content\Plugin\migrate\process\LinkUri as RealLinkUri;
|
||||
|
||||
/**
|
||||
* Processes a link path into an 'internal:' or 'entity:' URI.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "link_uri"
|
||||
* )
|
||||
* @deprecated in Drupal 8.2.0, will be removed before Drupal 9.0.0. Use
|
||||
* \Drupal\menu_link_content\Plugin\migrate\process\LinkUri instead.
|
||||
*/
|
||||
class LinkUri extends ProcessPluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The entity type manager, used to fetch entity link templates.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* Constructs a LinkUri object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager, used to fetch entity link templates.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity_type.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($path) = $value;
|
||||
$path = ltrim($path, '/');
|
||||
|
||||
if (parse_url($path, PHP_URL_SCHEME) === NULL) {
|
||||
$path = 'internal:/' . $path;
|
||||
|
||||
// Convert entity URIs to the entity scheme, if the path matches a route
|
||||
// of the form "entity.$entity_type_id.canonical".
|
||||
// @see \Drupal\Core\Url::fromEntityUri()
|
||||
$url = Url::fromUri($path);
|
||||
if ($url->isRouted()) {
|
||||
$route_name = $url->getRouteName();
|
||||
foreach (array_keys($this->entityTypeManager->getDefinitions()) as $entity_type_id) {
|
||||
if ($route_name == "entity.$entity_type_id.canonical" && isset($url->getRouteParameters()[$entity_type_id])) {
|
||||
return "entity:$entity_type_id/" . $url->getRouteParameters()[$entity_type_id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
}
|
||||
class LinkUri extends RealLinkUri {}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\menu_link_content\Unit\Plugin\migrate\process\d6;
|
||||
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\d6\LinkUri;
|
||||
use Drupal\menu_link_content\Plugin\migrate\process\LinkUri;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
|
@ -12,11 +12,11 @@ use Drupal\Core\Entity\EntityTypeManagerInterface;
|
|||
use Drupal\Core\Path\PathValidator;
|
||||
|
||||
/**
|
||||
* Tests \Drupal\menu_link_content\Plugin\migrate\process\d6\LinkUri.
|
||||
* Tests \Drupal\menu_link_content\Plugin\migrate\process\LinkUri.
|
||||
*
|
||||
* @group menu_link_content
|
||||
*
|
||||
* @coversDefaultClass \Drupal\menu_link_content\Plugin\migrate\process\d6\LinkUri
|
||||
* @coversDefaultClass \Drupal\menu_link_content\Plugin\migrate\process\LinkUri
|
||||
*/
|
||||
class LinkUriTest extends UnitTestCase {
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ class LinkUriTest extends UnitTestCase {
|
|||
/**
|
||||
* The 'link_uri' process plugin being tested.
|
||||
*
|
||||
* @var \Drupal\menu_link_content\Plugin\migrate\process\d6\LinkUri
|
||||
* @var \Drupal\menu_link_content\Plugin\migrate\process\LinkUri
|
||||
*/
|
||||
protected $processPlugin;
|
||||
|
||||
|
|
@ -23,15 +23,18 @@ use Drupal\migrate\Row;
|
|||
* means to load data into storage, while traditionally Drupal uses "load" to
|
||||
* mean load data from storage into memory.
|
||||
*
|
||||
* Source, process, and destination phases are each provided by plugins.
|
||||
* Source plugins extract data from a data source in "rows", containing
|
||||
* "properties". Each row is handed off to one or more process plugins which
|
||||
* transform the row's properties. After all the properties are processed, the
|
||||
* resulting row is handed off to a destination plugin, which saves the data.
|
||||
* In the source phase, a set of data, called the row, is retrieved from the
|
||||
* data source, typically a database but it can be a CSV, JSON or XML file. The
|
||||
* row is sent to the process phase where it is transformed as needed by the
|
||||
* destination, or marked to be skipped. Processing can also determine that a
|
||||
* stub needs to be created, for example, if a term has a parent term that does
|
||||
* not yet exist. After processing the transformed row is passed to the
|
||||
* destination phase where it is loaded (saved) into the Drupal 8 site.
|
||||
*
|
||||
* A source plugin, one or more process plugins, and a destination plugin are
|
||||
* brought together to extract, transform, and load (in the ETL sense) a specific
|
||||
* type of data by a migration plugin.
|
||||
* The ETL process is configured by the migration plugin. The different phases:
|
||||
* source, process, and destination are also plugins, and are managed by the
|
||||
* Migration plugin. So there are four types of plugins in the migration
|
||||
* process: migration, source, process and destination.
|
||||
*
|
||||
* @section sec_migrations Migration plugins
|
||||
* Migration plugin definitions are stored in a module's 'migrations' directory.
|
||||
|
|
@ -50,8 +53,8 @@ use Drupal\migrate\Row;
|
|||
* with \Drupal\migrate\Annotation\MigrateSource annotation, and must be in
|
||||
* namespace subdirectory Plugin\migrate\source under the namespace of the
|
||||
* module that defines them. Migration source plugins are managed by the
|
||||
* \Drupal\migrate\Plugin\MigratePluginManager class. Source plugin providers
|
||||
* are determined by their and their parents namespaces.
|
||||
* \Drupal\migrate\Plugin\MigrateSourcePluginManager class. Source plugin
|
||||
* providers are determined by their and their parents namespaces.
|
||||
*
|
||||
* @section sec_process Process plugins
|
||||
* Migration process plugins implement
|
||||
|
|
@ -107,6 +110,29 @@ function hook_migrate_prepare_row(Row $row, MigrateSourceInterface $source, Migr
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows altering the list of discovered migration plugins.
|
||||
*
|
||||
* Modules are able to alter specific migrations structures or even remove or
|
||||
* append additional migrations to the discovery. For example, this
|
||||
* implementation filters out Drupal 6 migrations from the discovered migration
|
||||
* list. This is done by checking the migration tags.
|
||||
*
|
||||
* @param array[] $migrations
|
||||
* An associative array of migrations keyed by migration ID. Each value is the
|
||||
* migration array, obtained by decoding the migration YAML file and enriched
|
||||
* with some meta information added during discovery phase, like migration
|
||||
* 'class', 'provider' or '_discovered_file_path'.
|
||||
*
|
||||
* @ingroup migration
|
||||
*/
|
||||
function hook_migration_plugins_alter(array &$migrations) {
|
||||
$migrations = array_filter($migrations, function (array $migration) {
|
||||
$tags = isset($migration['migration_tags']) ? (array) $migration['migration_tags'] : [];
|
||||
return !in_array('Drupal 6', $tags);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup hooks".
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
$value = NULL;
|
||||
break;
|
||||
}
|
||||
$multiple = $multiple || $plugin->multiple();
|
||||
$multiple = $plugin->multiple();
|
||||
}
|
||||
}
|
||||
// No plugins or no value means do not set.
|
||||
|
|
|
|||
|
|
@ -83,11 +83,8 @@ interface MigrateDestinationInterface extends PluginInspectionInterface {
|
|||
* Derived classes must implement fields(), returning a list of available
|
||||
* destination fields.
|
||||
*
|
||||
* @todo Review the cases where we need the Migration parameter, can we avoid
|
||||
* that? To be resolved with https://www.drupal.org/node/2543568.
|
||||
*
|
||||
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
|
||||
* (optional) The migration containing this destination. Defaults to NULL.
|
||||
* Unused, will be removed before Drupal 9.0.x. Defaults to NULL.
|
||||
*
|
||||
* @return array
|
||||
* - Keys: machine names of the fields
|
||||
|
|
|
|||
|
|
@ -20,13 +20,6 @@ use Drupal\migrate\Plugin\Discovery\ProviderFilterDecorator;
|
|||
*/
|
||||
class MigrateSourcePluginManager extends MigratePluginManager {
|
||||
|
||||
/**
|
||||
* The class loader.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $classLoader;
|
||||
|
||||
/**
|
||||
* MigrateSourcePluginManager constructor.
|
||||
*
|
||||
|
|
|
|||
107
core/modules/migrate/src/Plugin/migrate/process/ArrayBuild.php
Normal file
107
core/modules/migrate/src/Plugin/migrate/process/ArrayBuild.php
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Builds an array based on the key and value configuration.
|
||||
*
|
||||
* The array_build plugin builds a single associative array by extracting keys
|
||||
* and values from each array in the input value, which is expected to be an
|
||||
* array of arrays. The keys of the returned array will be determined by the
|
||||
* 'key' configuration option, and the values will be determined by the 'value'
|
||||
* option.
|
||||
*
|
||||
* Available configuration keys
|
||||
* - key: The key used to lookup a value in the source arrays to be used as
|
||||
* a key in the destination array.
|
||||
* - value: The key used to lookup a value in the source arrays to be used as
|
||||
* a value in the destination array.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Consider the migration of language negotiation by domain.
|
||||
* The source is an array of all the languages:
|
||||
*
|
||||
* @code
|
||||
* languages: Array
|
||||
* (
|
||||
* [0] => Array
|
||||
* (
|
||||
* [language] => en
|
||||
* ...
|
||||
* [domain] => http://example.com
|
||||
* )
|
||||
* [1] => Array
|
||||
* (
|
||||
* [language] => fr
|
||||
* ...
|
||||
* [domain] => http://fr.example.com
|
||||
* )
|
||||
* ...
|
||||
* @endcode
|
||||
*
|
||||
* The destination should be an array of all the domains keyed by their
|
||||
* language code:
|
||||
*
|
||||
* @code
|
||||
* domains: Array
|
||||
* (
|
||||
* [en] => http://example.com
|
||||
* [fr] => http://fr.example.com
|
||||
* ...
|
||||
* @endcode
|
||||
*
|
||||
* The array_build process plugin would be used like this:
|
||||
*
|
||||
* @code
|
||||
* process:
|
||||
* domains:
|
||||
* plugin: array_build
|
||||
* key: language
|
||||
* value: domain
|
||||
* source: languages
|
||||
* @endcode
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigrateProcessInterface
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "array_build",
|
||||
* handle_multiples = TRUE
|
||||
* )
|
||||
*/
|
||||
class ArrayBuild extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
$new_value = [];
|
||||
|
||||
foreach ((array) $value as $old_key => $old_value) {
|
||||
// Checks that $old_value is an array.
|
||||
if (!is_array($old_value)) {
|
||||
throw new MigrateException("The input should be an array of arrays");
|
||||
}
|
||||
|
||||
// Checks that the key exists.
|
||||
if (!array_key_exists($this->configuration['key'], $old_value)) {
|
||||
throw new MigrateException("The key '" . $this->configuration['key'] . "' does not exist");
|
||||
}
|
||||
|
||||
// Checks that the value exists.
|
||||
if (!array_key_exists($this->configuration['value'], $old_value)) {
|
||||
throw new MigrateException("The key '" . $this->configuration['value'] . "' does not exist");
|
||||
}
|
||||
|
||||
$new_value[$old_value[$this->configuration['key']]] = $old_value[$this->configuration['value']];
|
||||
}
|
||||
|
||||
return $new_value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -10,6 +10,9 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
/**
|
||||
* Ensures value is not duplicated against an entity field.
|
||||
*
|
||||
* If the 'migrated' configuration value is true, an entity will only be
|
||||
* considered a duplicate if it was migrated by the current migration.
|
||||
*
|
||||
* @link https://www.drupal.org/node/2135325 Online handbook documentation for dedupe_entity process plugin @endlink
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
|
|
@ -25,11 +28,19 @@ class DedupeEntity extends DedupeBase implements ContainerFactoryPluginInterface
|
|||
*/
|
||||
protected $entityQueryFactory;
|
||||
|
||||
/**
|
||||
* The current migration.
|
||||
*
|
||||
* @var \Drupal\migrate\Plugin\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, QueryFactory $entity_query_factory) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->migration = $migration;
|
||||
$this->entityQueryFactory = $entity_query_factory;
|
||||
}
|
||||
|
||||
|
|
@ -51,12 +62,25 @@ class DedupeEntity extends DedupeBase implements ContainerFactoryPluginInterface
|
|||
*/
|
||||
protected function exists($value) {
|
||||
// Plugins are cached so for every run we need a new query object.
|
||||
return $this
|
||||
$query = $this
|
||||
->entityQueryFactory
|
||||
->get($this->configuration['entity_type'], 'AND')
|
||||
->condition($this->configuration['field'], $value)
|
||||
->count()
|
||||
->execute();
|
||||
->condition($this->configuration['field'], $value);
|
||||
if (!empty($this->configuration['migrated'])) {
|
||||
// Check if each entity is in the ID map.
|
||||
$idMap = $this->migration->getIdMap();
|
||||
foreach ($query->execute() as $id) {
|
||||
$dest_id_values[$this->configuration['field']] = $id;
|
||||
if ($idMap->lookupSourceID($dest_id_values)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
// Just check if any such entity exists.
|
||||
return $query->count()->execute();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,13 @@ class Migration extends ProcessPluginBase implements ContainerFactoryPluginInter
|
|||
*/
|
||||
protected $migrationPluginManager;
|
||||
|
||||
/**
|
||||
* The migration to be executed.
|
||||
*
|
||||
* @var \Drupal\migrate\Plugin\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -70,9 +77,7 @@ class Migration extends ProcessPluginBase implements ContainerFactoryPluginInter
|
|||
if (!is_array($migration_ids)) {
|
||||
$migration_ids = array($migration_ids);
|
||||
}
|
||||
$scalar = FALSE;
|
||||
if (!is_array($value)) {
|
||||
$scalar = TRUE;
|
||||
$value = array($value);
|
||||
}
|
||||
$this->skipOnEmpty($value);
|
||||
|
|
@ -145,10 +150,8 @@ class Migration extends ProcessPluginBase implements ContainerFactoryPluginInter
|
|||
}
|
||||
}
|
||||
if ($destination_ids) {
|
||||
if ($scalar) {
|
||||
if (count($destination_ids) == 1) {
|
||||
return reset($destination_ids);
|
||||
}
|
||||
if (count($destination_ids) == 1) {
|
||||
return reset($destination_ids);
|
||||
}
|
||||
else {
|
||||
return $destination_ids;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\Core\Path\PathValidatorInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
|
|
@ -55,7 +55,14 @@ class Route extends ProcessPluginBase implements ContainerFactoryPluginInterface
|
|||
* Set the destination route information based on the source link_path.
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($link_path, $options) = $value;
|
||||
if (is_string($value)) {
|
||||
$link_path = $value;
|
||||
$options = [];
|
||||
}
|
||||
else {
|
||||
list($link_path, $options) = $value;
|
||||
}
|
||||
|
||||
$extracted = $this->pathValidator->getUrlIfValidWithoutAccessCheck($link_path);
|
||||
$route = array();
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue