',
+ ]
+ ],
+ ],
+ ]);
+ $filtered_html_format->save();
+ $editor = Editor::create([
+ 'format' => 'filtered_html',
+ 'editor' => 'ckeditor',
+ ]);
+ $editor->save();
+
+ // Create "CKEditor" text editor plugin instance.
+ $this->ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
+ }
+
+ /**
+ * Tests CKEditor::getJSSettings().
+ */
+ public function testGetJSSettings() {
+ $editor = Editor::load('filtered_html');
+
+ // Default toolbar.
+ $expected_config = $this->getDefaultInternalConfig() + [
+ 'drupalImage_dialogTitleAdd' => 'Insert Image',
+ 'drupalImage_dialogTitleEdit' => 'Edit Image',
+ 'drupalLink_dialogTitleAdd' => 'Add Link',
+ 'drupalLink_dialogTitleEdit' => 'Edit Link',
+ 'allowedContent' => $this->getDefaultAllowedContentConfig(),
+ 'disallowedContent' => $this->getDefaultDisallowedContentConfig(),
+ 'toolbar' => $this->getDefaultToolbarConfig(),
+ 'contentsCss' => $this->getDefaultContentsCssConfig(),
+ 'extraPlugins' => 'drupalimage,drupallink',
+ 'language' => 'en',
+ 'stylesSet' => FALSE,
+ 'drupalExternalPlugins' => [
+ 'drupalimage' => file_url_transform_relative(file_create_url('core/modules/ckeditor/js/plugins/drupalimage/plugin.js')),
+ 'drupallink' => file_url_transform_relative(file_create_url('core/modules/ckeditor/js/plugins/drupallink/plugin.js')),
+ ],
+ ];
+ $expected_config = $this->castSafeStrings($expected_config);
+ ksort($expected_config);
+ ksort($expected_config['allowedContent']);
+ $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for default configuration.');
+
+ // Customize the configuration: add button, have two contextually enabled
+ // buttons, and configure a CKEditor plugin setting.
+ $this->enableModules(['ckeditor_test']);
+ $this->container->get('plugin.manager.editor')->clearCachedDefinitions();
+ $this->ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
+ $this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
+ $settings = $editor->getSettings();
+ $settings['toolbar']['rows'][0][0]['items'][] = 'Strike';
+ $settings['toolbar']['rows'][0][0]['items'][] = 'Format';
+ $editor->setSettings($settings);
+ $editor->save();
+ $expected_config['toolbar'][0]['items'][] = 'Strike';
+ $expected_config['toolbar'][0]['items'][] = 'Format';
+ $expected_config['format_tags'] = 'p;h2;h3;h4;h5;h6';
+ $expected_config['extraPlugins'] .= ',llama_contextual,llama_contextual_and_button';
+ $expected_config['drupalExternalPlugins']['llama_contextual'] = file_url_transform_relative(file_create_url('core/modules/ckeditor/tests/modules/js/llama_contextual.js'));
+ $expected_config['drupalExternalPlugins']['llama_contextual_and_button'] = file_url_transform_relative(file_create_url('core/modules/ckeditor/tests/modules/js/llama_contextual_and_button.js'));
+ $expected_config['contentsCss'][] = file_url_transform_relative(file_create_url('core/modules/ckeditor/tests/modules/ckeditor_test.css'));
+ ksort($expected_config);
+ $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for customized configuration.');
+
+ // Change the allowed HTML tags; the "allowedContent" and "format_tags"
+ // settings for CKEditor should automatically be updated as well.
+ $format = $editor->getFilterFormat();
+ $format->filters('filter_html')->settings['allowed_html'] .= ' ';
+ $format->save();
+
+ $expected_config['allowedContent']['pre'] = ['attributes' => 'class', 'styles' => FALSE, 'classes' => TRUE];
+ $expected_config['allowedContent']['h1'] = ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE];
+ $expected_config['allowedContent']['blockquote'] = ['attributes' => 'class', 'styles' => FALSE, 'classes' => TRUE];
+ $expected_config['allowedContent']['address'] = ['attributes' => 'class', 'styles' => FALSE, 'classes' => 'foo,bar-*'];
+ $expected_config['format_tags'] = 'p;h1;h2;h3;h4;h5;h6;pre';
+ ksort($expected_config['allowedContent']);
+ $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for customized configuration.');
+
+ // Disable the filter_html filter: allow *all *tags.
+ $format->setFilterConfig('filter_html', ['status' => 0]);
+ $format->save();
+
+ $expected_config['allowedContent'] = TRUE;
+ $expected_config['disallowedContent'] = FALSE;
+ $expected_config['format_tags'] = 'p;h1;h2;h3;h4;h5;h6;pre';
+ $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for customized configuration.');
+
+ // Enable the filter_test_restrict_tags_and_attributes filter.
+ $format->setFilterConfig('filter_test_restrict_tags_and_attributes', [
+ 'status' => 1,
+ 'settings' => [
+ 'restrictions' => [
+ 'allowed' => [
+ 'p' => TRUE,
+ 'a' => [
+ 'href' => TRUE,
+ 'rel' => ['nofollow' => TRUE],
+ 'class' => ['external' => TRUE],
+ 'target' => ['_blank' => FALSE],
+ ],
+ 'span' => [
+ 'class' => ['dodo' => FALSE],
+ 'property' => ['dc:*' => TRUE],
+ 'rel' => ['foaf:*' => FALSE],
+ 'style' => ['underline' => FALSE, 'color' => FALSE, 'font-size' => TRUE],
+ ],
+ '*' => [
+ 'style' => FALSE,
+ 'on*' => FALSE,
+ 'class' => ['is-a-hipster-llama' => TRUE, 'and-more' => TRUE],
+ 'data-*' => TRUE,
+ ],
+ 'del' => FALSE,
+ ],
+ ],
+ ],
+ ]);
+ $format->save();
+
+ $expected_config['allowedContent'] = [
+ 'p' => [
+ 'attributes' => TRUE,
+ 'styles' => FALSE,
+ 'classes' => 'is-a-hipster-llama,and-more',
+ ],
+ 'a' => [
+ 'attributes' => 'href,rel,class,target',
+ 'styles' => FALSE,
+ 'classes' => 'external',
+ ],
+ 'span' => [
+ 'attributes' => 'class,property,rel,style',
+ 'styles' => 'font-size',
+ 'classes' => FALSE,
+ ],
+ '*' => [
+ 'attributes' => 'class,data-*',
+ 'styles' => FALSE,
+ 'classes' => 'is-a-hipster-llama,and-more',
+ ],
+ 'del' => [
+ 'attributes' => FALSE,
+ 'styles' => FALSE,
+ 'classes' => FALSE,
+ ],
+ ];
+ $expected_config['disallowedContent'] = [
+ 'span' => [
+ 'styles' => 'underline,color',
+ 'classes' => 'dodo',
+ ],
+ '*' => [
+ 'attributes' => 'on*',
+ ],
+ ];
+ $expected_config['format_tags'] = 'p';
+ ksort($expected_config);
+ ksort($expected_config['allowedContent']);
+ ksort($expected_config['disallowedContent']);
+ $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for customized configuration.');
+ }
+
+ /**
+ * Tests CKEditor::buildToolbarJSSetting().
+ */
+ public function testBuildToolbarJSSetting() {
+ $editor = Editor::load('filtered_html');
+
+ // Default toolbar.
+ $expected = $this->getDefaultToolbarConfig();
+ $this->assertIdentical($expected, $this->castSafeStrings($this->ckeditor->buildToolbarJSSetting($editor)), '"toolbar" configuration part of JS settings built correctly for default toolbar.');
+
+ // Customize the configuration.
+ $settings = $editor->getSettings();
+ $settings['toolbar']['rows'][0][0]['items'][] = 'Strike';
+ $editor->setSettings($settings);
+ $editor->save();
+ $expected[0]['items'][] = 'Strike';
+ $this->assertIdentical($expected, $this->castSafeStrings($this->ckeditor->buildToolbarJSSetting($editor)), '"toolbar" configuration part of JS settings built correctly for customized toolbar.');
+
+ // Enable the editor_test module, customize further.
+ $this->enableModules(['ckeditor_test']);
+ $this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
+ // Override the label of a toolbar component.
+ $settings['toolbar']['rows'][0][0]['name'] = 'JunkScience';
+ $settings['toolbar']['rows'][0][0]['items'][] = 'Llama';
+ $editor->setSettings($settings);
+ $editor->save();
+ $expected[0]['name'] = 'JunkScience';
+ $expected[0]['items'][] = 'Llama';
+ $this->assertIdentical($expected, $this->castSafeStrings($this->ckeditor->buildToolbarJSSetting($editor)), '"toolbar" configuration part of JS settings built correctly for customized toolbar with contrib module-provided CKEditor plugin.');
+ }
+
+ /**
+ * Tests CKEditor::buildContentsCssJSSetting().
+ */
+ public function testBuildContentsCssJSSetting() {
+ $editor = Editor::load('filtered_html');
+
+ // Default toolbar.
+ $expected = $this->getDefaultContentsCssConfig();
+ $this->assertIdentical($expected, $this->ckeditor->buildContentsCssJSSetting($editor), '"contentsCss" configuration part of JS settings built correctly for default toolbar.');
+
+ // Enable the editor_test module, which implements hook_ckeditor_css_alter().
+ $this->enableModules(['ckeditor_test']);
+ $expected[] = file_url_transform_relative(file_create_url(drupal_get_path('module', 'ckeditor_test') . '/ckeditor_test.css'));
+ $this->assertIdentical($expected, $this->ckeditor->buildContentsCssJSSetting($editor), '"contentsCss" configuration part of JS settings built correctly while a hook_ckeditor_css_alter() implementation exists.');
+
+ // Enable LlamaCss plugin, which adds an additional CKEditor stylesheet.
+ $this->container->get('plugin.manager.editor')->clearCachedDefinitions();
+ $this->ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
+ $this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
+ $settings = $editor->getSettings();
+ // LlamaCss: automatically enabled by adding its 'LlamaCSS' button.
+ $settings['toolbar']['rows'][0][0]['items'][] = 'LlamaCSS';
+ $editor->setSettings($settings);
+ $editor->save();
+ $expected[] = file_url_transform_relative(file_create_url(drupal_get_path('module', 'ckeditor_test') . '/css/llama.css'));
+ $this->assertIdentical($expected, $this->ckeditor->buildContentsCssJSSetting($editor), '"contentsCss" configuration part of JS settings built correctly while a CKEditorPluginInterface implementation exists.');
+
+ // Enable the Bartik theme, which specifies a CKEditor stylesheet.
+ \Drupal::service('theme_handler')->install(['bartik']);
+ $this->config('system.theme')->set('default', 'bartik')->save();
+ $expected[] = file_url_transform_relative(file_create_url('core/themes/bartik/css/base/elements.css'));
+ $expected[] = file_url_transform_relative(file_create_url('core/themes/bartik/css/components/captions.css'));
+ $expected[] = file_url_transform_relative(file_create_url('core/themes/bartik/css/components/table.css'));
+ $expected[] = file_url_transform_relative(file_create_url('core/themes/bartik/css/components/text-formatted.css'));
+ $this->assertIdentical($expected, $this->ckeditor->buildContentsCssJSSetting($editor), '"contentsCss" configuration part of JS settings built correctly while a theme providing a CKEditor stylesheet exists.');
+ }
+
+ /**
+ * Tests Internal::getConfig().
+ */
+ public function testInternalGetConfig() {
+ $editor = Editor::load('filtered_html');
+ $internal_plugin = $this->container->get('plugin.manager.ckeditor.plugin')->createInstance('internal');
+
+ // Default toolbar.
+ $expected = $this->getDefaultInternalConfig();
+ $expected['disallowedContent'] = $this->getDefaultDisallowedContentConfig();
+ $expected['allowedContent'] = $this->getDefaultAllowedContentConfig();
+ $this->assertEqual($expected, $internal_plugin->getConfig($editor), '"Internal" plugin configuration built correctly for default toolbar.');
+
+ // Format dropdown/button enabled: new setting should be present.
+ $settings = $editor->getSettings();
+ $settings['toolbar']['rows'][0][0]['items'][] = 'Format';
+ $editor->setSettings($settings);
+ $expected['format_tags'] = 'p;h2;h3;h4;h5;h6';
+ $this->assertEqual($expected, $internal_plugin->getConfig($editor), '"Internal" plugin configuration built correctly for customized toolbar.');
+ }
+
+ /**
+ * Tests StylesCombo::getConfig().
+ */
+ public function testStylesComboGetConfig() {
+ $editor = Editor::load('filtered_html');
+ $stylescombo_plugin = $this->container->get('plugin.manager.ckeditor.plugin')->createInstance('stylescombo');
+
+ // Styles dropdown/button enabled: new setting should be present.
+ $settings = $editor->getSettings();
+ $settings['toolbar']['rows'][0][0]['items'][] = 'Styles';
+ $settings['plugins']['stylescombo']['styles'] = '';
+ $editor->setSettings($settings);
+ $editor->save();
+ $expected['stylesSet'] = [];
+ $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
+
+ // Configure the optional "styles" setting in odd ways that shouldn't affect
+ // the end result.
+ $settings['plugins']['stylescombo']['styles'] = " \n";
+ $editor->setSettings($settings);
+ $editor->save();
+ $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor));
+ $settings['plugins']['stylescombo']['styles'] = "\r\n \n \r \n ";
+ $editor->setSettings($settings);
+ $editor->save();
+ $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
+
+ // Now configure it properly, the end result should change.
+ $settings['plugins']['stylescombo']['styles'] = "h1.title|Title\np.mAgical.Callout|Callout";
+ $editor->setSettings($settings);
+ $editor->save();
+ $expected['stylesSet'] = [
+ ['name' => 'Title', 'element' => 'h1', 'attributes' => ['class' => 'title']],
+ ['name' => 'Callout', 'element' => 'p', 'attributes' => ['class' => 'mAgical Callout']],
+ ];
+ $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
+
+ // Same configuration, but now interspersed with nonsense. Should yield the
+ // same result.
+ $settings['plugins']['stylescombo']['styles'] = " h1 .title | Title \r \n\r \np.mAgical .Callout|Callout\r";
+ $editor->setSettings($settings);
+ $editor->save();
+ $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
+
+ // Slightly different configuration: class names are optional.
+ $settings['plugins']['stylescombo']['styles'] = " h1 | Title ";
+ $editor->setSettings($settings);
+ $editor->save();
+ $expected['stylesSet'] = [['name' => 'Title', 'element' => 'h1']];
+ $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
+
+ // Invalid syntax should cause stylesSet to be set to FALSE.
+ $settings['plugins']['stylescombo']['styles'] = "h1";
+ $editor->setSettings($settings);
+ $editor->save();
+ $expected['stylesSet'] = FALSE;
+ $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
+ }
+
+ /**
+ * Tests language list availability in CKEditor.
+ */
+ public function testLanguages() {
+ // Get CKEditor supported language codes and spot-check.
+ $this->enableModules(['language']);
+ $this->installConfig(['language']);
+ $langcodes = $this->ckeditor->getLangcodes();
+
+ // Language codes transformed with browser mappings.
+ $this->assertTrue($langcodes['pt-pt'] == 'pt', '"pt" properly resolved');
+ $this->assertTrue($langcodes['zh-hans'] == 'zh-cn', '"zh-hans" properly resolved');
+
+ // Language code both in Drupal and CKEditor.
+ $this->assertTrue($langcodes['gl'] == 'gl', '"gl" properly resolved');
+
+ // Language codes only in CKEditor.
+ $this->assertTrue($langcodes['en-au'] == 'en-au', '"en-au" properly resolved');
+ $this->assertTrue($langcodes['sr-latn'] == 'sr-latn', '"sr-latn" properly resolved');
+
+ // No locale module, so even though languages are enabled, CKEditor should
+ // still be in English.
+ $this->assertCKEditorLanguage('en');
+ }
+
+ /**
+ * Tests that CKEditor plugins participate in JS translation.
+ */
+ public function testJSTranslation() {
+ $this->enableModules(['language', 'locale']);
+ $this->installSchema('locale', 'locales_source');
+ $this->installSchema('locale', 'locales_location');
+ $this->installSchema('locale', 'locales_target');
+ $editor = Editor::load('filtered_html');
+ $this->ckeditor->getJSSettings($editor);
+ $localeStorage = $this->container->get('locale.storage');
+ $string = $localeStorage->findString(['source' => 'Edit Link', 'context' => '']);
+ $this->assertTrue(!empty($string), 'String from JavaScript file saved.');
+
+ // With locale module, CKEditor should not adhere to the language selected.
+ $this->assertCKEditorLanguage();
+ }
+
+ /**
+ * Assert that CKEditor picks the expected language when French is default.
+ *
+ * @param string $langcode
+ * Language code to assert for. Defaults to French. That is the default
+ * language set in this assertion.
+ */
+ protected function assertCKEditorLanguage($langcode = 'fr') {
+ // Set French as the site default language.
+ ConfigurableLanguage::createFromLangcode('fr')->save();
+ $this->config('system.site')->set('default_langcode', 'fr')->save();
+
+ // Reset the language manager so new negotiations attempts will fall back on
+ // French. Reinject the language manager CKEditor to use the current one.
+ $this->container->get('language_manager')->reset();
+ $this->ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
+
+ // Test that we now get the expected language.
+ $editor = Editor::load('filtered_html');
+ $settings = $this->ckeditor->getJSSettings($editor);
+ $this->assertEqual($settings['language'], $langcode);
+ }
+
+ protected function getDefaultInternalConfig() {
+ return [
+ 'customConfig' => '',
+ 'pasteFromWordPromptCleanup' => TRUE,
+ 'resize_dir' => 'vertical',
+ 'justifyClasses' => ['text-align-left', 'text-align-center', 'text-align-right', 'text-align-justify'],
+ 'entities' => FALSE,
+ 'disableNativeSpellChecker' => FALSE,
+ ];
+ }
+
+ protected function getDefaultAllowedContentConfig() {
+ return [
+ 'h2' => ['attributes' => 'id', 'styles' => FALSE, 'classes' => FALSE],
+ 'h3' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+ 'h4' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+ 'h5' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+ 'h6' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+ 'p' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+ 'br' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+ 'strong' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+ 'a' => ['attributes' => 'href,hreflang', 'styles' => FALSE, 'classes' => FALSE],
+ '*' => ['attributes' => 'lang,dir', 'styles' => FALSE, 'classes' => FALSE],
+ ];
+ }
+
+ protected function getDefaultDisallowedContentConfig() {
+ return [
+ '*' => ['attributes' => 'on*'],
+ ];
+ }
+
+ protected function getDefaultToolbarConfig() {
+ return [
+ [
+ 'name' => 'Formatting',
+ 'items' => ['Bold', 'Italic'],
+ ],
+ [
+ 'name' => 'Links',
+ 'items' => ['DrupalLink', 'DrupalUnlink'],
+ ],
+ [
+ 'name' => 'Lists',
+ 'items' => ['BulletedList', 'NumberedList'],
+ ],
+ [
+ 'name' => 'Media',
+ 'items' => ['Blockquote', 'DrupalImage'],
+ ],
+ [
+ 'name' => 'Tools',
+ 'items' => ['Source'],
+ ],
+ '/',
+ ];
+ }
+
+ protected function getDefaultContentsCssConfig() {
+ return [
+ file_url_transform_relative(file_create_url('core/modules/ckeditor/css/ckeditor-iframe.css')),
+ file_url_transform_relative(file_create_url('core/modules/system/css/components/align.module.css')),
+ ];
+ }
+
+}
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/src/CommentStorage.php
--- a/core/modules/comment/src/CommentStorage.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/src/CommentStorage.php Fri Feb 23 15:52:07 2018 +0000
@@ -324,7 +324,7 @@
* {@inheritdoc}
*/
public function getUnapprovedCount() {
- return $this->database->select('comment_field_data', 'c')
+ return $this->database->select('comment_field_data', 'c')
->condition('status', CommentInterface::NOT_PUBLISHED, '=')
->condition('default_langcode', 1)
->countQuery()
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/src/Controller/CommentController.php
--- a/core/modules/comment/src/Controller/CommentController.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/src/Controller/CommentController.php Fri Feb 23 15:52:07 2018 +0000
@@ -279,9 +279,12 @@
// Check if the user has the proper permissions.
$access = AccessResult::allowedIfHasPermission($account, 'post comments');
+ // If commenting is open on the entity.
$status = $entity->{$field_name}->status;
$access = $access->andIf(AccessResult::allowedIf($status == CommentItemInterface::OPEN)
- ->addCacheableDependency($entity));
+ ->addCacheableDependency($entity))
+ // And if user has access to the host entity.
+ ->andIf(AccessResult::allowedIf($entity->access('view')));
// $pid indicates that this is a reply to a comment.
if ($pid) {
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/src/Entity/Comment.php
--- a/core/modules/comment/src/Entity/Comment.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/src/Entity/Comment.php Fri Feb 23 15:52:07 2018 +0000
@@ -73,6 +73,8 @@
/**
* The thread for which a lock was acquired.
+ *
+ * @var string
*/
protected $threadLock = '';
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php
--- a/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php Fri Feb 23 15:52:07 2018 +0000
@@ -78,7 +78,7 @@
protected $entityFormBuilder;
/**
- * @param \Drupal\Core\Routing\RouteMatchInterface $routeMatch
+ * @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/src/Plugin/migrate/destination/EntityComment.php
--- a/core/modules/comment/src/Plugin/migrate/destination/EntityComment.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/src/Plugin/migrate/destination/EntityComment.php Fri Feb 23 15:52:07 2018 +0000
@@ -41,9 +41,9 @@
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
- * @param MigrationInterface $migration
+ * @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The migration.
- * @param EntityStorageInterface $storage
+ * @param \Drupal\Core\Entity\EntityStorageInterface $storage
* The storage for this entity type.
* @param array $bundles
* The list of bundles this entity type has.
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/src/Plugin/migrate/source/d6/CommentVariable.php
--- a/core/modules/comment/src/Plugin/migrate/source/d6/CommentVariable.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/src/Plugin/migrate/source/d6/CommentVariable.php Fri Feb 23 15:52:07 2018 +0000
@@ -30,7 +30,7 @@
/**
* {@inheritdoc}
*/
- public function count() {
+ public function count($refresh = FALSE) {
return count($this->getCommentVariables());
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/src/Plugin/views/sort/Thread.php
--- a/core/modules/comment/src/Plugin/views/sort/Thread.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/src/Plugin/views/sort/Thread.php Fri Feb 23 15:52:07 2018 +0000
@@ -16,8 +16,8 @@
public function query() {
$this->ensureMyTable();
- // Read comment_render() in comment.module for an explanation of the
- // thinking behind this sort.
+ // See \Drupal\comment\CommentStorage::loadThread() for an explanation of
+ // the thinking behind this sort.
if ($this->options['order'] == 'DESC') {
$this->query->addOrderBy($this->tableAlias, $this->realField, $this->options['order']);
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/src/Plugin/views/wizard/Comment.php
--- a/core/modules/comment/src/Plugin/views/wizard/Comment.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/src/Plugin/views/wizard/Comment.php Fri Feb 23 15:52:07 2018 +0000
@@ -21,6 +21,8 @@
/**
* Set the created column.
+ *
+ * @var string
*/
protected $createdColumn = 'created';
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/tests/src/Functional/CommentAccessTest.php
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/comment/tests/src/Functional/CommentAccessTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -0,0 +1,120 @@
+ 'article',
+ 'name' => 'Article',
+ ]);
+ $node_type->save();
+ $node_author = $this->drupalCreateUser([
+ 'create article content',
+ 'access comments',
+ ]);
+
+ $this->drupalLogin($this->drupalCreateUser([
+ 'edit own comments',
+ 'skip comment approval',
+ 'post comments',
+ 'access comments',
+ 'access content',
+ ]));
+
+ $this->addDefaultCommentField('node', 'article');
+ $this->unpublishedNode = $this->createNode([
+ 'title' => 'This is unpublished',
+ 'uid' => $node_author->id(),
+ 'status' => 0,
+ 'type' => 'article',
+ ]);
+ $this->unpublishedNode->save();
+ }
+
+ /**
+ * Tests commenting disabled for access-blocked entities.
+ */
+ public function testCannotCommentOnEntitiesYouCannotView() {
+ $assert = $this->assertSession();
+
+ $comment_url = 'comment/reply/node/' . $this->unpublishedNode->id() . '/comment';
+
+ // Commenting on an unpublished node results in access denied.
+ $this->drupalGet($comment_url);
+ $assert->statusCodeEquals(403);
+
+ // Publishing the node grants access.
+ $this->unpublishedNode->setPublished(TRUE)->save();
+ $this->drupalGet($comment_url);
+ $assert->statusCodeEquals(200);
+ }
+
+ /**
+ * Tests cannot view comment reply form on entities you cannot view.
+ */
+ public function testCannotViewCommentReplyFormOnEntitiesYouCannotView() {
+ $assert = $this->assertSession();
+
+ // Create a comment on an unpublished node.
+ $comment = Comment::create([
+ 'entity_type' => 'node',
+ 'name' => 'Tony',
+ 'hostname' => 'magic.example.com',
+ 'mail' => 'foo@example.com',
+ 'subject' => 'Comment on unpublished node',
+ 'entity_id' => $this->unpublishedNode->id(),
+ 'comment_type' => 'comment',
+ 'field_name' => 'comment',
+ 'pid' => 0,
+ 'uid' => $this->unpublishedNode->getOwnerId(),
+ 'status' => 1,
+ ]);
+ $comment->save();
+
+ $comment_url = 'comment/reply/node/' . $this->unpublishedNode->id() . '/comment/' . $comment->id();
+
+ // Replying to a comment on an unpublished node results in access denied.
+ $this->drupalGet($comment_url);
+ $assert->statusCodeEquals(403);
+
+ // Publishing the node grants access.
+ $this->unpublishedNode->setPublished(TRUE)->save();
+ $this->drupalGet($comment_url);
+ $assert->statusCodeEquals(200);
+ }
+
+}
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/tests/src/Functional/CommentNonNodeTest.php
--- a/core/modules/comment/tests/src/Functional/CommentNonNodeTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/tests/src/Functional/CommentNonNodeTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -450,6 +450,7 @@
'post comments',
'administer comment fields',
'administer comment types',
+ 'view test entity',
]);
$this->drupalLogin($limited_user);
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/tests/src/Functional/CommentThreadingTest.php
--- a/core/modules/comment/tests/src/Functional/CommentThreadingTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/tests/src/Functional/CommentThreadingTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -54,7 +54,6 @@
// Confirm that there is a link to the parent comment.
$this->assertParentLink($comment1_3->id(), $comment1->id());
-
// Reply to comment #1_3 creating comment #1_3_4.
$this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment/' . $comment1_3->id());
$comment1_3_4 = $this->postComment(NULL, $this->randomMachineName(), $this->randomMachineName(), TRUE);
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/tests/src/Functional/CommentTokenReplaceTest.php
--- a/core/modules/comment/tests/src/Functional/CommentTokenReplaceTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/tests/src/Functional/CommentTokenReplaceTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -144,6 +144,7 @@
// Create a user and a comment.
$user = User::create(['name' => 'alice']);
+ $user->activate();
$user->save();
$this->postComment($user, 'user body', 'user subject', TRUE);
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/tests/src/Kernel/CommentItemTest.php
--- a/core/modules/comment/tests/src/Kernel/CommentItemTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/tests/src/Kernel/CommentItemTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -71,6 +71,9 @@
public function testCommentAuthorName() {
$this->installEntitySchema('comment');
+ $host = EntityTest::create(['name' => $this->randomString()]);
+ $host->save();
+
// Create some comments.
$comment = Comment::create([
'subject' => 'My comment title',
@@ -78,6 +81,7 @@
'name' => 'entity-test',
'mail' => 'entity@localhost',
'entity_type' => 'entity_test',
+ 'entity_id' => $host->id(),
'comment_type' => 'entity_test',
'status' => 1,
]);
@@ -95,6 +99,7 @@
'mail' => 'test@example.com',
'homepage' => 'https://example.com',
'entity_type' => 'entity_test',
+ 'entity_id' => $host->id(),
'comment_type' => 'entity_test',
'status' => 1,
]);
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/tests/src/Kernel/Views/CommentLinksTest.php
--- a/core/modules/comment/tests/src/Kernel/Views/CommentLinksTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/tests/src/Kernel/Views/CommentLinksTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -19,6 +19,13 @@
class CommentLinksTest extends CommentViewsKernelTestBase {
/**
+ * Modules to enable.
+ *
+ * @var array
+ */
+ public static $modules = ['entity_test'];
+
+ /**
* Views used by this test.
*
* @var array
@@ -26,14 +33,26 @@
public static $testViews = ['test_comment'];
/**
+ * {@inheritdoc}
+ */
+ protected function setUp($import_test_views = TRUE) {
+ parent::setUp($import_test_views);
+
+ $this->installEntitySchema('entity_test');
+ }
+
+ /**
* Test the comment approve link.
*/
public function testLinkApprove() {
+ $host = EntityTest::create(['name' => $this->randomString()]);
+ $host->save();
// Create an unapproved comment.
$comment = $this->commentStorage->create([
'uid' => $this->adminUser->id(),
'entity_type' => 'entity_test',
+ 'entity_id' => $host->id(),
'comment_type' => 'entity_test',
'status' => 0,
]);
@@ -91,8 +110,7 @@
* Test the comment reply link.
*/
public function testLinkReply() {
- $this->enableModules(['field', 'entity_test']);
- $this->installEntitySchema('entity_test');
+ $this->enableModules(['field']);
$this->installSchema('comment', ['comment_entity_statistics']);
$this->installConfig(['field']);
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/tests/src/Kernel/Views/CommentUserNameTest.php
--- a/core/modules/comment/tests/src/Kernel/Views/CommentUserNameTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/tests/src/Kernel/Views/CommentUserNameTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -4,6 +4,7 @@
use Drupal\comment\Entity\Comment;
use Drupal\Core\Session\AnonymousUserSession;
+use Drupal\entity_test\Entity\EntityTest;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
@@ -36,6 +37,7 @@
$this->installEntitySchema('user');
$this->installEntitySchema('comment');
+ $this->installEntitySchema('entity_test');
// Create the anonymous role.
$this->installConfig(['user']);
@@ -67,12 +69,16 @@
]);
$this->adminUser->save();
+ $host = EntityTest::create(['name' => $this->randomString()]);
+ $host->save();
+
// Create some comments.
$comment = Comment::create([
'subject' => 'My comment title',
'uid' => $this->adminUser->id(),
'name' => $this->adminUser->label(),
'entity_type' => 'entity_test',
+ 'entity_id' => $host->id(),
'comment_type' => 'entity_test',
'status' => 1,
]);
@@ -85,6 +91,7 @@
'mail' => 'test@example.com',
'homepage' => 'https://example.com',
'entity_type' => 'entity_test',
+ 'entity_id' => $host->id(),
'comment_type' => 'entity_test',
'created' => 123456,
'status' => 1,
diff -r bfffd8d7479a -r 7a779792577d core/modules/comment/tests/src/Kernel/Views/CommentViewsFieldAccessTest.php
--- a/core/modules/comment/tests/src/Kernel/Views/CommentViewsFieldAccessTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/comment/tests/src/Kernel/Views/CommentViewsFieldAccessTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -3,6 +3,7 @@
namespace Drupal\Tests\comment\Kernel\Views;
use Drupal\comment\Entity\Comment;
+use Drupal\entity_test\Entity\EntityTest;
use Drupal\user\Entity\User;
use Drupal\Tests\views\Kernel\Handler\FieldFieldAccessTestBase;
@@ -25,6 +26,7 @@
parent::setUp($import_test_views);
$this->installEntitySchema('comment');
+ $this->installEntitySchema('entity_test');
}
/**
@@ -36,10 +38,14 @@
]);
$user->save();
+ $host = EntityTest::create(['name' => $this->randomString()]);
+ $host->save();
+
$comment = Comment::create([
'subject' => 'My comment title',
'uid' => $user->id(),
'entity_type' => 'entity_test',
+ 'entity_id' => $host->id(),
'comment_type' => 'entity_test',
]);
$comment->save();
@@ -51,6 +57,7 @@
'mail' => 'test@example.com',
'homepage' => 'https://example.com',
'entity_type' => 'entity_test',
+ 'entity_id' => $host->id(),
'comment_type' => 'entity_test',
'created' => 123456,
'status' => 1,
diff -r bfffd8d7479a -r 7a779792577d core/modules/config/config.install
--- a/core/modules/config/config.install Fri Feb 23 15:51:18 2018 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
- t('Configuration directory: %type', ['%type' => CONFIG_SYNC_DIRECTORY]),
- 'description' => t('The directory %directory is not writable.', ['%directory' => $directory]),
- 'severity' => REQUIREMENT_WARNING,
- ];
- }
- return $requirements;
-}
diff -r bfffd8d7479a -r 7a779792577d core/modules/config/src/ConfigSubscriber.php
--- a/core/modules/config/src/ConfigSubscriber.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/config/src/ConfigSubscriber.php Fri Feb 23 15:52:07 2018 +0000
@@ -14,7 +14,7 @@
/**
* Checks that the Configuration module is not being uninstalled.
*
- * @param ConfigImporterEvent $event
+ * @param \Drupal\Core\Config\ConfigImporterEvent $event
* The config import event.
*/
public function onConfigImporterValidate(ConfigImporterEvent $event) {
diff -r bfffd8d7479a -r 7a779792577d core/modules/config/tests/config_test/src/Entity/ConfigTest.php
--- a/core/modules/config/tests/config_test/src/Entity/ConfigTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/config/tests/config_test/src/Entity/ConfigTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -117,9 +117,12 @@
* {@inheritdoc}
*/
public function onDependencyRemoval(array $dependencies) {
- // Record which entities have this method called on.
+ // Record which entities have this method called on and what dependencies
+ // are passed.
$called = \Drupal::state()->get('config_test.on_dependency_removal_called', []);
- $called[] = $this->id();
+ $called[$this->id()] = $dependencies;
+ $called[$this->id()]['config'] = array_keys($called[$this->id()]['config']);
+ $called[$this->id()]['content'] = array_keys($called[$this->id()]['content']);
\Drupal::state()->set('config_test.on_dependency_removal_called', $called);
$changed = parent::onDependencyRemoval($dependencies);
diff -r bfffd8d7479a -r 7a779792577d core/modules/config/tests/src/Functional/ConfigEntityTest.php
--- a/core/modules/config/tests/src/Functional/ConfigEntityTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/config/tests/src/Functional/ConfigEntityTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -35,7 +35,8 @@
public function testCRUD() {
$default_langcode = \Drupal::languageManager()->getDefaultLanguage()->getId();
// Verify default properties on a newly created empty entity.
- $empty = entity_create('config_test');
+ $storage = \Drupal::entityTypeManager()->getStorage('config_test');
+ $empty = $storage->create();
$this->assertTrue($empty->uuid());
$this->assertIdentical($empty->label, NULL);
$this->assertIdentical($empty->style, NULL);
@@ -76,7 +77,7 @@
}
// Verify that an entity with an empty ID string is considered empty, too.
- $empty_id = entity_create('config_test', [
+ $empty_id = $storage->create([
'id' => '',
]);
$this->assertIdentical($empty_id->isNew(), TRUE);
@@ -89,7 +90,7 @@
}
// Verify properties on a newly created entity.
- $config_test = entity_create('config_test', $expected = [
+ $config_test = $storage->create($expected = [
'id' => $this->randomMachineName(),
'label' => $this->randomString(),
'style' => $this->randomMachineName(),
@@ -141,7 +142,7 @@
// maximum allowed length, but not longer.
// Test with a short ID.
- $id_length_config_test = entity_create('config_test', [
+ $id_length_config_test = $storage->create([
'id' => $this->randomMachineName(8),
]);
try {
@@ -155,7 +156,7 @@
}
// Test with an ID of the maximum allowed length.
- $id_length_config_test = entity_create('config_test', [
+ $id_length_config_test = $storage->create([
'id' => $this->randomMachineName(static::MAX_ID_LENGTH),
]);
try {
@@ -169,7 +170,7 @@
}
// Test with an ID exceeding the maximum allowed length.
- $id_length_config_test = entity_create('config_test', [
+ $id_length_config_test = $storage->create([
'id' => $this->randomMachineName(static::MAX_ID_LENGTH + 1),
]);
try {
@@ -188,7 +189,7 @@
// Ensure that creating an entity with the same id as an existing one is not
// possible.
- $same_id = entity_create('config_test', [
+ $same_id = $storage->create([
'id' => $config_test->id(),
]);
$this->assertIdentical($same_id->isNew(), TRUE);
@@ -223,7 +224,7 @@
// Test config entity prepopulation.
\Drupal::state()->set('config_test.prepopulate', TRUE);
- $config_test = entity_create('config_test', ['foo' => 'bar']);
+ $config_test = $storage->create(['foo' => 'bar']);
$this->assertEqual($config_test->get('foo'), 'baz', 'Initial value correctly populated');
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/config/tests/src/Functional/ConfigInstallWebTest.php
--- a/core/modules/config/tests/src/Functional/ConfigInstallWebTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/config/tests/src/Functional/ConfigInstallWebTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -204,11 +204,6 @@
file_unmanaged_delete_recursive($directory);
$this->drupalGet('/admin/reports/status');
$this->assertRaw(t('The directory %directory does not exist.', ['%directory' => $directory]));
-
- file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
- \Drupal::service('file_system')->chmod($directory, 0555);
- $this->drupalGet('/admin/reports/status');
- $this->assertRaw(t('The directory %directory is not writable.', ['%directory' => $directory]));
}
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/config_translation/src/ConfigNamesMapper.php
--- a/core/modules/config_translation/src/ConfigNamesMapper.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/config_translation/src/ConfigNamesMapper.php Fri Feb 23 15:52:07 2018 +0000
@@ -61,7 +61,7 @@
/**
* The base route object that the mapper is attached to.
*
- * @return \Symfony\Component\Routing\Route
+ * @var \Symfony\Component\Routing\Route
*/
protected $baseRoute;
diff -r bfffd8d7479a -r 7a779792577d core/modules/config_translation/src/Controller/ConfigTranslationController.php
--- a/core/modules/config_translation/src/Controller/ConfigTranslationController.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/config_translation/src/Controller/ConfigTranslationController.php Fri Feb 23 15:52:07 2018 +0000
@@ -62,7 +62,7 @@
/**
* The language manager.
*
- * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+ * @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
diff -r bfffd8d7479a -r 7a779792577d core/modules/config_translation/tests/src/Functional/ConfigTranslationOverviewTest.php
--- a/core/modules/config_translation/tests/src/Functional/ConfigTranslationOverviewTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/config_translation/tests/src/Functional/ConfigTranslationOverviewTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -77,7 +77,7 @@
// Make sure there is only a single operation for each dropbutton, either
// 'List' or 'Translate'.
foreach ($this->cssSelect('ul.dropbutton') as $i => $dropbutton) {
- $this->assertIdentical(1, count($dropbutton->find('xpath', 'li')));
+ $this->assertIdentical(1, count($dropbutton->findAll('xpath', 'li')));
$this->assertTrue(($dropbutton->getText() === 'Translate') || ($dropbutton->getText() === 'List'));
}
@@ -87,8 +87,9 @@
$this->randomString(),
];
+ $storage = \Drupal::entityTypeManager()->getStorage('config_test');
foreach ($labels as $label) {
- $test_entity = entity_create('config_test', [
+ $test_entity = $storage->create([
'id' => $this->randomMachineName(),
'label' => $label,
]);
@@ -102,7 +103,7 @@
// Make sure there is only a single 'Translate' operation for each
// dropbutton.
foreach ($this->cssSelect('ul.dropbutton') as $i => $dropbutton) {
- $this->assertIdentical(1, count($dropbutton->find('xpath', 'li')));
+ $this->assertIdentical(1, count($dropbutton->findAll('xpath', 'li')));
$this->assertIdentical('Translate', $dropbutton->getText());
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/content_moderation.permissions.yml
--- a/core/modules/content_moderation/content_moderation.permissions.yml Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_moderation/content_moderation.permissions.yml Fri Feb 23 15:52:07 2018 +0000
@@ -3,7 +3,7 @@
view latest version:
title: 'View the latest version'
- description: 'Requires the "View any unpublished content" permission'
+ description: 'Requires the "View any unpublished content" or "View own unpublished content" permission'
permission_callbacks:
- \Drupal\content_moderation\Permissions::transitionPermissions
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/src/EntityTypeInfo.php
--- a/core/modules/content_moderation/src/EntityTypeInfo.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_moderation/src/EntityTypeInfo.php Fri Feb 23 15:52:07 2018 +0000
@@ -121,7 +121,7 @@
/**
* Adds Moderation configuration to appropriate entity types.
*
- * @param EntityTypeInterface[] $entity_types
+ * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
* The master entity type list to alter.
*
* @see hook_entity_type_alter()
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/src/Form/EntityModerationForm.php
--- a/core/modules/content_moderation/src/Form/EntityModerationForm.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_moderation/src/Form/EntityModerationForm.php Fri Feb 23 15:52:07 2018 +0000
@@ -2,6 +2,7 @@
namespace Drupal\content_moderation\Form;
+use Drupal\Component\Datetime\Time;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\RevisionLogInterface;
use Drupal\Core\Form\FormBase;
@@ -24,6 +25,13 @@
protected $moderationInfo;
/**
+ * The time service.
+ *
+ * @var \Drupal\Component\Datetime\Time
+ */
+ protected $time;
+
+ /**
* The moderation state transition validation service.
*
* @var \Drupal\content_moderation\StateTransitionValidation
@@ -37,9 +45,12 @@
* The moderation information service.
* @param \Drupal\content_moderation\StateTransitionValidation $validation
* The moderation state transition validation service.
+ * @param \Drupal\Component\Datetime\Time $time
+ * The time service.
*/
- public function __construct(ModerationInformationInterface $moderation_info, StateTransitionValidation $validation) {
+ public function __construct(ModerationInformationInterface $moderation_info, StateTransitionValidation $validation, Time $time) {
$this->moderationInfo = $moderation_info;
+ $this->time = $time;
$this->validation = $validation;
}
@@ -49,7 +60,8 @@
public static function create(ContainerInterface $container) {
return new static(
$container->get('content_moderation.moderation_information'),
- $container->get('content_moderation.state_transition_validation')
+ $container->get('content_moderation.state_transition_validation'),
+ $container->get('datetime.time')
);
}
@@ -122,7 +134,7 @@
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
- /** @var ContentEntityInterface $entity */
+ /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity = $form_state->get('entity');
$new_state = $form_state->getValue('new_state');
@@ -130,6 +142,7 @@
$entity->set('moderation_state', $new_state);
if ($entity instanceof RevisionLogInterface) {
+ $entity->setRevisionCreationTime($this->time->getRequestTime());
$entity->setRevisionLogMessage($form_state->getValue('revision_log'));
$entity->setRevisionUserId($this->currentUser()->id());
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/src/ModerationInformation.php
--- a/core/modules/content_moderation/src/ModerationInformation.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_moderation/src/ModerationInformation.php Fri Feb 23 15:52:07 2018 +0000
@@ -84,14 +84,15 @@
*/
public function getLatestRevisionId($entity_type_id, $entity_id) {
if ($storage = $this->entityTypeManager->getStorage($entity_type_id)) {
- $revision_ids = $storage->getQuery()
- ->allRevisions()
+ $result = $storage->getQuery()
+ ->latestRevision()
->condition($this->entityTypeManager->getDefinition($entity_type_id)->getKey('id'), $entity_id)
- ->sort($this->entityTypeManager->getDefinition($entity_type_id)->getKey('revision'), 'DESC')
- ->range(0, 1)
+ // No access check is performed here since this is an API function and
+ // should return the same ID regardless of the current user.
+ ->accessCheck(FALSE)
->execute();
- if ($revision_ids) {
- return array_keys($revision_ids)[0];
+ if ($result) {
+ return key($result);
}
}
}
@@ -101,13 +102,15 @@
*/
public function getDefaultRevisionId($entity_type_id, $entity_id) {
if ($storage = $this->entityTypeManager->getStorage($entity_type_id)) {
- $revision_ids = $storage->getQuery()
+ $result = $storage->getQuery()
+ ->currentRevision()
->condition($this->entityTypeManager->getDefinition($entity_type_id)->getKey('id'), $entity_id)
- ->sort($this->entityTypeManager->getDefinition($entity_type_id)->getKey('revision'), 'DESC')
- ->range(0, 1)
+ // No access check is performed here since this is an API function and
+ // should return the same ID regardless of the current user.
+ ->accessCheck(FALSE)
->execute();
- if ($revision_ids) {
- return array_keys($revision_ids)[0];
+ if ($result) {
+ return key($result);
}
}
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php
--- a/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php Fri Feb 23 15:52:07 2018 +0000
@@ -153,7 +153,7 @@
// Change the entity's default revision flag and the publishing status only
// if the new workflow state is a valid one.
- if ($workflow->getTypePlugin()->hasState($moderation_state_id)) {
+ if ($workflow && $workflow->getTypePlugin()->hasState($moderation_state_id)) {
/** @var \Drupal\content_moderation\ContentModerationState $current_state */
$current_state = $workflow->getTypePlugin()->getState($moderation_state_id);
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php
--- a/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -206,6 +206,7 @@
// Make a pending revision.
$node->title = $this->randomMachineName();
$node->moderation_state->value = 'draft';
+ $node->setRevisionCreationTime(12345);
$node->save();
$another_user = $this->drupalCreateUser($this->permissions);
@@ -217,6 +218,10 @@
$this->drupalGet(sprintf('node/%d/revisions', $node->id()));
$this->assertText('by ' . $another_user->getAccountName());
+
+ // Verify the revision creation time has been updated.
+ $node = $node->load($node->id());
+ $this->assertGreaterThan(12345, $node->getRevisionCreationTime());
}
/**
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/tests/src/Functional/ModerationStateAccessTest.php
--- a/core/modules/content_moderation/tests/src/Functional/ModerationStateAccessTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_moderation/tests/src/Functional/ModerationStateAccessTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -88,11 +88,11 @@
* @param string $machine_name
* The machine name of the type to create.
*
- * @return NodeType
+ * @return \Drupal\node\Entity\NodeType
* The node type just created.
*/
protected function createNodeType($label, $machine_name) {
- /** @var NodeType $node_type */
+ /** @var \Drupal\node\Entity\NodeType $node_type */
$node_type = NodeType::create([
'type' => $machine_name,
'label' => $label,
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/tests/src/Functional/ModerationStateTestBase.php
--- a/core/modules/content_moderation/tests/src/Functional/ModerationStateTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_moderation/tests/src/Functional/ModerationStateTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -13,6 +13,8 @@
/**
* Profile to use.
+ *
+ * @var string
*/
protected $profile = 'testing';
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php
--- a/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -2,6 +2,8 @@
namespace Drupal\Tests\content_moderation\Functional;
+use Drupal\node\Entity\NodeType;
+
/**
* Tests permission access control around nodes.
*
@@ -19,7 +21,7 @@
'block',
'block_content',
'node',
- 'node_access_test_empty',
+ 'node_access_test',
];
/**
@@ -49,6 +51,9 @@
$this->createContentTypeFromUi('Moderated content', 'moderated_content', FALSE);
$this->grantUserPermissionToCreateContentOfType($this->adminUser, 'moderated_content');
+ // Add the private field to the node type.
+ node_access_test_add_field(NodeType::load('moderated_content'));
+
// Rebuild permissions because hook_node_grants() is implemented by the
// node_access_test_empty module.
node_access_rebuild();
@@ -58,6 +63,10 @@
* Verifies that a non-admin user can still access the appropriate pages.
*/
public function testPageAccess() {
+ // Initially disable access grant records in
+ // node_access_test_node_access_records().
+ \Drupal::state()->set('node_access_test.private', TRUE);
+
$this->drupalLogin($this->adminUser);
// Access the node form before moderation is enabled, the publication state
@@ -149,6 +158,30 @@
$this->assertResponse(403);
$this->drupalGet($view_path);
$this->assertResponse(200);
+
+ // Now create a private node that the user is not granted access to by the
+ // node grants, but is granted access via hook_node_access().
+ // @see node_access_test_node_access
+ $node = $this->createNode([
+ 'type' => 'moderated_content',
+ 'private' => TRUE,
+ 'uid' => $this->adminUser->id(),
+ ]);
+ $user = $this->createUser([
+ 'use editorial transition publish',
+ ]);
+ $this->drupalLogin($user);
+
+ // Grant access to the node via node_access_test_node_access().
+ \Drupal::state()->set('node_access_test.allow_uid', $user->id());
+
+ $this->drupalGet($node->toUrl());
+ $this->assertResponse(200);
+
+ // Verify the moderation form is in place by publishing the node.
+ $this->drupalPostForm(NULL, [], t('Apply'));
+ $node = \Drupal::entityTypeManager()->getStorage('node')->loadUnchanged($node->id());
+ $this->assertEquals('published', $node->moderation_state->value);
}
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php
--- a/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -72,59 +72,12 @@
}
/**
- * Sets up a bundle entity type for the specified entity type, if needed.
- *
- * @param string $entity_type_id
- * The entity type identifier.
- *
- * @return string
- * The bundle identifier.
- */
- protected function setupBundleEntityType($entity_type_id) {
- $bundle_id = $entity_type_id;
- $bundle_entity_type_id = $this->entityTypeManager->getDefinition($entity_type_id)->getBundleEntityType();
- if ($bundle_entity_type_id) {
- $bundle_entity_type_definition = $this->entityTypeManager->getDefinition($bundle_entity_type_id);
- $entity_type_storage = $this->entityTypeManager->getStorage($bundle_entity_type_id);
-
- $entity_type = $entity_type_storage->create([
- $bundle_entity_type_definition->getKey('id') => 'example',
- ]);
- if ($entity_type_id == 'media') {
- $entity_type->set('source', 'test');
- $entity_type->save();
- $source_field = $entity_type->getSource()->createSourceField($entity_type);
- $source_field->getFieldStorageDefinition()->save();
- $source_field->save();
- $entity_type->set('source_configuration', [
- 'source_field' => $source_field->getName(),
- ]);
- }
- $entity_type->save();
- $bundle_id = $entity_type->id();
- }
-
- $workflow = Workflow::load('editorial');
- $workflow->getTypePlugin()->addEntityTypeAndBundle($entity_type_id, $bundle_id);
- $workflow->save();
-
- return $bundle_id;
- }
-
- /**
* Tests basic monolingual content moderation through the API.
*
* @dataProvider basicModerationTestCases
*/
public function testBasicModeration($entity_type_id) {
- $bundle_id = $this->setupBundleEntityType($entity_type_id);
-
- /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
- $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
- $entity = $entity_storage->create([
- 'title' => 'Test title',
- $this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
- ]);
+ $entity = $this->createEntity($entity_type_id);
if ($entity instanceof EntityPublishedInterface) {
$entity->setUnpublished();
}
@@ -175,6 +128,7 @@
$entity->save();
// Revert to the previous (published) revision.
+ $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
$previous_revision = $entity_storage->loadRevision(4);
$previous_revision->isDefaultRevision(TRUE);
$previous_revision->setNewRevision(TRUE);
@@ -225,15 +179,9 @@
* @dataProvider basicModerationTestCases
*/
public function testContentModerationStateDataRemoval($entity_type_id) {
- $bundle_id = $this->setupBundleEntityType($entity_type_id);
-
// Test content moderation state deletion.
- $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
- $entity = $entity_storage->create([
- 'title' => 'Test title',
- $this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
- ]);
+ $entity = $this->createEntity($entity_type_id);
$entity->save();
$entity = $this->reloadEntity($entity);
$entity->delete();
@@ -242,10 +190,7 @@
// Test content moderation state revision deletion.
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity2 */
- $entity2 = $entity_storage->create([
- 'title' => 'Test title',
- $this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
- ]);
+ $entity2 = $this->createEntity($entity_type_id);
$entity2->save();
$revision = clone $entity2;
$revision->isDefaultRevision(FALSE);
@@ -254,6 +199,7 @@
$entity2 = $this->reloadEntity($entity2);
$entity2->setNewRevision(TRUE);
$entity2->save();
+ $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
$entity_storage->deleteRevision($revision->getRevisionId());
$content_moderation_state = ContentModerationState::loadFromModeratedEntity($revision);
$this->assertFalse($content_moderation_state);
@@ -263,15 +209,16 @@
// Test content moderation state translation deletion.
if ($this->entityTypeManager->getDefinition($entity_type_id)->isTranslatable()) {
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity3 */
- $entity3 = $entity_storage->create([
- 'title' => 'Test title',
- $this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
- ]);
+ $entity3 = $this->createEntity($entity_type_id);
$langcode = 'it';
ConfigurableLanguage::createFromLangcode($langcode)
->save();
$entity3->save();
$translation = $entity3->addTranslation($langcode, ['title' => 'Titolo test']);
+ // Make sure we add values for all of the required fields.
+ if ($entity_type_id == 'block_content') {
+ $translation->info = $this->randomString();
+ }
$translation->save();
$content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity3);
$this->assertTrue($content_moderation_state->hasTranslation($langcode));
@@ -590,6 +537,63 @@
}
/**
+ * Creates an entity.
+ *
+ * The entity will have required fields populated and the corresponding bundle
+ * will be enabled for content moderation.
+ *
+ * @param string $entity_type_id
+ * The entity type ID.
+ *
+ * @return \Drupal\Core\Entity\ContentEntityInterface
+ * The created entity.
+ */
+ protected function createEntity($entity_type_id) {
+ $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
+
+ $bundle_id = $entity_type_id;
+ // Set up a bundle entity type for the specified entity type, if needed.
+ if ($bundle_entity_type_id = $entity_type->getBundleEntityType()) {
+ $bundle_entity_type = $this->entityTypeManager->getDefinition($bundle_entity_type_id);
+ $bundle_entity_storage = $this->entityTypeManager->getStorage($bundle_entity_type_id);
+
+ $bundle_id = 'example';
+ if (!$bundle_entity_storage->load($bundle_id)) {
+ $bundle_entity = $bundle_entity_storage->create([
+ $bundle_entity_type->getKey('id') => 'example',
+ ]);
+ if ($entity_type_id == 'media') {
+ $bundle_entity->set('source', 'test');
+ $bundle_entity->save();
+ $source_field = $bundle_entity->getSource()->createSourceField($bundle_entity);
+ $source_field->getFieldStorageDefinition()->save();
+ $source_field->save();
+ $bundle_entity->set('source_configuration', [
+ 'source_field' => $source_field->getName(),
+ ]);
+ }
+ $bundle_entity->save();
+ }
+ }
+
+ $workflow = Workflow::load('editorial');
+ $workflow->getTypePlugin()->addEntityTypeAndBundle($entity_type_id, $bundle_id);
+ $workflow->save();
+
+ /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+ $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
+ $entity = $entity_storage->create([
+ $entity_type->getKey('label') => 'Test title',
+ $entity_type->getKey('bundle') => $bundle_id,
+ ]);
+ // Make sure we add values for all of the required fields.
+ if ($entity_type_id == 'block_content') {
+ $entity->info = $this->randomString();
+ }
+ return $entity;
+ }
+
+ /**
* Reloads the entity after clearing the static cache.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/tests/src/Kernel/EntityOperationsTest.php
--- a/core/modules/content_moderation/tests/src/Kernel/EntityOperationsTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_moderation/tests/src/Kernel/EntityOperationsTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -69,7 +69,7 @@
// Verify the entity saved correctly, and that the presence of pending
// revisions doesn't affect the default node load.
- /** @var Node $page */
+ /** @var \Drupal\node\Entity\Node $page */
$page = Node::load($id);
$this->assertEquals('A', $page->getTitle());
$this->assertTrue($page->isDefaultRevision());
@@ -142,7 +142,7 @@
$id = $page->id();
// Verify the entity saved correctly.
- /** @var Node $page */
+ /** @var \Drupal\node\Entity\Node $page */
$page = Node::load($id);
$this->assertEquals('A', $page->getTitle());
$this->assertTrue($page->isDefaultRevision());
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/tests/src/Kernel/ModerationInformationTest.php
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/content_moderation/tests/src/Kernel/ModerationInformationTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -0,0 +1,64 @@
+installEntitySchema('entity_test_rev');
+ $this->installEntitySchema('content_moderation_state');
+ $this->installConfig(['content_moderation']);
+ }
+
+ /**
+ * @covers ::getDefaultRevisionId
+ * @covers ::getLatestRevisionId
+ */
+ public function testDefaultAndLatestRevisionId() {
+ $workflow = Workflow::load('editorial');
+ $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
+ $workflow->save();
+
+ $entity_test_rev = EntityTestRev::create([
+ 'name' => 'Default Revision',
+ 'moderation_state' => 'published',
+ ]);
+ $entity_test_rev->save();
+
+ $entity_test_rev->name = 'Pending revision';
+ $entity_test_rev->moderation_state = 'draft';
+ $entity_test_rev->save();
+
+ /** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */
+ $moderation_info = \Drupal::service('content_moderation.moderation_information');
+
+ // Check that moderation information service returns the correct default
+ // revision ID.
+ $default_revision_id = $moderation_info->getDefaultRevisionId('entity_test_rev', $entity_test_rev->id());
+ $this->assertSame(1, $default_revision_id);
+
+ // Check that moderation information service returns the correct latest
+ // revision ID.
+ $latest_revision_id = $moderation_info->getLatestRevisionId('entity_test_rev', $entity_test_rev->id());
+ $this->assertSame(2, $latest_revision_id);
+ }
+
+}
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/tests/src/Kernel/ModerationStateFieldItemListTest.php
--- a/core/modules/content_moderation/tests/src/Kernel/ModerationStateFieldItemListTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_moderation/tests/src/Kernel/ModerationStateFieldItemListTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -99,4 +99,29 @@
$this->assertFalse($this->testNode->isDefaultRevision());
}
+ /**
+ * Test updating the state for an entity without a workflow.
+ */
+ public function testEntityWithNoWorkflow() {
+ $node_type = NodeType::create([
+ 'type' => 'example_no_workflow',
+ ]);
+ $node_type->save();
+ $test_node = Node::create([
+ 'type' => 'example_no_workflow',
+ 'title' => 'Test node with no workflow',
+ ]);
+ $test_node->save();
+
+ /** @var \Drupal\content_moderation\ModerationInformationInterface $content_moderation_info */
+ $content_moderation_info = \Drupal::service('content_moderation.moderation_information');
+ $workflow = $content_moderation_info->getWorkflowForEntity($test_node);
+ $this->assertNull($workflow);
+
+ $this->assertTrue($test_node->isPublished());
+ $test_node->moderation_state->setValue('draft');
+ // The entity is still published because there is not a workflow.
+ $this->assertTrue($test_node->isPublished());
+ }
+
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/tests/src/Kernel/NodeAccessTest.php
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/content_moderation/tests/src/Kernel/NodeAccessTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -0,0 +1,88 @@
+installEntitySchema('content_moderation_state');
+ $this->installEntitySchema('node');
+ $this->installEntitySchema('user');
+ $this->installEntitySchema('workflow');
+ $this->installConfig(['content_moderation', 'filter']);
+ $this->installSchema('system', ['sequences']);
+ $this->installSchema('node', ['node_access']);
+
+ // Add a moderated node type.
+ $node_type = NodeType::create([
+ 'type' => 'page',
+ 'label' => 'Page',
+ ]);
+ $node_type->save();
+ $workflow = Workflow::load('editorial');
+ $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'page');
+ $workflow->save();
+
+ $this->moderationInformation = \Drupal::service('content_moderation.moderation_information');
+ }
+
+ /**
+ * Tests for moderation information methods with node access.
+ */
+ public function testModerationInformation() {
+ // Create an admin user.
+ $user = $this->createUser([], NULL, TRUE);
+ \Drupal::currentUser()->setAccount($user);
+
+ // Create a node.
+ $node = $this->createNode(['type' => 'page']);
+ $this->assertEquals($node->getRevisionId(), $this->moderationInformation->getDefaultRevisionId('node', $node->id()));
+ $this->assertEquals($node->getRevisionId(), $this->moderationInformation->getLatestRevisionId('node', $node->id()));
+
+ // Create a non-admin user.
+ $user = $this->createUser();
+ \Drupal::currentUser()->setAccount($user);
+ $this->assertEquals($node->getRevisionId(), $this->moderationInformation->getDefaultRevisionId('node', $node->id()));
+ $this->assertEquals($node->getRevisionId(), $this->moderationInformation->getLatestRevisionId('node', $node->id()));
+ }
+
+}
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_moderation/tests/src/Unit/ModerationInformationTest.php
--- a/core/modules/content_moderation/tests/src/Unit/ModerationInformationTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_moderation/tests/src/Unit/ModerationInformationTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -22,7 +22,7 @@
/**
* Builds a mock user.
*
- * @return AccountInterface
+ * @return \Drupal\Core\Session\AccountInterface
* The mocked user.
*/
protected function getUser() {
@@ -32,7 +32,7 @@
/**
* Returns a mock Entity Type Manager.
*
- * @return EntityTypeManagerInterface
+ * @return \Drupal\Core\Entity\EntityTypeManagerInterface
* The mocked entity type manager.
*/
protected function getEntityTypeManager() {
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_translation/migration_templates/d6_taxonomy_term_translation.yml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/content_translation/migration_templates/d6_taxonomy_term_translation.yml Fri Feb 23 15:52:07 2018 +0000
@@ -0,0 +1,39 @@
+id: d6_taxonomy_term_translation
+label: Taxonomy terms
+migration_tags:
+ - Drupal 6
+source:
+ plugin: d6_taxonomy_term
+ translations: true
+process:
+ # If you are using this file to build a custom migration consider removing
+ # the tid field to allow incremental migrations.
+ tid: tid
+ langcode: language
+ vid:
+ plugin: migration
+ migration: d6_taxonomy_vocabulary
+ source: vid
+ name: name
+ description: description
+ weight: weight
+ # Only attempt to stub real (non-zero) parents.
+ parent_id:
+ -
+ plugin: skip_on_empty
+ method: process
+ source: parent
+ -
+ plugin: migration
+ migration: d6_taxonomy_term
+ parent:
+ plugin: default_value
+ default_value: 0
+ source: '@parent_id'
+ changed: timestamp
+destination:
+ plugin: entity:taxonomy_term
+migration_dependencies:
+ required:
+ - d6_taxonomy_vocabulary
+ - d6_taxonomy_term
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_translation/src/ContentTranslationMetadataWrapper.php
--- a/core/modules/content_translation/src/ContentTranslationMetadataWrapper.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/content_translation/src/ContentTranslationMetadataWrapper.php Fri Feb 23 15:52:07 2018 +0000
@@ -27,7 +27,7 @@
/**
* Initializes an instance of the content translation metadata handler.
*
- * @param EntityInterface $translation
+ * @param \Drupal\Core\Entity\EntityInterface $translation
* The entity translation to be wrapped.
* @param ContentTranslationHandlerInterface $handler
* The content translation handler.
diff -r bfffd8d7479a -r 7a779792577d core/modules/content_translation/tests/src/Kernel/Migrate/d6/MigrateTaxonomyTermTranslationTest.php
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/content_translation/tests/src/Kernel/Migrate/d6/MigrateTaxonomyTermTranslationTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -0,0 +1,125 @@
+installEntitySchema('taxonomy_term');
+ $this->installConfig(static::$modules);
+ $this->executeMigrations([
+ 'd6_node_type',
+ 'd6_field',
+ 'd6_taxonomy_vocabulary',
+ 'd6_field_instance',
+ 'd6_taxonomy_term',
+ 'd6_taxonomy_term_translation',
+ ]);
+ }
+
+ /**
+ * Validate a migrated term contains the expected values.
+ *
+ * @param int $id
+ * Entity ID to load and check.
+ * @param string $expected_language
+ * The language code for this term.
+ * @param string $expected_label
+ * The label the migrated entity should have.
+ * @param string $expected_vid
+ * The parent vocabulary the migrated entity should have.
+ * @param string $expected_description
+ * The description the migrated entity should have.
+ * @param string $expected_format
+ * The format the migrated entity should have.
+ * @param int $expected_weight
+ * The weight the migrated entity should have.
+ * @param array $expected_parents
+ * The parent terms the migrated entity should have.
+ * @param int $expected_field_integer_value
+ * The value the migrated entity field should have.
+ * @param int $expected_term_reference_tid
+ * The term reference ID the migrated entity field should have.
+ */
+ protected function assertEntity($id, $expected_language, $expected_label, $expected_vid, $expected_description = '', $expected_format = NULL, $expected_weight = 0, $expected_parents = [], $expected_field_integer_value = NULL, $expected_term_reference_tid = NULL) {
+ /** @var \Drupal\taxonomy\TermInterface $entity */
+ $entity = Term::load($id);
+ $this->assertInstanceOf(TermInterface::class, $entity);
+ $this->assertSame($expected_language, $entity->language()->getId());
+ $this->assertSame($expected_label, $entity->label());
+ $this->assertSame($expected_vid, $entity->getVocabularyId());
+ $this->assertSame($expected_description, $entity->getDescription());
+ $this->assertSame($expected_format, $entity->getFormat());
+ $this->assertSame($expected_weight, $entity->getWeight());
+ $this->assertHierarchy($expected_vid, $id, $expected_parents);
+ }
+
+ /**
+ * Assert that a term is present in the tree storage, with the right parents.
+ *
+ * @param string $vid
+ * Vocabulary ID.
+ * @param int $tid
+ * ID of the term to check.
+ * @param array $parent_ids
+ * The expected parent term IDs.
+ */
+ protected function assertHierarchy($vid, $tid, array $parent_ids) {
+ if (!isset($this->treeData[$vid])) {
+ $tree = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree($vid);
+ $this->treeData[$vid] = [];
+ foreach ($tree as $item) {
+ $this->treeData[$vid][$item->tid] = $item;
+ }
+ }
+
+ $this->assertArrayHasKey($tid, $this->treeData[$vid], "Term $tid exists in taxonomy tree");
+ $term = $this->treeData[$vid][$tid];
+ $this->assertEquals($parent_ids, array_filter($term->parents), "Term $tid has correct parents in taxonomy tree");
+ }
+
+ /**
+ * Tests the Drupal 6 i18n taxonomy term to Drupal 8 migration.
+ */
+ public function testTranslatedTaxonomyTerms() {
+ $this->assertEntity(1, 'zu', 'zu - term 1 of vocabulary 1', 'vocabulary_1_i_0_', 'zu - description of term 1 of vocabulary 1', NULL, '0', []);
+ $this->assertEntity(2, 'fr', 'fr - term 2 of vocabulary 2', 'vocabulary_2_i_1_', 'fr - description of term 2 of vocabulary 2', NULL, '3', []);
+ $this->assertEntity(3, 'fr', 'fr - term 3 of vocabulary 2', 'vocabulary_2_i_1_', 'fr - description of term 3 of vocabulary 2', NULL, '4', ['2']);
+ $this->assertEntity(4, 'en', 'term 4 of vocabulary 3', 'vocabulary_3_i_2_', 'description of term 4 of vocabulary 3', NULL, '6', []);
+ $this->assertEntity(5, 'en', 'term 5 of vocabulary 3', 'vocabulary_3_i_2_', 'description of term 5 of vocabulary 3', NULL, '7', ['4']);
+ $this->assertEntity(6, 'en', 'term 6 of vocabulary 3', 'vocabulary_3_i_2_', 'description of term 6 of vocabulary 3', NULL, '8', ['4', '5']);
+ $this->assertEntity(7, 'fr', 'fr - term 2 of vocabulary 1', 'vocabulary_1_i_0_', 'fr - desc of term 2 vocab 1', NULL, '0', []);
+ }
+
+}
diff -r bfffd8d7479a -r 7a779792577d core/modules/datetime/src/Plugin/migrate/field/DateField.php
--- a/core/modules/datetime/src/Plugin/migrate/field/DateField.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/datetime/src/Plugin/migrate/field/DateField.php Fri Feb 23 15:52:07 2018 +0000
@@ -60,7 +60,7 @@
];
$process = [
- 'plugin' => 'iterator',
+ 'plugin' => 'sub_process',
'source' => $field_name,
'process' => $process,
];
diff -r bfffd8d7479a -r 7a779792577d core/modules/datetime/src/Plugin/migrate/field/d6/DateField.php
--- a/core/modules/datetime/src/Plugin/migrate/field/d6/DateField.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/datetime/src/Plugin/migrate/field/d6/DateField.php Fri Feb 23 15:52:07 2018 +0000
@@ -65,7 +65,7 @@
];
$process = [
- 'plugin' => 'iterator',
+ 'plugin' => 'sub_process',
'source' => $field_name,
'process' => $process,
];
diff -r bfffd8d7479a -r 7a779792577d core/modules/datetime/src/Plugin/views/filter/Date.php
--- a/core/modules/datetime/src/Plugin/views/filter/Date.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/datetime/src/Plugin/views/filter/Date.php Fri Feb 23 15:52:07 2018 +0000
@@ -96,7 +96,6 @@
// Formatting will vary on date storage.
-
// Convert to ISO format and format for query. UTC timezone is used since
// dates are stored in UTC.
$a = $this->query->getDateFormat("'" . $this->dateFormatter->format($a, 'custom', DATETIME_DATETIME_STORAGE_FORMAT, DATETIME_STORAGE_TIMEZONE) . "'", $this->dateFormat, TRUE);
diff -r bfffd8d7479a -r 7a779792577d core/modules/datetime/tests/src/Kernel/Views/FilterDateTimeTest.php
--- a/core/modules/datetime/tests/src/Kernel/Views/FilterDateTimeTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/datetime/tests/src/Kernel/Views/FilterDateTimeTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -24,6 +24,8 @@
/**
* Use a non-UTC timezone.
+ *
+ * @var string
*/
protected static $timezone = 'America/Vancouver';
diff -r bfffd8d7479a -r 7a779792577d core/modules/dblog/src/Plugin/views/wizard/Watchdog.php
--- a/core/modules/dblog/src/Plugin/views/wizard/Watchdog.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/dblog/src/Plugin/views/wizard/Watchdog.php Fri Feb 23 15:52:07 2018 +0000
@@ -18,6 +18,8 @@
/**
* Set the created column.
+ *
+ * @var string
*/
protected $createdColumn = 'timestamp';
diff -r bfffd8d7479a -r 7a779792577d core/modules/dblog/src/Tests/Rest/DbLogResourceTest.php
--- a/core/modules/dblog/src/Tests/Rest/DbLogResourceTest.php Fri Feb 23 15:51:18 2018 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-enableService('dblog');
- }
-
- /**
- * Writes a log messages and retrieves it via the REST API.
- */
- public function testWatchdog() {
- // Write a log message to the DB.
- $this->container->get('logger.channel.rest')->notice('Test message');
- // Get the ID of the written message.
- $id = db_query_range("SELECT wid FROM {watchdog} WHERE type = :type ORDER BY wid DESC", 0, 1, [':type' => 'rest'])
- ->fetchField();
-
- // Create a user account that has the required permissions to read
- // the watchdog resource via the REST API.
- $account = $this->drupalCreateUser(['restful get dblog']);
- $this->drupalLogin($account);
-
- $response = $this->httpRequest(Url::fromRoute('rest.dblog.GET.' . $this->defaultFormat, ['id' => $id, '_format' => $this->defaultFormat]), 'GET');
- $this->assertResponse(200);
- $this->assertHeader('content-type', $this->defaultMimeType);
- $log = Json::decode($response);
- $this->assertEqual($log['wid'], $id, 'Log ID is correct.');
- $this->assertEqual($log['type'], 'rest', 'Type of log message is correct.');
- $this->assertEqual($log['message'], 'Test message', 'Log message text is correct.');
-
- // Request an unknown log entry.
- $response = $this->httpRequest(Url::fromRoute('rest.dblog.GET.' . $this->defaultFormat, ['id' => 9999, '_format' => $this->defaultFormat]), 'GET');
- $this->assertResponse(404);
- $decoded = Json::decode($response);
- $this->assertEqual($decoded['message'], 'Log entry with ID 9999 was not found', 'Response message is correct.');
-
- // Make a bad request (a true malformed request would never be a route match).
- $response = $this->httpRequest(Url::fromRoute('rest.dblog.GET.' . $this->defaultFormat, ['id' => 0, '_format' => $this->defaultFormat]), 'GET');
- $this->assertResponse(400);
- $decoded = Json::decode($response);
- $this->assertEqual($decoded['message'], 'No log entry ID was provided', 'Response message is correct.');
- }
-
-}
diff -r bfffd8d7479a -r 7a779792577d core/modules/dblog/tests/src/Functional/DbLogResourceTest.php
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/dblog/tests/src/Functional/DbLogResourceTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -0,0 +1,127 @@
+provisionResource([static::$format], $auth);
+ }
+
+ /**
+ * Writes a log messages and retrieves it via the REST API.
+ */
+ public function testWatchdog() {
+ // Write a log message to the DB.
+ $this->container->get('logger.channel.rest')->notice('Test message');
+ // Get the ID of the written message.
+ $id = db_query_range("SELECT wid FROM {watchdog} WHERE type = :type ORDER BY wid DESC", 0, 1, [':type' => 'rest'])
+ ->fetchField();
+
+ $this->initAuthentication();
+ $url = Url::fromRoute('rest.dblog.GET.' . static::$format, ['id' => $id, '_format' => static::$format]);
+ $request_options = $this->getAuthenticationRequestOptions('GET');
+
+ $response = $this->request('GET', $url, $request_options);
+ $this->assertResourceErrorResponse(403, "The 'restful get dblog' permission is required.", $response);
+
+ // Create a user account that has the required permissions to read
+ // the watchdog resource via the REST API.
+ $this->setUpAuthorization('GET');
+
+ $response = $this->request('GET', $url, $request_options);
+ $this->assertResourceResponse(200, FALSE, $response, ['config:rest.resource.dblog', 'config:rest.settings', 'http_response'], ['user.permissions'], FALSE, 'MISS');
+ $log = Json::decode((string) $response->getBody());
+ $this->assertEqual($log['wid'], $id, 'Log ID is correct.');
+ $this->assertEqual($log['type'], 'rest', 'Type of log message is correct.');
+ $this->assertEqual($log['message'], 'Test message', 'Log message text is correct.');
+
+ // Request an unknown log entry.
+ $url->setRouteParameter('id', 9999);
+ $response = $this->request('GET', $url, $request_options);
+ $this->assertResourceErrorResponse(404, 'Log entry with ID 9999 was not found', $response);
+
+ // Make a bad request (a true malformed request would never be a route match).
+ $url->setRouteParameter('id', 0);
+ $response = $this->request('GET', $url, $request_options);
+ $this->assertResourceErrorResponse(400, 'No log entry ID was provided', $response);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUpAuthorization($method) {
+ switch ($method) {
+ case 'GET':
+ $this->grantPermissionsToTestedRole(['restful get dblog']);
+ break;
+
+ default:
+ throw new \UnexpectedValueException();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function assertNormalizationEdgeCases($method, Url $url, array $request_options) {}
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExpectedUnauthorizedAccessMessage($method) {}
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExpectedBcUnauthorizedAccessMessage($method) {}
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExpectedUnauthorizedAccessCacheability() {}
+
+}
diff -r bfffd8d7479a -r 7a779792577d core/modules/editor/editor.module
--- a/core/modules/editor/editor.module Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/editor/editor.module Fri Feb 23 15:52:07 2018 +0000
@@ -434,7 +434,7 @@
*
* @param array $uuids
* An array of file entity UUIDs.
- * @param EntityInterface $entity
+ * @param \Drupal\Core\Entity\EntityInterface $entity
* An entity whose fields to inspect for file references.
*/
function _editor_record_file_usage(array $uuids, EntityInterface $entity) {
@@ -454,7 +454,7 @@
*
* @param array $uuids
* An array of file entity UUIDs.
- * @param EntityInterface $entity
+ * @param \Drupal\Core\Entity\EntityInterface $entity
* An entity whose fields to inspect for file references.
* @param $count
* The number of references to delete. Should be 1 when deleting a single
@@ -545,7 +545,7 @@
/**
* Finds all files referenced (data-entity-uuid) by formatted text fields.
*
- * @param EntityInterface $entity
+ * @param \Drupal\Core\Entity\EntityInterface $entity
* An entity whose fields to analyze.
*
* @return array
diff -r bfffd8d7479a -r 7a779792577d core/modules/editor/src/Tests/EditorSecurityTest.php
--- a/core/modules/editor/src/Tests/EditorSecurityTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/editor/src/Tests/EditorSecurityTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -158,7 +158,6 @@
]);
$editor->save();
-
// Create node type.
$this->drupalCreateContentType([
'type' => 'article',
diff -r bfffd8d7479a -r 7a779792577d core/modules/editor/tests/src/Functional/Update/EditorUpdateTest.php
--- a/core/modules/editor/tests/src/Functional/Update/EditorUpdateTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/editor/tests/src/Functional/Update/EditorUpdateTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -46,7 +46,6 @@
$this->assertTrue($editor_full_html->get('status'));
$this->assertNotIdentical($format_full_html->get('status'), $editor_full_html->get('status'));
-
// Run updates.
$this->runUpdates();
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/field.api.php
--- a/core/modules/field/field.api.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/field.api.php Fri Feb 23 15:52:07 2018 +0000
@@ -138,7 +138,8 @@
* Alter forms for field widgets provided by other modules.
*
* @param $element
- * The field widget form element as constructed by hook_field_widget_form().
+ * The field widget form element as constructed by
+ * \Drupal\Core\Field\WidgetBaseInterface::form().
* @param $form_state
* The current state of the form.
* @param $context
@@ -152,6 +153,7 @@
* - default: A boolean indicating whether the form is being shown as a dummy
* form to set default values.
*
+ * @see \Drupal\Core\Field\WidgetBaseInterface::form()
* @see \Drupal\Core\Field\WidgetBase::formSingleElement()
* @see hook_field_widget_WIDGET_TYPE_form_alter()
*/
@@ -172,13 +174,15 @@
* checking the widget type.
*
* @param $element
- * The field widget form element as constructed by hook_field_widget_form().
+ * The field widget form element as constructed by
+ * \Drupal\Core\Field\WidgetBaseInterface::form().
* @param $form_state
* The current state of the form.
* @param $context
* An associative array. See hook_field_widget_form_alter() for the structure
* and content of the array.
*
+ * @see \Drupal\Core\Field\WidgetBaseInterface::form()
* @see \Drupal\Core\Field\WidgetBase::formSingleElement()
* @see hook_field_widget_form_alter()
*/
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/field.module
--- a/core/modules/field/field.module Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/field.module Fri Feb 23 15:52:07 2018 +0000
@@ -250,19 +250,6 @@
unset($handler_settings['target_bundles'][$bundle]);
$field_config->setSetting('handler_settings', $handler_settings);
$field_config->save();
-
- // In case we deleted the only target bundle allowed by the field we
- // have to log a critical message because the field will not function
- // correctly anymore.
- if ($handler_settings['target_bundles'] === []) {
- \Drupal::logger('entity_reference')->critical('The %target_bundle bundle (entity type: %target_entity_type) was deleted. As a result, the %field_name entity reference field (entity_type: %entity_type, bundle: %bundle) no longer has any valid bundle it can reference. The field is not working correctly anymore and has to be adjusted.', [
- '%target_bundle' => $bundle,
- '%target_entity_type' => $entity_type_id,
- '%field_name' => $field_config->getName(),
- '%entity_type' => $field_config->getTargetEntityTypeId(),
- '%bundle' => $field_config->getTargetBundle()
- ]);
- }
}
}
}
@@ -407,4 +394,17 @@
$selection_manager = \Drupal::service('plugin.manager.entity_reference_selection');
list($current_handler) = explode(':', $field->getSetting('handler'), 2);
$field->setSetting('handler', $selection_manager->getPluginId($target_type, $current_handler));
+
+ // In case we removed all the target bundles allowed by the field in
+ // EntityReferenceItem::onDependencyRemoval() or field_entity_bundle_delete()
+ // we have to log a critical message because the field will not function
+ // correctly anymore.
+ $handler_settings = $field->getSetting('handler_settings');
+ if (isset($handler_settings['target_bundles']) && $handler_settings['target_bundles'] === []) {
+ \Drupal::logger('entity_reference')->critical('The %field_name entity reference field (entity_type: %entity_type, bundle: %bundle) no longer has any valid bundle it can reference. The field is not working correctly anymore and has to be adjusted.', [
+ '%field_name' => $field->getName(),
+ '%entity_type' => $field->getTargetEntityTypeId(),
+ '%bundle' => $field->getTargetBundle(),
+ ]);
+ }
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/src/Plugin/migrate/process/d7/FieldSettings.php
--- a/core/modules/field/src/Plugin/migrate/process/d7/FieldSettings.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/src/Plugin/migrate/process/d7/FieldSettings.php Fri Feb 23 15:52:07 2018 +0000
@@ -26,6 +26,16 @@
}
break;
+ case 'date':
+ case 'datetime':
+ case 'datestamp':
+ if ($value['granularity']['hour'] === 0
+ && $value['granularity']['minute'] === 0
+ && $value['granularity']['second'] === 0) {
+ $value['datetime_type'] = 'date';
+ }
+ break;
+
case 'taxonomy_term_reference':
$value['target_type'] = 'taxonomy_term';
break;
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php
--- a/core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php Fri Feb 23 15:52:07 2018 +0000
@@ -145,7 +145,7 @@
/**
* {@inheritdoc}
*/
- public function count() {
+ public function count($refresh = FALSE) {
return $this->initializeIterator()->count();
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/src/Tests/EntityReference/EntityReferenceAdminTest.php
--- a/core/modules/field/src/Tests/EntityReference/EntityReferenceAdminTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/src/Tests/EntityReference/EntityReferenceAdminTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -330,6 +330,12 @@
$this->drupalPostForm(NULL, $edit, t('Save field settings'));
$this->drupalGet($bundle_path . '/fields/' . $field_path);
$term_name = $this->randomString();
+ $result = \Drupal::entityQuery('taxonomy_term')
+ ->condition('name', $term_name)
+ ->condition('vid', 'tags')
+ ->accessCheck(FALSE)
+ ->execute();
+ $this->assertIdentical(0, count($result), "No taxonomy terms exist with the name '$term_name'.");
$edit = [
// This must be set before new entities will be auto-created.
'settings[handler_settings][auto_create]' => 1,
@@ -342,8 +348,12 @@
];
$this->drupalPostForm(NULL, $edit, t('Save settings'));
// The term should now exist.
- $term = taxonomy_term_load_multiple_by_name($term_name, 'tags')[1];
- $this->assertIdentical(1, count($term), 'Taxonomy term was auto created when set as field default.');
+ $result = \Drupal::entityQuery('taxonomy_term')
+ ->condition('name', $term_name)
+ ->condition('vid', 'tags')
+ ->accessCheck(FALSE)
+ ->execute();
+ $this->assertIdentical(1, count($result), 'Taxonomy term was auto created when set as field default.');
}
/**
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/src/Tests/EntityReference/EntityReferenceFileUploadTest.php
--- a/core/modules/field/src/Tests/EntityReference/EntityReferenceFileUploadTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/src/Tests/EntityReference/EntityReferenceFileUploadTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -77,7 +77,6 @@
],
])->save();
-
// Create a file field.
$file_field_name = 'file_field';
$field_storage = FieldStorageConfig::create([
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/src/Tests/FieldTestBase.php
--- a/core/modules/field/src/Tests/FieldTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/src/Tests/FieldTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -36,7 +36,7 @@
*
* This function only checks a single column in the field values.
*
- * @param EntityInterface $entity
+ * @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to test.
* @param $field_name
* The name of the field to test
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/tests/src/Functional/EntityReference/EntityReferenceIntegrationTest.php
--- a/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceIntegrationTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceIntegrationTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -197,9 +197,10 @@
* An array of entity objects.
*/
protected function getTestEntities() {
- $config_entity_1 = entity_create('config_test', ['id' => $this->randomMachineName(), 'label' => $this->randomMachineName()]);
+ $storage = \Drupal::entityTypeManager()->getStorage('config_test');
+ $config_entity_1 = $storage->create(['id' => $this->randomMachineName(), 'label' => $this->randomMachineName()]);
$config_entity_1->save();
- $config_entity_2 = entity_create('config_test', ['id' => $this->randomMachineName(), 'label' => $this->randomMachineName()]);
+ $config_entity_2 = $storage->create(['id' => $this->randomMachineName(), 'label' => $this->randomMachineName()]);
$config_entity_2->save();
$content_entity_1 = EntityTest::create(['name' => $this->randomMachineName()]);
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/tests/src/Functional/FieldTestBase.php
--- a/core/modules/field/tests/src/Functional/FieldTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/tests/src/Functional/FieldTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -33,7 +33,7 @@
*
* This function only checks a single column in the field values.
*
- * @param EntityInterface $entity
+ * @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to test.
* @param $field_name
* The name of the field to test
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceSettingsTest.php
--- a/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceSettingsTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceSettingsTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -3,11 +3,14 @@
namespace Drupal\Tests\field\Kernel\EntityReference;
use Drupal\Component\Utility\Unicode;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\Logger\RfcLogLevel;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
use Drupal\node\Entity\NodeType;
use Drupal\KernelTests\KernelTestBase;
use Drupal\taxonomy\Entity\Vocabulary;
+use Symfony\Component\Debug\BufferingLogger;
/**
* Tests entity reference field settings.
@@ -45,6 +48,13 @@
protected $customBundle;
/**
+ * The service name for a logger implementation that collects anything logged.
+ *
+ * @var string
+ */
+ protected $testLogServiceName = 'entity_reference_settings_test.logger';
+
+ /**
* {@inheritdoc}
*/
protected function setUp() {
@@ -60,26 +70,38 @@
]);
$this->nodeType->save();
- $this->vocabulary = Vocabulary::create([
- 'vid' => Unicode::strtolower($this->randomMachineName()),
- 'name' => $this->randomString(),
- ]);
- $this->vocabulary->save();
-
// Create a custom bundle.
$this->customBundle = 'test_bundle_' . Unicode::strtolower($this->randomMachineName());
entity_test_create_bundle($this->customBundle, NULL, 'entity_test');
+
+ // Prepare the logger for collecting the expected critical error.
+ $this->container->get($this->testLogServiceName)->cleanLogs();
}
/**
* Tests that config bundle deletions are mirrored in field config settings.
*/
public function testConfigTargetBundleDeletion() {
+ // Create two vocabularies.
+ /** @var \Drupal\taxonomy\Entity\Vocabulary[] $vocabularies */
+ $vocabularies = [];
+ for ($i = 0; $i < 2; $i++) {
+ $vid = Unicode::strtolower($this->randomMachineName());
+ $vocabularies[$i] = Vocabulary::create([
+ 'name' => $this->randomString(),
+ 'vid' => $vid,
+ ]);
+ $vocabularies[$i]->save();
+ }
// Attach an entity reference field to $this->nodeType.
$name = Unicode::strtolower($this->randomMachineName());
$label = $this->randomString();
- $vid = $this->vocabulary->id();
- $handler_settings = ['target_bundles' => [$vid => $vid]];
+ $handler_settings = [
+ 'target_bundles' => [
+ $vocabularies[0]->id() => $vocabularies[0]->id(),
+ $vocabularies[1]->id() => $vocabularies[1]->id(),
+ ],
+ ];
$this->createEntityReferenceField('node', $this->nodeType->id(), $name, $label, 'taxonomy_term', 'default', $handler_settings);
// Check that the 'target_bundle' setting contains the vocabulary.
@@ -88,13 +110,32 @@
$this->assertEqual($handler_settings, $actual_handler_settings);
// Delete the vocabulary.
- $this->vocabulary->delete();
+ $vocabularies[0]->delete();
+ // Ensure that noting is logged.
+ $this->assertEmpty($this->container->get($this->testLogServiceName)->cleanLogs());
// Check that the deleted vocabulary is no longer present in the
// 'target_bundles' field setting.
$field_config = FieldConfig::loadByName('node', $this->nodeType->id(), $name);
$handler_settings = $field_config->getSetting('handler_settings');
- $this->assertTrue(empty($handler_settings['target_bundles']));
+ $this->assertEquals([$vocabularies[1]->id() => $vocabularies[1]->id()], $handler_settings['target_bundles']);
+
+ // Delete the other vocabulary.
+ $vocabularies[1]->delete();
+ // Ensure that field_field_config_presave() logs the expected critical
+ // error.
+ $log_message = $this->container->get($this->testLogServiceName)->cleanLogs()[0];
+ $this->assertEquals(RfcLogLevel::CRITICAL, $log_message[0]);
+ $this->assertEquals('The %field_name entity reference field (entity_type: %entity_type, bundle: %bundle) no longer has any valid bundle it can reference. The field is not working correctly anymore and has to be adjusted.', $log_message[1]);
+ $this->assertEquals($field_config->getName(), $log_message[2]['%field_name']);
+ $this->assertEquals('node', $log_message[2]['%entity_type']);
+ $this->assertEquals($this->nodeType->id(), $log_message[2]['%bundle']);
+
+ // Check that the deleted bundle is no longer present in the
+ // 'target_bundles' field setting.
+ $field_config = FieldConfig::loadByName('node', $this->nodeType->id(), $name);
+ $handler_settings = $field_config->getSetting('handler_settings');
+ $this->assertEquals([], $handler_settings['target_bundles']);
}
/**
@@ -115,6 +156,15 @@
// Delete the custom bundle.
entity_test_delete_bundle($this->customBundle, 'entity_test');
+ // Ensure that field_field_config_presave() logs the expected critical
+ // error.
+ $log_message = $this->container->get($this->testLogServiceName)->cleanLogs()[0];
+ $this->assertEquals(RfcLogLevel::CRITICAL, $log_message[0]);
+ $this->assertEquals('The %field_name entity reference field (entity_type: %entity_type, bundle: %bundle) no longer has any valid bundle it can reference. The field is not working correctly anymore and has to be adjusted.', $log_message[1]);
+ $this->assertEquals($field_config->getName(), $log_message[2]['%field_name']);
+ $this->assertEquals('node', $log_message[2]['%entity_type']);
+ $this->assertEquals($this->nodeType->id(), $log_message[2]['%bundle']);
+
// Check that the deleted bundle is no longer present in the
// 'target_bundles' field setting.
$field_config = FieldConfig::loadByName('node', $this->nodeType->id(), $name);
@@ -122,4 +172,14 @@
$this->assertTrue(empty($handler_settings['target_bundles']));
}
+ /**
+ * {@inheritdoc}
+ */
+ public function register(ContainerBuilder $container) {
+ parent::register($container);
+ $container
+ ->register($this->testLogServiceName, BufferingLogger::class)
+ ->addTag('logger');
+ }
+
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/tests/src/Kernel/FieldDefinitionIntegrityTest.php
--- a/core/modules/field/tests/src/Kernel/FieldDefinitionIntegrityTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/tests/src/Kernel/FieldDefinitionIntegrityTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -2,7 +2,13 @@
namespace Drupal\Tests\field\Kernel;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Exception\PluginNotFoundException;
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Entity\ContentEntityTypeInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Extension\Extension;
+use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\KernelTests\KernelTestBase;
/**
@@ -21,22 +27,13 @@
* Tests the integrity of field plugin definitions.
*/
public function testFieldPluginDefinitionIntegrity() {
-
- // Enable all core modules that provide field plugins.
- $modules = system_rebuild_module_data();
- $modules = array_filter($modules, function (Extension $module) {
- // Filter contrib, hidden, already enabled modules and modules in the
- // Testing package.
- if ($module->origin === 'core'
- && empty($module->info['hidden'])
- && $module->status == FALSE
- && $module->info['package'] !== 'Testing'
- && is_readable($module->getPath() . '/src/Plugin/Field')) {
- return TRUE;
- }
- return FALSE;
- });
- $this->enableModules(array_keys($modules));
+ // Enable all core modules that provide field plugins, and their
+ // dependencies.
+ $this->enableModules(
+ $this->modulesWithSubdirectory(
+ 'src' . DIRECTORY_SEPARATOR . 'Plugin' . DIRECTORY_SEPARATOR . 'Field'
+ )
+ );
/** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_type_manager */
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
@@ -108,7 +105,114 @@
else {
$this->pass(sprintf('Field formatter %s integrates with existing field types.', $definition['id']));
}
+
}
}
+ /**
+ * Tests to load field plugin definitions used in core's existing entities.
+ */
+ public function testFieldPluginDefinitionAvailability() {
+ $this->enableModules(
+ $this->modulesWithSubdirectory('src' . DIRECTORY_SEPARATOR . 'Entity')
+ );
+
+ /** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_type_manager */
+ $field_formatter_manager = $this->container->get('plugin.manager.field.formatter');
+
+ /** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_type_manager */
+ $field_widget_manager = $this->container->get('plugin.manager.field.widget');
+
+ /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */
+ $entity_field_manager = $this->container->get('entity_field.manager');
+
+ /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
+ $entity_type_manager = $this->container->get('entity_type.manager');
+
+ /** @var \Drupal\Core\Field\BaseFieldDefinition[][] $field_definitions */
+ $field_definitions = [];
+
+ /** @var \Drupal\Core\Entity\EntityTypeInterface[] $content_entity_types */
+ $content_entity_types = array_filter($entity_type_manager->getDefinitions(), function (EntityTypeInterface $entity_type) {
+ return $entity_type instanceof ContentEntityTypeInterface;
+ });
+
+ foreach ($content_entity_types as $entity_type_id => $entity_type_definition) {
+ $field_definitions[$entity_type_id] = $entity_field_manager->getBaseFieldDefinitions($entity_type_id);
+ }
+
+ foreach ($field_definitions as $entity_type_id => $definitions) {
+ foreach ($definitions as $field_id => $field_definition) {
+ $this->checkDisplayOption($entity_type_id, $field_id, $field_definition, $field_formatter_manager, 'view');
+ $this->checkDisplayOption($entity_type_id, $field_id, $field_definition, $field_widget_manager, 'form');
+ }
+ }
+ }
+
+ /**
+ * Helper method that tries to load plugin definitions.
+ *
+ * @param string $entity_type_id
+ * Id of entity type. Required by message.
+ * @param string $field_id
+ * Id of field. Required by message.
+ * @param \Drupal\Core\Field\BaseFieldDefinition $field_definition
+ * Field definition that provide display options.
+ * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $plugin_manager
+ * Plugin manager that will try to provide plugin definition.
+ * @param string $display_context
+ * Defines which display options should be loaded.
+ */
+ protected function checkDisplayOption($entity_type_id, $field_id, BaseFieldDefinition $field_definition, DiscoveryInterface $plugin_manager, $display_context) {
+ $display_options = $field_definition->getDisplayOptions($display_context);
+ if (!empty($display_options['type'])) {
+ try {
+ $plugin_manager->getDefinition($display_options['type']);
+ }
+ catch (PluginNotFoundException $e) {
+ $this->fail(sprintf(
+ 'PluginNotFoundException here for "%s" field %s display options of "%s" entity type. Original message: %s',
+ $field_id,
+ $display_context,
+ $entity_type_id,
+ $e->getMessage()
+ ));
+ }
+ }
+ }
+
+ /**
+ * Find modules with a specified subdirectory.
+ *
+ * @param string $subdirectory
+ * The required path, relative to the module directory.
+ *
+ * @return string[]
+ * A list of module names satisfying these criteria:
+ * - provided by core
+ * - not hidden
+ * - not already enabled
+ * - not in the Testing package
+ * - containing the required $subdirectory
+ * and all modules required by any of these modules.
+ */
+ protected function modulesWithSubdirectory($subdirectory) {
+ $modules = system_rebuild_module_data();
+ $modules = array_filter($modules, function (Extension $module) use ($subdirectory) {
+ // Filter contrib, hidden, already enabled modules and modules in the
+ // Testing package.
+ return ($module->origin === 'core'
+ && empty($module->info['hidden'])
+ && $module->status == FALSE
+ && $module->info['package'] !== 'Testing'
+ && is_readable($module->getPath() . DIRECTORY_SEPARATOR . $subdirectory));
+ });
+ // Gather the dependencies of the modules.
+ $dependencies = NestedArray::mergeDeepArray(array_map(function (Extension $module) {
+ return array_keys($module->requires);
+ }, $modules));
+
+ return array_unique(NestedArray::mergeDeep(array_keys($modules), $dependencies));
+ }
+
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/tests/src/Kernel/FieldKernelTestBase.php
--- a/core/modules/field/tests/src/Kernel/FieldKernelTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/tests/src/Kernel/FieldKernelTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -172,7 +172,7 @@
*
* This function only checks a single column in the field values.
*
- * @param EntityInterface $entity
+ * @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to test.
* @param $field_name
* The name of the field to test
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldInstanceTest.php
--- a/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldInstanceTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldInstanceTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -128,7 +128,6 @@
$this->assertEntity('comment.comment_node_test_content_type.field_integer', 'Integer', 'integer', FALSE, FALSE);
$this->assertEntity('user.user.field_file', 'File', 'file', FALSE, FALSE);
-
$this->assertLinkFields('node.test_content_type.field_link', DRUPAL_OPTIONAL);
$this->assertLinkFields('node.article.field_link', DRUPAL_DISABLED);
$this->assertLinkFields('node.blog.field_link', DRUPAL_REQUIRED);
diff -r bfffd8d7479a -r 7a779792577d core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldTest.php
--- a/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -101,6 +101,8 @@
$this->assertEntity('node.field_node_entityreference', 'entity_reference', TRUE, -1);
$this->assertEntity('node.field_user_entityreference', 'entity_reference', TRUE, 1);
$this->assertEntity('node.field_term_entityreference', 'entity_reference', TRUE, -1);
+ $this->assertEntity('node.field_date_without_time', 'datetime', TRUE, 1);
+ $this->assertEntity('node.field_datetime_without_time', 'datetime', TRUE, 1);
// Assert that the taxonomy term reference fields are referencing the
// correct entity type.
@@ -117,6 +119,18 @@
$this->assertEquals('user', $field->getSetting('target_type'));
$field = FieldStorageConfig::load('node.field_term_entityreference');
$this->assertEquals('taxonomy_term', $field->getSetting('target_type'));
+
+ // Make sure that datetime fields get the right datetime_type setting
+ $field = FieldStorageConfig::load('node.field_date');
+ $this->assertEquals('datetime', $field->getSetting('datetime_type'));
+ $field = FieldStorageConfig::load('node.field_date_without_time');
+ $this->assertEquals('date', $field->getSetting('datetime_type'));
+ $field = FieldStorageConfig::load('node.field_datetime_without_time');
+ $this->assertEquals('date', $field->getSetting('datetime_type'));
+ // Except for field_date_with_end_time which is a timestamp and so does not
+ // have a datetime_type setting.
+ $field = FieldStorageConfig::load('node.field_date_with_end_time');
+ $this->assertNull($field->getSetting('datetime_type'));
}
/**
diff -r bfffd8d7479a -r 7a779792577d core/modules/field_layout/src/FieldLayoutBuilder.php
--- a/core/modules/field_layout/src/FieldLayoutBuilder.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field_layout/src/FieldLayoutBuilder.php Fri Feb 23 15:52:07 2018 +0000
@@ -67,12 +67,15 @@
$regions = array_fill_keys($layout_definition->getRegionNames(), []);
foreach ($fields as $name => $field) {
- // Move the field from the top-level of $build into a region-specific
- // section.
+ // If the region is controlled by the layout, move the field from the
+ // top-level of $build into a region-specific section. Custom regions
+ // could be set by other code at run-time; these should be ignored.
// @todo Ideally the array structure would remain unchanged, see
// https://www.drupal.org/node/2846393.
- $regions[$field['region']][$name] = $build[$name];
- unset($build[$name]);
+ if (isset($regions[$field['region']])) {
+ $regions[$field['region']][$name] = $build[$name];
+ unset($build[$name]);
+ }
}
// Ensure this will not conflict with any existing array elements by
// prefixing with an underscore.
@@ -103,7 +106,7 @@
// avoids breaking hook_form_alter() implementations by not actually
// moving the field in the form structure. If a #group is already set,
// do not overwrite it.
- if (!isset($build[$name]['#group'])) {
+ if (isset($regions[$field['region']]) && !isset($build[$name]['#group'])) {
$build[$name]['#group'] = $field['region'];
}
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/field_layout/tests/src/Unit/FieldLayoutBuilderTest.php
--- a/core/modules/field_layout/tests/src/Unit/FieldLayoutBuilderTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field_layout/tests/src/Unit/FieldLayoutBuilderTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -93,6 +93,9 @@
'test1' => [
'#markup' => 'Test1',
],
+ 'test2' => [
+ '#markup' => 'Test2',
+ ],
'non_configurable_field' => [
'#markup' => 'Non-configurable',
],
@@ -111,6 +114,9 @@
'test1' => [
'region' => 'right',
],
+ 'test2' => [
+ 'region' => 'unknown_region',
+ ],
'non_configurable_field' => [
'region' => 'left',
],
@@ -120,6 +126,9 @@
]);
$expected = [
+ 'test2' => [
+ '#markup' => 'Test2',
+ ],
'non_configurable_field' => [
'#markup' => 'Non-configurable',
],
@@ -169,6 +178,9 @@
'#markup' => 'Test2',
'#group' => 'existing_group',
],
+ 'test3' => [
+ '#markup' => 'Test3',
+ ],
'field_layout' => [
'#markup' => 'Field created through the UI happens to be named "Layout"',
],
@@ -190,6 +202,9 @@
'test2' => [
'region' => 'left',
],
+ 'test3' => [
+ 'region' => 'unknown_region',
+ ],
'field_layout' => [
'region' => 'right',
],
@@ -207,6 +222,9 @@
'#markup' => 'Test2',
'#group' => 'existing_group',
],
+ 'test3' => [
+ '#markup' => 'Test3',
+ ],
'field_layout' => [
'#markup' => 'Field created through the UI happens to be named "Layout"',
'#group' => 'right',
diff -r bfffd8d7479a -r 7a779792577d core/modules/field_ui/src/Form/EntityViewDisplayEditForm.php
--- a/core/modules/field_ui/src/Form/EntityViewDisplayEditForm.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field_ui/src/Form/EntityViewDisplayEditForm.php Fri Feb 23 15:52:07 2018 +0000
@@ -111,7 +111,8 @@
/**
* {@inheritdoc}
*/
- protected function getDisplayModesLink() {;
+ protected function getDisplayModesLink() {
+ ;
return [
'#type' => 'link',
'#title' => t('Manage view modes'),
diff -r bfffd8d7479a -r 7a779792577d core/modules/field_ui/src/Tests/ManageDisplayTest.php
--- a/core/modules/field_ui/src/Tests/ManageDisplayTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/field_ui/src/Tests/ManageDisplayTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -452,7 +452,7 @@
/**
* Asserts that a string is found in the rendered node in a view mode.
*
- * @param EntityInterface $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
* The node.
* @param $view_mode
* The view mode in which the node should be displayed.
@@ -471,7 +471,7 @@
/**
* Asserts that a string is not found in the rendered node in a view mode.
*
- * @param EntityInterface $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
* The node.
* @param $view_mode
* The view mode in which the node should be displayed.
@@ -492,7 +492,7 @@
* This helper function is used by assertNodeViewText() and
* assertNodeViewNoText().
*
- * @param EntityInterface $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
* The node.
* @param $view_mode
* The view mode in which the node should be displayed.
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/src/Plugin/migrate/cckfield/d7/FileField.php
--- a/core/modules/file/src/Plugin/migrate/cckfield/d7/FileField.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/file/src/Plugin/migrate/cckfield/d7/FileField.php Fri Feb 23 15:52:07 2018 +0000
@@ -49,7 +49,7 @@
*/
public function processCckFieldValues(MigrationInterface $migration, $field_name, $data) {
$process = [
- 'plugin' => 'iterator',
+ 'plugin' => 'sub_process',
'source' => $field_name,
'process' => [
'target_id' => 'fid',
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/src/Plugin/migrate/cckfield/d7/ImageField.php
--- a/core/modules/file/src/Plugin/migrate/cckfield/d7/ImageField.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/file/src/Plugin/migrate/cckfield/d7/ImageField.php Fri Feb 23 15:52:07 2018 +0000
@@ -25,7 +25,7 @@
*/
public function processCckFieldValues(MigrationInterface $migration, $field_name, $data) {
$process = [
- 'plugin' => 'iterator',
+ 'plugin' => 'sub_process',
'source' => $field_name,
'process' => [
'target_id' => 'fid',
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/src/Plugin/migrate/field/d7/FileField.php
--- a/core/modules/file/src/Plugin/migrate/field/d7/FileField.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/file/src/Plugin/migrate/field/d7/FileField.php Fri Feb 23 15:52:07 2018 +0000
@@ -18,7 +18,7 @@
*/
public function processFieldValues(MigrationInterface $migration, $field_name, $data) {
$process = [
- 'plugin' => 'iterator',
+ 'plugin' => 'sub_process',
'source' => $field_name,
'process' => [
'target_id' => 'fid',
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/src/Plugin/migrate/field/d7/ImageField.php
--- a/core/modules/file/src/Plugin/migrate/field/d7/ImageField.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/file/src/Plugin/migrate/field/d7/ImageField.php Fri Feb 23 15:52:07 2018 +0000
@@ -18,7 +18,7 @@
*/
public function processFieldValues(MigrationInterface $migration, $field_name, $data) {
$process = [
- 'plugin' => 'iterator',
+ 'plugin' => 'sub_process',
'source' => $field_name,
'process' => [
'target_id' => 'fid',
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/src/Plugin/migrate/source/d6/UploadInstance.php
--- a/core/modules/file/src/Plugin/migrate/source/d6/UploadInstance.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/file/src/Plugin/migrate/source/d6/UploadInstance.php Fri Feb 23 15:52:07 2018 +0000
@@ -78,7 +78,7 @@
/**
* {@inheritdoc}
*/
- public function count() {
+ public function count($refresh = FALSE) {
return count($this->initializeIterator());
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/src/Plugin/views/wizard/File.php
--- a/core/modules/file/src/Plugin/views/wizard/File.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/file/src/Plugin/views/wizard/File.php Fri Feb 23 15:52:07 2018 +0000
@@ -17,6 +17,8 @@
/**
* Set the created column.
+ *
+ * @var string
*/
protected $createdColumn = 'created';
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/src/Tests/DownloadTest.php
--- a/core/modules/file/src/Tests/DownloadTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/file/src/Tests/DownloadTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -118,16 +118,6 @@
$this->checkUrl('private', '', $basename, $base_path . '/' . $script_path . 'system/files/' . $basename_encoded);
}
$this->assertEqual(file_create_url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='), 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==', t('Generated URL matches expected URL.'));
- // Test public files with a different host name from settings.
- $test_base_url = 'http://www.example.com/cdn';
- $this->settingsSet('file_public_base_url', $test_base_url);
- $filepath = file_create_filename('test.txt', '');
- $directory_uri = 'public://' . dirname($filepath);
- file_prepare_directory($directory_uri, FILE_CREATE_DIRECTORY);
- $file = $this->createFile($filepath, NULL, 'public');
- $url = file_create_url($file->getFileUri());
- $expected_url = $test_base_url . '/' . basename($filepath);
- $this->assertEqual($url, $expected_url);
}
/**
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/src/Tests/FileFieldValidateTest.php
--- a/core/modules/file/src/Tests/FileFieldValidateTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/file/src/Tests/FileFieldValidateTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -187,4 +187,25 @@
$this->assertText('Article ' . $node->getTitle() . ' has been updated.');
}
+ /**
+ * Test the validation message is displayed only once for ajax uploads.
+ */
+ public function testAJAXValidationMessage() {
+ $field_name = strtolower($this->randomMachineName());
+ $this->createFileField($field_name, 'node', 'article');
+
+ $this->drupalGet('node/add/article');
+ /** @var \Drupal\file\FileInterface $image_file */
+ $image_file = $this->getTestFile('image');
+ $edit = [
+ 'files[' . $field_name . '_0]' => $this->container->get('file_system')->realpath($image_file->getFileUri()),
+ 'title[0][value]' => $this->randomMachineName(),
+ ];
+ $this->drupalPostAjaxForm(NULL, $edit, $field_name . '_0_upload_button');
+ $elements = $this->xpath('//div[contains(@class, :class)]', [
+ ':class' => 'messages--error',
+ ]);
+ $this->assertEqual(count($elements), 1, 'Ajax validation messages are displayed once.');
+ }
+
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/tests/src/Functional/FileFieldCreationTrait.php
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/file/tests/src/Functional/FileFieldCreationTrait.php Fri Feb 23 15:52:07 2018 +0000
@@ -0,0 +1,86 @@
+ $entity_type,
+ 'field_name' => $name,
+ 'type' => 'file',
+ 'settings' => $storage_settings,
+ 'cardinality' => !empty($storage_settings['cardinality']) ? $storage_settings['cardinality'] : 1,
+ ]);
+ $field_storage->save();
+
+ $this->attachFileField($name, $entity_type, $bundle, $field_settings, $widget_settings);
+ return $field_storage;
+ }
+
+ /**
+ * Attaches a file field to an entity.
+ *
+ * @param string $name
+ * The name of the new field (all lowercase), exclude the "field_" prefix.
+ * @param string $entity_type
+ * The entity type this field will be added to.
+ * @param string $bundle
+ * The bundle this field will be added to.
+ * @param array $field_settings
+ * A list of field settings that will be added to the defaults.
+ * @param array $widget_settings
+ * A list of widget settings that will be added to the widget defaults.
+ */
+ public function attachFileField($name, $entity_type, $bundle, $field_settings = [], $widget_settings = []) {
+ $field = [
+ 'field_name' => $name,
+ 'label' => $name,
+ 'entity_type' => $entity_type,
+ 'bundle' => $bundle,
+ 'required' => !empty($field_settings['required']),
+ 'settings' => $field_settings,
+ ];
+ FieldConfig::create($field)->save();
+
+ entity_get_form_display($entity_type, $bundle, 'default')
+ ->setComponent($name, [
+ 'type' => 'file_generic',
+ 'settings' => $widget_settings,
+ ])
+ ->save();
+ // Assign display settings.
+ entity_get_display($entity_type, $bundle, 'default')
+ ->setComponent($name, [
+ 'label' => 'hidden',
+ 'type' => 'file_default',
+ ])
+ ->save();
+ }
+
+}
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/tests/src/Functional/FileFieldTestBase.php
--- a/core/modules/file/tests/src/Functional/FileFieldTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/file/tests/src/Functional/FileFieldTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -13,6 +13,8 @@
*/
abstract class FileFieldTestBase extends BrowserTestBase {
+ use FileFieldCreationTrait;
+
/**
* Modules to enable.
*
@@ -58,76 +60,6 @@
}
/**
- * Creates a new file field.
- *
- * @param string $name
- * The name of the new field (all lowercase), exclude the "field_" prefix.
- * @param string $entity_type
- * The entity type.
- * @param string $bundle
- * The bundle that this field will be added to.
- * @param array $storage_settings
- * A list of field storage settings that will be added to the defaults.
- * @param array $field_settings
- * A list of instance settings that will be added to the instance defaults.
- * @param array $widget_settings
- * A list of widget settings that will be added to the widget defaults.
- */
- public function createFileField($name, $entity_type, $bundle, $storage_settings = [], $field_settings = [], $widget_settings = []) {
- $field_storage = FieldStorageConfig::create([
- 'entity_type' => $entity_type,
- 'field_name' => $name,
- 'type' => 'file',
- 'settings' => $storage_settings,
- 'cardinality' => !empty($storage_settings['cardinality']) ? $storage_settings['cardinality'] : 1,
- ]);
- $field_storage->save();
-
- $this->attachFileField($name, $entity_type, $bundle, $field_settings, $widget_settings);
- return $field_storage;
- }
-
- /**
- * Attaches a file field to an entity.
- *
- * @param string $name
- * The name of the new field (all lowercase), exclude the "field_" prefix.
- * @param string $entity_type
- * The entity type this field will be added to.
- * @param string $bundle
- * The bundle this field will be added to.
- * @param array $field_settings
- * A list of field settings that will be added to the defaults.
- * @param array $widget_settings
- * A list of widget settings that will be added to the widget defaults.
- */
- public function attachFileField($name, $entity_type, $bundle, $field_settings = [], $widget_settings = []) {
- $field = [
- 'field_name' => $name,
- 'label' => $name,
- 'entity_type' => $entity_type,
- 'bundle' => $bundle,
- 'required' => !empty($field_settings['required']),
- 'settings' => $field_settings,
- ];
- FieldConfig::create($field)->save();
-
- entity_get_form_display($entity_type, $bundle, 'default')
- ->setComponent($name, [
- 'type' => 'file_generic',
- 'settings' => $widget_settings,
- ])
- ->save();
- // Assign display settings.
- entity_get_display($entity_type, $bundle, 'default')
- ->setComponent($name, [
- 'label' => 'hidden',
- 'type' => 'file_default',
- ])
- ->save();
- }
-
- /**
* Updates an existing file field with new settings.
*/
public function updateFileField($name, $type_name, $field_settings = [], $widget_settings = []) {
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/tests/src/FunctionalJavascript/MaximumFileSizeExceededUploadTest.php
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/file/tests/src/FunctionalJavascript/MaximumFileSizeExceededUploadTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -0,0 +1,119 @@
+fileSystem = $this->container->get('file_system');
+
+ // Create the Article node type.
+ $this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
+
+ // Attach a file field to the node type.
+ $field_settings = ['file_extensions' => 'txt'];
+ $this->createFileField('field_file', 'node', 'article', [], $field_settings);
+
+ // Log in as a content author who can create Articles.
+ $this->user = $this->drupalCreateUser([
+ 'access content',
+ 'create article content',
+ ]);
+ $this->drupalLogin($this->user);
+
+ // Disable the displaying of errors, so that the AJAX responses are not
+ // contaminated with error messages about exceeding the maximum POST size.
+ // @todo Remove this when issue #2905597 is fixed.
+ // @see https://www.drupal.org/node/2905597
+ $this->originalDisplayErrorsValue = ini_set('display_errors', '0');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function tearDown() {
+ // Restore the displaying of errors to the original value.
+ // @todo Remove this when issue #2905597 is fixed.
+ // @see https://www.drupal.org/node/2905597
+ ini_set('display_errors', $this->originalDisplayErrorsValue);
+
+ parent::tearDown();
+ }
+
+ /**
+ * Tests that uploading files exceeding maximum size are handled correctly.
+ */
+ public function testUploadFileExceedingMaximumFileSize() {
+ $session = $this->getSession();
+
+ // Create a test file that exceeds the maximum POST size with 1 kilobyte.
+ $post_max_size = Bytes::toInt(ini_get('post_max_size'));
+ $invalid_file = $this->generateFile('exceeding_post_max_size', ceil(($post_max_size + 1024) / 1024), 1024);
+
+ // Go to the node creation form and try to upload the test file.
+ $this->drupalGet('node/add/article');
+ $page = $session->getPage();
+ $page->attachFileToField("files[field_file_0]", $this->fileSystem->realpath($invalid_file));
+
+ // An error message should appear informing the user that the file exceeded
+ // the maximum file size.
+ $this->assertSession()->waitForElement('css', '.messages--error');
+ // The error message includes the actual file size limit which depends on
+ // the current environment, so we check for a part of the message.
+ $this->assertSession()->pageTextContains('An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size');
+
+ // Now upload a valid file and check that the error message disappears.
+ $valid_file = $this->generateFile('not_exceeding_post_max_size', 8, 8);
+ $page->attachFileToField("files[field_file_0]", $this->fileSystem->realpath($valid_file));
+ $this->assertSession()->waitForElement('named', ['id_or_name', 'field_file_0_remove_button']);
+ $this->assertSession()->elementNotExists('css', '.messages--error');
+ }
+
+}
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/tests/src/Kernel/FileUrlTest.php
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/file/tests/src/Kernel/FileUrlTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -0,0 +1,27 @@
+setSetting('file_public_base_url', $test_base_url);
+ $filepath = file_create_filename('test.txt', '');
+ $directory_uri = 'public://' . dirname($filepath);
+ file_prepare_directory($directory_uri, FILE_CREATE_DIRECTORY);
+ $file = $this->createFile($filepath, NULL, 'public');
+ $url = file_create_url($file->getFileUri());
+ $expected_url = $test_base_url . '/' . basename($filepath);
+ $this->assertSame($url, $expected_url);
+ }
+
+}
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/tests/src/Unit/Plugin/migrate/cckfield/d7/FileCckTest.php
--- a/core/modules/file/tests/src/Unit/Plugin/migrate/cckfield/d7/FileCckTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/file/tests/src/Unit/Plugin/migrate/cckfield/d7/FileCckTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -51,7 +51,7 @@
$this->plugin->processCckFieldValues($this->migration, 'somefieldname', []);
$expected = [
- 'plugin' => 'iterator',
+ 'plugin' => 'sub_process',
'source' => 'somefieldname',
'process' => [
'target_id' => 'fid',
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/tests/src/Unit/Plugin/migrate/cckfield/d7/ImageCckTest.php
--- a/core/modules/file/tests/src/Unit/Plugin/migrate/cckfield/d7/ImageCckTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/file/tests/src/Unit/Plugin/migrate/cckfield/d7/ImageCckTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -50,7 +50,7 @@
$this->plugin->processCckFieldValues($this->migration, 'somefieldname', []);
$expected = [
- 'plugin' => 'iterator',
+ 'plugin' => 'sub_process',
'source' => 'somefieldname',
'process' => [
'target_id' => 'fid',
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/tests/src/Unit/Plugin/migrate/field/d7/FileFieldTest.php
--- a/core/modules/file/tests/src/Unit/Plugin/migrate/field/d7/FileFieldTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/file/tests/src/Unit/Plugin/migrate/field/d7/FileFieldTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -50,7 +50,7 @@
$this->plugin->processFieldValues($this->migration, 'somefieldname', []);
$expected = [
- 'plugin' => 'iterator',
+ 'plugin' => 'sub_process',
'source' => 'somefieldname',
'process' => [
'target_id' => 'fid',
diff -r bfffd8d7479a -r 7a779792577d core/modules/file/tests/src/Unit/Plugin/migrate/field/d7/ImageFieldTest.php
--- a/core/modules/file/tests/src/Unit/Plugin/migrate/field/d7/ImageFieldTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/file/tests/src/Unit/Plugin/migrate/field/d7/ImageFieldTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -49,7 +49,7 @@
$this->plugin->processFieldValues($this->migration, 'somefieldname', []);
$expected = [
- 'plugin' => 'iterator',
+ 'plugin' => 'sub_process',
'source' => 'somefieldname',
'process' => [
'target_id' => 'fid',
diff -r bfffd8d7479a -r 7a779792577d core/modules/filter/filter.module
--- a/core/modules/filter/filter.module Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/filter/filter.module Fri Feb 23 15:52:07 2018 +0000
@@ -287,7 +287,7 @@
* @return \Drupal\Component\Render\MarkupInterface
* The filtered text.
*
- * @see filter_process_text()
+ * @see \Drupal\filter\Plugin\FilterInterface::process()
*
* @ingroup sanitization
*/
diff -r bfffd8d7479a -r 7a779792577d core/modules/filter/src/Plugin/FilterInterface.php
--- a/core/modules/filter/src/Plugin/FilterInterface.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/filter/src/Plugin/FilterInterface.php Fri Feb 23 15:52:07 2018 +0000
@@ -32,7 +32,7 @@
* should then actually change the content: transform URLs into hyperlinks,
* convert smileys into images, etc.
*
- * @see filter_process_text()
+ * @see \Drupal\filter\Plugin\FilterInterface::process()
* @see check_markup()
*
* Typically, only text processing is applied, but in more advanced use cases,
diff -r bfffd8d7479a -r 7a779792577d core/modules/filter/src/Plugin/migrate/process/FilterID.php
--- a/core/modules/filter/src/Plugin/migrate/process/FilterID.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/filter/src/Plugin/migrate/process/FilterID.php Fri Feb 23 15:52:07 2018 +0000
@@ -36,7 +36,7 @@
* The plugin definition.
* @param \Drupal\Component\Plugin\PluginManagerInterface $filter_manager
* The filter plugin manager.
- * @param TranslationInterface $translator
+ * @param \Drupal\Core\StringTranslation\TranslationInterface $translator
* (optional) The string translation service.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, PluginManagerInterface $filter_manager, TranslationInterface $translator = NULL) {
diff -r bfffd8d7479a -r 7a779792577d core/modules/filter/tests/src/Kernel/Plugin/migrate/process/FilterIdTest.php
--- a/core/modules/filter/tests/src/Kernel/Plugin/migrate/process/FilterIdTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/filter/tests/src/Kernel/Plugin/migrate/process/FilterIdTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -24,7 +24,7 @@
/**
* The mocked MigrateExecutable.
*
- * @var MigrateExecutableInterface|\PHPUnit_Framework_MockObject_MockObject
+ * @var \Drupal\migrate\MigrateExecutableInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $executable;
diff -r bfffd8d7479a -r 7a779792577d core/modules/forum/forum.views.inc
--- a/core/modules/forum/forum.views.inc Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/forum/forum.views.inc Fri Feb 23 15:52:07 2018 +0000
@@ -86,7 +86,6 @@
],
];
-
$data['forum_index']['created'] = [
'title' => t('Post date'),
'help' => t('The date the content was posted.'),
diff -r bfffd8d7479a -r 7a779792577d core/modules/forum/tests/src/Functional/ForumBlockTest.php
--- a/core/modules/forum/tests/src/Functional/ForumBlockTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/forum/tests/src/Functional/ForumBlockTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -52,7 +52,6 @@
// Create 5 forum topics.
$topics = $this->createForumTopics();
-
$this->assertLink(t('More'), 0, 'New forum topics block has a "more"-link.');
$this->assertLinkByHref('forum', 0, 'New forum topics block has a "more"-link.');
diff -r bfffd8d7479a -r 7a779792577d core/modules/forum/tests/src/Functional/ForumIndexTest.php
--- a/core/modules/forum/tests/src/Functional/ForumIndexTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/forum/tests/src/Functional/ForumIndexTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -69,7 +69,6 @@
$this->assertCacheTag('taxonomy_term:' . $tid);
$this->assertCacheTag('taxonomy_term:' . $tid_child);
-
// Unpublish the node.
$edit = ['status[value]' => FALSE];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
diff -r bfffd8d7479a -r 7a779792577d core/modules/forum/tests/src/Functional/ForumNodeAccessTest.php
--- a/core/modules/forum/tests/src/Functional/ForumNodeAccessTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/forum/tests/src/Functional/ForumNodeAccessTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -61,7 +61,6 @@
$public_node = $this->drupalGetNodeByTitle($public_node_title);
$this->assertTrue(!empty($public_node), 'New public forum node found in database.');
-
// Enable the new and active forum blocks.
$this->drupalPlaceBlock('forum_active_block');
$this->drupalPlaceBlock('forum_new_block');
diff -r bfffd8d7479a -r 7a779792577d core/modules/hal/tests/src/Functional/EntityResource/Comment/CommentHalJsonTestBase.php
--- a/core/modules/hal/tests/src/Functional/EntityResource/Comment/CommentHalJsonTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/hal/tests/src/Functional/EntityResource/Comment/CommentHalJsonTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -58,7 +58,7 @@
// User entity without a UUID, we cannot use it.
$author = User::load($this->entity->getOwnerId());
$commented_entity = EntityTest::load(1);
- return $normalization + [
+ return $normalization + [
'_links' => [
'self' => [
'href' => $this->baseUrl . '/comment/1?_format=hal_json',
diff -r bfffd8d7479a -r 7a779792577d core/modules/hal/tests/src/Functional/EntityResource/EntityTest/EntityTestHalJsonAnonTest.php
--- a/core/modules/hal/tests/src/Functional/EntityResource/EntityTest/EntityTestHalJsonAnonTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/hal/tests/src/Functional/EntityResource/EntityTest/EntityTestHalJsonAnonTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -39,7 +39,7 @@
$normalization = $this->applyHalFieldNormalization($default_normalization);
$author = User::load(0);
- return $normalization + [
+ return $normalization + [
'_links' => [
'self' => [
'href' => $this->baseUrl . '/entity_test/1?_format=hal_json',
diff -r bfffd8d7479a -r 7a779792577d core/modules/hal/tests/src/Functional/EntityResource/HalEntityNormalizationTrait.php
--- a/core/modules/hal/tests/src/Functional/EntityResource/HalEntityNormalizationTrait.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/hal/tests/src/Functional/EntityResource/HalEntityNormalizationTrait.php Fri Feb 23 15:52:07 2018 +0000
@@ -97,7 +97,6 @@
if ($this->entity->getEntityType()->hasKey('bundle')) {
$normalization = $this->getNormalizedPostEntity();
-
$normalization['_links']['type'] = Url::fromUri('base:rest/type/' . static::$entityTypeId . '/bad_bundle_name');
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
@@ -105,11 +104,9 @@
$response = $this->request($method, $url, $request_options);
$this->assertResourceErrorResponse(422, 'No entity type(s) specified', $response);
-
unset($normalization['_links']['type']);
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
-
// DX: 422 when no entity type bundle is specified.
$response = $this->request($method, $url, $request_options);
$this->assertResourceErrorResponse(422, 'The type link relation must be specified.', $response);
diff -r bfffd8d7479a -r 7a779792577d core/modules/hal/tests/src/Functional/EntityResource/Node/NodeHalJsonAnonTest.php
--- a/core/modules/hal/tests/src/Functional/EntityResource/Node/NodeHalJsonAnonTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/hal/tests/src/Functional/EntityResource/Node/NodeHalJsonAnonTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -52,7 +52,7 @@
$normalization = $this->applyHalFieldNormalization($default_normalization);
$author = User::load($this->entity->getOwnerId());
- return $normalization + [
+ return $normalization + [
'_links' => [
'self' => [
'href' => $this->baseUrl . '/llama?_format=hal_json',
diff -r bfffd8d7479a -r 7a779792577d core/modules/help/tests/src/Functional/HelpTest.php
--- a/core/modules/help/tests/src/Functional/HelpTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/help/tests/src/Functional/HelpTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -24,6 +24,8 @@
/**
* Use the Standard profile to test help implementations of many core modules.
+ *
+ * @var string
*/
protected $profile = 'standard';
diff -r bfffd8d7479a -r 7a779792577d core/modules/history/tests/src/Kernel/Views/HistoryTimestampTest.php
--- a/core/modules/history/tests/src/Kernel/Views/HistoryTimestampTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/history/tests/src/Kernel/Views/HistoryTimestampTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -81,7 +81,6 @@
'timestamp' => REQUEST_TIME + 100,
])->execute();
-
$column_map = [
'nid' => 'nid',
];
diff -r bfffd8d7479a -r 7a779792577d core/modules/image/src/ImageEffectInterface.php
--- a/core/modules/image/src/ImageEffectInterface.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/image/src/ImageEffectInterface.php Fri Feb 23 15:52:07 2018 +0000
@@ -50,8 +50,7 @@
public function transformDimensions(array &$dimensions, $uri);
/**
- * Returns the extension the derivative would have have after applying this
- * image effect.
+ * Returns the extension of the derivative after applying this image effect.
*
* @param string $extension
* The file extension the derivative has before applying.
diff -r bfffd8d7479a -r 7a779792577d core/modules/image/src/Tests/ImageDimensionsTest.php
--- a/core/modules/image/src/Tests/ImageDimensionsTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/image/src/Tests/ImageDimensionsTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -173,7 +173,6 @@
$this->assertResponse(200, 'Image was generated at the URL.');
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
-
// Add a crop effect.
$effect = [
'id' => 'image_crop',
@@ -208,14 +207,18 @@
$effect_id = $style->addImageEffect($effect);
$style->save();
- $this->assertEqual($this->getImageTag($variables), '
');
+ // @todo Uncomment this once
+ // https://www.drupal.org/project/drupal/issues/2670966 is resolved.
+ // $this->assertEqual($this->getImageTag($variables), '
');
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$this->drupalGet($this->getAbsoluteUrl($url));
$this->assertResponse(200, 'Image was generated at the URL.');
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
$image_file = $image_factory->get($generated_uri);
- $this->assertEqual($image_file->getWidth(), 41);
- $this->assertEqual($image_file->getHeight(), 41);
+ // @todo Uncomment this once
+ // https://www.drupal.org/project/drupal/issues/2670966 is resolved.
+ // $this->assertEqual($image_file->getWidth(), 41);
+ // $this->assertEqual($image_file->getHeight(), 41);
$effect_plugin = $style->getEffect($effect_id);
$style->deleteImageEffect($effect_plugin);
diff -r bfffd8d7479a -r 7a779792577d core/modules/image/src/Tests/ImageFieldValidateTest.php
--- a/core/modules/image/src/Tests/ImageFieldValidateTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/image/src/Tests/ImageFieldValidateTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -156,4 +156,26 @@
];
}
+ /**
+ * Test the validation message is displayed only once for ajax uploads.
+ */
+ public function testAJAXValidationMessage() {
+ $field_name = strtolower($this->randomMachineName());
+ $this->createImageField($field_name, 'article', ['cardinality' => -1]);
+
+ $this->drupalGet('node/add/article');
+ /** @var \Drupal\file\FileInterface[] $text_files */
+ $text_files = $this->drupalGetTestFiles('text');
+ $text_file = reset($text_files);
+ $edit = [
+ 'files[' . $field_name . '_0][]' => $this->container->get('file_system')->realpath($text_file->uri),
+ 'title[0][value]' => $this->randomMachineName(),
+ ];
+ $this->drupalPostAjaxForm(NULL, $edit, $field_name . '_0_upload_button');
+ $elements = $this->xpath('//div[contains(@class, :class)]', [
+ ':class' => 'messages--error',
+ ]);
+ $this->assertEqual(count($elements), 1, 'Ajax validation messages are displayed once.');
+ }
+
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/language/language.module
--- a/core/modules/language/language.module Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/language/language.module Fri Feb 23 15:52:07 2018 +0000
@@ -193,7 +193,7 @@
$bundle = $values['bundle'];
$form_object = $form_state->getFormObject();
if ($form_object instanceof EntityFormInterface) {
- /** @var EntityFormInterface $form_object */
+ /** @var \Drupal\Core\Entity\EntityFormInterface $form_object */
$entity = $form_object->getEntity();
if ($entity->getEntityType()->getBundleOf()) {
$bundle = $entity->id();
diff -r bfffd8d7479a -r 7a779792577d core/modules/language/src/EventSubscriber/ConfigSubscriber.php
--- a/core/modules/language/src/EventSubscriber/ConfigSubscriber.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/language/src/EventSubscriber/ConfigSubscriber.php Fri Feb 23 15:52:07 2018 +0000
@@ -81,7 +81,7 @@
* then this event must be changed to work with both the old and new schema
* definition so this event is update safe.
*
- * @param ConfigCrudEvent $event
+ * @param \Drupal\Core\Config\ConfigCrudEvent $event
* The configuration event.
*/
public function onConfigSave(ConfigCrudEvent $event) {
diff -r bfffd8d7479a -r 7a779792577d core/modules/language/src/EventSubscriber/LanguageRequestSubscriber.php
--- a/core/modules/language/src/EventSubscriber/LanguageRequestSubscriber.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/language/src/EventSubscriber/LanguageRequestSubscriber.php Fri Feb 23 15:52:07 2018 +0000
@@ -41,7 +41,7 @@
/**
* The current active user.
*
- * @return \Drupal\Core\Session\AccountInterface
+ * @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
diff -r bfffd8d7479a -r 7a779792577d core/modules/language/src/Form/NegotiationConfigureForm.php
--- a/core/modules/language/src/Form/NegotiationConfigureForm.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/language/src/Form/NegotiationConfigureForm.php Fri Feb 23 15:52:07 2018 +0000
@@ -213,7 +213,7 @@
* @param string $type
* The language type to generate the table for.
*/
- protected function configureFormTable(array &$form, $type) {
+ protected function configureFormTable(array &$form, $type) {
$info = $form['#language_types_info'][$type];
$table_form = [
diff -r bfffd8d7479a -r 7a779792577d core/modules/language/src/LanguageNegotiationMethodBase.php
--- a/core/modules/language/src/LanguageNegotiationMethodBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/language/src/LanguageNegotiationMethodBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -28,7 +28,7 @@
/**
* The current active user.
*
- * @return \Drupal\Core\Session\AccountInterface
+ * @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
diff -r bfffd8d7479a -r 7a779792577d core/modules/language/src/LanguageNegotiator.php
--- a/core/modules/language/src/LanguageNegotiator.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/language/src/LanguageNegotiator.php Fri Feb 23 15:52:07 2018 +0000
@@ -38,7 +38,7 @@
/**
* The settings instance.
*
- * @return \Drupal\Core\Site\Settings
+ * @var \Drupal\Core\Site\Settings
*/
protected $settings;
@@ -52,7 +52,7 @@
/**
* The current active user.
*
- * @return \Drupal\Core\Session\AccountInterface
+ * @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
diff -r bfffd8d7479a -r 7a779792577d core/modules/language/tests/src/Functional/LanguageConfigurationTest.php
--- a/core/modules/language/tests/src/Functional/LanguageConfigurationTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/language/tests/src/Functional/LanguageConfigurationTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -198,7 +198,7 @@
* @return int
* Maximum weight of configurable languages.
*/
- protected function getHighestConfigurableLanguageWeight(){
+ protected function getHighestConfigurableLanguageWeight() {
$max_weight = 0;
$storage = $this->container->get('entity_type.manager')
diff -r bfffd8d7479a -r 7a779792577d core/modules/link/tests/src/Unit/Plugin/Validation/Constraint/LinkNotExistingInternalConstraintValidatorTest.php
--- a/core/modules/link/tests/src/Unit/Plugin/Validation/Constraint/LinkNotExistingInternalConstraintValidatorTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/link/tests/src/Unit/Plugin/Validation/Constraint/LinkNotExistingInternalConstraintValidatorTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -31,7 +31,6 @@
->method('addViolation');
}
-
$constraint = new LinkNotExistingInternalConstraint();
$validator = new LinkNotExistingInternalConstraintValidator();
diff -r bfffd8d7479a -r 7a779792577d core/modules/locale/locale.post_update.php
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/locale/locale.post_update.php Fri Feb 23 15:52:07 2018 +0000
@@ -0,0 +1,13 @@
+setLanguageName($language_name);
$writer = new PoStreamWriter();
- $writer->setUri($uri);
+ $writer->setURI($uri);
$writer->setHeader($header);
$writer->open();
diff -r bfffd8d7479a -r 7a779792577d core/modules/locale/src/Form/TranslationStatusForm.php
--- a/core/modules/locale/src/Form/TranslationStatusForm.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/locale/src/Form/TranslationStatusForm.php Fri Feb 23 15:52:07 2018 +0000
@@ -40,7 +40,7 @@
/**
* Constructs a TranslationStatusForm object.
*
- * @param ModuleHandlerInterface $module_handler
+ * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* A module handler.
* @param \Drupal\Core\State\StateInterface $state
* The state service.
diff -r bfffd8d7479a -r 7a779792577d core/modules/locale/src/LocaleLookup.php
--- a/core/modules/locale/src/LocaleLookup.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/locale/src/LocaleLookup.php Fri Feb 23 15:52:07 2018 +0000
@@ -7,6 +7,7 @@
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Lock\LockBackendInterface;
+use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
use Symfony\Component\HttpFoundation\RequestStack;
/**
@@ -172,6 +173,12 @@
}
}
+ if (is_string($value) && strpos($value, PluralTranslatableMarkup::DELIMITER) !== FALSE) {
+ // Community translations imported from localize.drupal.org as well as
+ // migrated translations may contain @count[number].
+ $value = preg_replace('!@count\[\d+\]!', '@count', $value);
+ }
+
$this->storage[$offset] = $value;
// Disabling the usage of string caching allows a module to watch for
// the exact list of strings used on a page. From a performance
diff -r bfffd8d7479a -r 7a779792577d core/modules/locale/tests/src/Functional/LocaleFileSystemFormTest.php
--- a/core/modules/locale/tests/src/Functional/LocaleFileSystemFormTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/locale/tests/src/Functional/LocaleFileSystemFormTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -21,7 +21,7 @@
/**
* {@inheritdoc}
*/
- protected function setUp(){
+ protected function setUp() {
parent::setUp();
$account = $this->drupalCreateUser(['administer site configuration']);
$this->drupalLogin($account);
diff -r bfffd8d7479a -r 7a779792577d core/modules/locale/tests/src/Functional/LocaleLocaleLookupTest.php
--- a/core/modules/locale/tests/src/Functional/LocaleLocaleLookupTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/locale/tests/src/Functional/LocaleLocaleLookupTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -2,6 +2,7 @@
namespace Drupal\Tests\locale\Functional;
+use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\BrowserTestBase;
@@ -55,4 +56,45 @@
$this->assertEqual($context['operation'], 'locale_lookup');
}
+ /**
+ * Test old plural style @count[number] fix.
+ *
+ * @dataProvider providerTestFixOldPluralStyle
+ */
+ public function testFixOldPluralStyle($translation_value, $expected) {
+ $string_storage = \Drupal::service('locale.storage');
+ $string = $string_storage->findString(['source' => 'Member for', 'context' => '']);
+ $lid = $string->getId();
+ $string_storage->createTranslation([
+ 'lid' => $lid,
+ 'language' => 'fr',
+ 'translation' => $translation_value,
+ ])->save();
+ _locale_refresh_translations(['fr'], [$lid]);
+
+ // Check that 'count[2]' was fixed for render value.
+ $this->drupalGet('');
+ $this->assertSession()->pageTextContains($expected);
+
+ // Check that 'count[2]' was saved for source value.
+ $translation = $string_storage->findTranslation(['language' => 'fr', 'lid' => $lid])->translation;
+ $this->assertSame($translation_value, $translation, 'Source value not changed');
+ $this->assertNotFalse(strpos($translation, '@count[2]'), 'Source value contains @count[2]');
+ }
+
+ /**
+ * Provides data for testFixOldPluralStyle().
+ *
+ * @return array
+ * An array of test data:
+ * - translation value
+ * - expected result
+ */
+ public function providerTestFixOldPluralStyle() {
+ return [
+ 'non-plural translation' => ['@count[2] non-plural test', '@count[2] non-plural test'],
+ 'plural translation' => ['@count[2] plural test' . PluralTranslatableMarkup::DELIMITER, '@count plural test'],
+ ];
+ }
+
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/locale/tests/src/Unit/LocaleLookupTest.php
--- a/core/modules/locale/tests/src/Unit/LocaleLookupTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/locale/tests/src/Unit/LocaleLookupTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -3,6 +3,7 @@
namespace Drupal\Tests\locale\Unit;
use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
use Drupal\locale\LocaleLookup;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
@@ -266,4 +267,66 @@
$this->assertTrue($locale_lookup->get('test'));
}
+ /**
+ * Tests locale lookups with old plural style of translations.
+ *
+ * @param array $translations
+ * The source with translations.
+ * @param string $langcode
+ * The language code of translation string.
+ * @param string $string
+ * The string for translation.
+ * @param bool $is_fix
+ * The flag about expected fix translation.
+ *
+ * @covers ::resolveCacheMiss
+ * @dataProvider providerFixOldPluralTranslationProvider
+ */
+ public function testFixOldPluralStyleTranslations($translations, $langcode, $string, $is_fix) {
+ $this->storage->expects($this->any())
+ ->method('findTranslation')
+ ->will($this->returnCallback(function ($argument) use ($translations) {
+ if (isset($translations[$argument['language']][$argument['source']])) {
+ return (object) ['translation' => $translations[$argument['language']][$argument['source']]];
+ }
+ return TRUE;
+ }));
+ $this->languageManager->expects($this->any())
+ ->method('getFallbackCandidates')
+ ->will($this->returnCallback(function (array $context = []) {
+ switch ($context['langcode']) {
+ case 'by':
+ return ['ru'];
+ }
+ }));
+ $this->cache->expects($this->once())
+ ->method('get')
+ ->with('locale:' . $langcode . '::anonymous', FALSE);
+
+ $locale_lookup = new LocaleLookup($langcode, '', $this->storage, $this->cache, $this->lock, $this->configFactory, $this->languageManager, $this->requestStack);
+ $this->assertSame($is_fix, strpos($locale_lookup->get($string), '@count[2]') === FALSE);
+ }
+
+ /**
+ * Provides test data for testResolveCacheMissWithFallback().
+ */
+ public function providerFixOldPluralTranslationProvider() {
+ $translations = [
+ 'by' => [
+ 'word1' => '@count[2] word-by',
+ 'word2' => implode(PluralTranslatableMarkup::DELIMITER, ['word-by', '@count[2] word-by']),
+ ],
+ 'ru' => [
+ 'word3' => '@count[2] word-ru',
+ 'word4' => implode(PluralTranslatableMarkup::DELIMITER, ['word-ru', '@count[2] word-ru']),
+ ],
+ ];
+ return [
+ 'no-plural' => [$translations, 'by', 'word1', FALSE],
+ 'no-plural from other language' => [$translations, 'by', 'word3', FALSE],
+ 'plural' => [$translations, 'by', 'word2', TRUE],
+ 'plural from other language' => [$translations, 'by', 'word4', TRUE],
+ ];
+ }
+
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/media/config/install/core.entity_view_display.media.file.default.yml
--- a/core/modules/media/config/install/core.entity_view_display.media.file.default.yml Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/media/config/install/core.entity_view_display.media.file.default.yml Fri Feb 23 15:52:07 2018 +0000
@@ -16,8 +16,16 @@
settings: { }
third_party_settings: { }
type: file_default
+ weight: 1
+ region: content
+ name:
+ label: hidden
+ type: string
weight: 0
region: content
+ settings:
+ link_to_entity: false
+ third_party_settings: { }
hidden:
created: true
thumbnail: true
diff -r bfffd8d7479a -r 7a779792577d core/modules/media/config/install/core.entity_view_display.media.image.default.yml
--- a/core/modules/media/config/install/core.entity_view_display.media.image.default.yml Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/media/config/install/core.entity_view_display.media.image.default.yml Fri Feb 23 15:52:07 2018 +0000
@@ -19,8 +19,16 @@
image_link: file
third_party_settings: { }
type: image
+ weight: 1
+ region: content
+ name:
+ label: hidden
+ type: string
weight: 0
region: content
+ settings:
+ link_to_entity: false
+ third_party_settings: { }
hidden:
created: true
thumbnail: true
diff -r bfffd8d7479a -r 7a779792577d core/modules/media/src/Entity/Media.php
--- a/core/modules/media/src/Entity/Media.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/media/src/Entity/Media.php Fri Feb 23 15:52:07 2018 +0000
@@ -404,6 +404,7 @@
'weight' => -5,
])
->setDisplayConfigurable('form', TRUE)
+ ->setDisplayConfigurable('view', TRUE)
->setDisplayOptions('view', [
'label' => 'hidden',
'type' => 'string',
diff -r bfffd8d7479a -r 7a779792577d core/modules/media/tests/src/Kernel/MediaTest.php
--- a/core/modules/media/tests/src/Kernel/MediaTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/media/tests/src/Kernel/MediaTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -20,4 +20,15 @@
$this->assertSame($media, $media->setOwnerId($this->user->id()), 'setOwnerId() method returns its own entity.');
}
+ /**
+ * Ensure media name is configurable on manage display.
+ */
+ public function testNameIsConfigurable() {
+ /** @var \Drupal\Core\Field\BaseFieldDefinition[] $field_definitions */
+ $field_definitions = $this->container->get('entity_field.manager')
+ ->getBaseFieldDefinitions('media');
+
+ $this->assertTrue($field_definitions['name']->isDisplayConfigurable('view'));
+ }
+
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/menu_link_content/src/Entity/MenuLinkContent.php
--- a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php Fri Feb 23 15:52:07 2018 +0000
@@ -316,7 +316,7 @@
->setDefaultValue(0)
->setDisplayOptions('view', [
'label' => 'hidden',
- 'type' => 'integer',
+ 'type' => 'number_integer',
'weight' => 0,
])
->setDisplayOptions('form', [
diff -r bfffd8d7479a -r 7a779792577d core/modules/menu_link_content/tests/src/Functional/LinksTest.php
--- a/core/modules/menu_link_content/tests/src/Functional/LinksTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/menu_link_content/tests/src/Functional/LinksTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -127,6 +127,7 @@
'menu_name' => 'menu_test',
'bundle' => 'menu_link_content',
'link' => [['uri' => 'internal:/']],
+ 'title' => 'Link test',
];
$link = MenuLinkContent::create($options);
$link->save();
@@ -148,7 +149,12 @@
public function testMenuLinkOnEntityDelete() {
$user = User::create(['name' => 'username']);
$user->save();
- $menu_link_content = MenuLinkContent::create(['menu_name' => 'menu_test', 'link' => [['uri' => 'entity:user/' . $user->id()]], 'bundle' => 'menu_test']);
+ $menu_link_content = MenuLinkContent::create([
+ 'title' => 'username profile',
+ 'menu_name' => 'menu_test',
+ 'link' => [['uri' => 'entity:user/' . $user->id()]],
+ 'bundle' => 'menu_test',
+ ]);
$menu_link_content->save();
$menu_tree_condition = (new MenuTreeParameters())->addCondition('route_name', 'entity.user.canonical');
$this->assertCount(1, \Drupal::menuTree()->load('menu_test', $menu_tree_condition));
diff -r bfffd8d7479a -r 7a779792577d core/modules/menu_link_content/tests/src/Functional/MenuLinkContentTranslationUITest.php
--- a/core/modules/menu_link_content/tests/src/Functional/MenuLinkContentTranslationUITest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/menu_link_content/tests/src/Functional/MenuLinkContentTranslationUITest.php Fri Feb 23 15:52:07 2018 +0000
@@ -70,7 +70,11 @@
$this->drupalGet('admin/structure/menu/manage/tools');
$this->assertNoLink(t('Translate'));
- $menu_link_content = MenuLinkContent::create(['menu_name' => 'tools', 'link' => ['uri' => 'internal:/admin/structure/menu']]);
+ $menu_link_content = MenuLinkContent::create([
+ 'menu_name' => 'tools',
+ 'link' => ['uri' => 'internal:/admin/structure/menu'],
+ 'title' => 'Link test',
+ ]);
$menu_link_content->save();
$this->drupalGet('admin/structure/menu/manage/tools');
$this->assertLink(t('Translate'));
diff -r bfffd8d7479a -r 7a779792577d core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php
--- a/core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -59,7 +59,6 @@
$menu_tree = \Drupal::menuTree();
$renderer = \Drupal::service('renderer');
-
$default_menu_cacheability = (new BubbleableMetadata())
->setCacheMaxAge(Cache::PERMANENT)
->setCacheTags(['config:system.menu.tools'])
@@ -109,6 +108,7 @@
$menu_link_content = MenuLinkContent::create([
'link' => ['uri' => $expectation['uri']],
'menu_name' => 'tools',
+ 'title' => 'Link test',
]);
$menu_link_content->save();
$tree = $menu_tree->load('tools', new MenuTreeParameters());
@@ -129,6 +129,7 @@
$menu_link_content = MenuLinkContent::create([
'link' => ['uri' => $expectation['uri']],
'menu_name' => 'tools',
+ 'title' => 'Link test',
]);
$menu_link_content->save();
$expected_cacheability = $expected_cacheability->merge($expectation['cacheability']);
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/src/Annotation/MigrateProcessPlugin.php
--- a/core/modules/migrate/src/Annotation/MigrateProcessPlugin.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/src/Annotation/MigrateProcessPlugin.php Fri Feb 23 15:52:07 2018 +0000
@@ -36,7 +36,7 @@
* Whether the plugin handles multiples itself.
*
* Typically these plugins will expect an array as input and iterate over it
- * themselves, changing the whole array. For example the 'iterator' and the
+ * themselves, changing the whole array. For example the 'sub_process' and the
* 'flatten' plugins. If the plugin only need to change a single value it
* can skip setting this attribute and let
* \Drupal\migrate\MigrateExecutable::processRow() handle the iteration.
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/src/Plugin/MigrateSourceInterface.php
--- a/core/modules/migrate/src/Plugin/MigrateSourceInterface.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/src/Plugin/MigrateSourceInterface.php Fri Feb 23 15:52:07 2018 +0000
@@ -53,9 +53,12 @@
* An associative array of field definitions keyed by field ID. Values are
* associative arrays with a structure that contains the field type ('type'
* key). The other keys are the field storage settings as they are returned
- * by FieldStorageDefinitionInterface::getSettings(). As an example, for a
- * composite source primary key that is defined by an integer and a
- * string, the returned value might look like:
+ * by FieldStorageDefinitionInterface::getSettings().
+ *
+ * Examples:
+ *
+ * A composite source primary key that is defined by an integer and a string
+ * might look like this:
* @code
* return [
* 'id' => [
@@ -70,6 +73,7 @@
* ],
* ];
* @endcode
+ *
* If 'type' points to a field plugin with multiple columns and needs to
* refer to a column different than 'value', the key of that column will be
* appended as a suffix to the plugin name, separated by dot ('.'). Example:
@@ -80,9 +84,13 @@
* ],
* ];
* @endcode
- * Additional custom keys/values, that are not part of field storage
- * definition, can be passed in definitions. The most common setting, passed
- * along the ID definition, is 'alias' used by SqlBase source plugin:
+ *
+ * Additional custom keys/values that are not part of field storage
+ * definition can be added as shown below. The most common setting
+ * passed along to the ID definition is 'alias', used by the SqlBase source
+ * plugin in order to distinguish between ambiguous column names - for
+ * example, when a SQL source query joins two tables with the same column
+ * names.
* @code
* return [
* 'nid' => [
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/src/Plugin/Migration.php
--- a/core/modules/migrate/src/Plugin/Migration.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/src/Plugin/Migration.php Fri Feb 23 15:52:07 2018 +0000
@@ -621,7 +621,7 @@
if ($plugin_configuration['plugin'] == 'migration') {
$return = array_merge($return, (array) $plugin_configuration['migration']);
}
- if ($plugin_configuration['plugin'] == 'iterator') {
+ if ($plugin_configuration['plugin'] == 'sub_process') {
$return = array_merge($return, $this->findMigrationDependencies($plugin_configuration['process']));
}
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/src/Plugin/migrate/destination/Entity.php
--- a/core/modules/migrate/src/Plugin/migrate/destination/Entity.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/src/Plugin/migrate/destination/Entity.php Fri Feb 23 15:52:07 2018 +0000
@@ -45,9 +45,9 @@
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
- * @param MigrationInterface $migration
+ * @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The migration.
- * @param EntityStorageInterface $storage
+ * @param \Drupal\Core\Entity\EntityStorageInterface $storage
* The storage for this entity type.
* @param array $bundles
* The list of bundles this entity type has.
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/src/Plugin/migrate/destination/EntityFieldInstance.php
--- a/core/modules/migrate/src/Plugin/migrate/destination/EntityFieldInstance.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/src/Plugin/migrate/destination/EntityFieldInstance.php Fri Feb 23 15:52:07 2018 +0000
@@ -3,7 +3,43 @@
namespace Drupal\migrate\Plugin\migrate\destination;
/**
- * Provides entity field instance plugin.
+ * Provides destination plugin for field_config configuration entities.
+ *
+ * The Field API defines two primary data structures, FieldStorage and Field.
+ * A FieldStorage defines a particular type of data that can be attached to
+ * entities as a Field instance.
+ *
+ * The example below adds an instance of 'field_text_example' to 'article'
+ * bundle (node content type). The example uses the EmptySource source plugin
+ * and constant source values for the sake of simplicity. For an example on how
+ * the FieldStorage 'field_text_example' can be migrated, refer to
+ * \Drupal\migrate\Plugin\migrate\destination\EntityFieldStorageConfig.
+ * @code
+ * id: field_instance_example
+ * label: Field instance example
+ * source:
+ * plugin: empty
+ * constants:
+ * entity_type: node
+ * field_name: field_text_example
+ * bundle: article
+ * label: Text field example
+ * translatable: true
+ * process:
+ * entity_type: constants/entity_type
+ * field_name: constants/field_name
+ * bundle: constants/bundle
+ * label: constants/label
+ * translatable: constants/translatable
+ * destination:
+ * plugin: entity:field_config
+ * migration_dependencies:
+ * required:
+ * - field_storage_example
+ * @endcode
+ *
+ * @see \Drupal\field\Entity\FieldConfig
+ * @see \Drupal\field\Entity\FieldConfigBase
*
* @MigrateDestination(
* id = "entity:field_config"
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/src/Plugin/migrate/destination/EntityFieldStorageConfig.php
--- a/core/modules/migrate/src/Plugin/migrate/destination/EntityFieldStorageConfig.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/src/Plugin/migrate/destination/EntityFieldStorageConfig.php Fri Feb 23 15:52:07 2018 +0000
@@ -3,7 +3,48 @@
namespace Drupal\migrate\Plugin\migrate\destination;
/**
- * Provides entity field storage configuration plugin.
+ * Provides destination plugin for field_storage_config configuration entities.
+ *
+ * The Field API defines two primary data structures, FieldStorage and Field.
+ * A FieldStorage defines a particular type of data that can be attached to
+ * entities as a Field instance.
+ *
+ * The example below creates a storage for a simple text field. The example uses
+ * the EmptySource source plugin and constant source values for the sake of
+ * simplicity.
+ * @code
+ * id: field_storage_example
+ * label: Field storage example
+ * source:
+ * plugin: empty
+ * constants:
+ * entity_type: node
+ * id: node.field_text_example
+ * field_name: field_text_example
+ * type: string
+ * cardinality: 1
+ * settings:
+ * max_length: 10
+ * langcode: en
+ * translatable: true
+ * process:
+ * entity_type: constants/entity_type
+ * id: constants/id
+ * field_name: constants/field_name
+ * type: constants/type
+ * cardinality: constants/cardinality
+ * settings: constants/settings
+ * langcode: constants/langcode
+ * translatable: constants/translatable
+ * destination:
+ * plugin: entity:field_storage_config
+ * @endcode
+ *
+ * For a full list of the properties of a FieldStorage configuration entity,
+ * refer to \Drupal\field\Entity\FieldStorageConfig.
+ *
+ * For an example on how to migrate a Field instance of this FieldStorage,
+ * refer to \Drupal\migrate\Plugin\migrate\destination\EntityFieldInstance.
*
* @MigrateDestination(
* id = "entity:field_storage_config"
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/src/Plugin/migrate/process/SubProcess.php
--- a/core/modules/migrate/src/Plugin/migrate/process/SubProcess.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/src/Plugin/migrate/process/SubProcess.php Fri Feb 23 15:52:07 2018 +0000
@@ -94,7 +94,7 @@
*
* process:
* filters:
- * plugin: iterator
+ * plugin: sub_process
* source: filters
* key: "@id"
* process:
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/src/Plugin/migrate/source/DummyQueryTrait.php
--- a/core/modules/migrate/src/Plugin/migrate/source/DummyQueryTrait.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/src/Plugin/migrate/source/DummyQueryTrait.php Fri Feb 23 15:52:07 2018 +0000
@@ -27,7 +27,7 @@
/**
* {@inheritdoc}
*/
- public function count() {
+ public function count($refresh = FALSE) {
return 1;
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/src/Plugin/migrate/source/EmptySource.php
--- a/core/modules/migrate/src/Plugin/migrate/source/EmptySource.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/src/Plugin/migrate/source/EmptySource.php Fri Feb 23 15:52:07 2018 +0000
@@ -3,9 +3,20 @@
namespace Drupal\migrate\Plugin\migrate\source;
/**
- * Source returning an empty row.
+ * Source returning a row based on the constants provided.
*
- * This is generally useful when needing to create a field using a migration..
+ * Example:
+ *
+ * @code
+ * source:
+ * plugin: empty
+ * constants:
+ * entity_type: user
+ * field_name: image
+ * @endcode
+ *
+ * This will return a single row containing 'entity_type' and 'field_name'
+ * elements, with values of 'user' and 'image', respectively.
*
* @MigrateSource(
* id = "empty"
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/src/Plugin/migrate/source/SourcePluginBase.php
--- a/core/modules/migrate/src/Plugin/migrate/source/SourcePluginBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/src/Plugin/migrate/source/SourcePluginBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -436,7 +436,10 @@
* Returns -1 if the source is not countable.
*
* @param bool $refresh
- * (optional) Whether or not to refresh the count. Defaults to FALSE.
+ * (optional) Whether or not to refresh the count. Defaults to FALSE. Not
+ * all implementations support the reset flag. In such instances this
+ * parameter is ignored and the result of calling the method will always be
+ * up to date.
*
* @return int
* The count.
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/src/Plugin/migrate/source/SqlBase.php
--- a/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -17,35 +17,48 @@
/**
* Sources whose data may be fetched via a database connection.
*
- * Database configuration, which may appear either within the source plugin
- * configuration or in state, is structured as follows:
+ * Available configuration keys:
+ * - database_state_key: (optional) Name of the state key which contains an
+ * array with database connection information.
+ * - key: (optional) The database key name. Defaults to 'migrate'.
+ * - target: (optional) The database target name. Defaults to 'default'.
+ * - batch_size: (optional) Number of records to fetch from the database during
+ * each batch. If omitted, all records are fetched in a single query.
+ * - ignore_map: (optional) Source data is joined to the map table by default.
+ * If set to TRUE, the map table will not be joined.
*
- * 'key' - The database key name (defaults to 'migrate').
- * 'target' - The database target name (defaults to 'default').
- * 'database' - Database connection information as accepted by
- * Database::addConnectionInfo(). If not present, the key/target is assumed
- * to already be defined (e.g., in settings.php).
+ * For other optional configuration keys inherited from the parent class, refer
+ * to \Drupal\migrate\Plugin\migrate\source\SourcePluginBase.
*
- * This configuration info is obtained in the following order:
+ * About the source database determination:
+ * - If the source plugin configuration contains 'database_state_key', its value
+ * is taken as the name of a state key which contains an array with the
+ * database configuration.
+ * - Otherwise, if the source plugin configuration contains 'key', the database
+ * configuration with that name is used.
+ * - If both 'database_state_key' and 'key' are omitted in the source plugin
+ * configuration, the database connection named 'migrate' is used by default.
+ * - If all of the above steps fail, RequirementsException is thrown.
*
- * 1. If the source plugin configuration contains a key 'database_state_key',
- * its value is taken as the name of a state key which contains an array
- * with the above database configuration.
- * 2. Otherwise, if the source plugin configuration contains 'key', the above
- * database configuration is obtained directly from the plugin configuration.
- * 3. Otherwise, if the state 'migrate.fallback_state_key' exists, its value is
- * taken as the name of a state key which contains an array with the above
- * database configuration.
- * 4. Otherwise, if a connection named 'migrate' exists, that is used as the
- * database connection.
- * 5. Otherwise, RequirementsException is thrown.
+ * Drupal Database API supports multiple database connections. The connection
+ * parameters are defined in $databases array in settings.php or
+ * settings.local.php. It is also possible to modify the $databases array in
+ * runtime. For example, Migrate Drupal, which provides the migrations from
+ * Drupal 6 / 7, asks for the source database connection parameters in the UI
+ * and then adds the $databases['migrate'] connection in runtime before the
+ * migrations are executed.
*
- * It is strongly recommended that database connections be explicitly defined
- * via 'database_state_key' or in the source plugin configuration. Defining
- * migrate.fallback_state_key or a 'migrate' connection affects not only any
- * migrations intended to use that particular connection, but all
- * SqlBase-derived source plugins which do not have explicit database
- * configuration.
+ * As described above, the default source database is $databases['migrate']. If
+ * the source plugin needs another source connection, the database connection
+ * parameters should be added to the $databases array as, for instance,
+ * $databases['foo']. The source plugin can then use this connection by setting
+ * 'key' to 'foo' in its configuration.
+ *
+ * For a complete example on migrating data from an SQL source, refer to
+ * https://www.drupal.org/docs/8/api/migrate-api/migrating-data-from-sql-source
+ *
+ * @see https://www.drupal.org/docs/8/api/database-api
+ * @see \Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase
*/
abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPluginInterface, RequirementsInterface {
@@ -365,7 +378,7 @@
/**
* {@inheritdoc}
*/
- public function count() {
+ public function count($refresh = FALSE) {
return $this->query()->countQuery()->execute()->fetchField();
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/tests/src/Kernel/MigrateBundleTest.php
--- a/core/modules/migrate/tests/src/Kernel/MigrateBundleTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/tests/src/Kernel/MigrateBundleTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -66,7 +66,7 @@
// Import and validate the term entity was created with the correct bundle.
$term_executable = new MigrateExecutable($term_migration, $this);
$term_executable->import();
- /** @var Term $term */
+ /** @var \Drupal\taxonomy\Entity\Term $term */
$term = Term::load(1);
$this->assertEquals($term->bundle(), 'categories');
}
@@ -104,7 +104,7 @@
// Import and validate the term entities were created with the correct bundle.
$term_executable = new MigrateExecutable($term_migration, $this);
$term_executable->import();
- /** @var Term $term */
+ /** @var \Drupal\taxonomy\Entity\Term $term */
$term = Term::load(1);
$this->assertEquals($term->bundle(), 'categories');
$term = Term::load(2);
@@ -146,7 +146,7 @@
// Import and validate the term entities were created with the correct bundle.
$term_executable = new MigrateExecutable($term_migration, $this);
$term_executable->import();
- /** @var Term $term */
+ /** @var \Drupal\taxonomy\Entity\Term $term */
$term = Term::load(1);
$this->assertEquals($term->bundle(), 'categories');
$term = Term::load(2);
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/tests/src/Kernel/MigrateRollbackTest.php
--- a/core/modules/migrate/tests/src/Kernel/MigrateRollbackTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/tests/src/Kernel/MigrateRollbackTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -69,7 +69,7 @@
$vocabulary_executable = new MigrateExecutable($vocabulary_migration, $this);
$vocabulary_executable->import();
foreach ($vocabulary_data_rows as $row) {
- /** @var Vocabulary $vocabulary */
+ /** @var \Drupal\taxonomy\Entity\Vocabulary $vocabulary */
$vocabulary = Vocabulary::load($row['id']);
$this->assertTrue($vocabulary);
$map_row = $vocabulary_id_map->getRowBySource(['id' => $row['id']]);
@@ -122,7 +122,7 @@
$map_row['source_row_status'], MigrateIdMapInterface::ROLLBACK_PRESERVE);
foreach ($term_data_rows as $row) {
- /** @var Term $term */
+ /** @var \Drupal\taxonomy\Entity\Term $term */
$term = Term::load($row['id']);
$this->assertTrue($term);
$map_row = $term_id_map->getRowBySource(['id' => $row['id']]);
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/tests/src/Kernel/MigrateSourceTestBase.php
--- a/core/modules/migrate/tests/src/Kernel/MigrateSourceTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/tests/src/Kernel/MigrateSourceTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -20,7 +20,7 @@
/**
* The mocked migration.
*
- * @var MigrationInterface|\Prophecy\Prophecy\ObjectProphecy
+ * @var \Drupal\migrate\Plugin\MigrationInterface|\Prophecy\Prophecy\ObjectProphecy
*/
protected $migration;
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/tests/src/Kernel/Plugin/MigrationTest.php
--- a/core/modules/migrate/tests/src/Kernel/Plugin/MigrationTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/tests/src/Kernel/Plugin/MigrationTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -42,7 +42,7 @@
'migration' => 'm1'
],
'f3' => [
- 'plugin' => 'iterator',
+ 'plugin' => 'sub_process',
'process' => [
'target_id' => [
'plugin' => 'migration',
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/tests/src/Kernel/QueryBatchTest.php
--- a/core/modules/migrate/tests/src/Kernel/QueryBatchTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/tests/src/Kernel/QueryBatchTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -19,7 +19,7 @@
/**
* The mocked migration.
*
- * @var MigrationInterface|\Prophecy\Prophecy\ObjectProphecy
+ * @var \Drupal\migrate\Plugin\MigrationInterface|\Prophecy\Prophecy\ObjectProphecy
*/
protected $migration;
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate/tests/src/Unit/MigrationPluginManagerTest.php
--- a/core/modules/migrate/tests/src/Unit/MigrationPluginManagerTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate/tests/src/Unit/MigrationPluginManagerTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -15,7 +15,7 @@
/**
* A plugin manager.
*
- * @param \Drupal\migrate\Plugin\MigrationPluginManager $pluginManager
+ * @var \Drupal\migrate\Plugin\MigrationPluginManager
*/
protected $pluginManager;
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate_drupal/src/Plugin/migrate/destination/EntityFieldStorageConfig.php
--- a/core/modules/migrate_drupal/src/Plugin/migrate/destination/EntityFieldStorageConfig.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/destination/EntityFieldStorageConfig.php Fri Feb 23 15:52:07 2018 +0000
@@ -43,7 +43,7 @@
* The plugin implementation definition.
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The migration.
- * @param EntityStorageInterface $storage
+ * @param \Drupal\Core\Entity\EntityStorageInterface $storage
* The storage for this entity type.
* @param array $bundles
* The list of bundles this entity type has.
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate_drupal/src/Plugin/migrate/field/NodeReference.php
--- a/core/modules/migrate_drupal/src/Plugin/migrate/field/NodeReference.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/field/NodeReference.php Fri Feb 23 15:52:07 2018 +0000
@@ -20,7 +20,7 @@
*/
public function processFieldValues(MigrationInterface $migration, $field_name, $data) {
$process = [
- 'plugin' => 'iterator',
+ 'plugin' => 'sub_process',
'source' => $field_name,
'process' => [
'target_id' => [
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate_drupal/src/Plugin/migrate/field/UserReference.php
--- a/core/modules/migrate_drupal/src/Plugin/migrate/field/UserReference.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/field/UserReference.php Fri Feb 23 15:52:07 2018 +0000
@@ -20,7 +20,7 @@
*/
public function processFieldValues(MigrationInterface $migration, $field_name, $data) {
$process = [
- 'plugin' => 'iterator',
+ 'plugin' => 'sub_process',
'source' => $field_name,
'process' => [
'target_id' => [
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate_drupal/src/Plugin/migrate/source/DrupalSqlBase.php
--- a/core/modules/migrate_drupal/src/Plugin/migrate/source/DrupalSqlBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/DrupalSqlBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -13,10 +13,19 @@
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
- * A base source class for Drupal migrate sources.
+ * A base class for source plugins using a Drupal database as a source.
*
- * Mainly to let children retrieve information from the origin system in an
- * easier way.
+ * Provides general purpose helper methods that are commonly needed
+ * when writing source plugins that use a Drupal database as a source, for
+ * example:
+ * - Check if the given module exists in the source database.
+ * - Read Drupal configuration variables from the source database.
+ *
+ * For a full list, refer to the methods of this class.
+ *
+ * For available configuration keys, refer to the parent classes:
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
*/
abstract class DrupalSqlBase extends SqlBase implements ContainerFactoryPluginInterface, DependentPluginInterface {
@@ -52,7 +61,7 @@
}
/**
- * Retrieves all system data information from origin system.
+ * Retrieves all system data information from the source Drupal database.
*
* @return array
* List of system table information keyed by type and name.
@@ -109,7 +118,7 @@
}
/**
- * Get a module schema_version value in the source installation.
+ * Retrieves a module schema_version from the source Drupal database.
*
* @param string $module
* Name of module.
@@ -124,7 +133,7 @@
}
/**
- * Check to see if a given module is enabled in the source installation.
+ * Checks if a given module is enabled in the source Drupal database.
*
* @param string $module
* Name of module to check.
@@ -138,7 +147,7 @@
}
/**
- * Read a variable from a Drupal database.
+ * Reads a variable from a source Drupal database.
*
* @param $name
* Name of the variable.
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate_drupal/src/Plugin/migrate/source/Variable.php
--- a/core/modules/migrate_drupal/src/Plugin/migrate/source/Variable.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/Variable.php Fri Feb 23 15:52:07 2018 +0000
@@ -58,7 +58,7 @@
/**
* {@inheritdoc}
*/
- public function count() {
+ public function count($refresh = FALSE) {
return intval($this->query()->countQuery()->execute()->fetchField() > 0);
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate_drupal/src/Plugin/migrate/source/d6/VariableTranslation.php
--- a/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/VariableTranslation.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/VariableTranslation.php Fri Feb 23 15:52:07 2018 +0000
@@ -68,7 +68,7 @@
/**
* {@inheritdoc}
*/
- public function count() {
+ public function count($refresh = FALSE) {
return $this->initializeIterator()->count();
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate_drupal/tests/fixtures/drupal7.php
--- a/core/modules/migrate_drupal/tests/fixtures/drupal7.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate_drupal/tests/fixtures/drupal7.php Fri Feb 23 15:52:07 2018 +0000
@@ -3576,6 +3576,36 @@
'translatable' => '0',
'deleted' => '0',
))
+->values(array(
+ 'id' => '35',
+ 'field_name' => 'field_datetime_without_time',
+ 'type' => 'datetime',
+ 'module' => 'date',
+ 'active' => '1',
+ 'storage_type' => 'field_sql_storage',
+ 'storage_module' => 'field_sql_storage',
+ 'storage_active' => '1',
+ 'locked' => '0',
+ 'data' => 'a:7:{s:12:"translatable";s:1:"0";s:12:"entity_types";a:0:{}s:8:"settings";a:6:{s:11:"granularity";a:6:{s:5:"month";s:5:"month";s:3:"day";s:3:"day";s:4:"hour";i:0;s:6:"minute";i:0;s:4:"year";s:4:"year";s:6:"second";i:0;}s:11:"tz_handling";s:4:"site";s:11:"timezone_db";s:3:"UTC";s:13:"cache_enabled";i:0;s:11:"cache_count";s:1:"4";s:6:"todate";s:0:"";}s:7:"storage";a:5:{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:7:"details";a:1:{s:3:"sql";a:2:{s:18:"FIELD_LOAD_CURRENT";a:1:{s:38:"field_data_field_datetime_without_time";a:1:{s:5:"value";s:33:"field_datetime_without_time_value";}}s:19:"FIELD_LOAD_REVISION";a:1:{s:42:"field_revision_field_datetime_without_time";a:1:{s:5:"value";s:33:"field_datetime_without_time_value";}}}}}s:12:"foreign keys";a:0:{}s:7:"indexes";a:0:{}s:2:"id";s:1:"9";}',
+ 'cardinality' => '1',
+ 'translatable' => '0',
+ 'deleted' => '0',
+))
+->values(array(
+ 'id' => '36',
+ 'field_name' => 'field_date_without_time',
+ 'type' => 'date',
+ 'module' => 'date',
+ 'active' => '1',
+ 'storage_type' => 'field_sql_storage',
+ 'storage_module' => 'field_sql_storage',
+ 'storage_active' => '1',
+ 'locked' => '0',
+ 'data' => 'a:7:{s:12:"translatable";s:1:"0";s:12:"entity_types";a:0:{}s:8:"settings";a:6:{s:11:"granularity";a:6:{s:5:"month";s:5:"month";s:3:"day";s:3:"day";s:4:"hour";i:0;s:6:"minute";i:0;s:4:"year";s:4:"year";s:6:"second";i:0;}s:11:"tz_handling";s:4:"site";s:11:"timezone_db";s:3:"UTC";s:13:"cache_enabled";i:0;s:11:"cache_count";s:1:"4";s:6:"todate";s:0:"";}s:7:"storage";a:5:{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:7:"details";a:1:{s:3:"sql";a:2:{s:18:"FIELD_LOAD_CURRENT";a:1:{s:34:"field_data_field_date_without_time";a:1:{s:5:"value";s:29:"field_date_without_time_value";}}s:19:"FIELD_LOAD_REVISION";a:1:{s:38:"field_revision_field_date_without_time";a:1:{s:5:"value";s:29:"field_date_without_time_value";}}}}}s:12:"foreign keys";a:0:{}s:7:"indexes";a:0:{}s:2:"id";s:1:"9";}',
+ 'cardinality' => '1',
+ 'translatable' => '0',
+ 'deleted' => '0',
+))
->execute();
$connection->schema()->createTable('field_config_instance', array(
@@ -4158,6 +4188,24 @@
'data' => 'a:7:{s:5:"label";s:31:"Text summary plain and filtered";s:6:"widget";a:5:{s:6:"weight";s:2:"14";s:4:"type";s:26:"text_textarea_with_summary";s:6:"module";s:4:"text";s:6:"active";i:1;s:8:"settings";a:2:{s:4:"rows";s:2:"20";s:12:"summary_rows";i:5;}}s:8:"settings";a:3:{s:15:"text_processing";s:1:"1";s:15:"display_summary";i:0;s:18:"user_register_form";b:0;}s:7:"display";a:1:{s:7:"default";a:5:{s:5:"label";s:5:"above";s:4:"type";s:12:"text_default";s:8:"settings";a:0:{}s:6:"module";s:4:"text";s:6:"weight";i:9;}}s:8:"required";i:0;s:11:"description";s:0:"";s:13:"default_value";N;}',
'deleted' => '0',
))
+->values(array(
+ 'id' => '61',
+ 'field_id' => '35',
+ 'field_name' => 'field_datetime_without_time',
+ 'entity_type' => 'node',
+ 'bundle' => 'test_content_type',
+ 'data' => 'a:6:{s:5:"label";s:21:"Datetime without time";s:6:"widget";a:5:{s:6:"weight";s:1:"2";s:4:"type";s:11:"date_select";s:6:"module";s:4:"date";s:6:"active";i:1;s:8:"settings";a:6:{s:12:"input_format";s:13:"m/d/Y - H:i:s";s:19:"input_format_custom";s:0:"";s:10:"year_range";s:5:"-3:+3";s:9:"increment";s:2:"15";s:14:"label_position";s:5:"above";s:10:"text_parts";a:0:{}}}s:8:"settings";a:5:{s:13:"default_value";s:3:"now";s:18:"default_value_code";s:0:"";s:14:"default_value2";s:4:"same";s:19:"default_value_code2";s:0:"";s:18:"user_register_form";b:0;}s:7:"display";a:1:{s:7:"default";a:5:{s:5:"label";s:5:"above";s:4:"type";s:12:"date_default";s:6:"weight";s:1:"3";s:8:"settings";a:5:{s:11:"format_type";s:4:"long";s:15:"multiple_number";s:0:"";s:13:"multiple_from";s:0:"";s:11:"multiple_to";s:0:"";s:6:"fromto";s:4:"both";}s:6:"module";s:4:"date";}}s:8:"required";i:0;s:11:"description";s:0:"";}',
+ 'deleted' => '0',
+))
+->values(array(
+ 'id' => '62',
+ 'field_id' => '36',
+ 'field_name' => 'field_date_without_time',
+ 'entity_type' => 'node',
+ 'bundle' => 'test_content_type',
+ 'data' => 'a:6:{s:5:"label";s:17:"Date without time";s:6:"widget";a:5:{s:6:"weight";s:1:"2";s:4:"type";s:11:"date_select";s:6:"module";s:4:"date";s:6:"active";i:1;s:8:"settings";a:6:{s:12:"input_format";s:13:"m/d/Y - H:i:s";s:19:"input_format_custom";s:0:"";s:10:"year_range";s:5:"-3:+3";s:9:"increment";s:2:"15";s:14:"label_position";s:5:"above";s:10:"text_parts";a:0:{}}}s:8:"settings";a:5:{s:13:"default_value";s:3:"now";s:18:"default_value_code";s:0:"";s:14:"default_value2";s:4:"same";s:19:"default_value_code2";s:0:"";s:18:"user_register_form";b:0;}s:7:"display";a:1:{s:7:"default";a:5:{s:5:"label";s:5:"above";s:4:"type";s:12:"date_default";s:6:"weight";s:1:"3";s:8:"settings";a:5:{s:11:"format_type";s:4:"long";s:15:"multiple_number";s:0:"";s:13:"multiple_from";s:0:"";s:11:"multiple_to";s:0:"";s:6:"fromto";s:4:"both";}s:6:"module";s:4:"date";}}s:8:"required";i:0;s:11:"description";s:0:"";}',
+ 'deleted' => '0',
+))
->execute();
$connection->schema()->createTable('field_data_body', array(
@@ -4615,6 +4663,174 @@
))
->execute();
+$connection->schema()->createTable('field_data_field_datetime_without_time', array(
+ 'fields' => array(
+ 'entity_type' => array(
+ 'type' => 'varchar',
+ 'not null' => TRUE,
+ 'length' => '128',
+ 'default' => '',
+ ),
+ 'bundle' => array(
+ 'type' => 'varchar',
+ 'not null' => TRUE,
+ 'length' => '128',
+ 'default' => '',
+ ),
+ 'deleted' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'default' => '0',
+ ),
+ 'entity_id' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'unsigned' => TRUE,
+ ),
+ 'revision_id' => array(
+ 'type' => 'int',
+ 'not null' => FALSE,
+ 'size' => 'normal',
+ 'unsigned' => TRUE,
+ ),
+ 'language' => array(
+ 'type' => 'varchar',
+ 'not null' => TRUE,
+ 'length' => '32',
+ 'default' => '',
+ ),
+ 'delta' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'unsigned' => TRUE,
+ ),
+ 'field_datetime_without_time_value' => array(
+ 'mysql_type' => 'datetime',
+ 'pgsql_type' => 'timestamp without time zone',
+ 'sqlite_type' => 'varchar',
+ 'sqlsrv_type' => 'smalldatetime',
+ 'not null' => FALSE,
+ ),
+ ),
+ 'primary key' => array(
+ 'entity_type',
+ 'deleted',
+ 'entity_id',
+ 'language',
+ 'delta',
+ ),
+ 'mysql_character_set' => 'utf8',
+));
+
+$connection->insert('field_data_field_datetime_without_time')
+->fields(array(
+ 'entity_type',
+ 'bundle',
+ 'deleted',
+ 'entity_id',
+ 'revision_id',
+ 'language',
+ 'delta',
+ 'field_datetime_without_time_value',
+))
+->values(array(
+ 'entity_type' => 'node',
+ 'bundle' => 'test_content_type',
+ 'deleted' => '0',
+ 'entity_id' => '1',
+ 'revision_id' => '1',
+ 'language' => 'und',
+ 'delta' => '0',
+ 'field_datetime_without_time_value' => '2015-01-20 00:00:00',
+))
+->execute();
+
+$connection->schema()->createTable('field_data_field_date_without_time', array(
+ 'fields' => array(
+ 'entity_type' => array(
+ 'type' => 'varchar',
+ 'not null' => TRUE,
+ 'length' => '128',
+ 'default' => '',
+ ),
+ 'bundle' => array(
+ 'type' => 'varchar',
+ 'not null' => TRUE,
+ 'length' => '128',
+ 'default' => '',
+ ),
+ 'deleted' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'default' => '0',
+ ),
+ 'entity_id' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'unsigned' => TRUE,
+ ),
+ 'revision_id' => array(
+ 'type' => 'int',
+ 'not null' => FALSE,
+ 'size' => 'normal',
+ 'unsigned' => TRUE,
+ ),
+ 'language' => array(
+ 'type' => 'varchar',
+ 'not null' => TRUE,
+ 'length' => '32',
+ 'default' => '',
+ ),
+ 'delta' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'unsigned' => TRUE,
+ ),
+ 'field_date_without_time_value' => array(
+ 'type' => 'varchar',
+ 'not null' => FALSE,
+ 'length' => '100',
+ ),
+ ),
+ 'primary key' => array(
+ 'entity_type',
+ 'deleted',
+ 'entity_id',
+ 'language',
+ 'delta',
+ ),
+ 'mysql_character_set' => 'utf8',
+));
+
+$connection->insert('field_data_field_date_without_time')
+->fields(array(
+ 'entity_type',
+ 'bundle',
+ 'deleted',
+ 'entity_id',
+ 'revision_id',
+ 'language',
+ 'delta',
+ 'field_date_without_time_value',
+))
+->values(array(
+ 'entity_type' => 'node',
+ 'bundle' => 'test_content_type',
+ 'deleted' => '0',
+ 'entity_id' => '1',
+ 'revision_id' => '1',
+ 'language' => 'und',
+ 'delta' => '0',
+ 'field_date_without_time_value' => '2015-01-20T00:00:00',
+))
+->execute();
+
$connection->schema()->createTable('field_data_field_email', array(
'fields' => array(
'entity_type' => array(
@@ -7801,6 +8017,176 @@
))
->execute();
+$connection->schema()->createTable('field_revision_field_datetime_without_time', array(
+ 'fields' => array(
+ 'entity_type' => array(
+ 'type' => 'varchar',
+ 'not null' => TRUE,
+ 'length' => '128',
+ 'default' => '',
+ ),
+ 'bundle' => array(
+ 'type' => 'varchar',
+ 'not null' => TRUE,
+ 'length' => '128',
+ 'default' => '',
+ ),
+ 'deleted' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'default' => '0',
+ ),
+ 'entity_id' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'unsigned' => TRUE,
+ ),
+ 'revision_id' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'unsigned' => TRUE,
+ ),
+ 'language' => array(
+ 'type' => 'varchar',
+ 'not null' => TRUE,
+ 'length' => '32',
+ 'default' => '',
+ ),
+ 'delta' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'unsigned' => TRUE,
+ ),
+ 'field_datetime_without_time_value' => array(
+ 'mysql_type' => 'datetime',
+ 'pgsql_type' => 'timestamp without time zone',
+ 'sqlite_type' => 'varchar',
+ 'sqlsrv_type' => 'smalldatetime',
+ 'not null' => FALSE,
+ ),
+ ),
+ 'primary key' => array(
+ 'entity_type',
+ 'deleted',
+ 'entity_id',
+ 'revision_id',
+ 'language',
+ 'delta',
+ ),
+ 'mysql_character_set' => 'utf8',
+));
+
+$connection->insert('field_revision_field_datetime_without_time')
+->fields(array(
+ 'entity_type',
+ 'bundle',
+ 'deleted',
+ 'entity_id',
+ 'revision_id',
+ 'language',
+ 'delta',
+ 'field_datetime_without_time_value',
+))
+->values(array(
+ 'entity_type' => 'node',
+ 'bundle' => 'test_content_type',
+ 'deleted' => '0',
+ 'entity_id' => '1',
+ 'revision_id' => '1',
+ 'language' => 'und',
+ 'delta' => '0',
+ 'field_datetime_without_time_value' => '2015-01-20 00:00:00',
+))
+->execute();
+
+$connection->schema()->createTable('field_revision_field_date_without_time', array(
+ 'fields' => array(
+ 'entity_type' => array(
+ 'type' => 'varchar',
+ 'not null' => TRUE,
+ 'length' => '128',
+ 'default' => '',
+ ),
+ 'bundle' => array(
+ 'type' => 'varchar',
+ 'not null' => TRUE,
+ 'length' => '128',
+ 'default' => '',
+ ),
+ 'deleted' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'default' => '0',
+ ),
+ 'entity_id' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'unsigned' => TRUE,
+ ),
+ 'revision_id' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'unsigned' => TRUE,
+ ),
+ 'language' => array(
+ 'type' => 'varchar',
+ 'not null' => TRUE,
+ 'length' => '32',
+ 'default' => '',
+ ),
+ 'delta' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'size' => 'normal',
+ 'unsigned' => TRUE,
+ ),
+ 'field_date_without_time_value' => array(
+ 'type' => 'varchar',
+ 'not null' => FALSE,
+ 'length' => '100',
+ ),
+ ),
+ 'primary key' => array(
+ 'entity_type',
+ 'deleted',
+ 'entity_id',
+ 'revision_id',
+ 'language',
+ 'delta',
+ ),
+ 'mysql_character_set' => 'utf8',
+));
+
+$connection->insert('field_revision_field_date_without_time')
+->fields(array(
+ 'entity_type',
+ 'bundle',
+ 'deleted',
+ 'entity_id',
+ 'revision_id',
+ 'language',
+ 'delta',
+ 'field_date_without_time_value',
+))
+->values(array(
+ 'entity_type' => 'node',
+ 'bundle' => 'test_content_type',
+ 'deleted' => '0',
+ 'entity_id' => '1',
+ 'revision_id' => '1',
+ 'language' => 'und',
+ 'delta' => '0',
+ 'field_date_without_time_value' => '2015-01-20T00:00:00',
+))
+->execute();
+
$connection->schema()->createTable('field_revision_field_email', array(
'fields' => array(
'entity_type' => array(
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate_drupal_ui/migrate_drupal_ui.install
--- a/core/modules/migrate_drupal_ui/migrate_drupal_ui.install Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate_drupal_ui/migrate_drupal_ui.install Fri Feb 23 15:52:07 2018 +0000
@@ -11,6 +11,6 @@
* Implements hook_install().
*/
function migrate_drupal_ui_install() {
- $url = Url::fromUri('base:upgrade')->toString();
+ $url = Url::fromRoute('migrate_drupal_ui.upgrade')->toString();
drupal_set_message(t('The Migrate Drupal UI module has been enabled. Proceed to the upgrade form.', [':url' => $url]));
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php
--- a/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php Fri Feb 23 15:52:07 2018 +0000
@@ -236,7 +236,6 @@
$default_options = [];
-
$form['version'] = [
'#type' => 'radios',
'#default_value' => 7,
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate_drupal_ui/src/Tests/MigrateUpgradeTestBase.php
--- a/core/modules/migrate_drupal_ui/src/Tests/MigrateUpgradeTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate_drupal_ui/src/Tests/MigrateUpgradeTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -20,6 +20,8 @@
/**
* Use the Standard profile to test help implementations of many core modules.
+ *
+ * @var string
*/
protected $profile = 'standard';
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -15,6 +15,8 @@
/**
* Use the Standard profile to test help implementations of many core modules.
+ *
+ * @var string
*/
protected $profile = 'standard';
diff -r bfffd8d7479a -r 7a779792577d core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7Test.php
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7Test.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7Test.php Fri Feb 23 15:52:07 2018 +0000
@@ -52,8 +52,8 @@
'configurable_language' => 4,
'contact_form' => 3,
'editor' => 2,
- 'field_config' => 61,
- 'field_storage_config' => 44,
+ 'field_config' => 63,
+ 'field_storage_config' => 46,
'file' => 3,
'filter_format' => 7,
'image_style' => 6,
diff -r bfffd8d7479a -r 7a779792577d core/modules/node/node.install
--- a/core/modules/node/node.install Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/node/node.install Fri Feb 23 15:52:07 2018 +0000
@@ -255,3 +255,15 @@
$schema['fields']['realm']['description'] = 'The realm in which the user must possess the grant ID. Modules can define one or more realms by implementing hook_node_grants().';
Database::getConnection()->schema()->changeField('node_access', 'realm', 'realm', $schema['fields']['realm']);
}
+
+/**
+ * Run a node access rebuild, if required.
+ */
+function node_update_8401() {
+ // Get the list of node access modules.
+ $modules = \Drupal::moduleHandler()->getImplementations('node_grants');
+ // If multilingual usage, then rebuild node access.
+ if (count($modules) > 0 && \Drupal::languageManager()->isMultilingual()) {
+ node_access_needs_rebuild(TRUE);
+ }
+}
diff -r bfffd8d7479a -r 7a779792577d core/modules/node/node.module
--- a/core/modules/node/node.module Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/node/node.module Fri Feb 23 15:52:07 2018 +0000
@@ -133,7 +133,7 @@
case 'entity.entity_form_display.node.default':
case 'entity.entity_form_display.node.form_mode':
$type = $route_match->getParameter('node_type');
- return '' . t('Content items can be edited using different form modes. Here, you can define which fields are shown and hidden when %type content is edited in each form mode, and define how the field form widgets are displayed in each form mode.', ['%type' => $type->label()]) . '
' ;
+ return '' . t('Content items can be edited using different form modes. Here, you can define which fields are shown and hidden when %type content is edited in each form mode, and define how the field form widgets are displayed in each form mode.', ['%type' => $type->label()]) . '
';
case 'entity.entity_view_display.node.default':
case 'entity.entity_view_display.node.view_mode':
diff -r bfffd8d7479a -r 7a779792577d core/modules/node/src/NodeGrantDatabaseStorage.php
--- a/core/modules/node/src/NodeGrantDatabaseStorage.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/node/src/NodeGrantDatabaseStorage.php Fri Feb 23 15:52:07 2018 +0000
@@ -211,6 +211,7 @@
$query = $this->database->insert('node_access')->fields(['nid', 'langcode', 'fallback', 'realm', 'gid', 'grant_view', 'grant_update', 'grant_delete']);
// If we have defined a granted langcode, use it. But if not, add a grant
// for every language this node is translated to.
+ $fallback_langcode = $node->getUntranslated()->language()->getId();
foreach ($grants as $grant) {
if ($realm && $realm != $grant['realm']) {
continue;
@@ -227,7 +228,7 @@
$grant['nid'] = $node->id();
$grant['langcode'] = $grant_langcode;
// The record with the original langcode is used as the fallback.
- if ($grant['langcode'] == $node->language()->getId()) {
+ if ($grant['langcode'] == $fallback_langcode) {
$grant['fallback'] = 1;
}
else {
diff -r bfffd8d7479a -r 7a779792577d core/modules/node/src/NodeTranslationHandler.php
--- a/core/modules/node/src/NodeTranslationHandler.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/node/src/NodeTranslationHandler.php Fri Feb 23 15:52:07 2018 +0000
@@ -39,10 +39,8 @@
}
}
if (isset($status_translatable)) {
- foreach (['publish', 'unpublish', 'submit'] as $button) {
- if (isset($form['actions'][$button])) {
- $form['actions'][$button]['#value'] .= ' ' . ($status_translatable ? t('(this translation)') : t('(all translations)'));
- }
+ if (isset($form['actions']['submit'])) {
+ $form['actions']['submit']['#value'] .= ' ' . ($status_translatable ? t('(this translation)') : t('(all translations)'));
}
}
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/node/src/Plugin/Action/DeleteNode.php
--- a/core/modules/node/src/Plugin/Action/DeleteNode.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/node/src/Plugin/Action/DeleteNode.php Fri Feb 23 15:52:07 2018 +0000
@@ -45,7 +45,7 @@
* The plugin implementation definition.
* @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
* The tempstore factory.
- * @param AccountInterface $current_user
+ * @param \Drupal\Core\Session\AccountInterface $current_user
* Current user.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, PrivateTempStoreFactory $temp_store_factory, AccountInterface $current_user) {
diff -r bfffd8d7479a -r 7a779792577d core/modules/node/src/Plugin/migrate/source/d6/ViewModeBase.php
--- a/core/modules/node/src/Plugin/migrate/source/d6/ViewModeBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/node/src/Plugin/migrate/source/d6/ViewModeBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -12,7 +12,7 @@
/**
* {@inheritdoc}
*/
- public function count() {
+ public function count($refresh = FALSE) {
return count($this->initializeIterator());
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/node/src/Plugin/views/argument/Nid.php
--- a/core/modules/node/src/Plugin/views/argument/Nid.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/node/src/Plugin/views/argument/Nid.php Fri Feb 23 15:52:07 2018 +0000
@@ -29,7 +29,7 @@
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
- * @param NodeStorageInterface $node_storage
+ * @param \Drupal\node\NodeStorageInterface $node_storage
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, NodeStorageInterface $node_storage) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
diff -r bfffd8d7479a -r 7a779792577d core/modules/node/src/Plugin/views/wizard/Node.php
--- a/core/modules/node/src/Plugin/views/wizard/Node.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/node/src/Plugin/views/wizard/Node.php Fri Feb 23 15:52:07 2018 +0000
@@ -22,6 +22,8 @@
/**
* Set the created column.
+ *
+ * @var string
*/
protected $createdColumn = 'node_field_data-created';
diff -r bfffd8d7479a -r 7a779792577d core/modules/node/src/Plugin/views/wizard/NodeRevision.php
--- a/core/modules/node/src/Plugin/views/wizard/NodeRevision.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/node/src/Plugin/views/wizard/NodeRevision.php Fri Feb 23 15:52:07 2018 +0000
@@ -21,6 +21,8 @@
/**
* Set the created column.
+ *
+ * @var string
*/
protected $createdColumn = 'changed';
diff -r bfffd8d7479a -r 7a779792577d core/modules/node/src/Tests/NodeRevisionsTest.php
--- a/core/modules/node/src/Tests/NodeRevisionsTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/node/src/Tests/NodeRevisionsTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -166,7 +166,6 @@
$expected = 'Delete';
$this->assertTrue(strstr($json[$ids[0]], $expected), 'The "Delete" contextual link is shown for the default revision.');
-
// Confirm that revisions revert properly.
$this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionid() . "/revert", [], t('Revert'));
$this->assertRaw(t('@type %title has been reverted to the revision from %revision-date.', [
@@ -191,7 +190,6 @@
$this->assertFalse(strstr($json[$ids[0]], ''), 'The "Edit" contextual link is not shown for a non-default revision.');
$this->assertFalse(strstr($json[$ids[0]], ''), 'The "Delete" contextual link is not shown for a non-default revision.');
-
// Confirm revisions delete properly.
$this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionId() . "/delete", [], t('Delete'));
$this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.', [
diff -r bfffd8d7479a -r 7a779792577d core/modules/node/tests/modules/node_access_test/node_access_test.module
--- a/core/modules/node/tests/modules/node_access_test/node_access_test.module Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/node/tests/modules/node_access_test/node_access_test.module Fri Feb 23 15:52:07 2018 +0000
@@ -152,6 +152,12 @@
// Make all Catalan content secret.
return AccessResult::forbidden()->setCacheMaxAge(0);
}
+
+ // Grant access if a specific user is specified.
+ if (\Drupal::state()->get('node_access_test.allow_uid') === $account->id()) {
+ return AccessResult::allowed();
+ }
+
// No opinion.
return AccessResult::neutral()->setCacheMaxAge(0);
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/node/tests/src/Functional/NodeAccessLanguageFallbackTest.php
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/node/tests/src/Functional/NodeAccessLanguageFallbackTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -0,0 +1,131 @@
+save();
+ ConfigurableLanguage::createFromLangcode('ca')->save();
+ ConfigurableLanguage::createFromLangcode('af')->save();
+
+ // Enable content translation for the current entity type.
+ \Drupal::service('content_translation.manager')->setEnabled('node', 'page', TRUE);
+ }
+
+ /**
+ * Tests node access fallback handling with multiple node languages.
+ */
+ public function testNodeAccessLanguageFallback() {
+ // The node_access_test module allows nodes to be marked private. We need to
+ // ensure that system honors the fallback system of node access properly.
+ // Note that node_access_test_language is language-sensitive and does not
+ // apply to the fallback test.
+
+ // Create one node in Hungarian and marked as private.
+ $node = $this->drupalCreateNode([
+ 'body' => [[]],
+ 'langcode' => 'hu',
+ 'private' => [['value' => 1]],
+ 'status' => 1,
+ ]);
+
+ // There should be one entry in node_access, with fallback set to hu.
+ $this->checkRecords(1, 'hu');
+
+ // Create a translation user.
+ $admin = $this->drupalCreateUser([
+ 'bypass node access',
+ 'administer nodes',
+ 'translate any entity',
+ 'administer content translation',
+ ]);
+ $this->drupalLogin($admin);
+ $this->drupalGet('node/' . $node->id() . '/translations');
+ $this->assertSession()->statusCodeEquals(200);
+
+ // Create a Catalan translation through the UI.
+ $url_options = ['language' => \Drupal::languageManager()->getLanguage('ca')];
+ $this->drupalGet('node/' . $node->id() . '/translations/add/hu/ca', $url_options);
+ $this->assertSession()->statusCodeEquals(200);
+ // Save the form.
+ $this->getSession()->getPage()->pressButton('Save (this translation)');
+ $this->assertSession()->statusCodeEquals(200);
+
+ // Check the node access table.
+ $this->checkRecords(2, 'hu');
+
+ // Programmatically create a translation. This process lets us check that
+ // both forms and code behave in the same way.
+ $storage = \Drupal::entityTypeManager()->getStorage('node');
+ // Reload the node.
+ $node = $storage->load(1);
+ // Create an Afrikaans translation.
+ $translation = $node->addTranslation('af');
+ $translation->title->value = $this->randomString();
+ $translation->status = 1;
+ $node->save();
+
+ // Check the node access table.
+ $this->checkRecords(3, 'hu');
+
+ // For completeness, edit the Catalan version again.
+ $this->drupalGet('node/' . $node->id() . '/edit', $url_options);
+ $this->assertSession()->statusCodeEquals(200);
+ // Save the form.
+ $this->getSession()->getPage()->pressButton('Save (this translation)');
+ $this->assertSession()->statusCodeEquals(200);
+ // Check the node access table.
+ $this->checkRecords(3, 'hu');
+ }
+
+ /**
+ * Queries the node_access table and checks for proper storage.
+ *
+ * @param int $count
+ * The number of rows expected by the query (equal to the translation
+ * count).
+ * @param $langcode
+ * The expected language code set as the fallback property.
+ */
+ public function checkRecords($count, $langcode = 'hu') {
+ $select = \Drupal::database()
+ ->select('node_access', 'na')
+ ->fields('na', ['nid', 'fallback', 'langcode', 'grant_view'])
+ ->condition('na.realm', 'node_access_test', '=')
+ ->condition('na.gid', 8888, '=');
+ $records = $select->execute()->fetchAll();
+ // Check that the expected record count is returned.
+ $this->assertEquals(count($records), $count);
+ // The fallback value is 'hu' and should be set to 1. For other languages,
+ // it should be set to 0. Casting to boolean lets us run that comparison.
+ foreach ($records as $record) {
+ $this->assertEquals((bool) $record->fallback, $record->langcode === $langcode);
+ }
+ }
+
+}
diff -r bfffd8d7479a -r 7a779792577d core/modules/path/src/Form/DeleteForm.php
--- a/core/modules/path/src/Form/DeleteForm.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/path/src/Form/DeleteForm.php Fri Feb 23 15:52:07 2018 +0000
@@ -16,7 +16,7 @@
/**
* The alias storage service.
*
- * @var AliasStorageInterface
+ * @var \Drupal\Core\Path\AliasStorageInterface
*/
protected $aliasStorage;
diff -r bfffd8d7479a -r 7a779792577d core/modules/path/src/Form/PathFormBase.php
--- a/core/modules/path/src/Form/PathFormBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/path/src/Form/PathFormBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -191,7 +191,6 @@
}
}
-
if (!$this->pathValidator->isValid(trim($source, '/'))) {
$form_state->setErrorByName('source', t("The path '@link_path' is either invalid or you do not have access to it.", ['@link_path' => $source]));
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php
--- a/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php Fri Feb 23 15:52:07 2018 +0000
@@ -5,12 +5,42 @@
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Field\FieldItemList;
use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\TypedData\ComputedItemListTrait;
/**
* Represents a configurable entity path field.
*/
class PathFieldItemList extends FieldItemList {
+ use ComputedItemListTrait;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function computeValue() {
+ // Default the langcode to the current language if this is a new entity or
+ // there is no alias for an existent entity.
+ // @todo Set the langcode to not specified for untranslatable fields
+ // in https://www.drupal.org/node/2689459.
+ $value = ['langcode' => $this->getLangcode()];
+
+ $entity = $this->getEntity();
+ if (!$entity->isNew()) {
+ // @todo Support loading languge neutral aliases in
+ // https://www.drupal.org/node/2511968.
+ $alias = \Drupal::service('path.alias_storage')->load([
+ 'source' => '/' . $entity->toUrl()->getInternalPath(),
+ 'langcode' => $this->getLangcode(),
+ ]);
+
+ if ($alias) {
+ $value = $alias;
+ }
+ }
+
+ $this->list[0] = $this->createItem(0, $value);
+ }
+
/**
* {@inheritdoc}
*/
@@ -34,42 +64,4 @@
\Drupal::service('path.alias_storage')->delete($conditions);
}
- /**
- * {@inheritdoc}
- */
- public function getValue($include_computed = FALSE) {
- $this->ensureLoaded();
- return parent::getValue($include_computed);
- }
-
- /**
- * {@inheritdoc}
- */
- public function isEmpty() {
- $this->ensureLoaded();
- return parent::isEmpty();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getIterator() {
- $this->ensureLoaded();
- return parent::getIterator();
- }
-
- /**
- * Automatically create the first item for computed fields.
- *
- * This ensures that ::getValue() and ::isEmpty() calls will behave like a
- * non-computed field.
- *
- * @todo: Move this to the base class in https://www.drupal.org/node/2392845.
- */
- protected function ensureLoaded() {
- if (!isset($this->list[0]) && $this->definition->isComputed()) {
- $this->list[0] = $this->createItem(0);
- }
- }
-
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/path/src/Plugin/Field/FieldType/PathItem.php
--- a/core/modules/path/src/Plugin/Field/FieldType/PathItem.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/path/src/Plugin/Field/FieldType/PathItem.php Fri Feb 23 15:52:07 2018 +0000
@@ -24,20 +24,6 @@
class PathItem extends FieldItemBase {
/**
- * Whether the alias has been loaded from the alias storage service yet.
- *
- * @var bool
- */
- protected $isLoaded = FALSE;
-
- /**
- * Whether the alias is currently being set.
- *
- * @var bool
- */
- protected $isLoading = FALSE;
-
- /**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
@@ -53,14 +39,6 @@
/**
* {@inheritdoc}
*/
- public function __get($name) {
- $this->ensureLoaded();
- return parent::__get($name);
- }
-
- /**
- * {@inheritdoc}
- */
public static function schema(FieldStorageDefinitionInterface $field_definition) {
return [];
}
@@ -68,73 +46,17 @@
/**
* {@inheritdoc}
*/
- public function getValue() {
- $this->ensureLoaded();
- return parent::getValue();
- }
-
- /**
- * {@inheritdoc}
- */
public function isEmpty() {
- $this->ensureLoaded();
- return parent::isEmpty();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getIterator() {
- $this->ensureLoaded();
- return parent::getIterator();
+ return ($this->alias === NULL || $this->alias === '') && ($this->pid === NULL || $this->pid === '') && ($this->langcode === NULL || $this->langcode === '');
}
/**
* {@inheritdoc}
*/
public function preSave() {
- $this->alias = trim($this->alias);
- }
-
- /**
- * {@inheritdoc}
- */
- public function __set($name, $value) {
- // Also ensure that existing values are loaded when setting a value, this
- // ensures that it is possible to set a new value immediately after loading
- // an entity.
- $this->ensureLoaded();
- parent::__set($name, $value);
- }
-
- /**
- * {@inheritdoc}
- */
- public function set($property_name, $value, $notify = TRUE) {
- // Also ensure that existing values are loaded when setting a value, this
- // ensures that it is possible to set a new value immediately after loading
- // an entity.
- $this->ensureLoaded();
- return parent::set($property_name, $value, $notify);
- }
-
- /**
- * {@inheritdoc}
- */
- public function get($property_name) {
- $this->ensureLoaded();
- return parent::get($property_name);
- }
-
- /**
- * {@inheritdoc}
- */
- public function setValue($values, $notify = TRUE) {
- // Also ensure that existing values are loaded when setting a value, this
- // ensures that it is possible to set a new value immediately after loading
- // an entity.
- $this->ensureLoaded();
- return parent::setValue($values, $notify);
+ if ($this->alias !== NULL) {
+ $this->alias = trim($this->alias);
+ }
}
/**
@@ -178,42 +100,4 @@
return 'alias';
}
- /**
- * Ensures the alias properties are loaded if available.
- *
- * This ensures that the properties will always be loaded and act like
- * non-computed fields when calling ::__get() and getValue().
- *
- * @todo: Determine if this should be moved to the base class in
- * https://www.drupal.org/node/2392845.
- */
- protected function ensureLoaded() {
- // Make sure to avoid a infinite loop if setValue() has be called from this
- // block which calls ensureLoaded().
- if (!$this->isLoaded && !$this->isLoading) {
- $entity = $this->getEntity();
- if (!$entity->isNew()) {
- // @todo Support loading languge neutral aliases in
- // https://www.drupal.org/node/2511968.
- $alias = \Drupal::service('path.alias_storage')->load([
- 'source' => '/' . $entity->toUrl()->getInternalPath(),
- 'langcode' => $this->getLangcode(),
- ]);
- if ($alias) {
- $this->isLoading = TRUE;
- $this->setValue($alias);
- $this->isLoading = FALSE;
- }
- else {
- // If there is no existing alias, default the langcode to the current
- // language.
- // @todo Set the langcode to not specified for untranslatable fields
- // in https://www.drupal.org/node/2689459.
- $this->langcode = $this->getLangcode();
- }
- }
- $this->isLoaded = TRUE;
- }
- }
-
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/path/tests/src/Kernel/PathItemTest.php
--- a/core/modules/path/tests/src/Kernel/PathItemTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/path/tests/src/Kernel/PathItemTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -171,6 +171,24 @@
$this->assertEquals('/foobar', $loaded_node->get('path')->alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertEquals('/foobar', $stored_alias);
+
+ // Check that \Drupal\Core\Field\FieldItemList::equals() for the path field
+ // type.
+ $node = Node::create([
+ 'title' => $this->randomString(),
+ 'type' => 'foo',
+ 'path' => ['alias' => '/foo'],
+ ]);
+ $second_node = Node::create([
+ 'title' => $this->randomString(),
+ 'type' => 'foo',
+ 'path' => ['alias' => '/foo'],
+ ]);
+ $this->assertTrue($node->get('path')->equals($second_node->get('path')));
+
+ // Change the alias for the second node to a different one and try again.
+ $second_node->get('path')->alias = '/foobar';
+ $this->assertFalse($node->get('path')->equals($second_node->get('path')));
}
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/quickedit/quickedit.module
--- a/core/modules/quickedit/quickedit.module Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/quickedit/quickedit.module Fri Feb 23 15:52:07 2018 +0000
@@ -180,18 +180,16 @@
* @internal
*/
function _quickedit_entity_is_latest_revision(ContentEntityInterface $entity) {
- $entity_type_manager = \Drupal::entityTypeManager();
- $entity_definition = $entity_type_manager->getDefinition($entity->getEntityTypeId());
- if (!$entity_definition->isRevisionable()) {
+ if (!$entity->getEntityType()->isRevisionable() || $entity->isNew()) {
return TRUE;
}
- $revision_ids = $entity_type_manager
+
+ $latest_revision = \Drupal::entityTypeManager()
->getStorage($entity->getEntityTypeId())
->getQuery()
- ->allRevisions()
- ->condition($entity_definition->getKey('id'), $entity->id())
- ->sort($entity_definition->getKey('revision'), 'DESC')
- ->range(0, 1)
+ ->latestRevision()
+ ->condition($entity->getEntityType()->getKey('id'), $entity->id())
->execute();
- return $entity->getLoadedRevisionId() == array_keys($revision_ids)[0];
+
+ return !empty($latest_revision) && $entity->getLoadedRevisionId() == key($latest_revision) ? TRUE : FALSE;
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/quickedit/src/Tests/QuickEditLoadingTest.php
--- a/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -330,6 +330,13 @@
public function testWithPendingRevision() {
$this->drupalLogin($this->editorUser);
+ // Verify that the preview is loaded correctly.
+ $this->drupalPostForm('node/add/article', ['title[0][value]' => 'foo'], 'Preview');
+ $this->assertResponse(200);
+ // Verify that quickedit is not active on preview.
+ $this->assertNoRaw('data-quickedit-entity-id="node/' . $this->testNode->id() . '"');
+ $this->assertNoRaw('data-quickedit-field-id="node/' . $this->testNode->id() . '/title/' . $this->testNode->language()->getId() . '/full"');
+
$this->drupalGet('node/' . $this->testNode->id());
$this->assertRaw('data-quickedit-entity-id="node/' . $this->testNode->id() . '"');
$this->assertRaw('data-quickedit-field-id="node/' . $this->testNode->id() . '/title/' . $this->testNode->language()->getId() . '/full"');
@@ -340,6 +347,7 @@
$this->testNode->save();
$this->drupalGet('node/' . $this->testNode->id());
+ $this->assertResponse(200);
$this->assertNoRaw('data-quickedit-entity-id="node/' . $this->testNode->id() . '"');
$this->assertNoRaw('data-quickedit-field-id="node/' . $this->testNode->id() . '/title/' . $this->testNode->language()->getId() . '/full"');
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php
--- a/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php Fri Feb 23 15:52:07 2018 +0000
@@ -32,7 +32,7 @@
class ResponsiveImageFormatter extends ImageFormatterBase implements ContainerFactoryPluginInterface {
/**
- * @var EntityStorageInterface
+ * @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $responsiveImageStyleStorage;
diff -r bfffd8d7479a -r 7a779792577d core/modules/rest/src/Plugin/Type/ResourcePluginManager.php
--- a/core/modules/rest/src/Plugin/Type/ResourcePluginManager.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/rest/src/Plugin/Type/ResourcePluginManager.php Fri Feb 23 15:52:07 2018 +0000
@@ -43,7 +43,7 @@
*
* @see https://www.drupal.org/node/2874934
*/
- public function getInstance(array $options){
+ public function getInstance(array $options) {
if (isset($options['id'])) {
return $this->createInstance($options['id']);
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/rest/src/RequestHandler.php
--- a/core/modules/rest/src/RequestHandler.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/rest/src/RequestHandler.php Fri Feb 23 15:52:07 2018 +0000
@@ -74,7 +74,6 @@
$method = strtolower($route_match->getRouteObject()->getMethods()[0]);
assert(count($route_match->getRouteObject()->getMethods()) === 1);
-
$resource_config_id = $route_match->getRouteObject()->getDefault('_rest_resource_config');
/** @var \Drupal\rest\RestResourceConfigInterface $resource_config */
$resource_config = $this->resourceStorage->load($resource_config_id);
diff -r bfffd8d7479a -r 7a779792577d core/modules/rest/tests/src/Functional/AnonResourceTestTrait.php
--- a/core/modules/rest/tests/src/Functional/AnonResourceTestTrait.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/rest/tests/src/Functional/AnonResourceTestTrait.php Fri Feb 23 15:52:07 2018 +0000
@@ -31,6 +31,7 @@
/**
* {@inheritdoc}
*/
- protected function assertAuthenticationEdgeCases($method, Url $url, array $request_options) {}
+ protected function assertAuthenticationEdgeCases($method, Url $url, array $request_options) {
+ }
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/rest/tests/src/Functional/BasicAuthResourceTestTrait.php
--- a/core/modules/rest/tests/src/Functional/BasicAuthResourceTestTrait.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/rest/tests/src/Functional/BasicAuthResourceTestTrait.php Fri Feb 23 15:52:07 2018 +0000
@@ -38,6 +38,7 @@
/**
* {@inheritdoc}
*/
- protected function assertAuthenticationEdgeCases($method, Url $url, array $request_options) {}
+ protected function assertAuthenticationEdgeCases($method, Url $url, array $request_options) {
+ }
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/rest/tests/src/Functional/CookieResourceTestTrait.php
--- a/core/modules/rest/tests/src/Functional/CookieResourceTestTrait.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/rest/tests/src/Functional/CookieResourceTestTrait.php Fri Feb 23 15:52:07 2018 +0000
@@ -109,23 +109,18 @@
return;
}
-
unset($request_options[RequestOptions::HEADERS]['X-CSRF-Token']);
-
// DX: 403 when missing X-CSRF-Token request header.
$response = $this->request($method, $url, $request_options);
$this->assertResourceErrorResponse(403, 'X-CSRF-Token request header is missing', $response);
-
$request_options[RequestOptions::HEADERS]['X-CSRF-Token'] = 'this-is-not-the-token-you-are-looking-for';
-
// DX: 403 when invalid X-CSRF-Token request header.
$response = $this->request($method, $url, $request_options);
$this->assertResourceErrorResponse(403, 'X-CSRF-Token request header is invalid', $response);
-
$request_options[RequestOptions::HEADERS]['X-CSRF-Token'] = $this->csrfToken;
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
--- a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -301,17 +301,14 @@
$url = $this->getEntityResourceUrl();
$request_options = [];
-
// DX: 404 when resource not provisioned, 403 if canonical route. HTML
// response because missing ?_format query string.
$response = $this->request('GET', $url, $request_options);
$this->assertSame($has_canonical_url ? 403 : 404, $response->getStatusCode());
$this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
-
$url->setOption('query', ['_format' => static::$format]);
-
// DX: 404 when resource not provisioned, 403 if canonical route. Non-HTML
// response because ?_format query string is present.
$response = $this->request('GET', $url, $request_options);
@@ -322,12 +319,10 @@
$this->assertResourceErrorResponse(404, 'No route found for "GET ' . str_replace($this->baseUrl, '', $this->getEntityResourceUrl()->setAbsolute()->toString()) . '"', $response);
}
-
$this->provisionEntityResource();
// Simulate the developer again forgetting the ?_format query string.
$url->setOption('query', []);
-
// DX: 406 when ?_format is missing, except when requesting a canonical HTML
// route.
$response = $this->request('GET', $url, $request_options);
@@ -338,10 +333,8 @@
$this->assert406Response($response);
}
-
$url->setOption('query', ['_format' => static::$format]);
-
// DX: forgetting authentication: authentication provider-specific error
// response.
if (static::$auth) {
@@ -365,16 +358,13 @@
unset($request_options[RequestOptions::HEADERS]['REST-test-auth-global']);
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('GET'));
-
// DX: 403 when unauthorized.
$response = $this->request('GET', $url, $request_options);
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('GET'), $response);
$this->assertArrayNotHasKey('Link', $response->getHeaders());
-
$this->setUpAuthorization('GET');
-
// 200 for well-formed HEAD request.
$response = $this->request('HEAD', $url, $request_options);
$this->assertResourceResponse(200, '', $response);
@@ -508,11 +498,9 @@
// PrimitiveDataNormalizer.
$this->rebuildAll();
-
$response = $this->request('GET', $url, $request_options);
$this->assertResourceResponse(200, FALSE, $response);
-
// Again do an identical comparison, but this time transform the expected
// normalized entity's values to strings. This ensures the BC layer for
// bc_primitives_as_strings works as expected.
@@ -542,11 +530,9 @@
// TimestampItemNormalizer.
$this->rebuildAll();
-
$response = $this->request('GET', $url, $request_options);
$this->assertResourceResponse(200, FALSE, $response);
-
// This ensures the BC layer for bc_timestamp_normalizer_unix works as
// expected. This method should be using
// ::formatExpectedTimestampValue() to generate the timestamp value. This
@@ -564,75 +550,59 @@
$this->rebuildAll();
}
-
// BC: rest_update_8203().
$this->config('rest.settings')->set('bc_entity_resource_permissions', TRUE)->save(TRUE);
$this->refreshTestStateAfterRestConfigChange();
-
// DX: 403 when unauthorized.
$response = $this->request('GET', $url, $request_options);
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('GET'), $response);
-
$this->grantPermissionsToTestedRole(['restful get entity:' . static::$entityTypeId]);
-
// 200 for well-formed request.
$response = $this->request('GET', $url, $request_options);
$this->assertResourceResponse(200, FALSE, $response);
-
$this->resourceConfigStorage->load(static::$resourceConfigId)->disable()->save();
$this->refreshTestStateAfterRestConfigChange();
-
// DX: upon disabling a resource, it's immediately no longer available.
$this->assertResourceNotAvailable($url, $request_options);
-
$this->resourceConfigStorage->load(static::$resourceConfigId)->enable()->save();
$this->refreshTestStateAfterRestConfigChange();
-
// DX: upon re-enabling a resource, immediate 200.
$response = $this->request('GET', $url, $request_options);
$this->assertResourceResponse(200, FALSE, $response);
-
$this->resourceConfigStorage->load(static::$resourceConfigId)->delete();
$this->refreshTestStateAfterRestConfigChange();
-
// DX: upon deleting a resource, it's immediately no longer available.
$this->assertResourceNotAvailable($url, $request_options);
-
$this->provisionEntityResource();
$url->setOption('query', ['_format' => 'non_existing_format']);
-
// DX: 406 when requesting unsupported format.
$response = $this->request('GET', $url, $request_options);
$this->assert406Response($response);
$this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type'));
-
$request_options[RequestOptions::HEADERS]['Accept'] = static::$mimeType;
-
// DX: 406 when requesting unsupported format but specifying Accept header:
// should result in a text/plain response.
$response = $this->request('GET', $url, $request_options);
$this->assert406Response($response);
$this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type'));
-
$url = Url::fromRoute('rest.entity.' . static::$entityTypeId . '.GET.' . static::$format);
$url->setRouteParameter(static::$entityTypeId, 987654321);
$url->setOption('query', ['_format' => static::$format]);
-
// DX: 404 when GETting non-existing entity.
$response = $this->request('GET', $url, $request_options);
$path = str_replace('987654321', '{' . static::$entityTypeId . '}', $url->setAbsolute()->setOptions(['base_url' => '', 'query' => []])->toString());
@@ -714,27 +684,22 @@
$url = $this->getEntityResourcePostUrl();
$request_options = [];
-
// DX: 404 when resource not provisioned. HTML response because missing
// ?_format query string.
$response = $this->request('POST', $url, $request_options);
$this->assertSame(404, $response->getStatusCode());
$this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
-
$url->setOption('query', ['_format' => static::$format]);
-
// DX: 404 when resource not provisioned.
$response = $this->request('POST', $url, $request_options);
$this->assertResourceErrorResponse(404, 'No route found for "POST ' . str_replace($this->baseUrl, '', $this->getEntityResourcePostUrl()->setAbsolute()->toString()) . '"', $response);
-
$this->provisionEntityResource();
// Simulate the developer again forgetting the ?_format query string.
$url->setOption('query', []);
-
// DX: 415 when no Content-Type request header. HTML response because
// missing ?_format query string.
$response = $this->request('POST', $url, $request_options);
@@ -742,34 +707,26 @@
$this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
$this->assertContains('A client error happened', (string) $response->getBody());
-
$url->setOption('query', ['_format' => static::$format]);
-
// DX: 415 when no Content-Type request header.
$response = $this->request('POST', $url, $request_options);
$this->assertResourceErrorResponse(415, 'No "Content-Type" request header specified', $response);
-
$request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType;
-
// DX: 400 when no request body.
$response = $this->request('POST', $url, $request_options);
$this->assertResourceErrorResponse(400, 'No entity content received.', $response);
-
$request_options[RequestOptions::BODY] = $unparseable_request_body;
-
// DX: 400 when unparseable request body.
$response = $this->request('POST', $url, $request_options);
$this->assertResourceErrorResponse(400, 'Syntax error', $response);
-
$request_options[RequestOptions::BODY] = $parseable_invalid_request_body;
-
if (static::$auth) {
// DX: forgetting authentication: authentication provider-specific error
// response.
@@ -777,28 +734,22 @@
$this->assertResponseWhenMissingAuthentication($response);
}
-
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('POST'));
-
// DX: 403 when unauthorized.
$response = $this->request('POST', $url, $request_options);
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('POST'), $response);
-
$this->setUpAuthorization('POST');
-
// DX: 422 when invalid entity: multiple values sent for single-value field.
$response = $this->request('POST', $url, $request_options);
$label_field = $this->entity->getEntityType()->hasKey('label') ? $this->entity->getEntityType()->getKey('label') : static::$labelFieldName;
$label_field_capitalized = $this->entity->getFieldDefinition($label_field)->getLabel();
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\n$label_field: $label_field_capitalized: this field cannot hold more than 1 values.\n", $response);
-
$request_options[RequestOptions::BODY] = $parseable_invalid_request_body_2;
-
// DX: 422 when invalid entity: UUID field too long.
// @todo Fix this in https://www.drupal.org/node/2149851.
if ($this->entity->getEntityType()->hasKey('uuid')) {
@@ -806,35 +757,27 @@
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nuuid.0.value: UUID: may not be longer than 128 characters.\n", $response);
}
-
$request_options[RequestOptions::BODY] = $parseable_invalid_request_body_3;
-
// DX: 403 when entity contains field without 'edit' access.
$response = $this->request('POST', $url, $request_options);
$this->assertResourceErrorResponse(403, "Access denied on creating field 'field_rest_test'.", $response);
-
$request_options[RequestOptions::BODY] = $parseable_valid_request_body;
-
// Before sending a well-formed request, allow the normalization and
// authentication provider edge cases to also be tested.
$this->assertNormalizationEdgeCases('POST', $url, $request_options);
$this->assertAuthenticationEdgeCases('POST', $url, $request_options);
-
$request_options[RequestOptions::HEADERS]['Content-Type'] = 'text/xml';
-
// DX: 415 when request body in existing but not allowed format.
$response = $this->request('POST', $url, $request_options);
$this->assertResourceErrorResponse(415, 'No route found that matches "Content-Type: text/xml"', $response);
-
$request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType;
-
// 201 for well-formed request.
$response = $this->request('POST', $url, $request_options);
$this->assertResourceResponse(201, FALSE, $response);
@@ -866,20 +809,16 @@
}
}
-
$this->config('rest.settings')->set('bc_entity_resource_permissions', TRUE)->save(TRUE);
$this->refreshTestStateAfterRestConfigChange();
$request_options[RequestOptions::BODY] = $parseable_valid_request_body_2;
-
// DX: 403 when unauthorized.
$response = $this->request('POST', $url, $request_options);
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('POST'), $response);
-
$this->grantPermissionsToTestedRole(['restful post entity:' . static::$entityTypeId]);
-
// 201 for well-formed request.
// Delete the first created entity in case there is a uniqueness constraint.
$this->entityStorage->load(static::$firstCreatedEntityId)->delete();
@@ -934,7 +873,6 @@
$url = $this->getEntityResourceUrl();
$request_options = [];
-
// DX: 404 when resource not provisioned, 405 if canonical route. Plain text
// or HTML response because missing ?_format query string.
$response = $this->request('PATCH', $url, $request_options);
@@ -949,10 +887,8 @@
$this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
}
-
$url->setOption('query', ['_format' => static::$format]);
-
// DX: 404 when resource not provisioned, 405 if canonical route.
$response = $this->request('PATCH', $url, $request_options);
if ($has_canonical_url) {
@@ -962,46 +898,36 @@
$this->assertResourceErrorResponse(404, 'No route found for "PATCH ' . str_replace($this->baseUrl, '', $this->getEntityResourceUrl()->setAbsolute()->toString()) . '"', $response);
}
-
$this->provisionEntityResource();
// Simulate the developer again forgetting the ?_format query string.
$url->setOption('query', []);
-
// DX: 415 when no Content-Type request header.
$response = $this->request('PATCH', $url, $request_options);
$this->assertSame(415, $response->getStatusCode());
$this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
$this->assertContains('A client error happened', (string) $response->getBody());
-
$url->setOption('query', ['_format' => static::$format]);
-
// DX: 415 when no Content-Type request header.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceErrorResponse(415, 'No "Content-Type" request header specified', $response);
-
$request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType;
-
// DX: 400 when no request body.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceErrorResponse(400, 'No entity content received.', $response);
-
$request_options[RequestOptions::BODY] = $unparseable_request_body;
-
// DX: 400 when unparseable request body.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceErrorResponse(400, 'Syntax error', $response);
-
$request_options[RequestOptions::BODY] = $parseable_invalid_request_body;
-
if (static::$auth) {
// DX: forgetting authentication: authentication provider-specific error
// response.
@@ -1009,33 +935,26 @@
$this->assertResponseWhenMissingAuthentication($response);
}
-
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('PATCH'));
-
// DX: 403 when unauthorized.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('PATCH'), $response);
-
$this->setUpAuthorization('PATCH');
-
// DX: 422 when invalid entity: multiple values sent for single-value field.
$response = $this->request('PATCH', $url, $request_options);
$label_field = $this->entity->getEntityType()->hasKey('label') ? $this->entity->getEntityType()->getKey('label') : static::$labelFieldName;
$label_field_capitalized = $this->entity->getFieldDefinition($label_field)->getLabel();
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\n$label_field: $label_field_capitalized: this field cannot hold more than 1 values.\n", $response);
-
$request_options[RequestOptions::BODY] = $parseable_invalid_request_body_2;
-
// DX: 403 when entity contains field without 'edit' access.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceErrorResponse(403, "Access denied on updating field 'field_rest_test'.", $response);
-
// DX: 403 when sending PATCH request with read-only fields.
// First send all fields (the "maximum normalization"). Assert the expected
// error message for the first PATCH-protected field. Remove that field from
@@ -1055,27 +974,21 @@
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceResponse(200, FALSE, $response);
-
$request_options[RequestOptions::BODY] = $parseable_valid_request_body;
-
// Before sending a well-formed request, allow the normalization and
// authentication provider edge cases to also be tested.
$this->assertNormalizationEdgeCases('PATCH', $url, $request_options);
$this->assertAuthenticationEdgeCases('PATCH', $url, $request_options);
-
$request_options[RequestOptions::HEADERS]['Content-Type'] = 'text/xml';
-
// DX: 415 when request body in existing but not allowed format.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceErrorResponse(415, 'No route found that matches "Content-Type: text/xml"', $response);
-
$request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType;
-
// 200 for well-formed request.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceResponse(200, FALSE, $response);
@@ -1100,20 +1013,16 @@
// is not sent in the PATCH request.
$this->assertSame('All the faith he had had had had no effect on the outcome of his life.', $updated_entity->get('field_rest_test')->value);
-
$this->config('rest.settings')->set('bc_entity_resource_permissions', TRUE)->save(TRUE);
$this->refreshTestStateAfterRestConfigChange();
$request_options[RequestOptions::BODY] = $parseable_valid_request_body_2;
-
// DX: 403 when unauthorized.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('PATCH'), $response);
-
$this->grantPermissionsToTestedRole(['restful patch entity:' . static::$entityTypeId]);
-
// 200 for well-formed request.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceResponse(200, FALSE, $response);
@@ -1141,7 +1050,6 @@
$url = $this->getEntityResourceUrl();
$request_options = [];
-
// DX: 404 when resource not provisioned, but 405 if canonical route. Plain
// text or HTML response because missing ?_format query string.
$response = $this->request('DELETE', $url, $request_options);
@@ -1156,10 +1064,8 @@
$this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
}
-
$url->setOption('query', ['_format' => static::$format]);
-
// DX: 404 when resource not provisioned, 405 if canonical route.
$response = $this->request('DELETE', $url, $request_options);
if ($has_canonical_url) {
@@ -1172,7 +1078,6 @@
$this->provisionEntityResource();
-
if (static::$auth) {
// DX: forgetting authentication: authentication provider-specific error
// response.
@@ -1180,23 +1085,18 @@
$this->assertResponseWhenMissingAuthentication($response);
}
-
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('PATCH'));
-
// DX: 403 when unauthorized.
$response = $this->request('DELETE', $url, $request_options);
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('DELETE'), $response);
-
$this->setUpAuthorization('DELETE');
-
// Before sending a well-formed request, allow the authentication provider's
// edge cases to also be tested.
$this->assertAuthenticationEdgeCases('DELETE', $url, $request_options);
-
// 204 for well-formed request.
$response = $this->request('DELETE', $url, $request_options);
$this->assertSame(204, $response->getStatusCode());
@@ -1208,21 +1108,17 @@
$this->assertSame('', (string) $response->getBody());
$this->assertFalse($response->hasHeader('X-Drupal-Cache'));
-
$this->config('rest.settings')->set('bc_entity_resource_permissions', TRUE)->save(TRUE);
$this->refreshTestStateAfterRestConfigChange();
$this->entity = $this->createEntity();
$url = $this->getEntityResourceUrl()->setOption('query', $url->getOption('query'));
-
// DX: 403 when unauthorized.
$response = $this->request('DELETE', $url, $request_options);
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('DELETE'), $response);
-
$this->grantPermissionsToTestedRole(['restful delete entity:' . static::$entityTypeId]);
-
// 204 for well-formed request.
$response = $this->request('DELETE', $url, $request_options);
$this->assertSame(204, $response->getStatusCode());
@@ -1249,17 +1145,14 @@
$normalization[$bundle_field_name] = 'bad_bundle_name';
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
-
// DX: 422 when incorrect entity type bundle is specified.
$response = $this->request($method, $url, $request_options);
$this->assertResourceErrorResponse(422, '"bad_bundle_name" is not a valid bundle type for denormalization.', $response);
}
-
unset($normalization[$bundle_field_name]);
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
-
// DX: 422 when no entity type bundle is specified.
$response = $this->request($method, $url, $request_options);
$this->assertResourceErrorResponse(422, sprintf('Could not determine entity type bundle: "%s" field is missing.', $bundle_field_name), $response);
diff -r bfffd8d7479a -r 7a779792577d core/modules/rest/tests/src/Functional/EntityResource/User/UserResourceTestBase.php
--- a/core/modules/rest/tests/src/Functional/EntityResource/User/UserResourceTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/rest/tests/src/Functional/EntityResource/User/UserResourceTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -144,7 +144,6 @@
// @todo Remove the array_diff_key() call in https://www.drupal.org/node/2821077.
$original_normalization = array_diff_key($this->serializer->normalize($user, static::$format), ['created' => TRUE, 'changed' => TRUE, 'name' => TRUE]);
-
// Since this test must be performed by the user that is being modified,
// we cannot use $this->getUrl().
$url = $user->toUrl()->setOption('query', ['_format' => static::$format]);
@@ -153,18 +152,15 @@
];
$request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
-
// Test case 1: changing email.
$normalization = $original_normalization;
$normalization['mail'] = [['value' => 'new-email@example.com']];
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
-
// DX: 422 when changing email without providing the password.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the Email.\n", $response);
-
$normalization['pass'] = [['existing' => 'wrong']];
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
@@ -172,41 +168,33 @@
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the Email.\n", $response);
-
$normalization['pass'] = [['existing' => $this->account->passRaw]];
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
-
// 200 for well-formed request.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceResponse(200, FALSE, $response);
-
// Test case 2: changing password.
$normalization = $original_normalization;
$new_password = $this->randomString();
$normalization['pass'] = [['value' => $new_password]];
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
-
// DX: 422 when changing password without providing the current password.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\npass: Your current password is missing or incorrect; it's required to change the Password.\n", $response);
-
$normalization['pass'][0]['existing'] = $this->account->pass_raw;
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
-
// 200 for well-formed request.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceResponse(200, FALSE, $response);
-
// Verify that we can log in with the new password.
$this->assertRpcLogin($user->getAccountName(), $new_password);
-
// Update password in $this->account, prepare for future requests.
$this->account->passRaw = $new_password;
$this->initAuthentication();
@@ -215,21 +203,17 @@
];
$request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
-
// Test case 3: changing name.
$normalization = $original_normalization;
$normalization['name'] = [['value' => 'Cooler Llama']];
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
-
// DX: 403 when modifying username without required permission.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceErrorResponse(403, "Access denied on updating field 'name'.", $response);
-
$this->grantPermissionsToTestedRole(['change own username']);
-
// 200 for well-formed request.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceResponse(200, FALSE, $response);
diff -r bfffd8d7479a -r 7a779792577d core/modules/rest/tests/src/Functional/Views/StyleSerializerTest.php
--- a/core/modules/rest/tests/src/Functional/Views/StyleSerializerTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/rest/tests/src/Functional/Views/StyleSerializerTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -124,7 +124,6 @@
$this->assertIdentical($actual_json, json_encode($expected), 'The expected JSON output was found.');
-
// Test that the rendered output and the preview output are the same.
$view->destroy();
$view->setDisplay('rest_export_1');
diff -r bfffd8d7479a -r 7a779792577d core/modules/search/search.module
--- a/core/modules/search/search.module Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/search/search.module Fri Feb 23 15:52:07 2018 +0000
@@ -107,6 +107,13 @@
}
/**
+ * Implements hook_theme_suggestions_HOOK().
+ */
+function search_theme_suggestions_search_result(array $variables) {
+ return ['search_result__' . $variables['plugin_id']];
+}
+
+/**
* Implements hook_preprocess_HOOK() for block templates.
*/
function search_preprocess_block(&$variables) {
diff -r bfffd8d7479a -r 7a779792577d core/modules/search/search.pages.inc
--- a/core/modules/search/search.pages.inc Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/search/search.pages.inc Fri Feb 23 15:52:07 2018 +0000
@@ -9,13 +9,6 @@
use Drupal\Core\Language\LanguageInterface;
/**
- * Implements hook_theme_suggestions_HOOK().
- */
-function search_theme_suggestions_search_result(array $variables) {
- return ['search_result__' . $variables['plugin_id']];
-}
-
-/**
* Prepares variables for individual search result templates.
*
* Default template: search-result.html.twig
diff -r bfffd8d7479a -r 7a779792577d core/modules/search/src/Plugin/views/filter/Search.php
--- a/core/modules/search/src/Plugin/views/filter/Search.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/search/src/Plugin/views/filter/Search.php Fri Feb 23 15:52:07 2018 +0000
@@ -34,6 +34,8 @@
/**
* TRUE if the search query has been parsed.
+ *
+ * @var bool
*/
protected $parsed = FALSE;
diff -r bfffd8d7479a -r 7a779792577d core/modules/search/src/SearchQuery.php
--- a/core/modules/search/src/SearchQuery.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/search/src/SearchQuery.php Fri Feb 23 15:52:07 2018 +0000
@@ -571,7 +571,6 @@
}
}
-
// Add arguments for the keyword relevance normalization number.
$normalization = 1.0 / $this->normalize;
for ($i = 0; $i < $this->relevance_count; $i++) {
diff -r bfffd8d7479a -r 7a779792577d core/modules/search/src/Tests/SearchPageCacheTagsTest.php
--- a/core/modules/search/src/Tests/SearchPageCacheTagsTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/search/src/Tests/SearchPageCacheTagsTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -122,7 +122,6 @@
$this->container->get('module_installer')->install(['field_ui', 'entity_reference']);
$this->resetAll();
-
// Creates a new content type that will have an entity reference.
$type_name = 'entity_reference_test';
$type = $this->drupalCreateContentType(['name' => $type_name, 'type' => $type_name]);
diff -r bfffd8d7479a -r 7a779792577d core/modules/serialization/serialization.install
--- a/core/modules/serialization/serialization.install Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/serialization/serialization.install Fri Feb 23 15:52:07 2018 +0000
@@ -33,7 +33,8 @@
/**
* @see hal_update_8301()
*/
-function serialization_update_8301() {}
+function serialization_update_8301() {
+}
/**
* Add serialization.settings::bc_primitives_as_strings configuration.
diff -r bfffd8d7479a -r 7a779792577d core/modules/serialization/src/Encoder/XmlEncoder.php
--- a/core/modules/serialization/src/Encoder/XmlEncoder.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/serialization/src/Encoder/XmlEncoder.php Fri Feb 23 15:52:07 2018 +0000
@@ -56,7 +56,7 @@
/**
* {@inheritdoc}
*/
- public function encode($data, $format, array $context = []){
+ public function encode($data, $format, array $context = []) {
return $this->getBaseEncoder()->encode($data, $format, $context);
}
@@ -70,7 +70,7 @@
/**
* {@inheritdoc}
*/
- public function decode($data, $format, array $context = []){
+ public function decode($data, $format, array $context = []) {
return $this->getBaseEncoder()->decode($data, $format, $context);
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/serialization/src/Normalizer/FieldNormalizer.php
--- a/core/modules/serialization/src/Normalizer/FieldNormalizer.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/serialization/src/Normalizer/FieldNormalizer.php Fri Feb 23 15:52:07 2018 +0000
@@ -35,7 +35,7 @@
throw new InvalidArgumentException('The field passed in via $context[\'target_instance\'] must have a parent set.');
}
- /** @var FieldItemListInterface $items */
+ /** @var \Drupal\Core\Field\FieldItemListInterface $items */
$items = $context['target_instance'];
$item_class = $items->getItemDefinition()->getClass();
diff -r bfffd8d7479a -r 7a779792577d core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php
--- a/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -241,7 +241,6 @@
->willReturn('field_reference')
->shouldBeCalled();
-
$this->assertDenormalize($data);
}
@@ -261,7 +260,6 @@
->willReturn('field_reference')
->shouldBeCalled();
-
$this->assertDenormalize($data);
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/settings_tray/css/off-canvas.base.css
--- a/core/modules/settings_tray/css/off-canvas.base.css Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/settings_tray/css/off-canvas.base.css Fri Feb 23 15:52:07 2018 +0000
@@ -149,7 +149,7 @@
#drupal-off-canvas ol li {
display: block;
}
-#drupal-off-canvas quote,
+#drupal-off-canvas blockquote,
#drupal-off-canvas code {
margin: 20px 0;
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/settings_tray/js/settings_tray.es6.js
--- a/core/modules/settings_tray/js/settings_tray.es6.js Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/settings_tray/js/settings_tray.es6.js Fri Feb 23 15:52:07 2018 +0000
@@ -175,9 +175,9 @@
*/
Drupal.attachBehaviors(data.$el[0]);
/**
- * Bind a listener to all 'Quick edit' links for blocks. Click "Edit" button
- * in toolbar to force Contextual Edit which starts Settings Tray edit
- * mode also.
+ * Bind a listener to all 'Quick edit' links for blocks. Click "Edit"
+ * button in toolbar to force Contextual Edit which starts Settings Tray
+ * edit mode also.
*/
data.$el.find(blockConfigureSelector)
.on('click.settingstray', () => {
@@ -202,7 +202,8 @@
});
/**
- * Toggle the js-settings-tray-edit-mode class on items that we want to disable while in edit mode.
+ * Toggle the js-settings-tray-edit-mode class on items that we want to
+ * disable while in edit mode.
*
* @type {Drupal~behavior}
*
diff -r bfffd8d7479a -r 7a779792577d core/modules/settings_tray/src/Form/SystemBrandingOffCanvasForm.php
--- a/core/modules/settings_tray/src/Form/SystemBrandingOffCanvasForm.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/settings_tray/src/Form/SystemBrandingOffCanvasForm.php Fri Feb 23 15:52:07 2018 +0000
@@ -6,6 +6,7 @@
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\PluginFormBase;
+use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -32,13 +33,23 @@
protected $configFactory;
/**
+ * The current user.
+ *
+ * @var \Drupal\Core\Session\AccountInterface
+ */
+ protected $currentUser;
+
+ /**
* SystemBrandingOffCanvasForm constructor.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
+ * @param \Drupal\Core\Session\AccountInterface $current_user
+ * The current user.
*/
- public function __construct(ConfigFactoryInterface $config_factory) {
+ public function __construct(ConfigFactoryInterface $config_factory, AccountInterface $current_user) {
$this->configFactory = $config_factory;
+ $this->currentUser = $current_user;
}
/**
@@ -46,7 +57,8 @@
*/
public static function create(ContainerInterface $container) {
return new static(
- $container->get('config.factory')
+ $container->get('config.factory'),
+ $container->get('current_user')
);
}
@@ -67,6 +79,7 @@
'#type' => 'details',
'#title' => t('Site details'),
'#open' => TRUE,
+ '#access' => $this->currentUser->hasPermission('administer site configuration'),
];
$form['site_information']['site_name'] = [
'#type' => 'textfield',
diff -r bfffd8d7479a -r 7a779792577d core/modules/settings_tray/src/Form/SystemMenuOffCanvasForm.php
--- a/core/modules/settings_tray/src/Form/SystemMenuOffCanvasForm.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/settings_tray/src/Form/SystemMenuOffCanvasForm.php Fri Feb 23 15:52:07 2018 +0000
@@ -87,6 +87,7 @@
'#type' => 'details',
'#title' => $this->t('Edit menu %label', ['%label' => $this->menu->label()]),
'#open' => TRUE,
+ '#access' => $this->menu->access('edit'),
];
$form['entity_form'] += $this->getEntityForm($this->menu)->buildForm([], $form_state);
diff -r bfffd8d7479a -r 7a779792577d core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php
--- a/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -5,10 +5,13 @@
use Drupal\block\Entity\Block;
use Drupal\block_content\Entity\BlockContent;
use Drupal\block_content\Entity\BlockContentType;
+use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\settings_tray_test\Plugin\Block\SettingsTrayFormAnnotationIsClassBlock;
use Drupal\settings_tray_test\Plugin\Block\SettingsTrayFormAnnotationNoneBlock;
+use Drupal\system\Entity\Menu;
use Drupal\Tests\contextual\FunctionalJavascript\ContextualLinkClickTrait;
use Drupal\user\Entity\Role;
+use Drupal\user\RoleInterface;
/**
* Testing opening and saving block forms in the off-canvas dialog.
@@ -34,7 +37,6 @@
'toolbar',
'contextual',
'settings_tray',
- 'quickedit',
'search',
'block_content',
'settings_tray_test',
@@ -42,6 +44,8 @@
// cause test failures.
'settings_tray_test_css',
'settings_tray_test',
+ 'menu_link_content',
+ 'menu_ui',
];
/**
@@ -57,7 +61,6 @@
'access contextual links',
'access toolbar',
'administer nodes',
- 'access in-place editing',
'search content',
]);
$this->drupalLogin($user);
@@ -69,7 +72,11 @@
*
* @dataProvider providerTestBlocks
*/
- public function testBlocks($theme, $block_plugin, $new_page_text, $element_selector, $label_selector, $button_text, $toolbar_item) {
+ public function testBlocks($theme, $block_plugin, $new_page_text, $element_selector, $label_selector, $button_text, $toolbar_item, $permissions) {
+ if ($permissions) {
+ $this->grantPermissions(Role::load(Role::AUTHENTICATED_ID), $permissions);
+ }
+
$web_assert = $this->assertSession();
$page = $this->getSession()->getPage();
$this->enableTheme($theme);
@@ -170,6 +177,7 @@
'label_selector' => 'h2',
'button_text' => 'Save Powered by Drupal',
'toolbar_item' => '#toolbar-item-user',
+ NULL,
],
"$theme: block-branding" => [
'theme' => $theme,
@@ -179,6 +187,7 @@
'label_selector' => "a[rel='home']:last-child",
'button_text' => 'Save Site branding',
'toolbar_item' => '#toolbar-item-administration',
+ ['administer site configuration'],
],
"$theme: block-search" => [
'theme' => $theme,
@@ -188,6 +197,7 @@
'label_selector' => 'h2',
'button_text' => 'Save Search form',
'toolbar_item' => NULL,
+ NULL,
],
// This is the functional JS test coverage accompanying
// \Drupal\Tests\settings_tray\Functional\SettingsTrayTest::testPossibleAnnotations().
@@ -199,6 +209,7 @@
'label_selector' => NULL,
'button_text' => NULL,
'toolbar_item' => NULL,
+ NULL,
],
// This is the functional JS test coverage accompanying
// \Drupal\Tests\settings_tray\Functional\SettingsTrayTest::testPossibleAnnotations().
@@ -210,6 +221,7 @@
'label_selector' => NULL,
'button_text' => NULL,
'toolbar_item' => NULL,
+ NULL,
],
];
}
@@ -289,6 +301,8 @@
* Tests QuickEdit links behavior.
*/
public function testQuickEditLinks() {
+ $this->container->get('module_installer')->install(['quickedit']);
+ $this->grantPermissions(Role::load(RoleInterface::AUTHENTICATED_ID), ['access in-place editing']);
$quick_edit_selector = '#quickedit-entity-toolbar';
$node_selector = '[data-quickedit-entity-id="node/1"]';
$body_selector = '[data-quickedit-field-id="node/1/body/en/full"]';
@@ -506,6 +520,8 @@
* "Quick edit settings" is settings_tray.module link.
*/
public function testCustomBlockLinks() {
+ $this->container->get('module_installer')->install(['quickedit']);
+ $this->grantPermissions(Role::load(RoleInterface::AUTHENTICATED_ID), ['access in-place editing']);
$this->drupalGet('user');
$page = $this->getSession()->getPage();
$links = $page->findAll('css', "#block-custom .contextual-links li a");
@@ -544,6 +560,72 @@
}
/**
+ * Tests access to block forms with related configuration is correct.
+ */
+ public function testBlockConfigAccess() {
+ $page = $this->getSession()->getPage();
+ $web_assert = $this->assertSession();
+
+ // Confirm that System Branding block does not expose Site Name field
+ // without permission.
+ $block = $this->placeBlock('system_branding_block');
+ $this->drupalGet('user');
+ $this->enableEditMode();
+ $this->openBlockForm($this->getBlockSelector($block));
+ // The site name field should not appear because the user doesn't have
+ // permission.
+ $web_assert->fieldNotExists('settings[site_information][site_name]');
+ $page->pressButton('Save Site branding');
+ $this->assertElementVisibleAfterWait('css', 'div:contains(The block configuration has been saved)');
+ $web_assert->assertWaitOnAjaxRequest();
+ // Confirm we did not save changes to the configuration.
+ $this->assertEquals('Drupal', \Drupal::configFactory()->getEditable('system.site')->get('name'));
+
+ $this->grantPermissions(Role::load(Role::AUTHENTICATED_ID), ['administer site configuration']);
+ $this->drupalGet('user');
+ $this->openBlockForm($this->getBlockSelector($block));
+ // The site name field should appear because the user does have permission.
+ $web_assert->fieldExists('settings[site_information][site_name]');
+
+ // Confirm that the Menu block does not expose menu configuration without
+ // permission.
+ // Add a link or the menu will not render.
+ $menu_link_content = MenuLinkContent::create([
+ 'title' => 'This is on the menu',
+ 'menu_name' => 'main',
+ 'link' => ['uri' => 'route:'],
+ ]);
+ $menu_link_content->save();
+ $this->assertNotEmpty($menu_link_content->isEnabled());
+ $menu_without_overrides = \Drupal::configFactory()->getEditable('system.menu.main')->get();
+ $block = $this->placeBlock('system_menu_block:main');
+ $this->drupalGet('user');
+ $web_assert->pageTextContains('This is on the menu');
+ $this->openBlockForm($this->getBlockSelector($block));
+ // Edit menu form should not appear because the user doesn't have
+ // permission.
+ $web_assert->pageTextNotContains('Edit menu');
+ $page->pressButton('Save Main navigation');
+ $this->assertElementVisibleAfterWait('css', 'div:contains(The block configuration has been saved)');
+ $web_assert->assertWaitOnAjaxRequest();
+ // Confirm we did not save changes to the menu or the menu link.
+ $this->assertEquals($menu_without_overrides, \Drupal::configFactory()->getEditable('system.menu.main')->get());
+ $menu_link_content = MenuLinkContent::load($menu_link_content->id());
+ $this->assertNotEmpty($menu_link_content->isEnabled());
+ // Confirm menu is still on the page.
+ $this->drupalGet('user');
+ $web_assert->pageTextContains('This is on the menu');
+
+
+ $this->grantPermissions(Role::load(Role::AUTHENTICATED_ID), ['administer menu']);
+ $this->drupalGet('user');
+ $web_assert->pageTextContains('This is on the menu');
+ $this->openBlockForm($this->getBlockSelector($block));
+ // Edit menu form should appear because the user does have permission.
+ $web_assert->pageTextContains('Edit menu');
+ }
+
+ /**
* Test that validation errors appear in the off-canvas dialog.
*/
public function testValidationMessages() {
diff -r bfffd8d7479a -r 7a779792577d core/modules/simpletest/src/BlockCreationTrait.php
--- a/core/modules/simpletest/src/BlockCreationTrait.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/simpletest/src/BlockCreationTrait.php Fri Feb 23 15:52:07 2018 +0000
@@ -10,7 +10,7 @@
* This trait is meant to be used only by test classes.
*
* @deprecated in Drupal 8.4.x. Will be removed before Drupal 9.0.0. Use
- * Drupal\Tests\AssertHelperTrait instead.
+ * \Drupal\Tests\block\Traits\BlockCreationTrait instead.
*
* @see https://www.drupal.org/node/2884454
*/
diff -r bfffd8d7479a -r 7a779792577d core/modules/simpletest/src/ContentTypeCreationTrait.php
--- a/core/modules/simpletest/src/ContentTypeCreationTrait.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/simpletest/src/ContentTypeCreationTrait.php Fri Feb 23 15:52:07 2018 +0000
@@ -10,7 +10,7 @@
* This trait is meant to be used only by test classes.
*
* @deprecated in Drupal 8.4.x. Will be removed before Drupal 9.0.0. Use
- * Drupal\Tests\ContentTypeCreationTrait instead.
+ * \Drupal\Tests\node\Traits\ContentTypeCreationTrait instead.
*
* @see https://www.drupal.org/node/2884454
*/
diff -r bfffd8d7479a -r 7a779792577d core/modules/simpletest/src/KernelTestBase.php
--- a/core/modules/simpletest/src/KernelTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/simpletest/src/KernelTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -226,7 +226,6 @@
$this->kernel->shutdown();
$this->kernel->boot();
-
// Save the original site directory path, so that extensions in the
// site-specific directory can still be discovered in the test site
// environment.
diff -r bfffd8d7479a -r 7a779792577d core/modules/simpletest/src/NodeCreationTrait.php
--- a/core/modules/simpletest/src/NodeCreationTrait.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/simpletest/src/NodeCreationTrait.php Fri Feb 23 15:52:07 2018 +0000
@@ -10,7 +10,7 @@
* This trait is meant to be used only by test classes.
*
* @deprecated in Drupal 8.4.x. Will be removed before Drupal 9.0.0. Use
- * Drupal\Tests\NodeCreationTrait instead.
+ * \Drupal\Tests\node\Traits\NodeCreationTrait instead.
*
* @see https://www.drupal.org/node/2884454
*/
diff -r bfffd8d7479a -r 7a779792577d core/modules/simpletest/src/RouteProvider.php
--- a/core/modules/simpletest/src/RouteProvider.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/simpletest/src/RouteProvider.php Fri Feb 23 15:52:07 2018 +0000
@@ -49,7 +49,7 @@
/**
* {@inheritdoc}
*/
- public function preLoadRoutes($names){
+ public function preLoadRoutes($names) {
return $this->lazyLoadItself()->preLoadRoutes($names);
}
diff -r bfffd8d7479a -r 7a779792577d core/modules/simpletest/src/TestBase.php
--- a/core/modules/simpletest/src/TestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/simpletest/src/TestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -45,6 +45,8 @@
/**
* Time limit for the test.
+ *
+ * @var int
*/
protected $timeLimit = 500;
diff -r bfffd8d7479a -r 7a779792577d core/modules/simpletest/src/Tests/InstallationProfileModuleTestsTest.php
--- a/core/modules/simpletest/src/Tests/InstallationProfileModuleTestsTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/simpletest/src/Tests/InstallationProfileModuleTestsTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -36,6 +36,8 @@
* contained in the Testing profile.
*
* @see \Drupal\drupal_system_listing_compatible_test\Tests\SystemListingCompatibleTest
+ *
+ * @var string
*/
protected $profile = 'testing';
diff -r bfffd8d7479a -r 7a779792577d core/modules/simpletest/src/UserCreationTrait.php
--- a/core/modules/simpletest/src/UserCreationTrait.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/simpletest/src/UserCreationTrait.php Fri Feb 23 15:52:07 2018 +0000
@@ -12,7 +12,7 @@
* \Drupal\simpletest\TestBase.
*
* @deprecated in Drupal 8.4.x. Will be removed before Drupal 9.0.0. Use
- * Drupal\Tests\UserCreationTrait instead.
+ * \Drupal\Tests\user\Traits\UserCreationTrait instead.
*
* @see https://www.drupal.org/node/2884454
*/
diff -r bfffd8d7479a -r 7a779792577d core/modules/simpletest/src/WebTestBase.php
--- a/core/modules/simpletest/src/WebTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/simpletest/src/WebTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -96,7 +96,7 @@
/**
* The headers of the page currently loaded in the internal browser.
*
- * @var Array
+ * @var array
*/
protected $headers;
@@ -168,6 +168,8 @@
/**
* The maximum number of redirects to follow when handling responses.
+ *
+ * @var int
*/
protected $maximumRedirects = 5;
diff -r bfffd8d7479a -r 7a779792577d core/modules/simpletest/tests/src/Functional/OtherInstallationProfileTestsTest.php
--- a/core/modules/simpletest/tests/src/Functional/OtherInstallationProfileTestsTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/simpletest/tests/src/Functional/OtherInstallationProfileTestsTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -28,6 +28,8 @@
* The Standard profile contains \Drupal\standard\Tests\StandardTest, which
* should be found.
*
+ * @var string
+ *
* @see \Drupal\simpletest\Tests\InstallationProfileModuleTestsTest
* @see \Drupal\drupal_system_listing_compatible_test\Tests\SystemListingCompatibleTest
*/
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/config/install/system.site.yml
--- a/core/modules/system/config/install/system.site.yml Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/system/config/install/system.site.yml Fri Feb 23 15:52:07 2018 +0000
@@ -1,5 +1,5 @@
uuid: ''
-name: 'Drupal'
+name: ''
mail: ''
slogan: ''
page:
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/Controller/TimezoneController.php
--- a/core/modules/system/src/Controller/TimezoneController.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/system/src/Controller/TimezoneController.php Fri Feb 23 15:52:07 2018 +0000
@@ -24,7 +24,7 @@
* Daylight saving time indicator. If abbr does not exist then the time
* zone is searched solely by offset and isdst.
*
- * @return JsonResponse
+ * @return \Symfony\Component\HttpFoundation\JsonResponse
* The timezone name in JsonResponse object.
*/
public function getTimezone($abbreviation = '', $offset = -1, $is_daylight_saving_time = NULL) {
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/SystemConfigSubscriber.php
--- a/core/modules/system/src/SystemConfigSubscriber.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/system/src/SystemConfigSubscriber.php Fri Feb 23 15:52:07 2018 +0000
@@ -68,7 +68,7 @@
* This event listener checks that the system.site:uuid's in the source and
* target match.
*
- * @param ConfigImporterEvent $event
+ * @param \Drupal\Core\Config\ConfigImporterEvent $event
* The config import event.
*/
public function onConfigImporterValidateSiteUUID(ConfigImporterEvent $event) {
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php
--- a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -415,7 +415,6 @@
$cid = $this->createCacheId($cache_keys, $entity_cache_contexts);
$this->verifyRenderCache($cid, $non_referencing_entity_cache_tags);
-
$this->pass("Test listing of referencing entities.", 'Debug');
// Prime the page cache for the listing of referencing entities.
$this->verifyPageCache($listing_url, 'MISS');
@@ -434,7 +433,6 @@
$contexts_in_header = $this->drupalGetHeader('X-Drupal-Cache-Contexts');
$this->assertEqual(Cache::mergeContexts($page_cache_contexts, $this->getAdditionalCacheContextsForEntityListing()), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header));
-
$this->pass("Test listing containing referenced entity.", 'Debug');
// Prime the page cache for the listing containing the referenced entity.
$this->verifyPageCache($nonempty_entity_listing_url, 'MISS', $nonempty_entity_listing_cache_tags);
@@ -444,7 +442,6 @@
$contexts_in_header = $this->drupalGetHeader('X-Drupal-Cache-Contexts');
$this->assertEqual(Cache::mergeContexts($page_cache_contexts, $this->getAdditionalCacheContextsForEntityListing()), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header));
-
// Verify that after modifying the referenced entity, there is a cache miss
// for every route except the one for the non-referencing entity.
$this->pass("Test modification of referenced entity.", 'Debug');
@@ -461,7 +458,6 @@
$this->verifyPageCache($empty_entity_listing_url, 'HIT');
$this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
-
// Verify that after modifying the referencing entity, there is a cache miss
// for every route except the ones for the non-referencing entity and the
// empty entity listing.
@@ -478,7 +474,6 @@
$this->verifyPageCache($listing_url, 'HIT');
$this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
-
// Verify that after modifying the non-referencing entity, there is a cache
// miss only for the non-referencing entity route.
$this->pass("Test modification of non-referencing entity.", 'Debug');
@@ -492,7 +487,6 @@
// Verify cache hits.
$this->verifyPageCache($non_referencing_entity_url, 'HIT');
-
if ($this->entity->getEntityType()->hasHandlerClass('view_builder')) {
// Verify that after modifying the entity's display, there is a cache miss
// for both the referencing entity, and the listing of referencing
@@ -512,7 +506,6 @@
$this->verifyPageCache($listing_url, 'HIT');
}
-
if ($bundle_entity_type_id = $this->entity->getEntityType()->getBundleEntityType()) {
// Verify that after modifying the corresponding bundle entity, there is a
// cache miss for both the referencing entity, and the listing of
@@ -546,7 +539,6 @@
}
}
-
if ($this->entity->getEntityType()->get('field_ui_base_route')) {
// Verify that after modifying a configurable field on the entity, there
// is a cache miss.
@@ -564,7 +556,6 @@
$this->verifyPageCache($referencing_entity_url, 'HIT');
$this->verifyPageCache($listing_url, 'HIT');
-
// Verify that after modifying a configurable field on the entity, there
// is a cache miss.
$this->pass("Test modification of referenced entity's configurable field.", 'Debug');
@@ -582,7 +573,6 @@
$this->verifyPageCache($listing_url, 'HIT');
}
-
// Verify that after invalidating the entity's cache tag directly, there is
// a cache miss for every route except the ones for the non-referencing
// entity and the empty entity listing.
@@ -614,7 +604,6 @@
$this->verifyPageCache($empty_entity_listing_url, 'HIT');
$this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
-
if (!empty($view_cache_tag)) {
// Verify that after invalidating the generic entity type's view cache tag
// directly, there is a cache miss for both the referencing entity, and the
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php
--- a/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php Fri Feb 23 15:52:07 2018 +0000
@@ -34,7 +34,6 @@
$view_cache_tag = \Drupal::entityManager()->getViewBuilder($entity_type)->getCacheTags();
$render_cache_tag = 'rendered';
-
$this->pass("Test entity.", 'Debug');
$this->verifyPageCache($entity_url, 'MISS');
@@ -65,7 +64,6 @@
// Verify a cache hit.
$this->verifyPageCache($entity_url, 'HIT');
-
// Verify that after modifying the entity's display, there is a cache miss.
$this->pass("Test modification of entity's '$view_mode' display.", 'Debug');
$entity_display = entity_get_display($entity_type, $this->entity->bundle(), $view_mode);
@@ -75,7 +73,6 @@
// Verify a cache hit.
$this->verifyPageCache($entity_url, 'HIT');
-
if ($bundle_entity_type_id = $this->entity->getEntityType()->getBundleEntityType()) {
// Verify that after modifying the corresponding bundle entity, there is a
// cache miss.
@@ -90,7 +87,6 @@
$this->verifyPageCache($entity_url, 'HIT');
}
-
if ($this->entity->getEntityType()->get('field_ui_base_route')) {
// Verify that after modifying a configurable field on the entity, there
// is a cache miss.
@@ -115,7 +111,6 @@
$this->verifyPageCache($entity_url, 'HIT');
}
-
// Verify that after invalidating the entity's cache tag directly, there is
// a cache miss.
$this->pass("Test invalidation of entity's cache tag.", 'Debug');
@@ -125,7 +120,6 @@
// Verify a cache hit.
$this->verifyPageCache($entity_url, 'HIT');
-
// Verify that after invalidating the generic entity type's view cache tag
// directly, there is a cache miss.
$this->pass("Test invalidation of entity's 'view' cache tag.", 'Debug');
@@ -135,7 +129,6 @@
// Verify a cache hit.
$this->verifyPageCache($entity_url, 'HIT');
-
// Verify that after deleting the entity, there is a cache miss.
$this->pass('Test deletion of entity.', 'Debug');
$this->entity->delete();
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/Tests/Installer/DistributionProfileTest.php
--- a/core/modules/system/src/Tests/Installer/DistributionProfileTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/system/src/Tests/Installer/DistributionProfileTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -46,6 +46,8 @@
protected function setUpLanguage() {
// Verify that the distribution name appears.
$this->assertRaw($this->info['distribution']['name']);
+ // Verify that the distribution name is used in the site title.
+ $this->assertTitle('Choose language | ' . $this->info['distribution']['name']);
// Verify that the requested theme is used.
$this->assertRaw($this->info['distribution']['install']['theme']);
// Verify that the "Choose profile" step does not appear.
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/Tests/Installer/InstallerTranslationMultipleLanguageTest.php
--- a/core/modules/system/src/Tests/Installer/InstallerTranslationMultipleLanguageTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/system/src/Tests/Installer/InstallerTranslationMultipleLanguageTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -51,13 +51,29 @@
msgid "Language"
msgstr "Language $langcode"
+
+#: Testing site name configuration during the installer.
+msgid "Drupal"
+msgstr "Drupal"
ENDPO;
}
/**
+ * {@inheritdoc}
+ */
+ protected function installParameters() {
+ $params = parent::installParameters();
+ $params['forms']['install_configure_form']['site_name'] = 'SITE_NAME_' . $this->langcode;
+ return $params;
+ }
+
+ /**
* Tests that translations ended up at the expected places.
*/
public function testTranslationsLoaded() {
+ // Ensure the title is correct.
+ $this->assertEqual('SITE_NAME_' . $this->langcode, \Drupal::config('system.site')->get('name'));
+
// Verify German and Spanish were configured.
$this->drupalGet('admin/config/regional/language');
$this->assertText('German');
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/Tests/Module/DependencyTest.php
--- a/core/modules/system/src/Tests/Module/DependencyTest.php Fri Feb 23 15:51:18 2018 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,202 +0,0 @@
- TRUE,
- ];
- $this->drupalPostForm('admin/modules', $edit, t('Install'));
- // Enable module with project namespace to ensure nothing breaks.
- $edit = [
- 'modules[system_project_namespace_test][enable]' => TRUE,
- ];
- $this->drupalPostForm('admin/modules', $edit, t('Install'));
- $this->assertModules(['system_project_namespace_test'], TRUE);
- }
-
- /**
- * Attempts to enable the Content Translation module without Language enabled.
- */
- public function testEnableWithoutDependency() {
- // Attempt to enable Content Translation without Language enabled.
- $edit = [];
- $edit['modules[content_translation][enable]'] = 'content_translation';
- $this->drupalPostForm('admin/modules', $edit, t('Install'));
- $this->assertText(t('Some required modules must be enabled'), 'Dependency required.');
-
- $this->assertModules(['content_translation', 'language'], FALSE);
-
- // Assert that the language tables weren't enabled.
- $this->assertTableCount('language', FALSE);
-
- $this->drupalPostForm(NULL, NULL, t('Continue'));
- $this->assertText(t('2 modules have been enabled: Content Translation, Language.'), 'Modules status has been updated.');
- $this->assertModules(['content_translation', 'language'], TRUE);
-
- // Assert that the language YAML files were created.
- $storage = $this->container->get('config.storage');
- $this->assertTrue(count($storage->listAll('language.entity.')) > 0, 'Language config entity files exist.');
- }
-
- /**
- * Attempts to enable a module with a missing dependency.
- */
- public function testMissingModules() {
- // Test that the system_dependencies_test module is marked
- // as missing a dependency.
- $this->drupalGet('admin/modules');
- $this->assertRaw(t('@module (missing)', ['@module' => Unicode::ucfirst('_missing_dependency')]), 'A module with missing dependencies is marked as such.');
- $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[system_dependencies_test][enable]"]');
- $this->assert(count($checkbox) == 1, 'Checkbox for the module is disabled.');
- }
-
- /**
- * Tests enabling a module that depends on an incompatible version of a module.
- */
- public function testIncompatibleModuleVersionDependency() {
- // Test that the system_incompatible_module_version_dependencies_test is
- // marked as having an incompatible dependency.
- $this->drupalGet('admin/modules');
- $this->assertRaw(t('@module (incompatible with version @version)', [
- '@module' => 'System incompatible module version test (>2.0)',
- '@version' => '1.0',
- ]), 'A module that depends on an incompatible version of a module is marked as such.');
- $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[system_incompatible_module_version_dependencies_test][enable]"]');
- $this->assert(count($checkbox) == 1, 'Checkbox for the module is disabled.');
- }
-
- /**
- * Tests enabling a module that depends on a module with an incompatible core version.
- */
- public function testIncompatibleCoreVersionDependency() {
- // Test that the system_incompatible_core_version_dependencies_test is
- // marked as having an incompatible dependency.
- $this->drupalGet('admin/modules');
- $this->assertRaw(t('@module (incompatible with this version of Drupal core)', [
- '@module' => 'System incompatible core version test',
- ]), 'A module that depends on a module with an incompatible core version is marked as such.');
- $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[system_incompatible_core_version_dependencies_test][enable]"]');
- $this->assert(count($checkbox) == 1, 'Checkbox for the module is disabled.');
- }
-
- /**
- * Tests failing PHP version requirements.
- */
- public function testIncompatiblePhpVersionDependency() {
- $this->drupalGet('admin/modules');
- $this->assertRaw('This module requires PHP version 6502.* and is incompatible with PHP version ' . phpversion() . '.', 'User is informed when the PHP dependency requirement of a module is not met.');
- $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[system_incompatible_php_version_test][enable]"]');
- $this->assert(count($checkbox) == 1, 'Checkbox for the module is disabled.');
- }
-
- /**
- * Tests enabling a module that depends on a module which fails hook_requirements().
- */
- public function testEnableRequirementsFailureDependency() {
- \Drupal::service('module_installer')->install(['comment']);
-
- $this->assertModules(['requirements1_test'], FALSE);
- $this->assertModules(['requirements2_test'], FALSE);
-
- // Attempt to install both modules at the same time.
- $edit = [];
- $edit['modules[requirements1_test][enable]'] = 'requirements1_test';
- $edit['modules[requirements2_test][enable]'] = 'requirements2_test';
- $this->drupalPostForm('admin/modules', $edit, t('Install'));
-
- // Makes sure the modules were NOT installed.
- $this->assertText(t('Requirements 1 Test failed requirements'), 'Modules status has been updated.');
- $this->assertModules(['requirements1_test'], FALSE);
- $this->assertModules(['requirements2_test'], FALSE);
-
- // Makes sure that already enabled modules the failing modules depend on
- // were not disabled.
- $this->assertModules(['comment'], TRUE);
- }
-
- /**
- * Tests that module dependencies are enabled in the correct order in the UI.
- *
- * Dependencies should be enabled before their dependents.
- */
- public function testModuleEnableOrder() {
- \Drupal::service('module_installer')->install(['module_test'], FALSE);
- $this->resetAll();
- $this->assertModules(['module_test'], TRUE);
- \Drupal::state()->set('module_test.dependency', 'dependency');
- // module_test creates a dependency chain:
- // - color depends on config
- // - config depends on help
- $expected_order = ['help', 'config', 'color'];
-
- // Enable the modules through the UI, verifying that the dependency chain
- // is correct.
- $edit = [];
- $edit['modules[color][enable]'] = 'color';
- $this->drupalPostForm('admin/modules', $edit, t('Install'));
- $this->assertModules(['color'], FALSE);
- // Note that dependencies are sorted alphabetically in the confirmation
- // message.
- $this->assertText(t('You must enable the Configuration Manager, Help modules to install Color.'));
-
- $edit['modules[config][enable]'] = 'config';
- $edit['modules[help][enable]'] = 'help';
- $this->drupalPostForm('admin/modules', $edit, t('Install'));
- $this->assertModules(['color', 'config', 'help'], TRUE);
-
- // Check the actual order which is saved by module_test_modules_enabled().
- $module_order = \Drupal::state()->get('module_test.install_order') ?: [];
- $this->assertIdentical($module_order, $expected_order);
- }
-
- /**
- * Tests attempting to uninstall a module that has installed dependents.
- */
- public function testUninstallDependents() {
- // Enable the forum module.
- $edit = ['modules[forum][enable]' => 'forum'];
- $this->drupalPostForm('admin/modules', $edit, t('Install'));
- $this->drupalPostForm(NULL, [], t('Continue'));
- $this->assertModules(['forum'], TRUE);
-
- // Check that the comment module cannot be uninstalled.
- $this->drupalGet('admin/modules/uninstall');
- $checkbox = $this->xpath('//input[@type="checkbox" and @name="uninstall[comment]" and @disabled="disabled"]');
- $this->assert(count($checkbox) == 1, 'Checkbox for uninstalling the comment module is disabled.');
-
- // Delete any forum terms.
- $vid = $this->config('forum.settings')->get('vocabulary');
- // Ensure taxonomy has been loaded into the test-runner after forum was
- // enabled.
- \Drupal::moduleHandler()->load('taxonomy');
- $terms = entity_load_multiple_by_properties('taxonomy_term', ['vid' => $vid]);
- foreach ($terms as $term) {
- $term->delete();
- }
- // Uninstall the forum module, and check that taxonomy now can also be
- // uninstalled.
- $edit = ['uninstall[forum]' => 'forum'];
- $this->drupalPostForm('admin/modules/uninstall', $edit, t('Uninstall'));
- $this->drupalPostForm(NULL, NULL, t('Uninstall'));
- $this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.');
-
- // Uninstall comment module.
- $edit = ['uninstall[comment]' => 'comment'];
- $this->drupalPostForm('admin/modules/uninstall', $edit, t('Uninstall'));
- $this->drupalPostForm(NULL, NULL, t('Uninstall'));
- $this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.');
- }
-
-}
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/Tests/Module/HookRequirementsTest.php
--- a/core/modules/system/src/Tests/Module/HookRequirementsTest.php Fri Feb 23 15:51:18 2018 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-assertModules(['requirements1_test'], FALSE);
-
- // Attempt to install the requirements1_test module.
- $edit = [];
- $edit['modules[requirements1_test][enable]'] = 'requirements1_test';
- $this->drupalPostForm('admin/modules', $edit, t('Install'));
-
- // Makes sure the module was NOT installed.
- $this->assertText(t('Requirements 1 Test failed requirements'), 'Modules status has been updated.');
- $this->assertModules(['requirements1_test'], FALSE);
- }
-
-}
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/Tests/Module/InstallUninstallTest.php
--- a/core/modules/system/src/Tests/Module/InstallUninstallTest.php Fri Feb 23 15:51:18 2018 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,351 +0,0 @@
-container->get('state')->set('system_test.verbose_module_hooks', TRUE);
-
- // Install and uninstall module_test to ensure hook_preinstall_module and
- // hook_preuninstall_module are fired as expected.
- $this->container->get('module_installer')->install(['module_test']);
- $this->assertEqual($this->container->get('state')->get('system_test_preinstall_module'), 'module_test');
- $this->container->get('module_installer')->uninstall(['module_test']);
- $this->assertEqual($this->container->get('state')->get('system_test_preuninstall_module'), 'module_test');
- $this->resetAll();
-
- $all_modules = system_rebuild_module_data();
-
- // Test help on required modules, but do not test uninstalling.
- $required_modules = array_filter($all_modules, function ($module) {
- if (!empty($module->info['required']) || $module->status == TRUE) {
- if ($module->info['package'] != 'Testing' && empty($module->info['hidden'])) {
- return TRUE;
- }
- }
- return FALSE;
- });
-
- $required_modules['help'] = $all_modules['help'];
-
- // Test uninstalling without hidden, required, and already enabled modules.
- $all_modules = array_filter($all_modules, function ($module) {
- if (!empty($module->info['hidden']) || !empty($module->info['required']) || $module->status == TRUE || $module->info['package'] == 'Testing') {
- return FALSE;
- }
- return TRUE;
- });
-
- // Install the Help module, and verify it installed successfully.
- unset($all_modules['help']);
- $this->assertModuleNotInstalled('help');
- $edit = [];
- $edit["modules[help][enable]"] = TRUE;
- $this->drupalPostForm('admin/modules', $edit, t('Install'));
- $this->assertText('has been enabled', 'Modules status has been updated.');
- $this->assertText(t('hook_modules_installed fired for help'));
- $this->assertModuleSuccessfullyInstalled('help');
-
- // Test help for the required modules.
- foreach ($required_modules as $name => $module) {
- $this->assertHelp($name, $module->info['name']);
- }
-
- // Go through each module in the list and try to install and uninstall
- // it with its dependencies.
- while (list($name, $module) = each($all_modules)) {
- $was_installed_list = \Drupal::moduleHandler()->getModuleList();
-
- // Start a list of modules that we expect to be installed this time.
- $modules_to_install = [$name];
- foreach (array_keys($module->requires) as $dependency) {
- if (isset($all_modules[$dependency])) {
- $modules_to_install[] = $dependency;
- }
- }
-
- // Check that each module is not yet enabled and does not have any
- // database tables yet.
- foreach ($modules_to_install as $module_to_install) {
- $this->assertModuleNotInstalled($module_to_install);
- }
-
- // Install the module.
- $edit = [];
- $package = $module->info['package'];
- $edit['modules[' . $name . '][enable]'] = TRUE;
- $this->drupalPostForm('admin/modules', $edit, t('Install'));
-
- // Handle experimental modules, which require a confirmation screen.
- if ($package == 'Core (Experimental)') {
- $this->assertText('Are you sure you wish to enable experimental modules?');
- if (count($modules_to_install) > 1) {
- // When there are experimental modules, needed dependencies do not
- // result in the same page title, but there will be expected text
- // indicating they need to be enabled.
- $this->assertText('You must enable');
- }
- $this->drupalPostForm(NULL, [], t('Continue'));
- }
- // Handle the case where modules were installed along with this one and
- // where we therefore hit a confirmation screen.
- elseif (count($modules_to_install) > 1) {
- // Verify that we are on the correct form and that the expected text
- // about enabling dependencies appears.
- $this->assertText('Some required modules must be enabled');
- $this->assertText('You must enable');
- $this->drupalPostForm(NULL, [], t('Continue'));
- }
-
- // List the module display names to check the confirmation message.
- $module_names = [];
- foreach ($modules_to_install as $module_to_install) {
- $module_names[] = $all_modules[$module_to_install]->info['name'];
- }
- $expected_text = \Drupal::translation()->formatPlural(count($module_names), 'Module @name has been enabled.', '@count modules have been enabled: @names.', [
- '@name' => $module_names[0],
- '@names' => implode(', ', $module_names),
- ]);
- $this->assertText($expected_text, 'Modules status has been updated.');
-
- // Check that hook_modules_installed() was invoked with the expected list
- // of modules, that each module's database tables now exist, and that
- // appropriate messages appear in the logs.
- foreach ($modules_to_install as $module_to_install) {
- $this->assertText(t('hook_modules_installed fired for @module', ['@module' => $module_to_install]));
- $this->assertLogMessage('system', "%module module installed.", ['%module' => $module_to_install], RfcLogLevel::INFO);
- $this->assertInstallModuleUpdates($module_to_install);
- $this->assertModuleSuccessfullyInstalled($module_to_install);
- }
-
- // Verify the help page.
- $this->assertHelp($name, $module->info['name']);
-
- // Uninstall the original module, plus everything else that was installed
- // with it.
- if ($name == 'forum') {
- // Forum has an extra step to be able to uninstall it.
- $this->preUninstallForum();
- }
-
- $now_installed_list = \Drupal::moduleHandler()->getModuleList();
- $added_modules = array_diff(array_keys($now_installed_list), array_keys($was_installed_list));
- while ($added_modules) {
- $initial_count = count($added_modules);
- foreach ($added_modules as $to_uninstall) {
- // See if we can currently uninstall this module (if its dependencies
- // have been uninstalled), and do so if we can.
- $this->drupalGet('admin/modules/uninstall');
- $field_name = "uninstall[$to_uninstall]";
- $has_checkbox = $this->xpath('//input[@type="checkbox" and @name="' . $field_name . '"]');
- $disabled = $this->xpath('//input[@type="checkbox" and @name="' . $field_name . '" and @disabled="disabled"]');
-
- if (!empty($has_checkbox) && empty($disabled)) {
- // This one is eligible for being uninstalled.
- $package = $all_modules[$to_uninstall]->info['package'];
- $this->assertSuccessfulUninstall($to_uninstall, $package);
- $added_modules = array_diff($added_modules, [$to_uninstall]);
- }
- }
-
- // If we were not able to find a module to uninstall, fail and exit the
- // loop.
- $final_count = count($added_modules);
- if ($initial_count == $final_count) {
- $this->fail('Remaining modules could not be uninstalled for ' . $name);
- break;
- }
- }
- }
-
- // Uninstall the help module and put it back into the list of modules.
- $all_modules['help'] = $required_modules['help'];
- $this->assertSuccessfulUninstall('help', $required_modules['help']->info['package']);
-
- // Now that all modules have been tested, go back and try to enable them
- // all again at once. This tests two things:
- // - That each module can be successfully enabled again after being
- // uninstalled.
- // - That enabling more than one module at the same time does not lead to
- // any errors.
- $edit = [];
- $experimental = FALSE;
- foreach ($all_modules as $name => $module) {
- $edit['modules[' . $name . '][enable]'] = TRUE;
- // Track whether there is at least one experimental module.
- if ($module->info['package'] == 'Core (Experimental)') {
- $experimental = TRUE;
- }
- }
- $this->drupalPostForm('admin/modules', $edit, t('Install'));
-
- // If there are experimental modules, click the confirm form.
- if ($experimental) {
- $this->assertText('Are you sure you wish to enable experimental modules?');
- $this->drupalPostForm(NULL, [], t('Continue'));
- }
- // The string tested here is translatable but we are only using a part of it
- // so using a translated string is wrong. Doing so would create a new string
- // to translate.
- $this->assertText(new FormattableMarkup('@count modules have been enabled: ', ['@count' => count($all_modules)]), 'Modules status has been updated.');
- }
-
- /**
- * Asserts that a module is not yet installed.
- *
- * @param string $name
- * Name of the module to check.
- */
- protected function assertModuleNotInstalled($name) {
- $this->assertModules([$name], FALSE);
- $this->assertModuleTablesDoNotExist($name);
- }
-
- /**
- * Asserts that a module was successfully installed.
- *
- * @param string $name
- * Name of the module to check.
- */
- protected function assertModuleSuccessfullyInstalled($name) {
- $this->assertModules([$name], TRUE);
- $this->assertModuleTablesExist($name);
- $this->assertModuleConfig($name);
- }
-
- /**
- * Uninstalls a module and asserts that it was done correctly.
- *
- * @param string $module
- * The name of the module to uninstall.
- * @param string $package
- * (optional) The package of the module to uninstall. Defaults
- * to 'Core'.
- */
- protected function assertSuccessfulUninstall($module, $package = 'Core') {
- $edit = [];
- $edit['uninstall[' . $module . ']'] = TRUE;
- $this->drupalPostForm('admin/modules/uninstall', $edit, t('Uninstall'));
- $this->drupalPostForm(NULL, NULL, t('Uninstall'));
- $this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.');
- $this->assertModules([$module], FALSE);
-
- // Check that the appropriate hook was fired and the appropriate log
- // message appears. (But don't check for the log message if the dblog
- // module was just uninstalled, since the {watchdog} table won't be there
- // anymore.)
- $this->assertText(t('hook_modules_uninstalled fired for @module', ['@module' => $module]));
- $this->assertLogMessage('system', "%module module uninstalled.", ['%module' => $module], RfcLogLevel::INFO);
-
- // Check that the module's database tables no longer exist.
- $this->assertModuleTablesDoNotExist($module);
- // Check that the module's config files no longer exist.
- $this->assertNoModuleConfig($module);
- $this->assertUninstallModuleUpdates($module);
- }
-
- /**
- * Asserts the module post update functions after install.
- *
- * @param string $module
- * The module that got installed.
- */
- protected function assertInstallModuleUpdates($module) {
- /** @var \Drupal\Core\Update\UpdateRegistry $post_update_registry */
- $post_update_registry = \Drupal::service('update.post_update_registry');
- $all_update_functions = $post_update_registry->getPendingUpdateFunctions();
- $empty_result = TRUE;
- foreach ($all_update_functions as $function) {
- list($function_module,) = explode('_post_update_', $function);
- if ($module === $function_module) {
- $empty_result = FALSE;
- break;
- }
- }
- $this->assertTrue($empty_result, 'Ensures that no pending post update functions are available.');
-
- $existing_updates = \Drupal::keyValue('post_update')->get('existing_updates', []);
- switch ($module) {
- case 'block':
- $this->assertFalse(array_diff(['block_post_update_disable_blocks_with_missing_contexts'], $existing_updates));
- break;
- case 'update_test_postupdate':
- $this->assertFalse(array_diff(['update_test_postupdate_post_update_first', 'update_test_postupdate_post_update_second', 'update_test_postupdate_post_update_test1', 'update_test_postupdate_post_update_test0'], $existing_updates));
- break;
- }
- }
-
- /**
- * Asserts the module post update functions after uninstall.
- *
- * @param string $module
- * The module that got installed.
- */
- protected function assertUninstallModuleUpdates($module) {
- /** @var \Drupal\Core\Update\UpdateRegistry $post_update_registry */
- $post_update_registry = \Drupal::service('update.post_update_registry');
- $all_update_functions = $post_update_registry->getPendingUpdateFunctions();
-
- switch ($module) {
- case 'block':
- $this->assertFalse(array_intersect(['block_post_update_disable_blocks_with_missing_contexts'], $all_update_functions), 'Asserts that no pending post update functions are available.');
-
- $existing_updates = \Drupal::keyValue('post_update')->get('existing_updates', []);
- $this->assertFalse(array_intersect(['block_post_update_disable_blocks_with_missing_contexts'], $existing_updates), 'Asserts that no post update functions are stored in keyvalue store.');
- break;
- }
- }
-
- /**
- * Verifies a module's help.
- *
- * Verifies that the module help page from hook_help() exists and can be
- * displayed, and that it contains the phrase "Foo Bar module", where "Foo
- * Bar" is the name of the module from the .info.yml file.
- *
- * @param string $module
- * Machine name of the module to verify.
- * @param string $name
- * Human-readable name of the module to verify.
- */
- protected function assertHelp($module, $name) {
- $this->drupalGet('admin/help/' . $module);
- $this->assertResponse(200, "Help for $module displayed successfully");
- $this->assertText($name . ' module', "'$name module' is on the help page for $module");
- $this->assertLink('online documentation for the ' . $name . ' module', 0, "Correct online documentation link is in the help page for $module");
- }
-
- /**
- * Deletes forum taxonomy terms, so Forum can be uninstalled.
- */
- protected function preUninstallForum() {
- // There only should be a 'General discussion' term in the 'forums'
- // vocabulary, but just delete any terms there in case the name changes.
- $query = \Drupal::entityQuery('taxonomy_term');
- $query->condition('vid', 'forums');
- $ids = $query->execute();
- $storage = \Drupal::entityManager()->getStorage('taxonomy_term');
- $terms = $storage->loadMultiple($ids);
- $storage->delete($terms);
- }
-
-}
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/Tests/Module/PrepareUninstallTest.php
--- a/core/modules/system/src/Tests/Module/PrepareUninstallTest.php Fri Feb 23 15:51:18 2018 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,179 +0,0 @@
-drupalCreateUser(['administer modules']);
- $this->drupalLogin($admin_user);
-
- // Create 10 nodes.
- for ($i = 1; $i <= 5; $i++) {
- $this->nodes[] = $this->drupalCreateNode(['type' => 'page']);
- $this->nodes[] = $this->drupalCreateNode(['type' => 'article']);
- }
-
- // Create 3 top-level taxonomy terms, each with 11 children.
- $vocabulary = $this->createVocabulary();
- for ($i = 1; $i <= 3; $i++) {
- $term = $this->createTerm($vocabulary);
- $this->terms[] = $term;
- for ($j = 1; $j <= 11; $j++) {
- $this->terms[] = $this->createTerm($vocabulary, ['parent' => ['target_id' => $term->id()]]);
- }
- }
- }
-
- /**
- * Tests that Node and Taxonomy can be uninstalled.
- */
- public function testUninstall() {
- // Check that Taxonomy cannot be uninstalled yet.
- $this->drupalGet('admin/modules/uninstall');
- $this->assertText('Remove content items');
- $this->assertLinkByHref('admin/modules/uninstall/entity/taxonomy_term');
-
- // Delete Taxonomy term data.
- $this->drupalGet('admin/modules/uninstall/entity/taxonomy_term');
- $term_count = count($this->terms);
- for ($i = 1; $i < 11; $i++) {
- $this->assertText($this->terms[$term_count - $i]->label());
- }
- $term_count = $term_count - 10;
- $this->assertText("And $term_count more taxonomy term entities.");
- $this->assertText('This action cannot be undone.');
- $this->assertText('Make a backup of your database if you want to be able to restore these items.');
- $this->drupalPostForm(NULL, [], t('Delete all taxonomy term entities'));
-
- // Check that we are redirected to the uninstall page and data has been
- // removed.
- $this->assertUrl('admin/modules/uninstall', []);
- $this->assertText('All taxonomy term entities have been deleted.');
-
- // Check that there is no more data to be deleted, Taxonomy is ready to be
- // uninstalled.
- $this->assertText('Enables the categorization of content.');
- $this->assertNoLinkByHref('admin/modules/uninstall/entity/taxonomy_term');
-
- // Uninstall the Taxonomy module.
- $this->drupalPostForm('admin/modules/uninstall', ['uninstall[taxonomy]' => TRUE], t('Uninstall'));
- $this->drupalPostForm(NULL, [], t('Uninstall'));
- $this->assertText('The selected modules have been uninstalled.');
- $this->assertNoText('Enables the categorization of content.');
-
- // Check Node cannot be uninstalled yet, there is content to be removed.
- $this->drupalGet('admin/modules/uninstall');
- $this->assertText('Remove content items');
- $this->assertLinkByHref('admin/modules/uninstall/entity/node');
-
- // Delete Node data.
- $this->drupalGet('admin/modules/uninstall/entity/node');
- // All 10 nodes should be listed.
- foreach ($this->nodes as $node) {
- $this->assertText($node->label());
- }
-
- // Ensures there is no more count when not necessary.
- $this->assertNoText('And 0 more content');
- $this->assertText('This action cannot be undone.');
- $this->assertText('Make a backup of your database if you want to be able to restore these items.');
-
- // Create another node so we have 11.
- $this->nodes[] = $this->drupalCreateNode(['type' => 'page']);
- $this->drupalGet('admin/modules/uninstall/entity/node');
- // Ensures singular case is used when a single entity is left after listing
- // the first 10's labels.
- $this->assertText('And 1 more content item.');
-
- // Create another node so we have 12.
- $this->nodes[] = $this->drupalCreateNode(['type' => 'article']);
- $this->drupalGet('admin/modules/uninstall/entity/node');
- // Ensures singular case is used when a single entity is left after listing
- // the first 10's labels.
- $this->assertText('And 2 more content items.');
-
- $this->drupalPostForm(NULL, [], t('Delete all content items'));
-
- // Check we are redirected to the uninstall page and data has been removed.
- $this->assertUrl('admin/modules/uninstall', []);
- $this->assertText('All content items have been deleted.');
-
- // Check there is no more data to be deleted, Node is ready to be
- // uninstalled.
- $this->assertText('Allows content to be submitted to the site and displayed on pages.');
- $this->assertNoLinkByHref('admin/modules/uninstall/entity/node');
-
- // Uninstall Node module.
- $this->drupalPostForm('admin/modules/uninstall', ['uninstall[node]' => TRUE], t('Uninstall'));
- $this->drupalPostForm(NULL, [], t('Uninstall'));
- $this->assertText('The selected modules have been uninstalled.');
- $this->assertNoText('Allows content to be submitted to the site and displayed on pages.');
-
- // Ensure the proper response when accessing a non-existent entity type.
- $this->drupalGet('admin/modules/uninstall/entity/node');
- $this->assertResponse(404, 'Entity types that do not exist result in a 404.');
-
- // Test an entity type which does not have any existing entities.
- $this->drupalGet('admin/modules/uninstall/entity/entity_test_no_label');
- $this->assertText('There are 0 entity test without label entities to delete.');
- $button_xpath = '//input[@type="submit"][@value="Delete all entity test without label entities"]';
- $this->assertNoFieldByXPath($button_xpath, NULL, 'Button with value "Delete all entity test without label entities" not found');
-
- // Test an entity type without a label.
- /** @var \Drupal\Core\Entity\EntityStorageInterface $storage */
- $storage = $this->container->get('entity.manager')
- ->getStorage('entity_test_no_label');
- $storage->create([
- 'id' => Unicode::strtolower($this->randomMachineName()),
- 'name' => $this->randomMachineName(),
- ])->save();
- $this->drupalGet('admin/modules/uninstall/entity/entity_test_no_label');
- $this->assertText('This will delete 1 entity test without label.');
- $this->assertFieldByXPath($button_xpath, NULL, 'Button with value "Delete all entity test without label entities" found');
- $storage->create([
- 'id' => Unicode::strtolower($this->randomMachineName()),
- 'name' => $this->randomMachineName(),
- ])->save();
- $this->drupalGet('admin/modules/uninstall/entity/entity_test_no_label');
- $this->assertText('This will delete 2 entity test without label entities.');
- }
-
-}
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/Tests/Module/RequiredTest.php
--- a/core/modules/system/src/Tests/Module/RequiredTest.php Fri Feb 23 15:51:18 2018 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-drupalGet('admin/modules');
- foreach ($module_info as $module => $info) {
- // Check to make sure the checkbox for each required module is disabled
- // and checked (or absent from the page if the module is also hidden).
- if (!empty($info['required'])) {
- $field_name = 'modules[' . $module . '][enable]';
- if (empty($info['hidden'])) {
- $this->assertFieldByXPath("//input[@name='$field_name' and @disabled='disabled' and @checked='checked']", '', format_string('Field @name was disabled and checked.', ['@name' => $field_name]));
- }
- else {
- $this->assertNoFieldByName($field_name);
- }
- }
- }
- }
-
-}
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/Tests/Module/VersionTest.php
--- a/core/modules/system/src/Tests/Module/VersionTest.php Fri Feb 23 15:51:18 2018 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-2.x)',
- // Another branch compatibility.
- 'common_test (<=2.x)',
- // Another branch incompatibility.
- 'common_test (<2.x)',
- // Another branch compatibility.
- 'common_test (>=2.x)',
- // Nonsense, misses a dash. Incompatible with everything.
- 'common_test (=8.x2.x, >=2.4)',
- // Core version is optional. Compatible.
- 'common_test (=8.x-2.x, >=2.4-alpha2)',
- // Test !=, explicitly incompatible.
- 'common_test (=2.x, !=2.4-beta3)',
- // Three operations. Compatible.
- 'common_test (=2.x, !=2.3, <2.5)',
- // Testing extra version. Incompatible.
- 'common_test (<=2.4-beta2)',
- // Testing extra version. Compatible.
- 'common_test (>2.4-beta2)',
- // Testing extra version. Incompatible.
- 'common_test (>2.4-rc0)',
- ];
- \Drupal::state()->set('system_test.dependencies', $dependencies);
- $n = count($dependencies);
- for ($i = 0; $i < $n; $i++) {
- $this->drupalGet('admin/modules');
- $checkbox = $this->xpath('//input[@id="edit-modules-module-test-enable"]');
- $this->assertEqual(!empty($checkbox[0]['disabled']), $i % 2, $dependencies[$i]);
- }
- }
-
-}
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/Tests/Routing/MockRouteProvider.php
--- a/core/modules/system/src/Tests/Routing/MockRouteProvider.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/system/src/Tests/Routing/MockRouteProvider.php Fri Feb 23 15:52:07 2018 +0000
@@ -15,7 +15,7 @@
/**
* A collection of routes for this route provider.
*
- * @var RouteCollection
+ * @var \Symfony\Component\Routing\RouteCollection
*/
protected $routes;
diff -r bfffd8d7479a -r 7a779792577d core/modules/system/src/Tests/Routing/RouterTest.php
--- a/core/modules/system/src/Tests/Routing/RouterTest.php Fri Feb 23 15:51:18 2018 +0000
+++ b/core/modules/system/src/Tests/Routing/RouterTest.php Fri Feb 23 15:52:07 2018 +0000
@@ -53,7 +53,6 @@
// a page inception style. This test verifies that is not happening.
$this->assertNoPattern('#