' . t('Most configuration is organized into a hierarchy of settings; at a minimum, it is a one-level hierarchy where each setting has a name and a value, and the hierarchy comes in when some of the settings have multiple components.') . '
' . t('Configuration items are normalized and formatted before computing differences. The normalization step alphabetizes the components at each level of the hierarchy, and removes a few components whose differences should be ignored, such as the UUID. The formatting step shows the full hierarchy of each configuration value with :: separators for the hierarchy levels, and a : separator between the lowest-level setting name and the value, so that in a line-by-line diff you can always see which values are actually different. Green lines with + signs have been added, and yellow lines with - signs have been removed.') . '
' . t('Note that differences are considering the base configuration, without overrides from your settings.php file, or translations.') . '
';
}
}
+
+/**
+ * Implements hook_menu_links_discovered_alter().
+ */
+function config_update_ui_menu_links_discovered_alter(&$links) {
+ if (\Drupal::moduleHandler()->moduleExists('admin_toolbar_tools')) {
+ // Add the Updates report link to the Tools menu, but only if the
+ // Admin Toolbar Extra Tools module is present.
+ $links['admin_toolbar_tools.config.update'] = [
+ 'title' => t('Updates report'),
+ 'route_name' => 'config_update_ui.report',
+ 'menu_name' => 'admin',
+ 'parent' => 'config.sync',
+ 'weight' => 3,
+ ];
+ }
+}
diff --git a/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigDeleteConfirmForm.php b/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigDeleteConfirmForm.php
index e8206b581..c11e9ba94 100644
--- a/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigDeleteConfirmForm.php
+++ b/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigDeleteConfirmForm.php
@@ -137,7 +137,7 @@ class ConfigDeleteConfirmForm extends ConfirmFormBase {
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->configRevert->delete($this->type, $this->name);
- drupal_set_message($this->t('The configuration was deleted.'));
+ $this->messenger()->addMessage($this->t('The configuration %item has been deleted.', ['%item' => $this->name]));
$form_state->setRedirectUrl($this->getCancelUrl());
}
diff --git a/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigImportConfirmForm.php b/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigImportConfirmForm.php
index 20790ed73..2d064f6e2 100644
--- a/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigImportConfirmForm.php
+++ b/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigImportConfirmForm.php
@@ -139,7 +139,7 @@ class ConfigImportConfirmForm extends ConfirmFormBase {
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->configRevert->import($this->type, $this->name);
- drupal_set_message($this->t('The configuration was imported from its source.'));
+ $this->messenger()->addMessage($this->t('The configuration %item has been imported from its source.', ['%item' => $this->name]));
$form_state->setRedirectUrl($this->getCancelUrl());
}
diff --git a/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigRevertConfirmForm.php b/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigRevertConfirmForm.php
index 9699ba3a0..8785d0fc5 100644
--- a/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigRevertConfirmForm.php
+++ b/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigRevertConfirmForm.php
@@ -139,7 +139,7 @@ class ConfigRevertConfirmForm extends ConfirmFormBase {
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->configRevert->revert($this->type, $this->name);
- drupal_set_message($this->t('The configuration was reverted to its source.'));
+ $this->messenger()->addMessage($this->t('The configuration %item has been reverted to its source.', ['%item' => $this->name]));
$form_state->setRedirectUrl($this->getCancelUrl());
}
diff --git a/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Tests/ConfigProfileOverridesTest.php b/sites/all/modules/contrib/admin/config_update/config_update_ui/tests/src/Functional/ConfigProfileOverridesTest.php
similarity index 81%
rename from sites/all/modules/contrib/admin/config_update/config_update_ui/src/Tests/ConfigProfileOverridesTest.php
rename to sites/all/modules/contrib/admin/config_update/config_update_ui/tests/src/Functional/ConfigProfileOverridesTest.php
index 299ae9c3b..f2ced76e1 100644
--- a/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Tests/ConfigProfileOverridesTest.php
+++ b/sites/all/modules/contrib/admin/config_update/config_update_ui/tests/src/Functional/ConfigProfileOverridesTest.php
@@ -1,15 +1,15 @@
adminUser = $this->drupalCreateUser([
+ $this->adminUser = $this->createUser([
'access administration pages',
'administer themes',
'view config updates report',
@@ -68,7 +68,8 @@ class ConfigProfileOverridesTest extends WebTestBase {
// that system.theme is not shown (it should not be missing, or added,
// or overridden).
$this->drupalGet('admin/config/development/configuration/report/type/system.simple');
- $this->assertNoRaw('system.theme');
+ $session = $this->assertSession();
+ $session->responseNotContains('system.theme');
// Go to the Appearance page and change the theme to whatever is currently
// disabled. Return to the report and verify that system.theme is there,
@@ -76,22 +77,25 @@ class ConfigProfileOverridesTest extends WebTestBase {
$this->drupalGet('admin/appearance');
$this->clickLink('Install and set as default');
$this->drupalGet('admin/config/development/configuration/report/type/system.simple');
- $this->assertText('system.theme');
+ $session = $this->assertSession();
+ $session->pageTextContains('system.theme');
// Look at the differences for system.theme and verify it's against
// the standard profile version, not default version. The line for
// default should show bartik as the source; if it's against the system
// version, the word bartik would not be there.
$this->drupalGet('admin/config/development/configuration/report/diff/system.simple/system.theme');
- $this->assertText('bartik');
+ $session = $this->assertSession();
+ $session->pageTextContains('bartik');
// Revert and verify that it reverted to the profile version, not the
// system module version.
$this->drupalGet('admin/config/development/configuration/report/revert/system.simple/system.theme');
$this->drupalPostForm(NULL, [], 'Revert');
$this->drupalGet('admin/config/development/configuration/single/export/system.simple/system.theme');
- $this->assertText('admin: seven');
- $this->assertText('default: bartik');
+ $session = $this->assertSession();
+ $session->pageTextContains('admin: seven');
+ $session->pageTextContains('default: bartik');
}
}
diff --git a/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Tests/ConfigUpdateTest.php b/sites/all/modules/contrib/admin/config_update/config_update_ui/tests/src/Functional/ConfigUpdateTest.php
similarity index 70%
rename from sites/all/modules/contrib/admin/config_update/config_update_ui/src/Tests/ConfigUpdateTest.php
rename to sites/all/modules/contrib/admin/config_update/config_update_ui/tests/src/Functional/ConfigUpdateTest.php
index 1ac7aefba..4f2c943d1 100644
--- a/sites/all/modules/contrib/admin/config_update/config_update_ui/src/Tests/ConfigUpdateTest.php
+++ b/sites/all/modules/contrib/admin/config_update/config_update_ui/tests/src/Functional/ConfigUpdateTest.php
@@ -1,15 +1,15 @@
adminUser = $this->drupalCreateUser([
+ $this->adminUser = $this->createUser([
'access administration pages',
'administer search',
'view config updates report',
@@ -60,8 +60,8 @@ class ConfigUpdateTest extends WebTestBase {
$this->drupalLogin($this->adminUser);
// Make sure local tasks and page title are showing.
- $this->drupalPlaceBlock('local_tasks_block');
- $this->drupalPlaceBlock('page_title_block');
+ $this->placeBlock('local_tasks_block');
+ $this->placeBlock('page_title_block');
// Load the Drush include file so that its functions can be tested, plus
// the Drush testing include file.
@@ -103,13 +103,15 @@ class ConfigUpdateTest extends WebTestBase {
$this->assertReport('Testing profile', [], [], [], $inactive, ['added']);
// The locale.settings line should show that the Testing profile is the
// provider.
- $this->assertText('Testing profile');
+ $session = $this->assertSession();
+ $session->pageTextContains('Testing profile');
$this->assertDrushReports('profile', '', [], [], [], array_keys($inactive));
// Verify that the user search page cannot be imported (because it already
// exists).
$this->drupalGet('admin/config/development/configuration/report/import/search_page/user_search');
- $this->assertResponse(404);
+ $session = $this->assertSession();
+ $session->statusCodeEquals(404);
// Delete the user search page from the search UI and verify report for
// both the search page config type and user module.
@@ -121,7 +123,8 @@ class ConfigUpdateTest extends WebTestBase {
$this->assertReport('Search page', [], [], [], $inactive);
// The search.page.user_search line should show that the User module is the
// provider.
- $this->assertText('User module');
+ $session = $this->assertSession();
+ $session->pageTextContains('User module');
$this->assertDrushReports('type', 'search_page', [], [], [], array_keys($inactive));
$this->drupalGet('admin/config/development/configuration/report/module/user');
@@ -138,17 +141,20 @@ class ConfigUpdateTest extends WebTestBase {
// Verify that the user search page cannot be reverted (because it does
// not already exist).
$this->drupalGet('admin/config/development/configuration/report/revert/search_page/user_search');
- $this->assertResponse(404);
+ $session = $this->assertSession();
+ $session->statusCodeEquals(404);
// Verify that the delete URL doesn't work either.
$this->drupalGet('admin/config/development/configuration/report/delete/search_page/user_search');
- $this->assertResponse(404);
+ $session = $this->assertSession();
+ $session->statusCodeEquals(404);
// Use the import link to get it back. Do this from the search page
// report to make sure we are importing the right config.
$this->drupalGet('admin/config/development/configuration/report/type/search_page');
$this->clickLink('Import from source');
$this->drupalPostForm(NULL, [], 'Import');
- $this->assertText('The configuration was imported');
+ $session = $this->assertSession();
+ $session->pageTextContains('has been imported');
$this->assertNoReport();
$this->drupalGet('admin/config/development/configuration/report/type/search_page');
$this->assertReport('Search page', [], [], [], []);
@@ -156,8 +162,9 @@ class ConfigUpdateTest extends WebTestBase {
// Verify that after import, there is no config hash generated.
$this->drupalGet('admin/config/development/configuration/single/export/search_page/user_search');
- $this->assertText('id: user_search');
- $this->assertNoText('default_config_hash:');
+ $session = $this->assertSession();
+ $session->pageTextContains('id: user_search');
+ $session->pageTextNotContains('default_config_hash:');
// Test importing again, this time using the Drush import command.
$this->drupalGet('admin/config/search/pages');
@@ -184,10 +191,11 @@ class ConfigUpdateTest extends WebTestBase {
// Test the show differences link.
$this->clickLink('Show differences');
- $this->assertText('Content');
- $this->assertText('New label');
- $this->assertText('node');
- $this->assertText('new_path');
+ $session = $this->assertSession();
+ $session->pageTextContains('Content');
+ $session->pageTextContains('New label');
+ $session->pageTextContains('node');
+ $session->pageTextContains('new_path');
// Test the show differences Drush command.
$output = drush_config_update_ui_config_diff('search.page.node_search');
@@ -203,36 +211,39 @@ class ConfigUpdateTest extends WebTestBase {
// Test the export link.
$this->drupalGet('admin/config/development/configuration/report/type/search_page');
$this->clickLink('Export');
- $this->assertText('Here is your configuration:');
- $this->assertText('id: node_search');
- $this->assertText('New label');
- $this->assertText('path: new_path');
- $this->assertText('search.page.node_search.yml');
+ $session = $this->assertSession();
+ $session->pageTextContains('Here is your configuration:');
+ $session->pageTextContains('id: node_search');
+ $session->pageTextContains('New label');
+ $session->pageTextContains('path: new_path');
+ $session->pageTextContains('search.page.node_search.yml');
- // Grab the uuid and hash lines for the next test.
- $text = $this->getTextContent();
+ // Grab the uuid and hash lines from the exported config for the next test.
+ $text = strip_tags($this->getSession()->getPage()->find('css', 'textarea')->getHtml());
$matches = [];
preg_match('|^.*uuid:.*$|m', $text, $matches);
- $uuid_line = $matches[0];
+ $uuid_line = trim($matches[0]);
preg_match('|^.*default_config_hash:.*$|m', $text, $matches);
- $hash_line = $matches[0];
+ $hash_line = trim($matches[0]);
// Test reverting.
$this->drupalGet('admin/config/development/configuration/report/type/search_page');
$this->clickLink('Revert to source');
- $this->assertText('Are you sure you want to revert');
- $this->assertText('Search page');
- $this->assertText('node_search');
- $this->assertText('Customizations will be lost. This action cannot be undone');
+ $session = $this->assertSession();
+ $session->pageTextContains('Are you sure you want to revert');
+ $session->pageTextContains('Search page');
+ $session->pageTextContains('node_search');
+ $session->pageTextContains('Customizations will be lost. This action cannot be undone');
$this->drupalPostForm(NULL, [], 'Revert');
$this->drupalGet('admin/config/development/configuration/report/type/search_page');
$this->assertReport('Search page', [], [], [], []);
// Verify that the uuid and hash keys were retained in the revert.
$this->drupalGet('admin/config/development/configuration/single/export/search_page/node_search');
- $this->assertText('id: node_search');
- $this->assertText($uuid_line);
- $this->assertText($hash_line);
+ $session = $this->assertSession();
+ $session->pageTextContains('id: node_search');
+ $session->pageTextContains($uuid_line);
+ $session->pageTextContains($hash_line);
// Test reverting again, this time using Drush single revert command.
$this->drupalGet('admin/config/search/pages');
@@ -278,19 +289,22 @@ class ConfigUpdateTest extends WebTestBase {
// Test the export link.
$this->clickLink('Export');
- $this->assertText('Here is your configuration:');
- $this->assertText('id: test');
- $this->assertText('label: test');
- $this->assertText('path: test');
- $this->assertText('search.page.test.yml');
+ $session = $this->assertSession();
+ $session->pageTextContains('Here is your configuration:');
+ $session->pageTextContains('id: test');
+ $session->pageTextContains('label: test');
+ $session->pageTextContains('path: test');
+ $session->pageTextContains('search.page.test.yml');
// Test the delete link.
$this->drupalGet('admin/config/development/configuration/report/type/search_page');
$this->clickLink('Delete');
- $this->assertText('Are you sure');
- $this->assertText('cannot be undone');
+ $session = $this->assertSession();
+ $session->pageTextContains('Are you sure');
+ $session->pageTextContains('cannot be undone');
$this->drupalPostForm(NULL, [], 'Delete');
- $this->assertText('The configuration was deleted');
+ $session = $this->assertSession();
+ $session->pageTextContains('has been deleted');
// And verify the report again.
$this->drupalGet('admin/config/development/configuration/report/type/search_page');
@@ -306,18 +320,20 @@ class ConfigUpdateTest extends WebTestBase {
$this->assertReport('Search module', [], [], $changed, [], ['added']);
$this->clickLink('Show differences');
- $this->assertText('Config difference for Simple configuration search.settings');
- $this->assertText('index::minimum_word_size');
- $this->assertText('4');
+ $session = $this->assertSession();
+ $session->pageTextContains('Config difference for Simple configuration search.settings');
+ $session->pageTextContains('index::minimum_word_size');
+ $session->pageTextContains('4');
$this->drupalGet('admin/config/development/configuration/report/module/search');
$this->clickLink('Export');
- $this->assertText('minimum_word_size: 4');
+ $session = $this->assertSession();
+ $session->pageTextContains('minimum_word_size: 4');
// Grab the hash line for the next test.
- $text = $this->getTextContent();
+ $text = strip_tags($this->getSession()->getPage()->find('css', 'textarea')->getHtml());
$matches = [];
preg_match('|^.*default_config_hash:.*$|m', $text, $matches);
- $hash_line = $matches[0];
+ $hash_line = trim($matches[0]);
$this->drupalGet('admin/config/development/configuration/report/module/search');
$this->clickLink('Revert to source');
@@ -325,7 +341,8 @@ class ConfigUpdateTest extends WebTestBase {
// Verify that the hash was retained in the revert.
$this->drupalGet('admin/config/development/configuration/single/export/system.simple/search.settings');
- $this->assertText($hash_line);
+ $session = $this->assertSession();
+ $session->pageTextContains($hash_line);
$this->drupalGet('admin/config/development/configuration/report/module/search');
$this->assertReport('Search module', [], [], [], [], ['added']);
@@ -338,6 +355,10 @@ class ConfigUpdateTest extends WebTestBase {
$changed = ['filter.format.plain_text' => 'New label'];
$this->drupalGet('admin/config/development/configuration/report/type/filter_format');
$this->assertReport('Text format', [], [], $changed, []);
+
+ // Verify that we can revert non-entity configuration in Drush. Issue:
+ // https://www.drupal.org/project/config_update/issues/2935395
+ drush_config_update_ui_config_revert('system.date');
}
/**
@@ -359,62 +380,63 @@ class ConfigUpdateTest extends WebTestBase {
* Array of report sections to skip checking.
*/
protected function assertReport($title, array $missing, array $added, array $changed, array $inactive, array $skip = []) {
- $this->assertText('Configuration updates report for ' . $title);
- $this->assertText('Generate new report');
+ $session = $this->assertSession();
+ $session->pageTextContains('Configuration updates report for ' . $title);
+ $session->pageTextContains('Generate new report');
if (!in_array('missing', $skip)) {
- $this->assertText('Missing configuration items');
+ $session->pageTextContains('Missing configuration items');
if (count($missing)) {
foreach ($missing as $name => $label) {
- $this->assertText($name);
- $this->assertText($label);
+ $session->pageTextContains($name);
+ $session->pageTextContains($label);
}
- $this->assertNoText('None: all provided configuration items are in your active configuration.');
+ $session->pageTextNotContains('None: all provided configuration items are in your active configuration.');
}
else {
- $this->assertText('None: all provided configuration items are in your active configuration.');
+ $session->pageTextContains('None: all provided configuration items are in your active configuration.');
}
}
if (!in_array('inactive', $skip)) {
- $this->assertText('Inactive optional items');
+ $session->pageTextContains('Inactive optional items');
if (count($inactive)) {
foreach ($inactive as $name => $label) {
- $this->assertText($name);
- $this->assertText($label);
+ $session->pageTextContains($name);
+ $session->pageTextContains($label);
}
- $this->assertNoText('None: all optional configuration items are in your active configuration.');
+ $session->pageTextNotContains('None: all optional configuration items are in your active configuration.');
}
else {
- $this->assertText('None: all optional configuration items are in your active configuration.');
+ $session->pageTextContains('None: all optional configuration items are in your active configuration.');
}
}
if (!in_array('added', $skip)) {
- $this->assertText('Added configuration items');
+ $session->pageTextContains('Added configuration items');
if (count($added)) {
foreach ($added as $name => $label) {
- $this->assertText($name);
- $this->assertText($label);
+ $session->pageTextContains($name);
+ $session->pageTextContains($label);
}
- $this->assertNoText('None: all active configuration items of this type were provided by modules, themes, or install profile.');
+ $session->pageTextNotContains('None: all active configuration items of this type were provided by modules, themes, or install profile.');
}
else {
- $this->assertText('None: all active configuration items of this type were provided by modules, themes, or install profile.');
+ $session->pageTextContains('None: all active configuration items of this type were provided by modules, themes, or install profile.');
}
}
if (!in_array('changed', $skip)) {
- $this->assertText('Changed configuration items');
+ $session->pageTextContains('Changed configuration items');
if (count($changed)) {
foreach ($changed as $name => $label) {
- $this->assertText($name);
- $this->assertText($label);
+ $session->pageTextContains($name);
+ $session->pageTextContains($label);
}
- $this->assertNoText('None: no active configuration items differ from their current provided versions.');
+ $session->pageTextNotContains('None: no active configuration items differ from their current provided versions.');
}
else {
- $this->assertText('None: no active configuration items differ from their current provided versions.');
+ $session->pageTextContains('None: no active configuration items differ from their current provided versions.');
}
}
}
@@ -440,7 +462,7 @@ class ConfigUpdateTest extends WebTestBase {
protected function assertDrushReports($type, $name, array $missing, array $added, array $changed, array $inactive, array $skip = []) {
if (!in_array('missing', $skip)) {
$output = drush_config_update_ui_config_missing_report($type, $name);
- $this->assertEqual(count($output), count($missing), 'Drush missing report has correct number of items');
+ $this->assertEquals(count($output), count($missing), 'Drush missing report has correct number of items');
if (count($missing)) {
foreach ($missing as $item) {
$this->assertTrue(in_array($item, $output), "Item $item is in the Drush missing report");
@@ -450,7 +472,7 @@ class ConfigUpdateTest extends WebTestBase {
if (!in_array('added', $skip) && $type == 'type') {
$output = drush_config_update_ui_config_added_report($name);
- $this->assertEqual(count($output), count($added), 'Drush added report has correct number of items');
+ $this->assertEquals(count($output), count($added), 'Drush added report has correct number of items');
if (count($added)) {
foreach ($added as $item) {
$this->assertTrue(in_array($item, $output), "Item $item is in the Drush added report");
@@ -460,7 +482,7 @@ class ConfigUpdateTest extends WebTestBase {
if (!in_array('changed', $skip)) {
$output = drush_config_update_ui_config_different_report($type, $name);
- $this->assertEqual(count($output), count($changed), 'Drush changed report has correct number of items');
+ $this->assertEquals(count($output), count($changed), 'Drush changed report has correct number of items');
if (count($changed)) {
foreach ($changed as $item) {
$this->assertTrue(in_array($item, $output), "Item $item is in the Drush changed report");
@@ -470,7 +492,7 @@ class ConfigUpdateTest extends WebTestBase {
if (!in_array('inactive', $skip)) {
$output = drush_config_update_ui_config_inactive_report($type, $name);
- $this->assertEqual(count($output), count($inactive), 'Drush inactive report has correct number of items');
+ $this->assertEquals(count($output), count($inactive), 'Drush inactive report has correct number of items');
if (count($inactive)) {
foreach ($inactive as $item) {
$this->assertTrue(in_array($item, $output), "Item $item is in the Drush inactive report");
@@ -485,37 +507,38 @@ class ConfigUpdateTest extends WebTestBase {
* Assumes you are already on the report form page.
*/
protected function assertNoReport() {
- $this->assertText('Report type');
- $this->assertText('Full report');
- $this->assertText('Single configuration type');
- $this->assertText('Single module');
- $this->assertText('Single theme');
- $this->assertText('Installation profile');
- $this->assertText('Updates report');
- $this->assertNoText('Missing configuration items');
- $this->assertNoText('Added configuration items');
- $this->assertNoText('Changed configuration items');
- $this->assertNoText('Unchanged configuration items');
+ $session = $this->assertSession();
+ $session->pageTextContains('Report type');
+ $session->pageTextContains('Full report');
+ $session->pageTextContains('Single configuration type');
+ $session->pageTextContains('Single module');
+ $session->pageTextContains('Single theme');
+ $session->pageTextContains('Installation profile');
+ $session->pageTextContains('Updates report');
+ $session->pageTextNotContains('Missing configuration items');
+ $session->pageTextNotContains('Added configuration items');
+ $session->pageTextNotContains('Changed configuration items');
+ $session->pageTextNotContains('Unchanged configuration items');
// Verify that certain report links are shown or not shown. For extensions,
// only extensions that have configuration should be shown.
// Modules.
- $this->assertLink('Search');
- $this->assertLink('Field');
- $this->assertNoLink('Configuration Update Base');
- $this->assertNoLink('Configuration Update Reports');
+ $session->linkExists('Search');
+ $session->linkExists('Field');
+ $session->linkNotExists('Configuration Update Base');
+ $session->linkNotExists('Configuration Update Reports');
// Themes.
- $this->assertNoLink('Stark');
- $this->assertNoLink('Classy');
+ $session->linkNotExists('Stark');
+ $session->linkNotExists('Classy');
// Profiles.
- $this->assertLink('Testing');
+ $session->linkExists('Testing');
// Configuration types.
- $this->assertLink('Everything');
- $this->assertLink('Simple configuration');
- $this->assertLink('Search page');
+ $session->linkExists('Everything');
+ $session->linkExists('Simple configuration');
+ $session->linkExists('Search page');
}
}
diff --git a/sites/all/modules/contrib/admin/config_update/drupalci.yml b/sites/all/modules/contrib/admin/config_update/drupalci.yml
new file mode 100644
index 000000000..59a556b5e
--- /dev/null
+++ b/sites/all/modules/contrib/admin/config_update/drupalci.yml
@@ -0,0 +1,37 @@
+# This is the DrupalCI testbot build file for Configuration Update Manager.
+# Learn to make one for your own drupal.org project:
+# https://www.drupal.org/drupalorg/docs/drupal-ci/customizing-drupalci-testing
+build:
+ assessment:
+ validate_codebase:
+ phplint:
+ phpcs:
+ # phpcs will use core's specified version of Coder.
+ sniff-all-files: true
+ halt-on-fail: true
+ testing:
+ # run_tests task is executed several times in order of performance speeds.
+ # halt-on-fail can be set on the run_tests tasks in order to fail fast.
+ # suppress-deprecations is false in order to be alerted to usages of
+ # deprecated code.
+ run_tests.phpunit:
+ types: 'PHPUnit-Unit'
+ testgroups: '--all'
+ suppress-deprecations: false
+ halt-on-fail: false
+ run_tests.kernel:
+ types: 'PHPUnit-Kernel'
+ testgroups: '--all'
+ suppress-deprecations: false
+ halt-on-fail: false
+ run_tests.functional:
+ types: 'PHPUnit-Functional'
+ testgroups: '--all'
+ suppress-deprecations: false
+ halt-on-fail: false
+ run_tests.javascript:
+ concurrency: 15
+ types: 'PHPUnit-FunctionalJavascript'
+ testgroups: '--all'
+ suppress-deprecations: false
+ halt-on-fail: false
diff --git a/sites/all/modules/contrib/admin/config_update/src/ConfigDiffer.php b/sites/all/modules/contrib/admin/config_update/src/ConfigDiffer.php
index dbda8df23..ce161ba56 100644
--- a/sites/all/modules/contrib/admin/config_update/src/ConfigDiffer.php
+++ b/sites/all/modules/contrib/admin/config_update/src/ConfigDiffer.php
@@ -5,6 +5,7 @@ namespace Drupal\config_update;
use Drupal\Component\Diff\Diff;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Core\Serialization\Yaml;
/**
* Provides methods related to config differences.
@@ -14,7 +15,7 @@ class ConfigDiffer implements ConfigDiffInterface {
use StringTranslationTrait;
/**
- * List of elements to ignore when comparing config.
+ * List of elements to ignore on top level when comparing config.
*
* @var string[]
*
@@ -46,7 +47,7 @@ class ConfigDiffer implements ConfigDiffInterface {
* @param \Drupal\Core\StringTranslation\TranslationInterface $translation
* String translation service.
* @param string[] $ignore
- * Config components to ignore.
+ * Config components to ignore at the top level.
* @param string $hierarchy_prefix
* Prefix to use in diffs for array hierarchy.
* @param string $value_prefix
@@ -62,9 +63,9 @@ class ConfigDiffer implements ConfigDiffInterface {
/**
* Normalizes config for comparison.
*
- * Recursively removes elements in the ignore list from configuration,
- * as well as empty array values, and sorts at each level by array key, so
- * that config from different storage can be compared meaningfully.
+ * Removes elements in the ignore list from the top level of configuration,
+ * and at each level of the array, removes empty arrays and sorts by array
+ * key, so that config from different storage can be compared meaningfully.
*
* @param array|null $config
* Configuration array to normalize.
@@ -80,27 +81,40 @@ class ConfigDiffer implements ConfigDiffInterface {
return [];
}
- // Remove "ignore" elements.
+ // Remove "ignore" elements, only at the top level.
foreach ($this->ignore as $element) {
unset($config[$element]);
}
- // Recursively normalize remaining elements, if they are arrays.
- foreach ($config as $key => $value) {
+ // Recursively normalize and return.
+ return $this->normalizeArray($config);
+ }
+
+ /**
+ * Recursively sorts an array by key, and removes empty arrays.
+ *
+ * @param array $array
+ * An array to normalize.
+ *
+ * @return array
+ * An array that is sorted by key, at each level of the array, with empty
+ * arrays removed.
+ */
+ protected function normalizeArray(array $array) {
+ foreach ($array as $key => $value) {
if (is_array($value)) {
- $new = $this->normalize($value);
+ $new = $this->normalizeArray($value);
if (count($new)) {
- $config[$key] = $new;
+ $array[$key] = $new;
}
else {
- unset($config[$key]);
+ unset($array[$key]);
}
}
}
- // Sort and return.
- ksort($config);
- return $config;
+ ksort($array);
+ return $array;
}
/**
@@ -157,11 +171,8 @@ class ConfigDiffer implements ConfigDiffInterface {
$lines[] = $line;
}
}
- elseif (is_null($value)) {
- $lines[] = $section_prefix . $this->valuePrefix . $this->t('(NULL)');
- }
else {
- $lines[] = $section_prefix . $this->valuePrefix . $value;
+ $lines[] = $section_prefix . $this->valuePrefix . Yaml::encode($value);
}
}
diff --git a/sites/all/modules/contrib/admin/config_update/src/ConfigLister.php b/sites/all/modules/contrib/admin/config_update/src/ConfigLister.php
index 4c0bf9a14..06219cce9 100644
--- a/sites/all/modules/contrib/admin/config_update/src/ConfigLister.php
+++ b/sites/all/modules/contrib/admin/config_update/src/ConfigLister.php
@@ -89,7 +89,7 @@ class ConfigLister implements ConfigListInterface {
// Calculate and return the list.
foreach ($this->entityManager->getDefinitions() as $entity_type => $definition) {
- if ($definition->isSubclassOf('Drupal\Core\Config\Entity\ConfigEntityInterface')) {
+ if ($definition->entityClassImplements('Drupal\Core\Config\Entity\ConfigEntityInterface')) {
$this->definitions[$entity_type] = $definition;
$prefix = $definition->getConfigPrefix();
$this->typesByPrefix[$prefix] = $entity_type;
diff --git a/sites/all/modules/contrib/admin/config_update/src/ConfigRevertInterface.php b/sites/all/modules/contrib/admin/config_update/src/ConfigRevertInterface.php
index 18e03fa40..c0ef26d60 100644
--- a/sites/all/modules/contrib/admin/config_update/src/ConfigRevertInterface.php
+++ b/sites/all/modules/contrib/admin/config_update/src/ConfigRevertInterface.php
@@ -72,7 +72,7 @@ interface ConfigRevertInterface {
* The name of the config item, without the prefix.
*
* @return array
- * The configuration value.
+ * The configuration value, or FALSE if it is not found.
*/
public function getFromActive($type, $name);
diff --git a/sites/all/modules/contrib/admin/config_update/src/ConfigReverter.php b/sites/all/modules/contrib/admin/config_update/src/ConfigReverter.php
index 51e255ab6..e47103c8b 100644
--- a/sites/all/modules/contrib/admin/config_update/src/ConfigReverter.php
+++ b/sites/all/modules/contrib/admin/config_update/src/ConfigReverter.php
@@ -87,11 +87,15 @@ class ConfigReverter implements ConfigRevertInterface, ConfigDeleteInterface {
* {@inheritdoc}
*/
public function import($type, $name) {
- // Read the config from the file.
+ // Read the config from the file. Note: Do not call getFromExtension() here
+ // because we need $full_name below.
$full_name = $this->getFullName($type, $name);
- $value = $this->extensionConfigStorage->read($full_name);
- if (!$value) {
- $value = $this->extensionOptionalConfigStorage->read($full_name);
+ $value = FALSE;
+ if ($full_name) {
+ $value = $this->extensionConfigStorage->read($full_name);
+ if (!$value) {
+ $value = $this->extensionOptionalConfigStorage->read($full_name);
+ }
}
if (!$value) {
return FALSE;
@@ -118,36 +122,44 @@ class ConfigReverter implements ConfigRevertInterface, ConfigDeleteInterface {
* {@inheritdoc}
*/
public function revert($type, $name) {
- // Read the config from the file.
+ // Read the config from the file. Note: Do not call getFromExtension() here
+ // because we need $full_name below.
+ $value = FALSE;
$full_name = $this->getFullName($type, $name);
- $value = $this->extensionConfigStorage->read($full_name);
- if (!$value) {
- $value = $this->extensionOptionalConfigStorage->read($full_name);
+ if ($full_name) {
+ $value = $this->extensionConfigStorage->read($full_name);
+ if (!$value) {
+ $value = $this->extensionOptionalConfigStorage->read($full_name);
+ }
}
if (!$value) {
return FALSE;
}
+ // Make sure the configuration exists currently in active storage.
+ if (!$this->activeConfigStorage->read($full_name)) {
+ return FALSE;
+ }
+
+ // Load the current config and replace the value, retaining the config
+ // hash (which is part of the _core config key's value).
if ($type == 'system.simple') {
- // Load the current config and replace the value, retaining the config
- // hash (which is part of the _core config key's value).
$config = $this->configFactory->getEditable($full_name);
$core = $config->get('_core');
- $config->setData($value);
- $config->set('_core', $core);
- $config->save();
+ $config
+ ->setData($value)
+ ->set('_core', $core)
+ ->save();
}
else {
- // Load the current config entity and replace the value. Note that
- // the uuid and _core/hash values are retained for entity-based config,
- // since updateFromStorageRecord() only updates values that are part of
- // the passed-in array, and doesn't remove or alter other values.
$definition = $this->entityManager->getDefinition($type);
$id_key = $definition->getKey('id');
$id = $value[$id_key];
$entity_storage = $this->entityManager->getStorage($type);
$entity = $entity_storage->load($id);
+ $core = $entity->get('_core');
$entity = $entity_storage->updateFromStorageRecord($entity, $value);
+ $entity->set('_core', $core);
$entity->save();
}
@@ -162,11 +174,15 @@ class ConfigReverter implements ConfigRevertInterface, ConfigDeleteInterface {
* {@inheritdoc}
*/
public function delete($type, $name) {
+ $config = FALSE;
$full_name = $this->getFullName($type, $name);
- if (!$full_name) {
- return FALSE;
+ if ($full_name) {
+ // Make sure the configuration exists currently in active storage.
+ if (!$this->activeConfigStorage->read($full_name)) {
+ return FALSE;
+ }
+ $config = $this->configFactory->getEditable($full_name);
}
- $config = $this->configFactory->getEditable($full_name);
if (!$config) {
return FALSE;
}
@@ -183,17 +199,23 @@ class ConfigReverter implements ConfigRevertInterface, ConfigDeleteInterface {
*/
public function getFromActive($type, $name) {
$full_name = $this->getFullName($type, $name);
- return $this->activeConfigStorage->read($full_name);
+ if ($full_name) {
+ return $this->activeConfigStorage->read($full_name);
+ }
+ return FALSE;
}
/**
* {@inheritdoc}
*/
public function getFromExtension($type, $name) {
+ $value = FALSE;
$full_name = $this->getFullName($type, $name);
- $value = $this->extensionConfigStorage->read($full_name);
- if (!$value) {
- $value = $this->extensionOptionalConfigStorage->read($full_name);
+ if ($full_name) {
+ $value = $this->extensionConfigStorage->read($full_name);
+ if (!$value) {
+ $value = $this->extensionOptionalConfigStorage->read($full_name);
+ }
}
return $value;
}
@@ -207,7 +229,7 @@ class ConfigReverter implements ConfigRevertInterface, ConfigDeleteInterface {
* The config name, without prefix.
*
* @return string
- * The config item's full name.
+ * The config item's full name, or FALSE if there is an error.
*/
protected function getFullName($type, $name) {
if ($type == 'system.simple' || !$type) {
@@ -215,8 +237,13 @@ class ConfigReverter implements ConfigRevertInterface, ConfigDeleteInterface {
}
$definition = $this->entityManager->getDefinition($type);
- $prefix = $definition->getConfigPrefix() . '.';
- return $prefix . $name;
+ if ($definition) {
+ $prefix = $definition->getConfigPrefix() . '.';
+ return $prefix . $name;
+ }
+ else {
+ return FALSE;
+ }
}
}
diff --git a/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigDifferTest.php b/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigDifferTest.php
index 9b2ad5746..085291091 100644
--- a/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigDifferTest.php
+++ b/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigDifferTest.php
@@ -3,7 +3,6 @@
namespace Drupal\Tests\config_update\Unit;
use Drupal\config_update\ConfigDiffer;
-use Drupal\Tests\UnitTestCase;
/**
* Tests the \Drupal\config_update\ConfigDiffer class.
@@ -12,14 +11,7 @@ use Drupal\Tests\UnitTestCase;
*
* @coversDefaultClass \Drupal\config_update\ConfigDiffer
*/
-class ConfigDifferTest extends UnitTestCase {
-
- /**
- * The mock translation object.
- *
- * @var \Drupal\Core\StringTranslation\TranslationInterface
- */
- protected $stringTranslation;
+class ConfigDifferTest extends ConfigUpdateUnitTestBase {
/**
* The config differ to test.
@@ -32,12 +24,7 @@ class ConfigDifferTest extends UnitTestCase {
* {@inheritdoc}
*/
protected function setUp() {
- $this->stringTranslation = $this->getMockBuilder('Drupal\Core\StringTranslation\TranslationInterface')->getMock();
- $this->stringTranslation
- ->method('t')
- ->will($this->returnArgument(0));
-
- $this->configDiffer = new ConfigDiffer($this->stringTranslation);
+ $this->configDiffer = new ConfigDiffer($this->getTranslationMock());
}
/**
@@ -59,13 +46,14 @@ class ConfigDifferTest extends UnitTestCase {
'c' => [
'd' => TRUE,
'e' => FALSE,
+ 'empty' => [],
],
];
-
return [
[$base, $base, TRUE],
- // Add _core, omit uuid. Should match.
+ // Add _core, omit uuid at top level. Should match, as both are removed
+ // in normalization process.
[
$base,
[
@@ -75,27 +63,30 @@ class ConfigDifferTest extends UnitTestCase {
'c' => [
'd' => TRUE,
'e' => FALSE,
+ 'empty' => [],
],
],
TRUE,
],
- // Change order. Should match.
+ // Change order in top and deep level. Should match.
[
$base,
[
- 'a' => 'a',
'uuid' => 'bar',
'b' => 0,
+ 'a' => 'a',
'c' => [
- 'd' => TRUE,
'e' => FALSE,
+ 'empty' => [],
+ 'd' => TRUE,
],
],
TRUE,
],
- // Change order and add _core in deeper level. Should match.
+ // Add _core in deeper level. Should not match, as this is removed
+ // only at the top level during normalization.
[
$base,
[
@@ -103,12 +94,31 @@ class ConfigDifferTest extends UnitTestCase {
'a' => 'a',
'b' => 0,
'c' => [
- 'e' => FALSE,
- '_core' => 'foo',
+ '_core' => 'do-not-use-this-key',
'd' => TRUE,
+ 'e' => FALSE,
+ 'empty' => [],
],
],
- TRUE,
+ FALSE,
+ ],
+
+ // Add uuid in deeper level. Should not match, as this is removed
+ // only at the top level during normalization.
+ [
+ $base,
+ [
+ 'uuid' => 'bar',
+ 'a' => 'a',
+ 'b' => 0,
+ 'c' => [
+ 'd' => TRUE,
+ 'e' => FALSE,
+ 'uuid' => 'important',
+ 'empty' => [],
+ ],
+ ],
+ FALSE,
],
// Omit a component. Should not match.
@@ -120,6 +130,7 @@ class ConfigDifferTest extends UnitTestCase {
'c' => [
'd' => TRUE,
'e' => FALSE,
+ 'empty' => [],
],
],
FALSE,
@@ -135,6 +146,7 @@ class ConfigDifferTest extends UnitTestCase {
'c' => [
'd' => TRUE,
'e' => FALSE,
+ 'empty' => [],
],
'f' => 'f',
],
@@ -152,6 +164,24 @@ class ConfigDifferTest extends UnitTestCase {
'c' => [
'd' => TRUE,
'e' => FALSE,
+ 'empty' => [],
+ ],
+ ],
+ FALSE,
+ ],
+
+ // 0 should not match NULL.
+ [
+ $base,
+ [
+ '_core' => 'foo',
+ 'uuid' => 'bar',
+ 'a' => 'a',
+ 'b' => NULL,
+ 'c' => [
+ 'd' => TRUE,
+ 'e' => FALSE,
+ 'empty' => [],
],
],
FALSE,
@@ -168,6 +198,7 @@ class ConfigDifferTest extends UnitTestCase {
'c' => [
'd' => TRUE,
'e' => 'e',
+ 'empty' => [],
],
],
FALSE,
@@ -184,10 +215,29 @@ class ConfigDifferTest extends UnitTestCase {
'c' => [
'd' => 'd',
'e' => FALSE,
+ 'empty' => [],
],
],
FALSE,
],
+
+ // Add an empty array at top, and remove at lower level. Should still
+ // match.
+ [
+ $base,
+ [
+ '_core' => 'foo',
+ 'uuid' => 'bar',
+ 'a' => 'a',
+ 'b' => 0,
+ 'c' => [
+ 'd' => TRUE,
+ 'e' => FALSE,
+ ],
+ 'empty_two' => [],
+ ],
+ TRUE,
+ ],
];
}
@@ -201,6 +251,7 @@ class ConfigDifferTest extends UnitTestCase {
'id_to_remove' => 'test.remove.id',
'type' => 'old_type',
'true_value' => TRUE,
+ 'null_value' => NULL,
'nested_array' => [
'flat_array' => [
'value2',
@@ -216,6 +267,7 @@ class ConfigDifferTest extends UnitTestCase {
'id' => 'test.config.id',
'type' => 'new_type',
'true_value' => FALSE,
+ 'null_value' => FALSE,
'nested_array' => [
'flat_array' => [
'value2',
@@ -284,12 +336,14 @@ class ConfigDifferTest extends UnitTestCase {
'orig' => [
'nested_array::flat_array::1 : value1',
'nested_array::flat_array::2 : value3',
- 'true_value : 1',
+ 'null_value : null',
+ 'true_value : true',
'type : old_type',
],
'closing' => [
'nested_array::flat_array::1 : value3',
- 'true_value : ',
+ 'null_value : false',
+ 'true_value : false',
'type : new_type',
],
],
diff --git a/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigListerTest.php b/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigListerTest.php
index b2a749335..668e8b929 100644
--- a/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigListerTest.php
+++ b/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigListerTest.php
@@ -2,169 +2,73 @@
namespace Drupal\Tests\config_update\Unit;
-use Drupal\config_update\ConfigLister;
-use Drupal\Tests\UnitTestCase;
-
/**
- * Tests the \Drupal\config_update\ConfigLister class.
+ * Tests the \Drupal\config_update\ConfigListerWithProviders class.
+ *
+ * The methods from \Drupal\config_update\ConfigLister are also tested.
*
* @group config_update
*
- * @coversDefaultClass \Drupal\config_update\ConfigLister
+ * @coversDefaultClass \Drupal\config_update\ConfigListerWithProviders
*/
-class ConfigListerTest extends UnitTestCase {
+class ConfigListerTest extends ConfigUpdateUnitTestBase {
/**
* The config lister to test.
*
- * @var \Drupal\config_update\ConfigLister
+ * @var \Drupal\config_update\ConfigListerWithProviders
*/
protected $configLister;
/**
- * The mocked entity definition information.
+ * List of configuration by provider in the mocks.
*
- * @var string[]
+ * This is an array whose keys are provider names, and whose values are
+ * each an array containing the provider type, the name of one config item
+ * mocked to be in config/install, and one in config/optional.
+ *
+ * @var array
*/
- protected $entityDefinitionInformation;
+ protected $configProviderList = [
+ 'foo_module' => ['module', 'foo.barbaz.one', 'foo.barbaz.two'],
+ 'foo_theme' => ['theme', 'foo.bar.one', 'foo.bar.two'],
+ 'standard' => ['profile', 'baz.bar.one', 'baz.bar.two'],
+ ];
/**
* {@inheritdoc}
*/
protected function setUp() {
- $this->configLister = new ConfigLister($this->getEntityManagerMock(), $this->getConfigStorageMock('active'), $this->getConfigStorageMock('extension'), $this->getConfigStorageMock('optional'));
+ $lister = $this->getMockBuilder('Drupal\config_update\ConfigListerWithProviders')
+ ->setConstructorArgs([
+ $this->getEntityManagerMock(),
+ $this->getConfigStorageMock('active'),
+ $this->getConfigStorageMock('extension'),
+ $this->getConfigStorageMock('optional'),
+ $this->getModuleHandlerMock(),
+ $this->getThemeHandlerMock(),
+ ])
+ ->setMethods(['listProvidedItems', 'getProfileName'])
+ ->getMock();
+
+ $lister->method('getProfileName')
+ ->willReturn('standard');
+
+ $map = [];
+ foreach ($this->configProviderList as $provider => $info) {
+ // Info has: [type, install storage item, optional storage item].
+ // Map needs: [type, provider name, isOptional, [config items]].
+ $map[] = [$info[0], $provider, FALSE, [$info[1]]];
+ $map[] = [$info[0], $provider, TRUE, [$info[2]]];
+ }
+ $lister->method('listProvidedItems')
+ ->will($this->returnValueMap($map));
+
+ $this->configLister = $lister;
}
/**
- * Creates a mock entity manager for the test.
- */
- protected function getEntityManagerMock() {
- // Make a list of fake entity definitions. Make sure they are not sorted,
- // to test that the methods sort them. Also make sure there are a couple
- // with prefixes that are subsets of each other.
- $this->entityDefinitionInformation = [
- ['prefix' => 'foo.bar', 'type' => 'foo'],
- ['prefix' => 'foo.barbaz', 'type' => 'bar'],
- ['prefix' => 'baz.foo', 'type' => 'baz'],
- ];
-
- $definitions = [];
- foreach ($this->entityDefinitionInformation as $info) {
- $def = $this->getMockBuilder('Drupal\Core\Config\Entity\ConfigEntityTypeInterface')->getMock();
- $def
- ->expects($this->any())
- ->method('getConfigPrefix')
- ->willReturn($info['prefix']);
- $def
- ->expects($this->any())
- ->method('isSubclassOf')
- ->willReturn(TRUE);
-
- $def->getConfigPrefix();
-
- $definitions[$info['type']] = $def;
- }
-
- $manager = $this->getMockBuilder('Drupal\Core\Entity\EntityTypeManagerInterface')->getMock();
- $manager
- ->method('getDefinitions')
- ->willReturn($definitions);
-
- return($manager);
- }
-
- /**
- * Creates a mock config storage object for the test.
- *
- * @param string $type
- * Type of storage object to return: 'active', 'extension', or 'optional'.
- */
- protected function getConfigStorageMock($type) {
- if ($type == 'active') {
- $storage = $this->getMockBuilder('Drupal\Core\Config\StorageInterface')->getMock();
-
- // The only use of the read() method on active storage is
- // with the core.extension config, to get the profile name.
- $storage
- ->method('read')
- ->willReturn(['profile' => 'standard']);
-
- $map = [
- ['foo.bar', ['foo.bar.one', 'foo.bar.two', 'foo.bar.three']],
- ['foo.barbaz', ['foo.barbaz.four', 'foo.barbaz.five', 'foo.barbaz.six']],
- ['baz.foo'], [],
- ['',
- [
- 'foo.bar.one',
- 'foo.bar.two',
- 'foo.bar.three',
- 'foo.barbaz.four',
- 'foo.barbaz.five',
- 'foo.barbaz.six',
- 'something.else',
- 'another.one',
- ],
- ],
- ];
-
- $storage
- ->method('listAll')
- ->will($this->returnValueMap($map));
- }
- elseif ($type == 'extension') {
- $storage = $this->getMockBuilder('Drupal\Core\Config\ExtensionInstallStorage')->disableOriginalConstructor()->getMock();
- $storage
- ->method('getComponentNames')
- ->willReturn([
- 'foo.bar.one' => 'ignored',
- 'foo.bar.two' => 'ignored',
- 'foo.bar.seven' => 'ignored',
- 'foo.barnot.three' => 'ignored',
- 'something.else' => 'ignored',
- ]);
-
- $map = [
- ['foo.bar', ['foo.bar.one', 'foo.bar.two', 'foo.bar.seven']],
- ['baz.foo'], [],
- ['',
- [
- 'foo.bar.one',
- 'foo.bar.two',
- 'foo.bar.seven',
- 'foo.barbaz.four',
- 'foo.barnot.three',
- 'something.else',
- ],
- ],
- ];
-
- $storage
- ->method('listAll')
- ->will($this->returnValueMap($map));
- }
- else {
- $storage = $this->getMockBuilder('Drupal\Core\Config\ExtensionInstallStorage')->disableOriginalConstructor()->getMock();
- $storage
- ->method('getComponentNames')
- ->willReturn([
- 'foo.barbaz.four' => 'ignored',
- ]);
-
- $map = [
- ['foo.bar'], [],
- ['foo.barbaz', ['foo.barbaz.four']],
- ['', ['foo.barbaz.four']],
- ];
- $storage
- ->method('listAll')
- ->will($this->returnValueMap($map));
- }
- return $storage;
-
- }
-
- /**
- * @covers \Drupal\config_update\ConfigLister::listConfig
+ * @covers \Drupal\config_update\ConfigListerWithProviders::listConfig
* @dataProvider listConfigProvider
*/
public function testListConfig($a, $b, $expected) {
@@ -176,12 +80,8 @@ class ConfigListerTest extends UnitTestCase {
*/
public function listConfigProvider() {
return [
- // Arguments are $list_type, $name.
- // We cannot really test the extension types here, because they rely
- // on the going out to the file system to find out what config objects
- // are there. This is too complex to mock. It is tested in the tests for
- // the report output in the config_update_ui module tests. Anyway, we
- // can test the other types.
+ // Arguments are $list_type, $name, and return value is that list of
+ // configuration in active, extension, and optional storage.
['type', 'system.all',
[
[
@@ -220,11 +120,59 @@ class ConfigListerTest extends UnitTestCase {
],
],
['type', 'unknown.type', [[], [], []]],
+ ['profile', 'dummy',
+ [
+ [
+ 'foo.bar.one',
+ 'foo.bar.two',
+ 'foo.bar.three',
+ 'foo.barbaz.four',
+ 'foo.barbaz.five',
+ 'foo.barbaz.six',
+ 'something.else',
+ 'another.one',
+ ],
+ ['baz.bar.one'],
+ ['baz.bar.two'],
+ ],
+ ],
+ ['module', 'foo_module',
+ [
+ [
+ 'foo.bar.one',
+ 'foo.bar.two',
+ 'foo.bar.three',
+ 'foo.barbaz.four',
+ 'foo.barbaz.five',
+ 'foo.barbaz.six',
+ 'something.else',
+ 'another.one',
+ ],
+ ['foo.barbaz.one'],
+ ['foo.barbaz.two'],
+ ],
+ ],
+ ['theme', 'foo_theme',
+ [
+ [
+ 'foo.bar.one',
+ 'foo.bar.two',
+ 'foo.bar.three',
+ 'foo.barbaz.four',
+ 'foo.barbaz.five',
+ 'foo.barbaz.six',
+ 'something.else',
+ 'another.one',
+ ],
+ ['foo.bar.one'],
+ ['foo.bar.two'],
+ ],
+ ],
];
}
/**
- * @covers \Drupal\config_update\ConfigLister::getType
+ * @covers \Drupal\config_update\ConfigListerWithProviders::getType
*/
public function testGetType() {
$return = $this->configLister->getType('not_in_list');
@@ -237,7 +185,7 @@ class ConfigListerTest extends UnitTestCase {
}
/**
- * @covers \Drupal\config_update\ConfigLister::getTypeByPrefix
+ * @covers \Drupal\config_update\ConfigListerWithProviders::getTypeByPrefix
*/
public function testGetTypeByPrefix() {
$return = $this->configLister->getTypeByPrefix('not_in_list');
@@ -250,7 +198,7 @@ class ConfigListerTest extends UnitTestCase {
}
/**
- * @covers \Drupal\config_update\ConfigLister::getTypeNameByConfigName
+ * @covers \Drupal\config_update\ConfigListerWithProviders::getTypeNameByConfigName
*/
public function testGetTypeNameByConfigName() {
$return = $this->configLister->getTypeNameByConfigName('not_in_list');
@@ -262,4 +210,84 @@ class ConfigListerTest extends UnitTestCase {
}
}
+ /**
+ * @covers \Drupal\config_update\ConfigListerWithProviders::listTypes
+ */
+ public function testListTypes() {
+ $return = $this->configLister->listTypes();
+ // Should return an array in sorted order, of just the config entities
+ // that $this->getEntityManagerMock() set up.
+ $expected = ['bar' => 'foo.barbaz', 'baz' => 'baz.foo', 'foo' => 'foo.bar'];
+ $this->assertEquals(array_keys($return), array_keys($expected));
+ foreach ($return as $key => $definition) {
+ $this->assertTrue($definition->entityClassImplements('Drupal\Core\Config\Entity\ConfigEntityInterface'));
+ $this->assertEquals($definition->getConfigPrefix(), $expected[$key]);
+ }
+ }
+
+ /**
+ * @covers \Drupal\config_update\ConfigListerWithProviders::listProviders
+ */
+ public function testListProviders() {
+ // This method's return value is not sorted in any particular way.
+ $return = $this->configLister->listProviders();
+ $expected = [];
+ foreach ($this->configProviderList as $provider => $info) {
+ // Info has: [type, install storage item, optional storage item].
+ // Expected needs: key is item name, value is [type, provider name].
+ $expected[$info[1]] = [$info[0], $provider];
+ $expected[$info[2]] = [$info[0], $provider];
+ }
+ ksort($return);
+ ksort($expected);
+ $this->assertEquals($return, $expected);
+ }
+
+ /**
+ * @covers \Drupal\config_update\ConfigListerWithProviders::getConfigProvider
+ * @dataProvider getConfigProviderProvider
+ */
+ public function testGetConfigProvider($a, $expected) {
+ $this->assertEquals($expected, $this->configLister->getConfigProvider($a));
+ }
+
+ /**
+ * Data provider for self:testGetConfigProvider().
+ */
+ public function getConfigProviderProvider() {
+ $values = [];
+ foreach ($this->configProviderList as $provider => $info) {
+ // Info has: [type, install storage item, optional storage item].
+ // Values needs: [item, [type, provider name]].
+ $values[] = [$info[1], [$info[0], $provider]];
+ $values[] = [$info[2], [$info[0], $provider]];
+ }
+ $values[] = ['not.a.config.item', NULL];
+ return $values;
+ }
+
+ /**
+ * @covers \Drupal\config_update\ConfigListerWithProviders::providerHasConfig
+ * @dataProvider providerHasConfigProvider
+ */
+ public function testProviderHasConfig($a, $b, $expected) {
+ $this->assertEquals($expected, $this->configLister->providerHasConfig($a, $b));
+ }
+
+ /**
+ * Data provider for self:testProviderHasConfig().
+ */
+ public function providerHasConfigProvider() {
+ $values = [];
+ foreach ($this->configProviderList as $provider => $info) {
+ // Info has: [type, install storage item, optional storage item].
+ // Values needs: [type, provider name, TRUE] for valid providers,
+ // change the last to FALSE for invalid providers.
+ $values[] = [$info[0], $provider, TRUE];
+ $values[] = [$info[0], $provider . '_suffix', FALSE];
+ }
+ $values[] = ['invalid_type', 'foo_module', FALSE];
+ return $values;
+ }
+
}
diff --git a/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigReverterTest.php b/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigReverterTest.php
new file mode 100644
index 000000000..6c35cd72c
--- /dev/null
+++ b/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigReverterTest.php
@@ -0,0 +1,356 @@
+configReverter = new ConfigReverter(
+ $this->getEntityManagerMock(),
+ $this->getConfigStorageMock('active'),
+ $this->getConfigStorageMock('extension'),
+ $this->getConfigStorageMock('optional'),
+ $this->getConfigFactoryMock(),
+ $this->getEventDispatcherMock());
+ }
+
+ /**
+ * @covers \Drupal\config_update\ConfigReverter::getFromActive
+ * @dataProvider getFromActiveProvider
+ */
+ public function testGetFromActive($a, $b, $expected) {
+ $this->assertEquals($expected, $this->configReverter->getFromActive($a, $b));
+ }
+
+ /**
+ * Data provider for self:testGetFromActive().
+ */
+ public function getFromActiveProvider() {
+ return [
+ // Arguments are $type, $name, and return value is the config.
+ // Some config items that are already prefixed.
+ ['', 'foo.bar.one', ['foo.bar.one' => 'active', 'id' => 'one']],
+ ['system.simple', 'foo.bar.one',
+ ['foo.bar.one' => 'active', 'id' => 'one'],
+ ],
+ // Config item with a defined entity definition prefix. Entity type 'foo'
+ // has prefix 'foo.bar'.
+ ['foo', 'one', ['foo.bar.one' => 'active', 'id' => 'one']],
+ // Unknown type. This should not generate a call into the config read,
+ // so should not return the known value.
+ ['unknown', 'foo.bar.one', FALSE],
+ // Missing configuration. Config mock is configured to return FALSE for
+ // this particular config name.
+ ['system.simple', 'missing', FALSE],
+ ];
+ }
+
+ /**
+ * @covers \Drupal\config_update\ConfigReverter::getFromExtension
+ * @dataProvider getFromExtensionProvider
+ */
+ public function testGetFromExtension($a, $b, $expected) {
+ $this->assertEquals($expected, $this->configReverter->getFromExtension($a, $b));
+ }
+
+ /**
+ * Data provider for self:testGetFromExtension().
+ */
+ public function getFromExtensionProvider() {
+ return [
+ // Arguments are $type, $name, and return value is the config.
+ // Some config items that are already prefixed, and exist in the mock
+ // extension storage.
+ ['', 'in.extension', ['in.extension' => 'extension']],
+ ['system.simple', 'in.extension', ['in.extension' => 'extension']],
+ // Config item with a defined entity definition prefix. Entity type 'foo'
+ // has prefix 'foo.bar'.
+ ['foo', 'one', ['foo.bar.one' => 'extension', 'id' => 'one']],
+ // One that exists in both extension and optional storage.
+ ['system.simple', 'in.both', ['in.both' => 'extension']],
+ // One that exists only in optional storage.
+ ['system.simple', 'in.optional', ['in.optional' => 'optional']],
+ // Unknown type. This should not generate a call into the config read,
+ // so should not return the known value.
+ ['unknown', 'in.extension', FALSE],
+ // Missing configuration. Storage mock is configured to return FALSE for
+ // this particular config name.
+ ['system.simple', 'missing2', FALSE],
+ ];
+ }
+
+ /**
+ * @covers \Drupal\config_update\ConfigReverter::import
+ * @dataProvider importProvider
+ */
+ public function testImport($type, $name, $config_name, $expected, $config_before, $config_after) {
+ // Clear dispatch log and set pre-config.
+ $this->dispatchedEvents = [];
+ if ($config_name) {
+ $this->configStorage[$config_name] = $config_before;
+ }
+ $save_config = $this->configStorage;
+
+ // Call the importer and test the Boolean result.
+ $result = $this->configReverter->import($type, $name);
+ $this->assertEquals($result, $expected);
+
+ if ($result) {
+ // Verify that the config is correct after import, and logging worked.
+ $this->assertEquals($this->configStorage[$config_name], $config_after);
+ $this->assertEquals(count($this->dispatchedEvents), 1);
+ $this->assertEquals($this->dispatchedEvents[0][0], ConfigRevertInterface::IMPORT);
+ }
+ else {
+ // Verify that the config didn't change and no events were logged.
+ $this->assertEquals($this->configStorage, $save_config);
+ $this->assertEquals(count($this->dispatchedEvents), 0);
+ }
+ }
+
+ /**
+ * Data provider for self:testImport().
+ */
+ public function importProvider() {
+ return [
+ // Elements: type, name, config name, return value,
+ // config to set up before, config expected after. See also
+ // getFromExtensionProvider().
+ [
+ 'system.simple',
+ 'in.extension',
+ 'in.extension',
+ TRUE,
+ ['in.extension' => 'before'],
+ ['in.extension' => 'extension', '_core' => 'core_for_in.extension'],
+ ],
+ [
+ 'foo',
+ 'one',
+ 'foo.bar.one',
+ TRUE,
+ ['foo.bar.one' => 'before', 'id' => 'one'],
+ [
+ 'foo.bar.one' => 'extension',
+ 'id' => 'one',
+ '_core' => 'core_for_foo.bar.one',
+ ],
+ ],
+ [
+ 'system.simple',
+ 'in.both',
+ 'in.both',
+ TRUE,
+ ['in.both' => 'before'],
+ ['in.both' => 'extension', '_core' => 'core_for_in.both'],
+ ],
+ [
+ 'system.simple',
+ 'in.optional',
+ 'in.optional',
+ TRUE,
+ ['in.optional' => 'before'],
+ ['in.optional' => 'optional', '_core' => 'core_for_in.optional'],
+ ],
+ [
+ 'unknown',
+ 'in.extension',
+ FALSE,
+ FALSE,
+ FALSE,
+ FALSE,
+ ],
+ [
+ 'system.simple',
+ 'missing2',
+ 'missing2',
+ FALSE,
+ FALSE,
+ FALSE,
+ ],
+ ];
+ }
+
+ /**
+ * @covers \Drupal\config_update\ConfigReverter::revert
+ * @dataProvider revertProvider
+ */
+ public function testRevert($type, $name, $config_name, $expected, $config_before, $config_after) {
+ // Clear dispatch log and set pre-config.
+ $this->dispatchedEvents = [];
+ if ($config_name) {
+ $this->configStorage[$config_name] = $config_before;
+ }
+ $save_config = $this->configStorage;
+
+ // Call the reverter and test the Boolean result.
+ $result = $this->configReverter->revert($type, $name);
+ $this->assertEquals($result, $expected);
+
+ if ($result) {
+ // Verify that the config is correct after revert, and logging worked.
+ $this->assertEquals($this->configStorage[$config_name], $config_after);
+ $this->assertEquals(count($this->dispatchedEvents), 1);
+ $this->assertEquals($this->dispatchedEvents[0][0], ConfigRevertInterface::REVERT);
+ }
+ else {
+ // Verify that the config didn't change and no events were logged.
+ $this->assertEquals($this->configStorage, $save_config);
+ $this->assertEquals(count($this->dispatchedEvents), 0);
+ }
+ }
+
+ /**
+ * Data provider for self:testRevert().
+ */
+ public function revertProvider() {
+ return [
+ // Elements: type, name, config name, return value,
+ // config to set up before, config expected after. See also
+ // getFromExtensionProvider().
+ [
+ 'system.simple',
+ 'in.extension',
+ 'in.extension',
+ TRUE,
+ ['in.extension' => 'active'],
+ ['in.extension' => 'extension', '_core' => 'core_for_in.extension'],
+ ],
+ [
+ 'foo',
+ 'one',
+ 'foo.bar.one',
+ TRUE,
+ ['foo.bar.one' => 'active', 'id' => 'one'],
+ [
+ 'foo.bar.one' => 'extension',
+ 'id' => 'one',
+ '_core' => 'core_for_foo.bar.one',
+ ],
+ ],
+ [
+ 'system.simple',
+ 'in.both',
+ 'in.both',
+ TRUE,
+ ['in.both' => 'active'],
+ ['in.both' => 'extension', '_core' => 'core_for_in.both'],
+ ],
+ [
+ 'system.simple',
+ 'in.optional',
+ 'in.optional',
+ TRUE,
+ ['in.optional' => 'active'],
+ ['in.optional' => 'optional', '_core' => 'core_for_in.optional'],
+ ],
+ [
+ 'unknown',
+ 'in.extension',
+ FALSE,
+ FALSE,
+ FALSE,
+ FALSE,
+ ],
+ // Missing from extension storage.
+ [
+ 'system.simple',
+ 'missing2',
+ 'missing2',
+ FALSE,
+ FALSE,
+ FALSE,
+ ],
+ // Present in extension storage but missing from active storage.
+ [
+ 'system.simple',
+ 'another',
+ 'another',
+ FALSE,
+ FALSE,
+ FALSE,
+ ],
+ ];
+ }
+
+ /**
+ * @covers \Drupal\config_update\ConfigReverter::delete
+ * @dataProvider deleteProvider
+ */
+ public function testDelete($type, $name, $config_name, $expected) {
+ // Clear dispatch log.
+ $this->dispatchedEvents = [];
+ $save_config = $this->configStorage;
+
+ // Call the deleteer and test the Boolean result.
+ $result = $this->configReverter->delete($type, $name);
+ $this->assertEquals($result, $expected);
+
+ if ($result) {
+ // Verify that the config is missing after delete, and logging worked.
+ $this->assertTrue(!isset($this->configStorage[$config_name]));
+ $this->assertEquals(count($this->dispatchedEvents), 1);
+ $this->assertEquals($this->dispatchedEvents[0][0], ConfigDeleteInterface::DELETE);
+ }
+ else {
+ // Verify that the config didn't change and no events were logged.
+ $this->assertEquals($this->configStorage, $save_config);
+ $this->assertEquals(count($this->dispatchedEvents), 0);
+ }
+ }
+
+ /**
+ * Data provider for self:testDelete().
+ */
+ public function deleteProvider() {
+ return [
+ // Elements: type, name, config name, return value.
+ [
+ 'system.simple',
+ 'in.extension',
+ 'in.extension',
+ TRUE,
+ ],
+ [
+ 'foo',
+ 'one',
+ 'foo.bar.one',
+ TRUE,
+ ],
+ [
+ 'unknown',
+ 'in.extension',
+ FALSE,
+ FALSE,
+ ],
+ [
+ 'system.simple',
+ 'missing2',
+ 'missing2',
+ FALSE,
+ ],
+ ];
+ }
+
+}
diff --git a/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigUpdateUnitTestBase.php b/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigUpdateUnitTestBase.php
new file mode 100644
index 000000000..519474484
--- /dev/null
+++ b/sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigUpdateUnitTestBase.php
@@ -0,0 +1,547 @@
+ 'foo.bar', 'type' => 'foo'],
+ ['prefix' => 'foo.barbaz', 'type' => 'bar'],
+ ['prefix' => 'baz.foo', 'type' => 'baz'],
+ ];
+
+ /**
+ * Creates a mock entity manager for the test.
+ *
+ * @see ConfigUpdateUnitTestBase::entityDefinitionInformation
+ */
+ protected function getEntityManagerMock() {
+ $definitions = [];
+ $map = [];
+ foreach ($this->entityDefinitionInformation as $info) {
+ $def = $this->getMockBuilder('Drupal\Core\Config\Entity\ConfigEntityTypeInterface')->getMock();
+ $def
+ ->expects($this->any())
+ ->method('getConfigPrefix')
+ ->willReturn($info['prefix']);
+ $def
+ ->expects($this->any())
+ ->method('entityClassImplements')
+ ->willReturn(TRUE);
+
+ $def
+ ->method('getKey')
+ ->willReturn('id');
+
+ $def->getConfigPrefix();
+
+ $definitions[$info['type']] = $def;
+ $map[] = [$info['type'], FALSE, $def];
+ $map[] = [$info['type'], TRUE, $def];
+ }
+
+ // Add in a content entity definition, which shouldn't be recognized by the
+ // config lister class.
+ $def = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityTypeInterface')->getMock();
+ $def
+ ->expects($this->any())
+ ->method('entityClassImplements')
+ ->willReturn(FALSE);
+ $definitions['content_entity'] = $def;
+
+ $manager = $this->getMockBuilder('Drupal\Core\Entity\EntityTypeManagerInterface')->getMock();
+ $manager
+ ->method('getDefinitions')
+ ->willReturn($definitions);
+
+ $manager
+ ->method('getDefinition')
+ ->will($this->returnValueMap($map));
+
+ $manager
+ ->method('getStorage')
+ ->will($this->returnCallback([$this, 'mockGetStorage']));
+
+ return $manager;
+ }
+
+ /**
+ * Mocks the getStorage() method for the entity manager.
+ */
+ public function mockGetStorage($entity_type) {
+ // Figure out the config prefix for this entity type.
+ $prefix = '';
+ foreach ($this->entityDefinitionInformation as $info) {
+ if ($info['type'] == $entity_type) {
+ $prefix = $info['prefix'];
+ }
+ }
+
+ // This is used in ConfigReverter::import(). Although it is supposed to
+ // be entity storage, we'll use our mock config object instead.
+ return new MockConfig('', $prefix, $this);
+ }
+
+ /**
+ * Array of active configuration information for mocking.
+ *
+ * Array structure: Each element is an array whose first element is a
+ * provider name, and second is an array of config items it provides.
+ *
+ * @var array
+ *
+ * @see ConfigUpdateUnitTestBase::getConfigStorageMock()
+ */
+ protected $configStorageActiveInfo = [
+ ['foo.bar', ['foo.bar.one', 'foo.bar.two', 'foo.bar.three']],
+ ['foo.barbaz', ['foo.barbaz.four', 'foo.barbaz.five', 'foo.barbaz.six']],
+ ['baz.foo', []],
+ ['',
+ [
+ 'foo.bar.one',
+ 'foo.bar.two',
+ 'foo.bar.three',
+ 'foo.barbaz.four',
+ 'foo.barbaz.five',
+ 'foo.barbaz.six',
+ 'something.else',
+ 'another.one',
+ ],
+ ],
+ ];
+
+ /**
+ * Array of extension configuration information for mocking.
+ *
+ * Array structure: Each element is an array whose first element is a
+ * provider name, and second is an array of config items it provides.
+ *
+ * @var array
+ *
+ * @see ConfigUpdateUnitTestBase::getConfigStorageMock()
+ */
+ protected $configStorageExtensionInfo = [
+ ['foo.bar', ['foo.bar.one', 'foo.bar.two', 'foo.bar.seven']],
+ ['baz.foo', []],
+ // This next item is assumed to be element 2 of the array. If not, you
+ // will need to change ConfigUpdateUnitTestBase::getConfigStorageMock().
+ ['',
+ [
+ 'foo.bar.one',
+ 'foo.bar.two',
+ 'foo.bar.seven',
+ 'foo.barbaz.four',
+ 'foo.barnot.three',
+ 'something.else',
+ ],
+ ],
+ ];
+
+ /**
+ * Array of optional configuration information for mocking.
+ *
+ * Array structure: Each element is an array whose first element is a
+ * provider name, and second is an array of config items it provides.
+ *
+ * @var array
+ *
+ * @see ConfigUpdateUnitTestBase::getConfigStorageMock()
+ */
+ protected $configStorageOptionalInfo = [
+ ['foo.bar', []],
+ ['foo.barbaz', ['foo.barbaz.four']],
+ // This next item is assumed to be element 2 of the array. If not, you
+ // will need to change ConfigUpdateUnitTestBase::getConfigStorageMock().
+ ['', ['foo.barbaz.four']],
+ ];
+
+ /**
+ * Creates a mock config storage object for the test.
+ *
+ * @param string $type
+ * Type of storage object to return: 'active', 'extension', or 'optional'.
+ * In active storage, the read() method is mocked to assume you are reading
+ * core.extension to get the profile name, so it returns that information.
+ * For extension and optional storage, the getComponentNames() method is
+ * mocked, and for all storages, the listAll() method is mocked.
+ *
+ * @see ConfigUpdateUnitTestBase::configStorageActiveInfo
+ * @see ConfigUpdateUnitTestBase::configStorageExtensionInfo
+ * @see ConfigUpdateUnitTestBase::configStorageOptionalInfo
+ */
+ protected function getConfigStorageMock($type) {
+ if ($type == 'active') {
+ $storage = $this->getMockBuilder('Drupal\Core\Config\StorageInterface')->getMock();
+
+ // Various tests assume various values of configuration that need to be
+ // read from active storage.
+ $map = [
+ ['core.extension', ['profile' => 'standard']],
+ ['foo.bar.one', ['foo.bar.one' => 'active', 'id' => 'one']],
+ ['missing', FALSE],
+ ['in.extension',
+ ['in.extension' => 'active', '_core' => 'core_for_in.extension'],
+ ],
+ ['in.both', ['in.both' => 'active']],
+ ['in.optional', ['in.optional' => 'active']],
+ ];
+ $storage
+ ->method('read')
+ ->will($this->returnValueMap($map));
+
+ $storage
+ ->method('listAll')
+ ->will($this->returnValueMap($this->configStorageActiveInfo));
+ }
+ elseif ($type == 'extension') {
+ $storage = $this->getMockBuilder('Drupal\Core\Config\ExtensionInstallStorage')->disableOriginalConstructor()->getMock();
+
+ $value = [];
+ foreach ($this->configStorageExtensionInfo[2][1] as $item) {
+ $value[$item] = 'ignored';
+ }
+ $storage
+ ->method('getComponentNames')
+ ->willReturn($value);
+
+ $storage
+ ->method('listAll')
+ ->will($this->returnValueMap($this->configStorageExtensionInfo));
+ $map = [
+ ['in.extension', ['in.extension' => 'extension']],
+ ['in.both', ['in.both' => 'extension']],
+ ['in.optional', FALSE],
+ ['foo.bar.one', ['foo.bar.one' => 'extension', 'id' => 'one']],
+ ['another', ['another' => 'extension', 'id' => 'one']],
+ ['missing2', FALSE],
+ ];
+ $storage
+ ->method('read')
+ ->will($this->returnValueMap($map));
+
+ }
+ else {
+ $storage = $this->getMockBuilder('Drupal\Core\Config\ExtensionInstallStorage')->disableOriginalConstructor()->getMock();
+
+ $value = [];
+ foreach ($this->configStorageOptionalInfo[2][1] as $item) {
+ $value[$item] = 'ignored';
+ }
+ $storage
+ ->method('getComponentNames')
+ ->willReturn($value);
+
+ $storage
+ ->method('listAll')
+ ->will($this->returnValueMap($this->configStorageOptionalInfo));
+
+ $map = [
+ ['in.optional', ['in.optional' => 'optional']],
+ ['in.both', ['in.both' => 'optional']],
+ ['missing2', FALSE],
+ ];
+ $storage
+ ->method('read')
+ ->will($this->returnValueMap($map));
+ }
+ return $storage;
+
+ }
+
+ /**
+ * Creates a mock module handler for the test.
+ */
+ protected function getModuleHandlerMock() {
+ $manager = $this->getMockBuilder('Drupal\Core\Extension\ModuleHandlerInterface')->getMock();
+ $manager->method('getModuleList')
+ ->willReturn(['foo_module' => '', 'standard' => '']);
+
+ return $manager;
+ }
+
+ /**
+ * Creates a mock theme handler for the test.
+ */
+ protected function getThemeHandlerMock() {
+ $manager = $this->getMockBuilder('Drupal\Core\Extension\ThemeHandlerInterface')->getMock();
+ $manager->method('listInfo')
+ ->willReturn(['foo_theme' => '']);
+ return $manager;
+ }
+
+ /**
+ * Creates a mock string translation class for the test.
+ */
+ protected function getTranslationMock() {
+ $translation = $this->getMockBuilder('Drupal\Core\StringTranslation\TranslationInterface')->getMock();
+ $translation
+ ->method('translateString')
+ ->will($this->returnCallback([$this, 'mockTranslate']));
+ return $translation;
+ }
+
+ /**
+ * Mocks the translateString() method for the string translation mock object.
+ *
+ * @param \Drupal\Core\StringTranslation\TranslatableMarkup $input
+ * Object to translate.
+ *
+ * @return string
+ * The untranslated string from $input.
+ */
+ public function mockTranslate(TranslatableMarkup $input) {
+ return $input->getUntranslatedString();
+ }
+
+ /**
+ * List of mock-dispatched events.
+ *
+ * Each element of the array is the call parameters to dispatchEvent() in
+ * the mocked dispatch class: name and event instance.
+ *
+ * @var array
+ *
+ * @see ConfigUpdateUnitTestBase::getEventDispatcherMock()
+ */
+ protected $dispatchedEvents = [];
+
+ /**
+ * Mocks the event dispatcher service.
+ *
+ * Stores dispatched events in ConfigUpdateUnitTestBase::dispatchedEvents.
+ */
+ protected function getEventDispatcherMock() {
+ $event = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
+ $event
+ ->method('dispatch')
+ ->will($this->returnCallback([$this, 'mockDispatch']));
+
+ return $event;
+ }
+
+ /**
+ * Mocks event dispatch.
+ *
+ * For \Symfony\Component\EventDispatcher\EventDispatchInterface::dispatch().
+ */
+ public function mockDispatch($name, Event $event = NULL) {
+ $this->dispatchedEvents[] = [$name, $event];
+ }
+
+ /**
+ * Mock config storage for the mock config factory.
+ *
+ * This is actually managed by the MockConfig class in this file.
+ *
+ * @var array
+ */
+ protected $configStorage = [];
+
+ /**
+ * Gets the value of the mocked config storage.
+ */
+ public function getConfigStorage() {
+ return $this->configStorage;
+ }
+
+ /**
+ * Sets the value of the mocked config storage.
+ */
+ public function setConfigStorage($values) {
+ $this->configStorage = $values;
+ }
+
+ /**
+ * Creates a mock config factory class for the test.
+ */
+ protected function getConfigFactoryMock() {
+ $config = $this->getMockBuilder('Drupal\Core\Config\ConfigFactoryInterface')->getMock();
+ $config
+ ->method('getEditable')
+ ->will($this->returnCallback([$this, 'mockGetEditable']));
+
+ return $config;
+ }
+
+ /**
+ * Mocks the getEditable() method for the mock config factory.
+ *
+ * @param string $name
+ * Name of the config object to get an editable object for.
+ *
+ * @return MockConfig
+ * Editable mock config object.
+ */
+ public function mockGetEditable($name) {
+ return new MockConfig($name, '', $this);
+ }
+
+}
+
+/**
+ * Mock class for mutable configuration, config entity, and entity storage.
+ */
+class MockConfig {
+
+ /**
+ * Name of the config.
+ *
+ * @var string
+ */
+ protected $name = '';
+
+ /**
+ * Prefix for the entity type being mocked, for entity storage mocking.
+ *
+ * @var string
+ */
+ protected $entityPrefix = '';
+
+ /**
+ * Test class this comes from.
+ *
+ * @var \Drupal\Tests\config_update\Unit\ConfigUpdateUnitTestBase
+ */
+ protected $test;
+
+ /**
+ * Current value of the configuration.
+ *
+ * @var array
+ */
+ protected $value = '';
+
+ /**
+ * Constructs a mock config object.
+ *
+ * @param string $name
+ * Name of the config that is being mocked. Can be blank.
+ * @param string $entity_prefix
+ * Prefix for the entity type that is being mocked. Often blank.
+ * @param \Drupal\Tests\config_update\Unit\ConfigUpdateUnitTestBase $test
+ * Test class this comes from.
+ */
+ public function __construct($name, $entity_prefix, ConfigUpdateUnitTestBase $test) {
+ $this->name = $name;
+ $this->entityPrefix = $entity_prefix;
+ $this->test = $test;
+
+ $storage = $test->getConfigStorage();
+ if ($name && isset($storage[$name])) {
+ $value = $storage[$name];
+ $value['is_new'] = FALSE;
+ }
+ else {
+ $value['is_new'] = TRUE;
+ }
+ $value['_core'] = 'core_for_' . $name;
+
+ $this->value = $value;
+ }
+
+ /**
+ * Gets a component of the configuration value.
+ */
+ public function get($key) {
+ return isset($this->value[$key]) ? $this->value[$key] : NULL;
+ }
+
+ /**
+ * Sets a component of the configuration value.
+ */
+ public function set($key, $value) {
+ $this->value[$key] = $value;
+ return $this;
+ }
+
+ /**
+ * Sets the entire configuration value.
+ */
+ public function setData($value) {
+ // Retain the _core key.
+ $core = isset($this->value['_core']) ? $this->value['_core'] : '';
+ $this->value = $value;
+ if ($core) {
+ $this->value['_core'] = $core;
+ }
+ return $this;
+ }
+
+ /**
+ * Saves the configuration.
+ */
+ public function save() {
+ $config = $this->test->getConfigStorage();
+ $config[$this->name] = $this->value;
+ $this->test->setConfigStorage($config);
+ return $this;
+ }
+
+ /**
+ * Deletes the configuration.
+ */
+ public function delete() {
+ $config = $this->test->getConfigStorage();
+ unset($config[$this->name]);
+ $this->test->setConfigStorage($config);
+ return $this;
+ }
+
+ /**
+ * Mocks the createFromStorageRecord() method from entity storage.
+ */
+ public function createFromStorageRecord($values) {
+ if (!$this->entityPrefix) {
+ return NULL;
+ }
+
+ // This is supposed to return an entity, but the only method we need is
+ // save(), so instead set up and return this object.
+ $this->name = $this->entityPrefix . '.' . $values['id'];
+ $this->value = $values;
+ $this->value['_core'] = 'core_for_' . $this->name;
+ return $this;
+ }
+
+ /**
+ * Mocks the updateFromStorageRecord() method from entity storage.
+ */
+ public function updateFromStorageRecord($object, $values) {
+ return $object->createFromStorageRecord($values);
+ }
+
+ /**
+ * Mocks the load() method for entity storage.
+ */
+ public function load($id) {
+ $full_name = $this->entityPrefix . '.' . $id;
+ $configs = $this->test->getConfigStorage();
+ if (isset($configs[$full_name])) {
+ $this->value = $configs[$full_name];
+ $this->name = $full_name;
+ $this->value['_core'] = 'core_for_' . $full_name;
+ return $this;
+ }
+ return NULL;
+ }
+
+}
diff --git a/sites/all/modules/contrib/admin/domain/.travis.yml b/sites/all/modules/contrib/admin/domain/.travis.yml
index 48b918847..8e82646e4 100644
--- a/sites/all/modules/contrib/admin/domain/.travis.yml
+++ b/sites/all/modules/contrib/admin/domain/.travis.yml
@@ -4,21 +4,13 @@ sudo: false
matrix:
fast_finish: true
include:
- - env: DRUPAL=8.5.x
- php: 5.5
- - env: DRUPAL=8.5.x
- php: 5.6
- - env: DRUPAL=8.5.x
+ - env: DRUPAL=8.6.x
php: 7.1
- - env: DRUPAL=8.5.x
+ - env: DRUPAL=8.6.x
php: 7.2
- - env: DRUPAL=8.6.x
- php: 5.5
- - env: DRUPAL=8.6.x
- php: 5.6
- - env: DRUPAL=8.6.x
+ - env: DRUPAL=8.7.x
php: 7.1
- - env: DRUPAL=8.6.x
+ - env: DRUPAL=8.7.x
php: 7.2
addons:
@@ -94,11 +86,11 @@ before_script:
- until curl -s example.com:8080; do true; done > /dev/null
script:
- - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 4 --types "PHPUnit-Functional" --php `which php` --url http://example.com:8080 domain
- - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 4 --types "PHPUnit-Kernel" --php `which php` --url http://example.com:8080 domain
- - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 4 --types "PHPUnit-Functional" --php `which php` --url http://example.com:8080 domain_access
- - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 4 --types "PHPUnit-Functional" --php `which php` --url http://example.com:8080 domain_alias
- - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 4 --types "PHPUnit-Kernel" --php `which php` --url http://example.com:8080 domain_alias
- - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 4 --types "PHPUnit-Functional" --php `which php` --url http://example.com:8080 domain_config
- - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 4 --types "PHPUnit-Functional" --php `which php` --url http://example.com:8080 domain_content
- - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 4 --types "PHPUnit-Functional" --php `which php` --url http://example.com:8080 domain_source
+ - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 20 --types "PHPUnit-Functional" --php `which php` --url http://example.com:8080 domain
+ - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 20 --types "PHPUnit-Kernel" --php `which php` --url http://example.com:8080 domain
+ - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 20 --types "PHPUnit-Functional" --php `which php` --url http://example.com:8080 domain_access
+ - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 20 --types "PHPUnit-Functional" --php `which php` --url http://example.com:8080 domain_alias
+ - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 20 --types "PHPUnit-Kernel" --php `which php` --url http://example.com:8080 domain_alias
+ - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 20 --types "PHPUnit-Functional" --php `which php` --url http://example.com:8080 domain_config
+ - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 20 --types "PHPUnit-Functional" --php `which php` --url http://example.com:8080 domain_content
+ - php core/scripts/run-tests.sh --suppress-deprecations --verbose --color --concurrency 20 --types "PHPUnit-Functional" --php `which php` --url http://example.com:8080 domain_source
diff --git a/sites/all/modules/contrib/admin/domain/CHANGELOG.md b/sites/all/modules/contrib/admin/domain/CHANGELOG.md
index 7c83d7ace..37be56dfc 100644
--- a/sites/all/modules/contrib/admin/domain/CHANGELOG.md
+++ b/sites/all/modules/contrib/admin/domain/CHANGELOG.md
@@ -16,6 +16,7 @@ Changelog
12-FEB-2018 8.x-1.0-alpha12
07-MAR-2018 8.x-1.0-alpha13
19-OCT-2018 8.x-1.0-alpha14
+21-FEB-2019 8.x-1.0-alpha15
Status
====
@@ -113,7 +114,7 @@ marked with [x] are considered complete.
- [x] Check domain responses on configuration forms
- [x] Remove deprecated `entity_get_form_display`
- [x] Implement theme functions or twig templates where proper
-- [ ] Advanced drush integration / complete labelled tasks
+- [x] Advanced drush integration / complete labelled tasks
- [ ] Add filter options to domain_access and domain_source views
- [ ] Test cron handling
- [ ] Caching strategies in DomainNegotiator
diff --git a/sites/all/modules/contrib/admin/domain/README.md b/sites/all/modules/contrib/admin/domain/README.md
index abd5f4c79..691d60bba 100644
--- a/sites/all/modules/contrib/admin/domain/README.md
+++ b/sites/all/modules/contrib/admin/domain/README.md
@@ -199,23 +199,16 @@ a beta release on Drupal.org.
We would like to tackle issues in that order, but feel free to work on what motivates you.
-Testing
+Testing [](https://travis-ci.com/agentrickard/domain)
====
@zerolab built a Travis definition file for automated testing! That means all pull requests will automatically run tests!
-[](https://travis-ci.org/agentrickard/domain)
-
-The module does have solid test coverage, and complete coverage is required for release.
-Right now, we mostly use SimpleTest, because it is most familiar, and much of our
-testing is about browser and http behavior.
-
If you file a pull request or patch, please (at a minimum) run the existing tests to check
for failures. Writing additional tests will greatly speed completion, as I won't commit
code without test coverage.
-New tests should be written as Functional, Kernel, or Unit tests. Conversion patches that
-move Simpletests to Functional tests are welcome.
+New tests should be written in PHPUnit as Functional, Kernel, or Unit tests.
Because Domain requires varying http host requests to test, we can't normally use the Drupal.org
testing infrastructure. (This may change, but we are not counting on it.)
@@ -227,5 +220,3 @@ point to your drupal instance. I use variants of `example.com` for local tests.
in most test cases. See `DomainTestBase::domainCreateTestDomains()` for the logic.
When running tests, you normally need to be on the default domain.
-
-If anyone is capable of building a vagrant box to simplify testing, that would be ideal.
diff --git a/sites/all/modules/contrib/admin/domain/composer.json b/sites/all/modules/contrib/admin/domain/composer.json
index c5d5ff1d6..1613e13c2 100644
--- a/sites/all/modules/contrib/admin/domain/composer.json
+++ b/sites/all/modules/contrib/admin/domain/composer.json
@@ -13,5 +13,14 @@
"issues": "http://drupal.org/project/issues/domain",
"irc": "http://irc.freenode.org/drupal-contribute",
"source": "http://cgit.drupalcode.org/domain"
+ },
+ "extra": {
+ "drush": {
+ "services": {
+ "domain/drush.services.yml": "^9",
+ "domain_access/drush.services.yml": "^9",
+ "domain_source/drush.services.yml": "^9"
+ }
+ }
}
}
diff --git a/sites/all/modules/contrib/admin/domain/domain/domain.info.yml b/sites/all/modules/contrib/admin/domain/domain/domain.info.yml
index cad33c02f..190ac69b3 100644
--- a/sites/all/modules/contrib/admin/domain/domain/domain.info.yml
+++ b/sites/all/modules/contrib/admin/domain/domain/domain.info.yml
@@ -9,8 +9,8 @@ dependencies:
- drupal:options
configure: domain.admin
-# Information added by Drupal.org packaging script on 2018-11-14
-version: '8.x-1.0-alpha14+9-dev'
+# Information added by Drupal.org packaging script on 2019-02-21
+version: '8.x-1.0-alpha15'
core: '8.x'
project: 'domain'
-datestamp: 1542230887
+datestamp: 1550763190
diff --git a/sites/all/modules/contrib/admin/domain/domain/domain.module b/sites/all/modules/contrib/admin/domain/domain/domain.module
index b2de29eaf..960674976 100644
--- a/sites/all/modules/contrib/admin/domain/domain/domain.module
+++ b/sites/all/modules/contrib/admin/domain/domain/domain.module
@@ -159,3 +159,19 @@ function domain_theme() {
function template_preprocess_domain_nav_block(array &$variables) {
$variables['items'] = $variables['items']['#items'];
}
+
+/**
+ * Implements hook_hook_info().
+ */
+function domain_hook_info() {
+ $hooks['domain_request_alter'] = [
+ 'group' => 'domain',
+ ];
+ $hooks['domain_validate_alter'] = [
+ 'group' => 'domain',
+ ];
+ $hooks['domain_references_alter'] = [
+ 'group' => 'domain',
+ ];
+ return $hooks;
+}
diff --git a/sites/all/modules/contrib/admin/domain/domain/drush.services.yml b/sites/all/modules/contrib/admin/domain/domain/drush.services.yml
new file mode 100644
index 000000000..84d23f785
--- /dev/null
+++ b/sites/all/modules/contrib/admin/domain/domain/drush.services.yml
@@ -0,0 +1,5 @@
+services:
+ domain.commands:
+ class: \Drupal\domain\Commands\DomainCommands
+ tags:
+ - { name: drush.command }
diff --git a/sites/all/modules/contrib/admin/domain/domain/src/Access/DomainAccessCheck.php b/sites/all/modules/contrib/admin/domain/domain/src/Access/DomainAccessCheck.php
index c74e2ce71..0a48aec4f 100644
--- a/sites/all/modules/contrib/admin/domain/domain/src/Access/DomainAccessCheck.php
+++ b/sites/all/modules/contrib/admin/domain/domain/src/Access/DomainAccessCheck.php
@@ -75,17 +75,17 @@ class DomainAccessCheck implements AccessCheckInterface {
// Is the domain allowed?
// No domain, let it pass.
if (empty($domain)) {
- return AccessResult::allowed()->setCacheMaxAge(0);
+ return AccessResult::allowed()->addCacheTags(['url.site']);
}
// Active domain, let it pass.
if ($domain->status()) {
- return AccessResult::allowed()->setCacheMaxAge(0);
+ return AccessResult::allowed()->addCacheTags(['url.site']);
}
// Inactive domain, require permissions.
else {
$permissions = ['administer domains', 'access inactive domains'];
$operator = 'OR';
- return AccessResult::allowedIfHasPermissions($account, $permissions, $operator)->setCacheMaxAge(0);
+ return AccessResult::allowedIfHasPermissions($account, $permissions, $operator)->addCacheTags(['url.site']);
}
}
diff --git a/sites/all/modules/contrib/admin/domain/domain/src/Commands/DomainCommandException.php b/sites/all/modules/contrib/admin/domain/domain/src/Commands/DomainCommandException.php
new file mode 100644
index 000000000..0ab54726b
--- /dev/null
+++ b/sites/all/modules/contrib/admin/domain/domain/src/Commands/DomainCommandException.php
@@ -0,0 +1,10 @@
+domainStorage()->loadMultipleSorted();
+
+ if (empty($domains)) {
+ $this->logger()->warning(dt('No domains have been created. Use "drush domain:add" to create one.'));
+ return new RowsOfFields([]);
+ }
+
+ $keys = [
+ 'weight',
+ 'name',
+ 'hostname',
+ 'response',
+ 'scheme',
+ 'status',
+ 'is_default',
+ 'domain_id',
+ 'id',
+ ];
+ $rows = [];
+ /** @var \Drupal\domain\DomainInterface $domain */
+ foreach ($domains as $domain) {
+ $row = [];
+ foreach ($keys as $key) {
+ switch($key) {
+ case 'response':
+ try {
+ $v = $this->checkDomain($domain);
+ }
+ catch(\GuzzleHttp\Exception\TransferException $ex) {
+ $v = dt('500 - Failed');
+ }
+ catch(Exception $ex) {
+ $v = dt('500 - Exception');
+ }
+ if ($v >= 200 && $v <= 299) {
+ $v = dt('200 - OK');
+ }
+ elseif ($v == 500) {
+ $v = dt('500 - No server');
+ }
+ break;
+ case 'status':
+ $v = $domain->get($key);
+ if (($options['inactive'] && $v) || ($options['active'] && !$v)) {
+ continue 3; // switch, for, for
+ }
+ $v = !empty($v) ? dt('Active') : dt('Inactive');
+ break;
+ case 'is_default':
+ $v = $domain->get($key);
+ $v = !empty($v) ? dt('Default') : '';
+ break;
+ default:
+ $v = $domain->get($key);
+ break;
+ }
+
+ $row[$key] = Html::escape($v);
+ }
+ $rows[] = $row;
+ }
+ return new RowsOfFields($rows);
+ }
+
+ /**
+ * List general information about the domains on the site.
+ *
+ * @usage drush domain:info
+ *
+ * @command domain:info
+ * @aliases domain-info,dinf
+ *
+ * @return \Consolidation\OutputFormatters\StructuredData\PropertyList
+ * @field-labels
+ * count: All Domains
+ * count_active: Active Domains
+ * default_id: Default Domain ID
+ * default_host: Default Domain hostname
+ * scheme: Fields in Domain entity
+ * domain_admin_entities: Domain admin entities
+ * @list-orientation true
+ * @format table
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ public function infoDomains() {
+ $default_domain = $this->domainStorage()->loadDefaultDomain();
+
+ // Load all domains:
+ $all_domains = $this->domainStorage()->loadMultiple(NULL);
+ $active_domains = [];
+ foreach ($all_domains as $domain) {
+ if ($domain->status()) {
+ $active_domains[] = $domain;
+ }
+ }
+
+ $keys = [
+ 'count',
+ 'count_active',
+ 'default_id',
+ 'default_host',
+ 'scheme',
+ ];
+ $rows = [];
+ foreach ($keys as $key) {
+ $v = '';
+ switch($key) {
+ case 'count':
+ $v = count($all_domains);
+ break;
+ case 'count_active':
+ $v = count($active_domains);
+ break;
+ case 'default_id':
+ $v = '-unset-';
+ if ($default_domain) {
+ $v = $default_domain->id();
+ }
+ break;
+ case 'default_host':
+ $v = '-unset-';
+ if ($default_domain) {
+ $v = $default_domain->getHostname();
+ }
+ break;
+ case 'scheme':
+ $v = implode(', ', array_keys($this->domainStorage()->loadSchema()));
+ break;
+ }
+
+ $rows[$key] = $v;
+ }
+
+
+ // Display which entities are enabled for domain by checking for the fields.
+ $rows['domain_admin_entities'] = $this->getFieldEntities(DOMAIN_ADMIN_FIELD);
+
+ return new PropertyList($rows);
+ }
+
+ /**
+ * Finds entities that reference a specific field.
+ *
+ * @param $field_name
+ * The field name to lookup.
+ */
+ public function getFieldEntities($field_name) {
+ $entity_manager = \Drupal::entityManager();
+ $field_map = $entity_manager->getFieldMap();
+ $domain_entities = [];
+ foreach($field_map as $type => $fields) {
+ if (array_key_exists($field_name, $fields)) {
+ $domain_entities[] = $type;
+ }
+ }
+ return implode(', ', $domain_entities);
+ }
+
+ /**
+ * Add a new domain to the site.
+ *
+ * @param $hostname
+ * The domain hostname to register (e.g. example.com).
+ * @param $name
+ * The name of the site (e.g. Domain Two).
+ * @param array $options An associative array of optional values.
+ *
+ * @option inactive
+ * Set the domain to inactive status if set.
+ * @option scheme
+ * Use indicated protocol for this domain, defaults to 'https'. Options:
+ * - http: normal http (no SSL).
+ * - https: secure https (with SSL).
+ * - variable: match the scheme used by the request.
+ * @option weight
+ * Set the order (weight) of the domain.
+ * @option is_default
+ * Set this domain as the default domain.
+ * @option validate
+ * Force a check of the URL response before allowing registration.
+ *
+ * @usage drush domain-add example.com 'My Test Site'
+ * @usage drush domain-add example.com 'My Test Site' --scheme=https --inactive
+ * @usage drush domain-add example.com 'My Test Site' --weight=10
+ * @usage drush domain-add example.com 'My Test Site' --validate
+ *
+ * @command domain:add
+ * @aliases domain-add
+ *
+ * @return string
+ * The entity id of the created domain.
+ *
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ public function add($hostname, $name, array $options = ['weight' => null, 'scheme' => null]) {
+ // Validate the weight arg.
+ if (!empty($options['weight']) && !is_numeric($options['weight'])) {
+ throw new DomainCommandException(
+ dt('Domain weight "!weight" must be a number',
+ ['!weight' => !empty($options['weight']) ? $options['weight'] : ''])
+ );
+ }
+
+ // Validate the scheme arg.
+ if (!empty($options['scheme']) &&
+ ($options['scheme'] !== 'http' && $options['scheme'] !== 'https' && $options['scheme'] !== 'variable')
+ ) {
+ throw new DomainCommandException(
+ dt('Scheme name "!scheme" not known',
+ ['!scheme' => !empty($options['scheme']) ? $options['scheme'] : ''])
+ );
+ }
+
+ $domains = $this->domainStorage()->loadMultipleSorted();
+ $start_weight = count($domains) + 1;
+ $values = [
+ 'hostname' => $hostname,
+ 'name' => $name,
+ 'status' => empty($options['inactive']),
+ 'scheme' => empty($options['scheme']) ? 'http' : $options['scheme'],
+ 'weight' => empty($options['weight']) ? $start_weight : $options['weight'],
+ 'is_default' => !empty($options['is_default']),
+ 'id' => $this->domainStorage()->createMachineName($hostname),
+ ];
+ /** @var DomainInterface $domain */
+ $domain = $this->domainStorage()->create($values);
+
+ // Check for hostname validity. This is required.
+ $valid = $this->validateDomain($domain);
+ if (!empty($valid)) {
+ throw new DomainCommandException(
+ dt('Hostname is not valid. !errors',
+ ['!errors' => implode(" ", $valid)])
+ );
+ }
+ // Check for hostname and id uniqueness.
+ foreach ($domains as $existing) {
+ if ($hostname == $existing->getHostname()) {
+ throw new DomainCommandException(
+ dt('No domain created. Hostname is a duplicate of !hostname.',
+ ['!hostname' => $hostname])
+ );
+ }
+ if ($values['id'] == $existing->id()) {
+ throw new DomainCommandException(
+ dt('No domain created. Id is a duplicate of !id.',
+ ['!id' => $existing->id()])
+ );
+ }
+ }
+
+ $validate_response = (bool) $options['validate'];
+ if ($this->createDomain($domain, $validate_response)) {
+ return dt('Created the !hostname with machine id !id.', ['!hostname' => $values['hostname'], '!id' => $values['id']]);
+ }
+ else {
+ return dt('No domain created.');
+ }
+ }
+
+ /**
+ * Delete a domain from the site.
+ *
+ * Deletes the domain from the Drupal configuration and optionally reassign
+ * content and/or profiles associated with the deleted domain to another.
+ * The domain marked as default cannot be deleted: to achieve this goal,
+ * mark another, possibly newly created, domain as the default domain, then
+ * delete the old default.
+ *
+ * The usage example descriptions are based on starting with three domains:
+ * - id:19476, machine: example_com, domain: example.com
+ * - id:29389, machine: example_org, domain: example.org (default)
+ * - id:91736, machine: example_net, domain: example.net
+ *
+ * @param $domain_id
+ * The numeric id, machine name, or hostname of the domain to delete. The
+ * value "all" is taken to mean delete all except the default domain.
+ * @param array $options
+ * An associative array of options whose values come from cli, aliases,
+ * config, etc.
+ *
+ * @usage drush domain:delete example.com
+ * Delete the domain example.com, assigning its content and users to
+ * the default domain, example.org.
+ *
+ * @usage drush domain:delete --content-assign=ignore example.com
+ * Delete the domain example.com, leaving its content untouched but
+ * assigning its users to the default domain.
+ *
+ * @usage drush domain:delete --content-assign=example_net --users-assign=example_net
+ * example.com Delete the domain example.com, assigning its content and
+ * users to the example.net domain.
+ *
+ * @usage drush domain:delete --dryrun 19476
+ * Show the effects of delete the domain example.com and assigning its
+ * content and users to the default domain, example.org, but not doing so.
+ *
+ * @usage drush domain:delete --chatty example_net
+ * Verbosely Delete the domain example.net and assign its content and users
+ * to the default domain, example.org.
+ *
+ * @usage drush domain-delete --chatty all
+ * Verbosely Delete the domains example.com and example.net and assign
+ * their content and users to the default domain, example.org.
+ *
+ * @option chatty
+ * Document each step as it is performed.
+ * @option dryrun
+ * Do not do anything, but explain what would be done. Implies --chatty.
+ * @option users-assign
+ * Values "prompt", "ignore", "default", , Reassign user accounts
+ * associated with the the domain being deleted to the default domain,
+ * to the domain whose machine name is , or leave the user accounts
+ * alone (and so inaccessible in the normal way). The default value is
+ * 'prompt': ask which domain to use.
+ *
+ * @command domain:delete
+ * @aliases domain-delete
+ *
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ *
+ * @see https://github.com/consolidation/annotated-command#option-event-hook
+ */
+ public function delete($domain_id, $options = ['users-assign' => null, 'dryrun' => null, 'chatty' => null]) {
+ if (is_null($options['users-assign'])) {
+ $policy_users = 'prompt';
+ }
+
+ $this->is_dry_run = (bool) $options['dryrun'];
+
+ // Get current domain list and perform validation checks.
+ $default_domain = $this->domainStorage()->loadDefaultDomain();
+ $all_domains = $this->domainStorage()->loadMultipleSorted(NULL);
+
+ if (empty($all_domains)) {
+ throw new DomainCommandException('There are no configured domains.');
+ }
+ if (empty($domain_id)) {
+ throw new DomainCommandException('You must specify a domain to delete.');
+ }
+
+ // Determine which domains to be deleted.
+ if ($domain_id === 'all') {
+ $domains = $all_domains;
+ if (empty($domains)) {
+ $this->logger()->info(dt('There are no domains to delete.'));
+ return;
+ }
+ $really = $this->io()->confirm(dt('This action cannot be undone. Continue?:'), FALSE);
+ if (empty($really)) {
+ return;
+ }
+ // TODO: handle deletion of all domains.
+ }
+ elseif ($domain = $this->getDomainFromArgument($domain_id)) {
+ if ($domain->isDefault()) {
+ throw new DomainCommandException('The primary domain may not be deleted.
+ Use drush domain:default to set a new default domain.');
+ }
+ $domains = [$domain];
+ }
+
+ if (!empty($options['users-assign'])) {
+ if (in_array($options['users-assign'], $this->reassignment_policies, TRUE)) {
+ $policy_users = $options['users-assign'];
+ }
+ }
+
+ $delete_options = [
+ 'entity_filter' => 'user',
+ 'policy' => $policy_users,
+ 'field' => DOMAIN_ADMIN_FIELD,
+ ];
+
+ if ($policy_users !== 'ignore') {
+ $messages[] = $this->doReassign($domain, $delete_options);
+ }
+
+ // Fire any registered hooks for deletion, passing them current imput.
+ $handlers = $this->getCustomEventHandlers('domain-delete');
+ $messages = [];
+ foreach ($handlers as $handler) {
+ $messages[] = $handler($domain, $options);
+ }
+
+ $this->deleteDomain($domains, $options);
+
+ $message = dt('Domain record !domain deleted.', ['!domain' => $domain->id()]);
+ if ($messages) {
+ $message .= "\n" . implode("\n", $messages);
+ }
+ $this->logger()->info($message);
+ return $message;
+ }
+
+ /**
+ * Handles reassignment of entities to another domain.
+ *
+ * This method includes necessary UI elements if the user is prompted to
+ * choose a new domain.
+ *
+ * @param Drupal\domain\DomainInterface $target_domain
+ * The domain selected for deletion.
+ * @param array $delete_options
+ * A selection of options for deletion, defined in reassignLinkedEntities().
+ */
+ public function doReassign(DomainInterface $target_domain, array $delete_options) {
+ $policy = $delete_options['policy'];
+ $default_domain = $this->domainStorage()->loadDefaultDomain();
+ $all_domains = $this->domainStorage()->loadMultipleSorted(NULL);
+
+ // Perform the 'prompt' for a destination domain.
+ if ($policy === 'prompt') {
+ // Make a list of the eligible destination domains in form id -> name.
+ $noassign_domain = [$target_domain->id()];
+
+ $reassign_list = $this->filterDomains($all_domains, $noassign_domain);
+ $reassign_base = [
+ 'ignore' => dt('Do not reassign'),
+ 'default' => dt('Reassign to default domain'),
+ ];
+ $reassign_list = array_map(
+ function (DomainInterface $d) {
+ return $d->getHostname();
+ },
+ $reassign_list
+ );
+ $reassign_list = array_merge($reassign_base, $reassign_list);
+ $policy = $this->io()->choice(dt('Reassign @type field @field data to:', ['@type' => $delete_options['entity_filter'], '@field' => $delete_options['field']]), $reassign_list);
+ }
+ elseif ($policy === 'default') {
+ $policy = $default_domain->id();
+ }
+ if ($policy !== 'ignore') {
+ $delete_options['policy'] = $policy;
+ $target = [$target_domain];
+ $count = $this->reassignLinkedEntities($target, $delete_options);
+ return dt('@count @type entities updated field @field.', ['@count' => $count, '@type' => $delete_options['entity_filter'], '@field' => $delete_options['field']]);
+ }
+ }
+
+ /**
+ * Tests domains for proper response.
+ *
+ * If run from a subfolder, you must specify the --uri.
+ *
+ * @param $domain_id
+ * The machine name or hostname of the domain to make default.
+ *
+ * @usage drush domain-test
+ * @usage drush domain-test example.com
+ *
+ * @command domain:test
+ * @aliases domain-test
+ *
+ * @field-labels
+ * id: Machine name
+ * url: URL
+ * response: HTTP Response
+ * @default-fields id,url,response
+ *
+ * @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
+ *
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ public function test($domain_id = null) {
+ if (is_null($domain_id)) {
+ $domains = $this->domainStorage()->loadMultipleSorted();
+ }
+ else {
+ if ($domain = $this->getDomainFromArgument($domain_id)) {
+ $domains = [$domain];
+ }
+ else {
+ throw new DomainCommandException(dt('Domain @domain not found.',
+ ['@domain' => $options['domain']]));
+ }
+ }
+ $keys = ['url', 'response'];
+ $rows = [];
+ foreach ($domains as $domain) {
+ $rows[] = [
+ 'id' => $domain->id(),
+ 'url' => $domain->getPath(),
+ 'response' => $domain->getResponse(),
+ ];
+ }
+ return new RowsOfFields($rows);
+ }
+
+ /**
+ * Sets the default domain.
+ *
+ * @param $domain_id
+ * The machine name or hostname of the domain to make default.
+ * @param array $options
+ * An associative array of options whose values come from cli, aliases,
+ * config, etc.
+ * @option validate
+ * Force a check of the URL response before allowing registration.
+ * @usage drush domain-default www.example.com
+ * @usage drush domain-default example_org
+ * @usage drush domain-default www.example.org --validate=1
+ *
+ * @command domain:default
+ * @aliases domain-default
+ *
+ * @return string
+ * The machine name of the default domain.
+ *
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ public function defaultDomain($domain_id, array $options = ['validate' => null]) {
+ // Resolve the domain.
+ if (!empty($domain_id) && $domain = $this->getDomainFromArgument($domain_id)) {
+ $validate = ($options['validate']) ? 1 : 0;
+ $domain->addProperty('validate_url', $validate);
+ if ($error = $this->checkHTTPResponse($domain)) {
+ throw new DomainCommandException(dt('Unable to verify domain !domain: !error',
+ ['!domain' => $domain->getHostname(), '!error' => $error]));
+ }
+ else {
+ $domain->saveDefault();
+ }
+ }
+
+ // Now, ask for the current default, so we know if it worked.
+ $domain = $this->domainStorage()->loadDefaultDomain();
+ if ($domain->status()) {
+ $this->logger()->info(dt('!domain set to primary domain.',
+ ['!domain' => $domain->getHostname()]));
+ }
+ else {
+ $this->logger()->warning(dt('!domain set to primary domain, but is also inactive.',
+ ['!domain' => $domain->getHostname()]));
+ }
+ return $domain->id();
+ }
+
+ /**
+ * Deactivates the domain.
+ *
+ * @param $domain_id
+ * The numeric id or hostname of the domain to disable.
+ * @usage drush domain-disable example.com
+ * @usage drush domain-disable 1
+ *
+ * @command domain:disable
+ * @aliases domain-disable
+ *
+ * @return string
+ * 'disabled' if the domain is now disabled.
+ *
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ public function disable($domain_id) {
+ // Resolve the domain.
+ if ($domain = $this->getDomainFromArgument($domain_id)) {
+ if ($domain->status()) {
+ $domain->disable();
+ $this->logger()->info(dt('!domain has been disabled.',
+ ['!domain' => $domain->getHostname()]));
+ return dt('Disabled !domain.', ['!domain' => $domain->getHostname()]);
+ }
+ else {
+ $this->logger()->info(dt('!domain is already disabled.',
+ ['!domain' => $domain->getHostname()]));
+ return dt('!domain is already disabled.', ['!domain' => $domain->getHostname()]);
+ }
+ }
+ return dt('No matching domain record found.');
+ }
+
+ /**
+ * Activates the domain.
+ *
+ * @param $domain_id
+ * The numeric id or hostname of the domain to enable.
+ * @usage drush domain-disable example.com
+ * @usage drush domain-enable 1
+ *
+ * @command domain:enable
+ * @aliases domain-enable
+ *
+ * @return string
+ * 'enabled' if the domain is now enabled.
+ *
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ public function enable($domain_id) {
+ // Resolve the domain.
+ if ($domain = $this->getDomainFromArgument($domain_id)) {
+ if (!$domain->status()) {
+ $domain->enable();
+ $this->logger()->info(dt('!domain has been enabled.',
+ ['!domain' => $domain->getHostname()]));
+ return dt('Enabled !domain.', ['!domain' => $domain->getHostname()]);
+ }
+ else {
+ $this->logger()->info(dt('!domain is already enabled.',
+ ['!domain' => $domain->getHostname()]));
+ return dt('!domain is already enabled.', ['!domain' => $domain->getHostname()]);
+ }
+ }
+ return dt('No matching domain record found.');
+ }
+
+ /**
+ * Changes a domain label.
+ *
+ * @param $domain_id
+ * The machine name or hostname of the domain to relabel.
+ * @param $name
+ * The name to use for the domain.
+ * @usage drush domain-name example.com Foo
+ * @usage drush domain-name 1 Foo
+ *
+ * @command domain:name
+ * @aliases domain-name
+ *
+ * @return string
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ public function renameDomain($domain_id, $name) {
+ // Resolve the domain.
+ if ($domain = $this->getDomainFromArgument($domain_id)) {
+ $domain->saveProperty('name', $name);
+ return dt('Renamed !domain to !name.', ['!domain' => $domain->getHostname(), '!name' => $domain->label()]);
+ }
+ return dt('No matching domain record found.');
+ }
+
+ /**
+ * Changes a domain scheme.
+ *
+ * @param $domain_id
+ * The machine name or hostname of the domain to change.
+ * @param $scheme
+ * The scheme to use for the domain: http, https, or variable.
+ *
+ * @usage drush domain-scheme example.com http
+ * @usage drush domain-scheme example_com https
+ *
+ * @command domain:scheme
+ * @aliases domain-scheme
+ *
+ * @return string
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ public function scheme($domain_id, $scheme = null) {
+ $new_scheme = null;
+
+ // Resolve the domain.
+ if ($domain = $this->getDomainFromArgument($domain_id)) {
+ if (!empty($scheme)) {
+ // --set with a value
+ $new_scheme = $scheme;
+ }
+ else {
+ // Prompt for selection.
+ $new_scheme = $this->io()->choice(dt('Select the default http scheme:'),
+ [
+ 'http' => 'http',
+ 'https' => 'https',
+ 'variable' => 'variable',
+ ]);
+ }
+
+ // If we were asked to change scheme, validate the value and do so.
+ if (!empty($new_scheme)) {
+ switch ($new_scheme) {
+ case 'http':
+ $new_scheme = 'http';
+ break;
+
+ case 'https':
+ $new_scheme = 'https';
+ break;
+
+ case 'variable':
+ $new_scheme = 'variable';
+ break;
+
+ default:
+ throw new DomainCommandException(
+ dt('Scheme name "!scheme" not known', ['!scheme' => $new_scheme])
+ );
+ }
+ $domain->saveProperty('scheme', $new_scheme);
+ }
+
+ // Either way, return the (new | current) scheme for this domain.
+ return dt('Scheme is now to "!scheme" for !domain', ['!scheme' => $domain->get('scheme'),'!domain' => $domain->id()]);
+ }
+
+ // We couldn't find the domain - so fail.
+ throw new DomainCommandException(
+ dt('Domain name "!domain" not known', ['!domain' => $domain_id])
+ );
+ }
+
+ /**
+ * Generate domains for testing.
+ *
+ * @param $primary
+ * The primary domain to use. This will be created and used for
+ * *.example.com hostnames.
+ * @param array $options
+ * An associative array of options whose values come from cli, aliases,
+ * config, etc.
+ * @option count
+ * The count of extra domains to generate. Default is 15.
+ * @option empty
+ * Pass empty=1 to truncate the {domain} table before creating records.
+ * @usage drush domain-generate example.com
+ * @usage drush domain-generate example.com --count=25
+ * @usage drush domain-generate example.com --count=25 --empty=1
+ * @usage drush gend
+ * @usage drush gend --count=25
+ * @usage drush gend --count=25 --empty=1
+ *
+ * @command domain:generate
+ * @aliases gend,domgen,domain-generate
+ *
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ public function generate($primary = 'example.com', array $options = ['count' => null, 'empty' => null]) {
+ // Check the number of domains to create.
+ $count = $options['count'];
+ if (is_null($count)) {
+ $count = 15;
+ }
+
+ $domains = $this->domainStorage()->loadMultiple(NULL);
+ if (!empty($options['empty'])) {
+ $this->domainStorage()->delete($domains);
+ $domains = $this->domainStorage()->loadMultiple(NULL);
+ }
+ // Ensure we don't duplicate any domains.
+ $existing = [];
+ if (!empty($domains)) {
+ /** @var DomainInterface $domain */
+ foreach ($domains as $domain) {
+ $existing[] = $domain->getHostname();
+ }
+ }
+ // Set up one.* and so on.
+ $names = [
+ 'one',
+ 'two',
+ 'three',
+ 'four',
+ 'five',
+ 'six',
+ 'seven',
+ 'eight',
+ 'nine',
+ 'ten',
+ 'foo',
+ 'bar',
+ 'baz',
+ ];
+ // Set the creation array.
+ $new = [$primary];
+ foreach ($names as $name) {
+ $new[] = $name . '.' . $primary;
+ }
+ // Include a non hostname.
+ $new[] = 'my' . $primary;
+ // Filter against existing so we can count correctly.
+ $prepared = [];
+ foreach ($new as $key => $value) {
+ if (!in_array($value, $existing, true)) {
+ $prepared[] = $value;
+ }
+ }
+
+ // Add any test domains that have numeric prefixes. We don't expect these URLs to work,
+ // and mainly use these for testing the user interface.
+ // Test that we already have test domains.
+ $start = 1;
+ foreach ($existing as $exists) {
+ $name = explode('.', $exists);
+ if (substr_count($name[0], 'test') > 0) {
+ $num = (int) str_replace('test', '', $name[0]) + 1;
+ if ($num > $start) {
+ $start = $num;
+ }
+ }
+ }
+ $needed = $count - count($prepared) + $start;
+ for ($i = $start; $i <= $needed; $i++) {
+ $prepared[] = 'test' . $i . '.' . $primary;
+ }
+ // Get the initial item weight for sorting.
+ $start_weight = count($domains);
+ $prepared = array_slice($prepared, 0, $count);
+ $list = [];
+
+ // Create the domains.
+ foreach ($prepared as $key => $item) {
+ $hostname = mb_strtolower($item);
+ $values = [
+ 'name' => ($item != $primary) ? ucwords(str_replace(".$primary", '', $item)) : \Drupal::config('system.site')->get('name'),
+ 'hostname' => $hostname,
+ 'scheme' => 'http',
+ 'status' => 1,
+ 'weight' => ($item != $primary) ? $key + $start_weight + 1 : -1,
+ 'is_default' => 0,
+ 'id' => $this->domainStorage()->createMachineName($hostname),
+ ];
+ $domain = $this->domainStorage()->create($values);
+ $domain->save();
+ $list[] = dt('Created @domain.', ['@domain' => $domain->getHostname()]);
+ }
+
+ // If nothing created, say so.
+ if (empty($prepared)) {
+ return dt('No new domains were created.');
+ }
+ else {
+ return dt("Created @count new domains:\n@list", ['@count' => count($prepared), '@list' => implode("\n", $list)]);
+ }
+ }
+
+ /**
+ * Gets a domain storage object or throw an exception.
+ *
+ * Note that domain can run very early in the bootstrap, so we cannot
+ * reliably inject this service.
+ *
+ * @return DomainStorageInterface
+ *
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ protected function domainStorage() {
+ if (!is_null($this->domain_storage)) {
+ return $this->domain_storage;
+ }
+
+ try {
+ $this->domain_storage = \Drupal::entityTypeManager()->getStorage('domain');
+ }
+ catch (PluginNotFoundException $e) {
+ throw new DomainCommandException('Unable to get domain: no storage', $e);
+ }
+ catch (InvalidPluginDefinitionException $e) {
+ throw new DomainCommandException('Unable to get domain: bad storage', $e);
+ }
+
+ return $this->domain_storage;
+ }
+
+ /**
+ * Loads a domain based on a string identifier.
+ *
+ * @param string $argument
+ * The machine name or the hostname of an existing domain.
+ *
+ * @return \Drupal\domain\DomainInterface
+ *
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ protected function getDomainFromArgument($argument) {
+
+ // Try loading domain assuming arg is a machine name.
+ $domain = $this->domainStorage()->load($argument);
+ if (!$domain) {
+ // Try loading assuming it is a host name.
+ $domain = $this->domainStorage()->loadByHostname($argument);
+ }
+
+ // domain_id (an INT) is only used internally because the Node Access
+ // system demands the use of numeric keys. It should never be used to load
+ // or identify domain records. Use the machine_name or hostname instead.
+ if (!$domain) {
+ throw new DomainCommandException(
+ dt('Domain record could not be found from "!a".', ['!a' => $argument])
+ );
+ }
+
+ return $domain;
+ }
+
+ /**
+ * Filters a list of domains by excluding domains appearing in a specific list.
+ *
+ * @param DomainInterface[] $domains
+ * List of domains.
+ * @param string[] $exclude
+ * List of domain id to exclude from the list.
+ * @param DomainInterface[] $initial
+ * Initial value of list that will be returned.
+ *
+ * @return array
+ */
+ protected function filterDomains(array $domains, array $exclude, array $initial = []) {
+ foreach ($domains as $domain) {
+ // Exclude unwanted domains.
+ if (!in_array($domain->id(), $exclude, FALSE)) {
+ $initial[$domain->id()] = $domain;
+ }
+ }
+ return $initial;
+ }
+
+ /**
+ * Checks the domain response.
+ *
+ * @param \Drupal\domain\DomainInterface $domain
+ * The domain to check.
+ * @param bool $validate_url
+ * True to validate this domain by performing a URL lookup; False to skip
+ * the checks.
+ *
+ * @return bool
+ * True if the domain resolves properly, or we are not checking,
+ * False otherwise.
+ */
+ protected function checkHTTPResponse(DomainInterface $domain, $validate_url = FALSE) {
+ // Ensure the url is rebuilt.
+ if ($validate_url) {
+ $code = $this->checkDomain($domain);
+
+ // Some sort of success:
+ return $code >= 200 && $code <= 299;
+ }
+ // Not validating, so all is well!
+ return FALSE;
+ }
+
+ /**
+ * Helper function: check a domain is responsive and create it.
+ *
+ * @param DomainInterface $domain
+ * The (as yet unsaved) domain to create.
+ * @param bool $check_response
+ * Indicates that registration should not be allowed unless the server
+ * returns a 200 response.
+ *
+ * @return bool
+ * TODO: stndardize this return so we can issue good messages.
+ *
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ protected function createDomain(DomainInterface $domain, $check_response = FALSE) {
+ if ($check_response) {
+ $valid = $this->checkHTTPResponse($domain, TRUE);
+ if (!$valid) {
+ throw new DomainCommandException(
+ dt('The server did not return a 200 response for !d. Domain creation failed. Remove the --validate flag to save this domain.', ['!d' => $domain->getHostname()])
+ );
+ }
+ }
+ else {
+ try {
+ $domain->save();
+ }
+ catch (EntityStorageException $e) {
+ throw new DomainCommandException('Unable to save domain', $e);
+ }
+
+ if ($domain->getDomainId()) {
+ $this->logger()->info(dt('Created @name at @domain.',
+ ['@name' => $domain->label(), '@domain' => $domain->getHostname()]));
+ return TRUE;
+ }
+ else {
+ $this->logger()->error(dt('The request could not be completed.'));
+ }
+ }
+ return FALSE;
+ }
+
+ /**
+ * Checks a domain exists by trying to do an http request to it.
+ *
+ * @param DomainInterface $domain
+ * The domain to validate for syntax and uniqueness.
+ *
+ * @return int
+ * The server response code for the request.
+ *
+ * @see domain_validate()
+ */
+ protected function checkDomain(DomainInterface $domain) {
+ /** @var \Drupal\domain\DomainValidatorInterface $validator */
+ $validator = \Drupal::service('domain.validator');
+ return $validator->checkResponse($domain);
+ }
+
+ /**
+ * Validates a domain meets the standards for a hostname.
+ *
+ * @param DomainInterface $domain
+ * The domain to validate for syntax and uniqueness.
+ * @return string[]
+ * Array of strings indicating issues found.
+ *
+ * @see domain_validate()
+ */
+ protected function validateDomain(DomainInterface $domain) {
+ /** @var \Drupal\domain\DomainValidatorInterface $validator */
+ $validator = \Drupal::service('domain.validator');
+ return $validator->validate($domain->getHostname());
+ }
+
+ /**
+ * Deletes a domain record.
+ *
+ * @param DomainInterface[] $domains
+ * The domain_id to delete. Pass 'all' to delete all records.
+ *
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ * @throws \UnexpectedValueException
+ */
+ protected function deleteDomain(array $domains) {
+ foreach ($domains as $domain) {
+ if (!$domain instanceof DomainInterface) {
+ throw new StorageException('deleting domains: value is not a domain');
+ }
+ $hostname = $domain->getHostname();
+
+ if ($this->is_dry_run) {
+ $this->logger()->info(dt('DRYRUN: Domain record @domain deleted.',
+ ['@domain' => $hostname]));
+ continue;
+ }
+
+ try {
+ $domain->delete();
+ }
+ catch (EntityStorageException $e) {
+ throw new DomainCommandException(dt('Unable to delete domain: @domain',
+ ['@domain' => $hostname]), $e);
+ }
+ $this->logger()->info(dt('Domain record @domain deleted.',
+ ['@domain' => $hostname]));
+ }
+ }
+
+ /**
+ * Returns a list of the entity types that are domain enabled.
+ *
+ * A domain-enabled entity is defined here as an entity type that includes
+ * the domain access field(s).
+ *
+ * @param string $using_field
+ * The specific field name to look for.
+ *
+ * @return string[]
+ * List of entity machine names that support domain references.
+ */
+ protected function findDomainEnabledEntities($using_field = DOMAIN_ADMIN_FIELD) {
+ $this->ensureEntityFieldMap();
+ $entities = [];
+ foreach($this->entity_field_map as $type => $fields) {
+ if (array_key_exists($using_field, $fields)) {
+ $entities[] = $type;
+ }
+ }
+ return $entities;
+ }
+
+ /**
+ * Determines whether or not a given entity is domain-enabled.
+ *
+ * @param string $entity_type
+ * The machine name of the entity.
+ * @param string $field
+ * The name of the field to check for existence.
+ *
+ * @return bool
+ * True if this type of entity has a domain field.
+ */
+ protected function entityHasDomainField($entity_type, $field = DOMAIN_ADMIN_FIELD) {
+ // Try to avoid repeated calls to getFieldMap(), assuming it's expensive.
+ $this->ensureEntityFieldMap();
+ return array_key_exists($field, $this->entity_field_map[$entity_type]);
+ }
+
+ /**
+ * Ensure the local entity field map has been defined.
+ *
+ * Asking for the entity field map cause a lot of lookup, so we lazily
+ * fetch it and then remember it to avoid repeated checks.
+ */
+ protected function ensureEntityFieldMap() {
+ // Try to avoid repeated calls to getFieldMap() assuming it's expensive.
+ if (empty($this->entity_field_map)) {
+ $entity_manager = \Drupal::entityManager();
+ $this->entity_field_map = $entity_manager->getFieldMap();
+ }
+ }
+
+ /**
+ * Enumerate entity instances of the supplied type and domain.
+ *
+ * @param string $entity_type
+ * The entity type name, e.g. 'node'
+ * @param string $domain_id
+ * The machine name of the domain to enumerate.
+ * @param string $field
+ * The field to manipulate in the entity, e.g. DOMAIN_ACCESS_FIELD.
+ *
+ * @return int|string[]
+ * List of entity IDs for the selected domain.
+ * @todo: should this really be a string[] of fields?
+ */
+ protected function enumerateDomainEntities($entity_type, $domain_id, $field, $just_count = FALSE) {
+ if (!$this->entityHasDomainField($entity_type, $field)) {
+ $this->logger()->info('Entity type @entity_type does not have field @field, so none found.',
+ ['@entity_type'=> $entity_type,
+ '@field' => $field]);
+ return [];
+ }
+
+ $efq = \Drupal::entityQuery($entity_type);
+ // Don't access check or we wont get all of the possible entities moved.
+ $efq->accessCheck(FALSE);
+ $efq->condition($field, $domain_id, '=');
+ if ($just_count) {
+ $efq->count();
+ }
+ return $efq->execute();
+ }
+
+ /**
+ * Reassign old_domain entities, of the supplied type, to the new_domain.
+ *
+ * @param string $entity_type
+ * The entity type name, e.g. 'node'
+ * @param string $field
+ * The field to manipulate in the entity, e.g. DOMAIN_ADMIN_FIELD.
+ * @param \Drupal\domain\DomainInterface $old_domain
+ * The domain the entities currently belong to. It is not an error for
+ * entity ids to be passed in that are not in this domain, though of course
+ * not very useful.
+ * @param \Drupal\domain\DomainInterface $new_domain
+ * The domain the entities should now belong to: When an entity belongs to
+ * the old_domain, this domain replaces it.
+ * @param array $ids
+ * List of entity IDs for the selected domain and all of type $entity_type.
+ *
+ * @return int
+ *
+ * @throws \Drupal\Component\Plugin\Exception\PluginException
+ * @throws \Drupal\Core\Entity\EntityStorageException
+ */
+ protected function reassignEntities($entity_type, $field, DomainInterface $old_domain, DomainInterface $new_domain, array $ids) {
+ $entity_storage = \Drupal::entityTypeManager()->getStorage($entity_type);
+ $entities = $entity_storage->loadMultiple($ids);
+
+ foreach($entities as $entity) {
+ $changed = FALSE;
+ if (!$entity->hasField($field)) {
+ continue;
+ }
+ // Multivalue fields are used, so check each one.
+ foreach ($entity->get($field) as $k => $item) {
+ if ($item->target_id == $old_domain->id()) {
+
+ if ($this->is_dry_run) {
+ $this->logger()->info(dt('DRYRUN: Update domain membership for entity @id to @new.',
+ [ '@id' => $entity->id(), '@new' => $new_domain->id() ]));
+
+ // Don't set changed, so don't save either.
+ continue;
+ }
+
+ $changed = TRUE;
+ $item->target_id = $new_domain->id();
+ }
+ }
+ if ($changed) {
+ $entity->save();
+ }
+ }
+ return count($entities);
+ }
+
+ /**
+ * Return the Domain object corresponding to a policy string.
+ *
+ * @param string $policy
+ * In general one of 'prompt' | 'default' | 'ignore' or a domain entity
+ * machine name, but this function does not process 'prompt'.
+ *
+ * @return \Drupal\Core\Entity\EntityInterface|\Drupal\domain\DomainInterface|null
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ protected function getDomainInstanceFromPolicy($policy) {
+ switch($policy) {
+ /* Use the Default Domain machine name */
+ case 'default':
+ $new_domain = $this->domainStorage()->loadDefaultDomain();
+ break;
+
+ /* Ask interactively for a Domain machine name */
+ case 'prompt':
+ case 'ignore':
+ return NULL;
+
+ /* Use this (specified) Domain machine name */
+ default:
+ $new_domain = $this->domainStorage()->load($policy);
+ break;
+ }
+ return $new_domain;
+ }
+
+ /**
+ * Reassign entities of the supplied type to the $policy domain.
+ *
+ * @param array $options
+ * [
+ * 'entity_filter' => 'node',
+ * 'policy' => 'prompt' | 'default' | 'ignore' | {domain_id}
+ * 'field' => DOMAIN_ACCESS_FIELD,
+ * ];
+ *
+ * @param DomainInterface[] $domains
+ * List of the domains to reassign content away from.
+ *
+ * @throws \Drupal\domain\Commands\DomainCommandException
+ */
+ protected function reassignLinkedEntities($domains, array $options) {
+ $count = 0;
+ $field = $options['field'];
+ $entity_typenames = $this->findDomainEnabledEntities($field);
+
+ $new_domain = $this->getDomainInstanceFromPolicy($options['policy']);
+ if (empty($new_domain)) {
+ throw new DomainCommandException('invalid destination domain');
+ }
+
+ // For each entity type...
+ $exceptions = FALSE;
+ foreach ($entity_typenames as $name) {
+ if (empty($options['entity_filter']) || $options['entity_filter'] === $name) {
+
+ // For each domain being reassigned from...
+ foreach ($domains as $domain) {
+ $ids = $this->enumerateDomainEntities($name, $domain->id(), $field);
+ if (!empty($ids)) {
+ try {
+ if ($options['chatty']) {
+ $this->logger()->info('Reassigning @count @entity_name entities to @domain',
+ ['@entity_name'=>'',
+ '@count' => \count($ids),
+ '@domain' => $new_domain->id()]);
+ }
+ $count = $this->reassignEntities($name, $field, $domain, $new_domain, $ids);
+ }
+ catch (PluginException $e) {
+ $exceptions = TRUE;
+ $this->logger()->error('Unable to reassign content to @new_domain: plugin exception: @ex',
+ ['@ex' => $e->getMessage(),
+ '@new_domain' => $new_domain->id()]);
+ }
+ catch (EntityStorageException $e) {
+ $exceptions = TRUE;
+ $this->logger()->error('Unable to reassign content to @new_domain: storage exception: @ex',
+ ['@ex' => $e->getMessage(),
+ '@new_domain' => $new_domain->id()]);
+ }
+ }
+ }
+ }
+ }
+ if ($exceptions) {
+ throw new DomainCommandException('Errors encountered during reassign.');
+ }
+
+ return $count;
+ }
+
+}
diff --git a/sites/all/modules/contrib/admin/domain/domain/src/DomainElementManager.php b/sites/all/modules/contrib/admin/domain/domain/src/DomainElementManager.php
index 4afc7cc21..fe051241e 100644
--- a/sites/all/modules/contrib/admin/domain/domain/src/DomainElementManager.php
+++ b/sites/all/modules/contrib/admin/domain/domain/src/DomainElementManager.php
@@ -59,8 +59,15 @@ class DomainElementManager implements DomainElementManagerInterface {
return $form;
}
$fields = $this->fieldList($field_name);
+ $empty = FALSE;
$disallowed = $this->disallowedOptions($form_state, $form[$field_name]);
- $empty = empty($form[$field_name]['widget']['#options']);
+ if (empty($form[$field_name]['widget']['#options']) ||
+ (count($form[$field_name]['widget']['#options']) == 1 &&
+ isset($form[$field_name]['widget']['#options']['_none'])
+ )
+ ) {
+ $empty = TRUE;
+ }
// If the domain form element is set as a group, and the field is not
// assigned to another group, then move it. See
@@ -68,7 +75,10 @@ class DomainElementManager implements DomainElementManagerInterface {
if (isset($form['domain']) && !isset($form[$field_name]['#group'])) {
$form[$field_name]['#group'] = 'domain';
}
-
+ // If no values and we should hide the element, do so.
+ if ($hide_on_disallow && $empty) {
+ $form[$field_name]['#access'] = FALSE;
+ }
// Check for domains the user cannot access or the absence of any options.
if (!empty($disallowed) || $empty) {
// @TODO: Potentially show this information to users with permission.
diff --git a/sites/all/modules/contrib/admin/domain/domain/src/DomainNegotiator.php b/sites/all/modules/contrib/admin/domain/domain/src/DomainNegotiator.php
index 4bed560f0..ef68f7c5f 100644
--- a/sites/all/modules/contrib/admin/domain/domain/src/DomainNegotiator.php
+++ b/sites/all/modules/contrib/admin/domain/domain/src/DomainNegotiator.php
@@ -38,7 +38,7 @@ class DomainNegotiator implements DomainNegotiatorInterface {
/**
* The domain storage class.
*
- * @var \Drupal\domain\DomainStorageInterface
+ * @var \Drupal\domain\DomainStorageInterface|null
*/
protected $domainStorage;
@@ -87,7 +87,6 @@ class DomainNegotiator implements DomainNegotiatorInterface {
$this->requestStack = $requestStack;
$this->moduleHandler = $module_handler;
$this->entityTypeManager = $entity_type_manager;
- $this->domainStorage = $this->entityTypeManager->getStorage('domain');
$this->configFactory = $config_factory;
}
@@ -98,7 +97,7 @@ class DomainNegotiator implements DomainNegotiatorInterface {
// @TODO: Investigate caching methods.
$this->setHttpHost($httpHost);
// Try to load a direct match.
- if ($domain = $this->domainStorage->loadByHostname($httpHost)) {
+ if ($domain = $this->domainStorage()->loadByHostname($httpHost)) {
// If the load worked, set an exact match flag for the hook.
$domain->setMatchType(self::DOMAIN_MATCH_EXACT);
}
@@ -107,16 +106,10 @@ class DomainNegotiator implements DomainNegotiatorInterface {
else {
$values = ['hostname' => $httpHost];
/** @var \Drupal\domain\DomainInterface $domain */
- $domain = $this->domainStorage->create($values);
+ $domain = $this->domainStorage()->create($values);
$domain->setMatchType(self::DOMAIN_MATCH_NONE);
}
- // Make sure all modules are loaded and can alter the found domains.
- // See https://www.drupal.org/node/2896434#comment-12267208.
- $this->moduleHandler->reload();
- foreach ($this->moduleHandler->getImplementations('domain_request_alter') as $module) {
- $this->moduleHandler->load($module);
- }
// Now check with modules (like Domain Alias) that register alternate
// lookup systems with the main module.
$this->moduleHandler->alter('domain_request', $domain);
@@ -126,7 +119,7 @@ class DomainNegotiator implements DomainNegotiatorInterface {
$this->setActiveDomain($domain);
}
// Fallback to default domain if no match.
- elseif ($domain = $this->domainStorage->loadDefaultDomain()) {
+ elseif ($domain = $this->domainStorage()->loadDefaultDomain()) {
$this->moduleHandler->alter('domain_request', $domain);
$domain->setMatchType(self::DOMAIN_MATCH_NONE);
if (!empty($domain->id())) {
@@ -180,7 +173,7 @@ class DomainNegotiator implements DomainNegotiatorInterface {
$httpHost = $_SERVER['HTTP_HOST'];
}
$hostname = !empty($httpHost) ? $httpHost : 'localhost';
- return $this->domainStorage->prepareHostname($hostname);
+ return $this->domainStorage()->prepareHostname($hostname);
}
/**
@@ -202,13 +195,13 @@ class DomainNegotiator implements DomainNegotiatorInterface {
*/
public function isRegisteredDomain($hostname) {
// Direct hostname match always passes.
- if ($domain = $this->domainStorage->loadByHostname($hostname)) {
+ if ($domain = $this->domainStorage()->loadByHostname($hostname)) {
return TRUE;
}
// Check for registered alias matches.
$values = ['hostname' => $hostname];
/** @var \Drupal\domain\DomainInterface $domain */
- $domain = $this->domainStorage->create($values);
+ $domain = $this->domainStorage()->create($values);
$domain->setMatchType(self::DOMAIN_MATCH_NONE);
// Now check with modules (like Domain Alias) that register alternate
@@ -222,4 +215,17 @@ class DomainNegotiator implements DomainNegotiatorInterface {
return FALSE;
}
+ /**
+ * Retrieves the domain storage handler.
+ *
+ * @return \Drupal\domain\DomainStorageInterface
+ * The domain storage handler.
+ */
+ protected function domainStorage() {
+ if (!$this->domainStorage) {
+ $this->domainStorage = $this->entityTypeManager->getStorage('domain');
+ }
+ return $this->domainStorage;
+ }
+
}
diff --git a/sites/all/modules/contrib/admin/domain/domain/src/DomainValidator.php b/sites/all/modules/contrib/admin/domain/domain/src/DomainValidator.php
index 8b570b6e5..5d68100af 100644
--- a/sites/all/modules/contrib/admin/domain/domain/src/DomainValidator.php
+++ b/sites/all/modules/contrib/admin/domain/domain/src/DomainValidator.php
@@ -132,10 +132,9 @@ class DomainValidator implements DomainValidatorInterface {
}
// We cannot know which Guzzle Exception class will be returned; be generic.
catch (RequestException $e) {
- watchdog_exception('domain', $e);
// File a general server failure.
$domain->setResponse(500);
- return;
+ return $domain->getResponse();
}
// Expected result (i.e. no exception thrown.)
$domain->setResponse($request->getStatusCode());
diff --git a/sites/all/modules/contrib/admin/domain/domain/src/Entity/Domain.php b/sites/all/modules/contrib/admin/domain/domain/src/Entity/Domain.php
index 2fbb6e8d1..7f5167147 100644
--- a/sites/all/modules/contrib/admin/domain/domain/src/Entity/Domain.php
+++ b/sites/all/modules/contrib/admin/domain/domain/src/Entity/Domain.php
@@ -343,8 +343,8 @@ class Domain extends ConfigEntityBase implements DomainInterface {
$default->is_default = FALSE;
$default->save();
}
- // Ensures we have a proper domain_id.
- if ($this->isNew()) {
+ // Ensures we have a proper domain_id but does not erase existing ones.
+ if ($this->isNew() && empty($this->getDomainId())) {
$this->createDomainId();
}
// Prevent duplicate hostname.
diff --git a/sites/all/modules/contrib/admin/domain/domain/src/Plugin/Condition/Domain.php b/sites/all/modules/contrib/admin/domain/domain/src/Plugin/Condition/Domain.php
index 965911af5..7347401b4 100644
--- a/sites/all/modules/contrib/admin/domain/domain/src/Plugin/Condition/Domain.php
+++ b/sites/all/modules/contrib/admin/domain/domain/src/Plugin/Condition/Domain.php
@@ -15,7 +15,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
* id = "domain",
* label = @Translation("Domain"),
* context = {
- * "entity:domain" = @ContextDefinition("entity:domain", label = @Translation("Domain"), required = TRUE)
+ * "entity:domain" = @ContextDefinition("entity:domain", label = @Translation("Domain"), required = FALSE)
* }
* )
*/
@@ -73,7 +73,12 @@ class Domain extends ConditionPluginBase implements ContainerFactoryPluginInterf
],
],
];
- return parent::buildConfigurationForm($form, $form_state);
+ $form = parent::buildConfigurationForm($form, $form_state);
+ if (isset($form['context_mapping']['entity:domain']['#title'])) {
+ $form['context_mapping']['entity:domain']['#title'] = $this->t('Select the Domain condition');
+ $form['context_mapping']['entity:domain']['#description'] = $this->t('This value must be set to "Active domain" for the context to work.');
+ }
+ return $form;
}
/**
diff --git a/sites/all/modules/contrib/admin/domain/domain/tests/modules/domain_config_schema_test/domain_config_schema_test.info.yml b/sites/all/modules/contrib/admin/domain/domain/tests/modules/domain_config_schema_test/domain_config_schema_test.info.yml
index 0fb379830..eb1f32218 100644
--- a/sites/all/modules/contrib/admin/domain/domain/tests/modules/domain_config_schema_test/domain_config_schema_test.info.yml
+++ b/sites/all/modules/contrib/admin/domain/domain/tests/modules/domain_config_schema_test/domain_config_schema_test.info.yml
@@ -9,8 +9,8 @@ hidden: TRUE
dependencies:
- domain
-# Information added by Drupal.org packaging script on 2018-11-14
-version: '8.x-1.0-alpha14+9-dev'
+# Information added by Drupal.org packaging script on 2019-02-21
+version: '8.x-1.0-alpha15'
core: '8.x'
project: 'domain'
-datestamp: 1542230887
+datestamp: 1550763190
diff --git a/sites/all/modules/contrib/admin/domain/domain/tests/modules/domain_test/domain_test.info.yml b/sites/all/modules/contrib/admin/domain/domain/tests/modules/domain_test/domain_test.info.yml
index 61308a6a4..c7a2793bc 100644
--- a/sites/all/modules/contrib/admin/domain/domain/tests/modules/domain_test/domain_test.info.yml
+++ b/sites/all/modules/contrib/admin/domain/domain/tests/modules/domain_test/domain_test.info.yml
@@ -9,8 +9,8 @@ hidden: TRUE
dependencies:
- domain
-# Information added by Drupal.org packaging script on 2018-11-14
-version: '8.x-1.0-alpha14+9-dev'
+# Information added by Drupal.org packaging script on 2019-02-21
+version: '8.x-1.0-alpha15'
core: '8.x'
project: 'domain'
-datestamp: 1542230887
+datestamp: 1550763190
diff --git a/sites/all/modules/contrib/admin/domain/domain_access/domain_access.info.yml b/sites/all/modules/contrib/admin/domain/domain_access/domain_access.info.yml
index 01269c9cc..b7e3f245f 100644
--- a/sites/all/modules/contrib/admin/domain/domain_access/domain_access.info.yml
+++ b/sites/all/modules/contrib/admin/domain/domain_access/domain_access.info.yml
@@ -8,8 +8,8 @@ dependencies:
- drupal:node
- domain:domain
-# Information added by Drupal.org packaging script on 2018-11-14
-version: '8.x-1.0-alpha14+9-dev'
+# Information added by Drupal.org packaging script on 2019-02-21
+version: '8.x-1.0-alpha15'
core: '8.x'
project: 'domain'
-datestamp: 1542230887
+datestamp: 1550763190
diff --git a/sites/all/modules/contrib/admin/domain/domain_access/drush.services.yml b/sites/all/modules/contrib/admin/domain/domain_access/drush.services.yml
new file mode 100644
index 000000000..e7541c0ec
--- /dev/null
+++ b/sites/all/modules/contrib/admin/domain/domain_access/drush.services.yml
@@ -0,0 +1,5 @@
+services:
+ domain_access.commands:
+ class: \Drupal\domain_access\Commands\DomainAccessCommands
+ tags:
+ - { name: drush.command }
diff --git a/sites/all/modules/contrib/admin/domain/domain_access/src/Commands/DomainAccessCommands.php b/sites/all/modules/contrib/admin/domain/domain_access/src/Commands/DomainAccessCommands.php
new file mode 100644
index 000000000..fe408cb3f
--- /dev/null
+++ b/sites/all/modules/contrib/admin/domain/domain_access/src/Commands/DomainAccessCommands.php
@@ -0,0 +1,79 @@
+getFieldEntities(DOMAIN_ACCESS_FIELD);
+
+ return $result;
+ }
+
+/**
+ * @hook option domain:delete
+ */
+ public function deleteOptions(Command $command, AnnotationData $annotationData) {
+ $command->addOption(
+ 'content-assign',
+ '',
+ InputOption::VALUE_OPTIONAL,
+ 'Reassign content for Domain Access',
+ null
+ );
+ }
+
+/**
+ * @hook on-event domain-delete
+ */
+ public function domainAccessDomainDelete($target_domain, $options) {
+ // Run our own deletion routine here.
+ if (is_null($options['content-assign'])) {
+ $policy_content = 'prompt';
+ }
+ if (!empty($options['content-assign'])) {
+ if (in_array($options['content-assign'], $this->reassignment_policies, TRUE)) {
+ $policy_content = $options['content-assign'];
+ }
+ }
+
+ $delete_options = [
+ 'entity_filter' => 'node',
+ 'policy' => $policy_content,
+ 'field' => DOMAIN_ACCESS_FIELD,
+ ];
+
+ return $this->doReassign($target_domain, $delete_options);
+ }
+
+}
diff --git a/sites/all/modules/contrib/admin/domain/domain_access/tests/modules/domain_access_test/domain_access_test.info.yml b/sites/all/modules/contrib/admin/domain/domain_access/tests/modules/domain_access_test/domain_access_test.info.yml
index be931b476..b9635a950 100644
--- a/sites/all/modules/contrib/admin/domain/domain_access/tests/modules/domain_access_test/domain_access_test.info.yml
+++ b/sites/all/modules/contrib/admin/domain/domain_access/tests/modules/domain_access_test/domain_access_test.info.yml
@@ -11,8 +11,8 @@ dependencies:
- domain_access
- taxonomy
-# Information added by Drupal.org packaging script on 2018-11-14
-version: '8.x-1.0-alpha14+9-dev'
+# Information added by Drupal.org packaging script on 2019-02-21
+version: '8.x-1.0-alpha15'
core: '8.x'
project: 'domain'
-datestamp: 1542230887
+datestamp: 1550763190
diff --git a/sites/all/modules/contrib/admin/domain/domain_alias/domain_alias.info.yml b/sites/all/modules/contrib/admin/domain/domain_alias/domain_alias.info.yml
index 69441e904..b6adc6d03 100644
--- a/sites/all/modules/contrib/admin/domain/domain_alias/domain_alias.info.yml
+++ b/sites/all/modules/contrib/admin/domain/domain_alias/domain_alias.info.yml
@@ -7,8 +7,8 @@ package: Domain
dependencies:
- domain:domain
-# Information added by Drupal.org packaging script on 2018-11-14
-version: '8.x-1.0-alpha14+9-dev'
+# Information added by Drupal.org packaging script on 2019-02-21
+version: '8.x-1.0-alpha15'
core: '8.x'
project: 'domain'
-datestamp: 1542230887
+datestamp: 1550763190
diff --git a/sites/all/modules/contrib/admin/domain/domain_config/domain_config.info.yml b/sites/all/modules/contrib/admin/domain/domain_config/domain_config.info.yml
index 0419af371..dae75bca8 100644
--- a/sites/all/modules/contrib/admin/domain/domain_config/domain_config.info.yml
+++ b/sites/all/modules/contrib/admin/domain/domain_config/domain_config.info.yml
@@ -7,8 +7,8 @@ package: Domain
dependencies:
- domain:domain
-# Information added by Drupal.org packaging script on 2018-11-14
-version: '8.x-1.0-alpha14+9-dev'
+# Information added by Drupal.org packaging script on 2019-02-21
+version: '8.x-1.0-alpha15'
core: '8.x'
project: 'domain'
-datestamp: 1542230887
+datestamp: 1550763190
diff --git a/sites/all/modules/contrib/admin/domain/domain_config/domain_config.services.yml b/sites/all/modules/contrib/admin/domain/domain_config/domain_config.services.yml
index 1c8ecb791..1e1029f93 100644
--- a/sites/all/modules/contrib/admin/domain/domain_config/domain_config.services.yml
+++ b/sites/all/modules/contrib/admin/domain/domain_config/domain_config.services.yml
@@ -3,7 +3,7 @@ services:
class: Drupal\domain_config\DomainConfigOverrider
tags:
- { name: config.factory.override, priority: -150}
- arguments: ['@config.storage']
+ arguments: ['@config.storage', '@module_handler']
domain_config.library.discovery.collector:
decorates: library.discovery.collector
diff --git a/sites/all/modules/contrib/admin/domain/domain_config/src/DomainConfigOverrider.php b/sites/all/modules/contrib/admin/domain/domain_config/src/DomainConfigOverrider.php
index a712eeadf..97f3ec09e 100644
--- a/sites/all/modules/contrib/admin/domain/domain_config/src/DomainConfigOverrider.php
+++ b/sites/all/modules/contrib/admin/domain/domain_config/src/DomainConfigOverrider.php
@@ -6,6 +6,7 @@ use Drupal\domain\DomainInterface;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Config\ConfigFactoryOverrideInterface;
use Drupal\Core\Config\StorageInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
/**
* Domain-specific config overrides.
@@ -29,6 +30,13 @@ class DomainConfigOverrider implements ConfigFactoryOverrideInterface {
*/
protected $storage;
+ /**
+ * The module handler.
+ *
+ * @var \Drupal\Core\Extension\ModuleHandlerInterface
+ */
+ protected $moduleHandler;
+
/**
* The domain context of the request.
*
@@ -64,9 +72,12 @@ class DomainConfigOverrider implements ConfigFactoryOverrideInterface {
*
* @param \Drupal\Core\Config\StorageInterface $storage
* The configuration storage engine.
+ * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+ * The module handler.
*/
- public function __construct(StorageInterface $storage) {
+ public function __construct(StorageInterface $storage, ModuleHandlerInterface $module_handler) {
$this->storage = $storage;
+ $this->moduleHandler = $module_handler;
}
/**
@@ -77,11 +88,16 @@ class DomainConfigOverrider implements ConfigFactoryOverrideInterface {
static $lookups;
// Key should be a known length, so hash.
$key = md5(implode(':', $names));
-
if (isset($lookups[$key])) {
return $lookups[$key];
}
+ // Set the context of the override request.
+ if (empty($this->contextSet)) {
+ $this->initiateContext();
+ }
+
+ // Prepare our overrides.
$overrides = [];
// loadOverrides() runs on config entities, which means that if we try
// to run this routine on our own data, then we end up in an infinite loop.
@@ -92,9 +108,6 @@ class DomainConfigOverrider implements ConfigFactoryOverrideInterface {
$lookups[$key] = $overrides;
return $overrides;
}
- if (empty($this->contextSet)) {
- $this->initiateContext();
- }
if (!empty($this->domain)) {
foreach ($names as $name) {
$config_name = $this->getDomainConfigName($name, $this->domain);
@@ -198,7 +211,11 @@ class DomainConfigOverrider implements ConfigFactoryOverrideInterface {
// run.
if (empty($this->domain)) {
$this->domain = $this->domainNegotiator->getActiveDomain(TRUE);
+ // Ensure the module hook cache is set properly.
+ // See https://www.drupal.org/project/domain/issues/3025541
+ $this->moduleHandler->resetImplementations();
}
+
}
}
diff --git a/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/domain_config_hook_test.info.yml b/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/domain_config_hook_test.info.yml
new file mode 100644
index 000000000..86b70de9b
--- /dev/null
+++ b/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/domain_config_hook_test.info.yml
@@ -0,0 +1,24 @@
+name: "Domain config hook test"
+description: "Support module for domain config testing."
+type: module
+package: Testing
+# version: VERSION
+# core: 8.x
+hidden: TRUE
+
+dependencies: []
+
+# This module represents several services that could be provided by multiple modules in the Drupal community.
+# The following are not playing nice together:
+# - A page cache policy service that uses the config factory.
+# - A module that implements hook_module_implements.
+# - A random hook that hook_module_implements wishes to control.
+# - The domain_config module (and domain negotiator service, I believe).
+
+# When this module is functioning correctly, when a user logs in, there will not be a state key set.
+
+# Information added by Drupal.org packaging script on 2019-02-21
+version: '8.x-1.0-alpha15'
+core: '8.x'
+project: 'domain'
+datestamp: 1550763190
diff --git a/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/domain_config_hook_test.module b/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/domain_config_hook_test.module
new file mode 100644
index 000000000..dfbfcf56e
--- /dev/null
+++ b/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/domain_config_hook_test.module
@@ -0,0 +1,23 @@
+set('domain_config_test__user_login', TRUE);
+}
+
+/**
+ * Implements hook_module_implements_alter().
+ */
+function domain_config_hook_test_module_implements_alter(&$implementations, $hook) {
+ if ($hook == 'user_login') {
+ // Turn off the domain_config_hook_test's hook_user_login (above).
+ unset($implementations['domain_config_hook_test']);
+ }
+}
diff --git a/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/domain_config_hook_test.services.yml b/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/domain_config_hook_test.services.yml
new file mode 100644
index 000000000..8cb02a0d8
--- /dev/null
+++ b/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/domain_config_hook_test.services.yml
@@ -0,0 +1,7 @@
+services:
+ domain_config_service.page_cache_request_policy:
+ class: Drupal\domain_config_hook_test\PageCache\RequestPolicy\PageCacheRequestPolicy
+ arguments: ['@config.factory']
+ tags:
+ - { name: page_cache_request_policy }
+
diff --git a/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/src/PageCache/RequestPolicy/PageCacheRequestPolicy.php b/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/src/PageCache/RequestPolicy/PageCacheRequestPolicy.php
new file mode 100644
index 000000000..6d0cc4b4d
--- /dev/null
+++ b/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/src/PageCache/RequestPolicy/PageCacheRequestPolicy.php
@@ -0,0 +1,47 @@
+configFactory = $config_factory;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function check(Request $request) {
+ // This line is important. You have to use this service for it to fail.
+ $this->configFactory
+ ->get('system.site');
+
+ return NULL;
+ }
+
+}
diff --git a/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_middleware_test/domain_config_middleware_test.info.yml b/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_middleware_test/domain_config_middleware_test.info.yml
index 3b0859de0..0ba18b603 100644
--- a/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_middleware_test/domain_config_middleware_test.info.yml
+++ b/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_middleware_test/domain_config_middleware_test.info.yml
@@ -10,8 +10,8 @@ dependencies:
- domain
- domain_config
-# Information added by Drupal.org packaging script on 2018-11-14
-version: '8.x-1.0-alpha14+9-dev'
+# Information added by Drupal.org packaging script on 2019-02-21
+version: '8.x-1.0-alpha15'
core: '8.x'
project: 'domain'
-datestamp: 1542230887
+datestamp: 1550763190
diff --git a/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_test/domain_config_test.info.yml b/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_test/domain_config_test.info.yml
index ec624cc98..0c1f3bbf0 100644
--- a/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_test/domain_config_test.info.yml
+++ b/sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_test/domain_config_test.info.yml
@@ -10,8 +10,8 @@ dependencies:
- domain
- domain_config
-# Information added by Drupal.org packaging script on 2018-11-14
-version: '8.x-1.0-alpha14+9-dev'
+# Information added by Drupal.org packaging script on 2019-02-21
+version: '8.x-1.0-alpha15'
core: '8.x'
project: 'domain'
-datestamp: 1542230887
+datestamp: 1550763190
diff --git a/sites/all/modules/contrib/admin/domain/domain_config/tests/src/Functional/DomainConfigHookProblemTest.php b/sites/all/modules/contrib/admin/domain/domain_config/tests/src/Functional/DomainConfigHookProblemTest.php
new file mode 100644
index 000000000..c6fb7a11e
--- /dev/null
+++ b/sites/all/modules/contrib/admin/domain/domain_config/tests/src/Functional/DomainConfigHookProblemTest.php
@@ -0,0 +1,30 @@
+drupalGet('user/login');
+ $user = $this->drupalCreateUser([]);
+ $edit = ['name' => $user->getUserName(), 'pass' => $user->passRaw];
+ $this->drupalPostForm(NULL, $edit, t('Log in'));
+
+ $test = \Drupal::state()->get('domain_config_test__user_login', NULL);
+ // When this test passes, it means domain_config_hook_test_user_login was
+ // not run.
+ $this->assertNull($test, 'The hook_user_login state message is set.');
+ }
+
+}
diff --git a/sites/all/modules/contrib/admin/domain/domain_content/domain_content.info.yml b/sites/all/modules/contrib/admin/domain/domain_content/domain_content.info.yml
index ac0df89c8..1af7da3f7 100644
--- a/sites/all/modules/contrib/admin/domain/domain_content/domain_content.info.yml
+++ b/sites/all/modules/contrib/admin/domain/domain_content/domain_content.info.yml
@@ -11,8 +11,8 @@ dependencies:
- domain:domain
- domain:domain_access
-# Information added by Drupal.org packaging script on 2018-11-14
-version: '8.x-1.0-alpha14+9-dev'
+# Information added by Drupal.org packaging script on 2019-02-21
+version: '8.x-1.0-alpha15'
core: '8.x'
project: 'domain'
-datestamp: 1542230887
+datestamp: 1550763190
diff --git a/sites/all/modules/contrib/admin/domain/domain_content/src/Controller/DomainContentController.php b/sites/all/modules/contrib/admin/domain/domain_content/src/Controller/DomainContentController.php
index cd69c7a90..385cc3531 100644
--- a/sites/all/modules/contrib/admin/domain/domain_content/src/Controller/DomainContentController.php
+++ b/sites/all/modules/contrib/admin/domain/domain_content/src/Controller/DomainContentController.php
@@ -13,7 +13,7 @@ use Drupal\Core\Url;
class DomainContentController extends ControllerBase {
/**
- * Builds the lost of domains and relevant entities.
+ * Builds the list of domains and relevant entities.
*
* @param array $options
* A list of variables required to build editor or content pages.
diff --git a/sites/all/modules/contrib/admin/domain/domain_source/domain_source.info.yml b/sites/all/modules/contrib/admin/domain/domain_source/domain_source.info.yml
index 5ba7f787f..1ba6c6fd4 100644
--- a/sites/all/modules/contrib/admin/domain/domain_source/domain_source.info.yml
+++ b/sites/all/modules/contrib/admin/domain/domain_source/domain_source.info.yml
@@ -8,8 +8,8 @@ dependencies:
- drupal:node
- domain:domain
-# Information added by Drupal.org packaging script on 2018-11-14
-version: '8.x-1.0-alpha14+9-dev'
+# Information added by Drupal.org packaging script on 2019-02-21
+version: '8.x-1.0-alpha15'
core: '8.x'
project: 'domain'
-datestamp: 1542230887
+datestamp: 1550763190
diff --git a/sites/all/modules/contrib/admin/domain/domain_source/domain_source.module b/sites/all/modules/contrib/admin/domain/domain_source/domain_source.module
index 8e4a12573..0e1f37a76 100644
--- a/sites/all/modules/contrib/admin/domain/domain_source/domain_source.module
+++ b/sites/all/modules/contrib/admin/domain/domain_source/domain_source.module
@@ -286,3 +286,17 @@ function domain_source_presave_generate(EntityInterface $entity) {
}
}
}
+
+
+/**
+ * Implements hook_hook_info().
+ */
+function domain_source_hook_info() {
+ $hooks['domain_source_alter'] = [
+ 'group' => 'domain_source',
+ ];
+ $hooks['domain_source_path_alter'] = [
+ 'group' => 'domain_source',
+ ];
+ return $hooks;
+}
diff --git a/sites/all/modules/contrib/admin/domain/domain_source/drush.services.yml b/sites/all/modules/contrib/admin/domain/domain_source/drush.services.yml
new file mode 100644
index 000000000..6c115c943
--- /dev/null
+++ b/sites/all/modules/contrib/admin/domain/domain_source/drush.services.yml
@@ -0,0 +1,5 @@
+services:
+ domain_source.commands:
+ class: \Drupal\domain_source\Commands\DomainSourceCommands
+ tags:
+ - { name: drush.command }
diff --git a/sites/all/modules/contrib/admin/domain/domain_source/src/Commands/DomainSourceCommands.php b/sites/all/modules/contrib/admin/domain/domain_source/src/Commands/DomainSourceCommands.php
new file mode 100644
index 000000000..452f0efd3
--- /dev/null
+++ b/sites/all/modules/contrib/admin/domain/domain_source/src/Commands/DomainSourceCommands.php
@@ -0,0 +1,79 @@
+getFieldEntities(DOMAIN_SOURCE_FIELD);
+
+ return $result;
+ }
+
+ /**
+ * @hook option domain:delete
+ */
+ public function deleteOptions(Command $command, AnnotationData $annotationData) {
+ $command->addOption(
+ 'source-assign',
+ '',
+ InputOption::VALUE_OPTIONAL,
+ 'Reassign content for Domain Source',
+ null
+ );
+ }
+
+ /**
+ * @hook on-event domain-delete
+ */
+ public function domainSourceDomainDelete($target_domain, $options) {
+ // Run our own deletion routine here.
+ if (is_null($options['content-assign'])) {
+ $policy_content = 'prompt';
+ }
+ if (!empty($options['content-assign'])) {
+ if (in_array($options['content-assign'], $this->reassignment_policies, TRUE)) {
+ $policy_content = $options['content-assign'];
+ }
+ }
+
+ $delete_options = [
+ 'entity_filter' => 'node',
+ 'policy' => $policy_content,
+ 'field' => DOMAIN_SOURCE_FIELD,
+ ];
+
+ return $this->doReassign($target_domain, $delete_options);
+ }
+
+}
diff --git a/sites/all/modules/contrib/admin/domain/domain_source/src/HttpKernel/DomainSourcePathProcessor.php b/sites/all/modules/contrib/admin/domain/domain_source/src/HttpKernel/DomainSourcePathProcessor.php
index 06fba8c10..799ececd4 100644
--- a/sites/all/modules/contrib/admin/domain/domain_source/src/HttpKernel/DomainSourcePathProcessor.php
+++ b/sites/all/modules/contrib/admin/domain/domain_source/src/HttpKernel/DomainSourcePathProcessor.php
@@ -76,7 +76,7 @@ class DomainSourcePathProcessor implements OutboundPathProcessorInterface {
/**
* The domain storage.
*
- * @var \Drupal\domain\DomainStorageInterface
+ * @var \Drupal\domain\DomainStorageInterface|null
*/
protected $domainStorage;
@@ -100,7 +100,6 @@ class DomainSourcePathProcessor implements OutboundPathProcessorInterface {
$this->entityTypeManager = $entity_type_manager;
$this->aliasManager = $alias_manager;
$this->configFactory = $config_factory;
- $this->domainStorage = $entity_type_manager->getStorage('domain');
}
/**
@@ -159,7 +158,7 @@ class DomainSourcePathProcessor implements OutboundPathProcessorInterface {
$target_id = domain_source_get($entity);
}
if (!empty($target_id)) {
- $source = $this->domainStorage->load($target_id);
+ $source = $this->domainStorage()->load($target_id);
}
$options['entity'] = $entity;
$options['entity_type'] = $entity->getEntityTypeId();
@@ -169,7 +168,7 @@ class DomainSourcePathProcessor implements OutboundPathProcessorInterface {
else {
if (isset($options['domain_target_id'])) {
$target_id = $options['domain_target_id'];
- $source = $this->domainStorage->load($target_id);
+ $source = $this->domainStorage()->load($target_id);
}
$this->moduleHandler->alter('domain_source_path', $source, $path, $options);
}
@@ -279,4 +278,17 @@ class DomainSourcePathProcessor implements OutboundPathProcessorInterface {
return $this->activeDomain;
}
+ /**
+ * Retrieves the domain storage handler.
+ *
+ * @return \Drupal\domain\DomainStorageInterface
+ * The domain storage handler.
+ */
+ protected function domainStorage() {
+ if (!$this->domainStorage) {
+ $this->domainStorage = $this->entityTypeManager->getStorage('domain');
+ }
+ return $this->domainStorage;
+ }
+
}
diff --git a/sites/all/modules/contrib/admin/domain/domain_source/tests/modules/domain_source_test/domain_source_test.info.yml b/sites/all/modules/contrib/admin/domain/domain_source/tests/modules/domain_source_test/domain_source_test.info.yml
index 2705e4c5e..b30a708ef 100644
--- a/sites/all/modules/contrib/admin/domain/domain_source/tests/modules/domain_source_test/domain_source_test.info.yml
+++ b/sites/all/modules/contrib/admin/domain/domain_source/tests/modules/domain_source_test/domain_source_test.info.yml
@@ -14,8 +14,8 @@ dependencies:
- serialization
- user
-# Information added by Drupal.org packaging script on 2018-11-14
-version: '8.x-1.0-alpha14+9-dev'
+# Information added by Drupal.org packaging script on 2019-02-21
+version: '8.x-1.0-alpha15'
core: '8.x'
project: 'domain'
-datestamp: 1542230887
+datestamp: 1550763190
diff --git a/sites/all/modules/contrib/admin/domain/domain_source/tests/src/Functional/DomainSourceElementTest.php b/sites/all/modules/contrib/admin/domain/domain_source/tests/src/Functional/DomainSourceElementTest.php
index 208a32d07..981c2cbb9 100644
--- a/sites/all/modules/contrib/admin/domain/domain_source/tests/src/Functional/DomainSourceElementTest.php
+++ b/sites/all/modules/contrib/admin/domain/domain_source/tests/src/Functional/DomainSourceElementTest.php
@@ -141,4 +141,44 @@ class DomainSourceElementTest extends DomainTestBase {
$this->assert(strpos($url, 'node/' . $nid . '/edit') === FALSE, 'Form submitted.');
}
+ /**
+ * Test for https://www.drupal.org/project/domain/issues/3010256.
+ */
+ public function testAnonForm() {
+ // Editor with no domain permissions should not see the element.
+ $editor = $this->drupalCreateUser([
+ 'create article content',
+ ]);
+ $this->drupalLogin($editor);
+
+ $this->drupalGet('node/add/article');
+ $this->assertSession()->statusCodeEquals(200);
+
+ $locator = DOMAIN_SOURCE_FIELD;
+ $this->assertSession()->fieldNotExists($locator);
+
+ // Editor with domain permissions should see the element once they
+ // are assigned to domains.
+ $editor2 = $this->drupalCreateUser([
+ 'create article content',
+ 'publish to any assigned domain',
+ ]);
+ $this->drupalLogin($editor2);
+
+ $this->drupalGet('node/add/article');
+ $this->assertSession()->statusCodeEquals(200);
+
+ $locator = DOMAIN_SOURCE_FIELD;
+ $this->assertSession()->fieldNotExists($locator);
+
+ // Domain assignment.
+ $ids = ['example_com', 'one_example_com'];
+ $this->addDomainsToEntity('user', $editor2->id(), $ids, DOMAIN_ACCESS_FIELD);
+
+ $this->drupalGet('node/add/article');
+ $this->assertSession()->statusCodeEquals(200);
+
+ $this->assertSession()->fieldExists($locator);
+ }
+
}
diff --git a/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings-circular_dependency-2930391-7.patch b/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings-circular_dependency-2930391-7.patch
deleted file mode 100644
index 57ae8f93f..000000000
--- a/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings-circular_dependency-2930391-7.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-diff --git a/domain_site_settings.services.yml b/domain_site_settings.services.yml
-index 65e9113..6ebd87d 100644
---- a/domain_site_settings.services.yml
-+++ b/domain_site_settings.services.yml
-@@ -1,6 +1,6 @@
- services:
- domain_site_settings.overrider:
- class: \Drupal\domain_site_settings\Configuration\DomainConfigOverride
-- arguments: ['@domain.negotiator', '@config.factory']
-+ arguments: ['@config.factory']
- tags:
- - {name: config.factory.override, priority: 5}
-diff --git a/src/Configuration/DomainConfigOverride.php b/src/Configuration/DomainConfigOverride.php
-index b2571b4..506feef 100644
---- a/src/Configuration/DomainConfigOverride.php
-+++ b/src/Configuration/DomainConfigOverride.php
-@@ -16,13 +16,6 @@ use Drupal\Core\Config\ConfigFactoryInterface;
- */
- class DomainConfigOverride implements ConfigFactoryOverrideInterface {
-
-- /**
-- * The Domain negotiator.
-- *
-- * @var \Drupal\domain\DomainNegotiatorInterface
-- */
-- protected $negotiator;
--
- /**
- * The config factory.
- *
-@@ -33,16 +26,11 @@ class DomainConfigOverride implements ConfigFactoryOverrideInterface {
- /**
- * Constructs a DomainSourcePathProcessor object.
- *
-- * The domain loader.
-- * @param \Drupal\domain\DomainNegotiatorInterface $negotiator
-- * The domain negotiator.
- * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
- * The module handler service.
- */
- public function __construct(
-- DomainNegotiatorInterface $negotiator,
- ConfigFactoryInterface $config_factory) {
-- $this->negotiator = $negotiator;
- $this->configFactory = $config_factory;
- }
-
-@@ -59,7 +47,9 @@ class DomainConfigOverride implements ConfigFactoryOverrideInterface {
- public function loadOverrides($names) {
- $overrides = array();
- if (in_array('system.site', $names)) {
-- $domain = $this->negotiator->getActiveDomain();
-+ /* @var \Drupal\domain\DomainNegotiator $negotiator */
-+ $negotiator = \Drupal::service('domain.negotiator');
-+ $domain = $negotiator->getActiveDomain();
- if (!empty($domain)) {
- $domain_key = $domain->id();
- $configFactory = $this->configFactory->get('domain_site_settings.domainconfigsettings');
diff --git a/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.info.yml b/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.info.yml
index 634d764e2..cc1b1a98c 100644
--- a/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.info.yml
+++ b/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.info.yml
@@ -2,15 +2,15 @@ name: Domain Site Settings
type: module
description: 'Basic Site Setting for Domains.'
dependencies:
- - domain
- - domain_config
+ - domain:domain
+ - domain:domain_config
package: Domain
# core: 8.x
configure: domain_site_settings.list
-# Information added by Drupal.org packaging script on 2017-04-04
-version: '8.x-1.2'
+# Information added by Drupal.org packaging script on 2018-09-23
+version: '8.x-1.3'
core: '8.x'
project: 'domain_site_settings'
-datestamp: 1491339784
+datestamp: 1537684984
diff --git a/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.links.menu.yml b/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.links.menu.yml
index c3b1a52a2..80d81683b 100644
--- a/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.links.menu.yml
+++ b/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.links.menu.yml
@@ -4,4 +4,3 @@ domain_site_settings.menu_domain_list:
description: 'Change domains site name, email address, slogan, default front page, and error pages.'
parent: domain.admin
weight: 10
-
diff --git a/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.services.yml b/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.services.yml
index 6ebd87db9..65e9113fb 100644
--- a/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.services.yml
+++ b/sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.services.yml
@@ -1,6 +1,6 @@
services:
domain_site_settings.overrider:
class: \Drupal\domain_site_settings\Configuration\DomainConfigOverride
- arguments: ['@config.factory']
+ arguments: ['@domain.negotiator', '@config.factory']
tags:
- {name: config.factory.override, priority: 5}
diff --git a/sites/all/modules/contrib/admin/domain_site_settings/src/Configuration/DomainConfigOverride.php b/sites/all/modules/contrib/admin/domain_site_settings/src/Configuration/DomainConfigOverride.php
index 506feefb4..272e0527b 100644
--- a/sites/all/modules/contrib/admin/domain_site_settings/src/Configuration/DomainConfigOverride.php
+++ b/sites/all/modules/contrib/admin/domain_site_settings/src/Configuration/DomainConfigOverride.php
@@ -5,7 +5,6 @@ namespace Drupal\domain_site_settings\Configuration;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Config\ConfigFactoryOverrideInterface;
use Drupal\Core\Config\StorageInterface;
-use Drupal\domain\DomainLoaderInterface;
use Drupal\domain\DomainNegotiatorInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
@@ -16,6 +15,13 @@ use Drupal\Core\Config\ConfigFactoryInterface;
*/
class DomainConfigOverride implements ConfigFactoryOverrideInterface {
+ /**
+ * The Domain negotiator.
+ *
+ * @var \Drupal\domain\DomainNegotiatorInterface
+ */
+ protected $negotiator;
+
/**
* The config factory.
*
@@ -26,11 +32,15 @@ class DomainConfigOverride implements ConfigFactoryOverrideInterface {
/**
* Constructs a DomainSourcePathProcessor object.
*
+ * @param \Drupal\domain\DomainNegotiatorInterface $negotiator
+ * The domain negotiator.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The module handler service.
*/
public function __construct(
+ DomainNegotiatorInterface $negotiator,
ConfigFactoryInterface $config_factory) {
+ $this->negotiator = $negotiator;
$this->configFactory = $config_factory;
}
@@ -44,12 +54,10 @@ class DomainConfigOverride implements ConfigFactoryOverrideInterface {
* An array keyed by configuration name of override data. Override data
* contains a nested array structure of overrides.
*/
- public function loadOverrides($names) {
- $overrides = array();
+ public function loadOverrides($names = []) {
+ $overrides = [];
if (in_array('system.site', $names)) {
- /* @var \Drupal\domain\DomainNegotiator $negotiator */
- $negotiator = \Drupal::service('domain.negotiator');
- $domain = $negotiator->getActiveDomain();
+ $domain = $this->negotiator->getActiveDomain();
if (!empty($domain)) {
$domain_key = $domain->id();
$configFactory = $this->configFactory->get('domain_site_settings.domainconfigsettings');
@@ -60,6 +68,8 @@ class DomainConfigOverride implements ConfigFactoryOverrideInterface {
$site_403 = $configFactory->get($domain_key . '.site_403');
$site_404 = $configFactory->get($domain_key . '.site_404');
$site_front = $configFactory->get($domain_key . '.site_frontpage');
+ $front = ($site_front !== \NULL) ? $site_front : '/node';
+
// Create the new settings array to override the configuration.
$overrides['system.site'] = [
'name' => $site_name,
@@ -68,7 +78,8 @@ class DomainConfigOverride implements ConfigFactoryOverrideInterface {
'page' => [
'403' => $site_403,
'404' => $site_404,
- 'front' => ($site_front !== NULL) ? $site_front : '/node']
+ 'front' => $front,
+ ],
];
}
}
diff --git a/sites/all/modules/contrib/admin/domain_site_settings/src/Controller/DomainSiteSettingsController.php b/sites/all/modules/contrib/admin/domain_site_settings/src/Controller/DomainSiteSettingsController.php
index f7d5649fa..b5a3d512c 100644
--- a/sites/all/modules/contrib/admin/domain_site_settings/src/Controller/DomainSiteSettingsController.php
+++ b/sites/all/modules/contrib/admin/domain_site_settings/src/Controller/DomainSiteSettingsController.php
@@ -25,7 +25,7 @@ class DomainSiteSettingsController extends ControllerBase {
/**
* Construct function.
*
- * @param DomainLoader $domain_loader
+ * @param \Drupal\domain\DomainLoader $domain_loader
* Load the domain records.
*/
public function __construct(
@@ -37,7 +37,7 @@ class DomainSiteSettingsController extends ControllerBase {
/**
* Create function return static domain loader configuration.
*
- * @param ContainerInterface $container
+ * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* Load the ContainerInterface.
*
* @return \static
@@ -62,22 +62,22 @@ class DomainSiteSettingsController extends ControllerBase {
foreach ($domains as $domain) {
$row = [
$domain->label(),
- $domain->id(),
- Link::fromTextAndUrl($this->t('Edit'), Url::fromRoute('domain_site_settings.config_form', array('domain_id' => $domain->id()))),
+ $domain->getCanonical(),
+ Link::fromTextAndUrl($this->t('Edit'), Url::fromRoute('domain_site_settings.config_form', ['domain_id' => $domain->id()])),
];
$rows[] = $row;
}
// Build a render array which will be themed as a table.
- $build['pager_example'] = array(
+ $build['pager_example'] = [
'#rows' => $rows,
- '#header' => array(
+ '#header' => [
$this->t('Name'),
$this->t('Hostname'),
- $this->t('Edit Settings')
- ),
+ $this->t('Edit Settings'),
+ ],
'#type' => 'table',
'#empty' => $this->t('No domain record found.'),
- );
+ ];
return $build;
}
diff --git a/sites/all/modules/contrib/admin/domain_site_settings/src/Form/DomainConfigSettingsForm.php b/sites/all/modules/contrib/admin/domain_site_settings/src/Form/DomainConfigSettingsForm.php
index 97eedabc5..21b429035 100644
--- a/sites/all/modules/contrib/admin/domain_site_settings/src/Form/DomainConfigSettingsForm.php
+++ b/sites/all/modules/contrib/admin/domain_site_settings/src/Form/DomainConfigSettingsForm.php
@@ -98,67 +98,64 @@ class DomainConfigSettingsForm extends ConfigFormBase {
$site_mail = $config->get($domain_id . '.site_mail');
}
- $form['site_information'] = array(
+ $form['site_information'] = [
'#type' => 'details',
'#title' => $this->t('Site details'),
'#open' => TRUE,
- );
- $form['site_information']['site_name'] = array(
+ ];
+ $form['site_information']['site_name'] = [
'#type' => 'textfield',
'#title' => $this->t('Site name'),
'#default_value' => ($config->get($domain_id) != NULL) ? $config->get($domain_id . '.site_name') : $site_config->get('name'),
'#required' => TRUE,
- );
- $form['site_information']['site_slogan'] = array(
+ ];
+ $form['site_information']['site_slogan'] = [
'#type' => 'textfield',
'#title' => $this->t('Slogan'),
'#default_value' => ($config->get($domain_id) != NULL) ? $config->get($domain_id . '.site_slogan') : $site_config->get('slogan'),
'#description' => $this->t("How this is used depends on your site's theme."),
- );
- $form['site_information']['site_mail'] = array(
+ ];
+ $form['site_information']['site_mail'] = [
'#type' => 'email',
'#title' => $this->t('Email address'),
'#default_value' => $site_mail,
'#description' => $this->t("The From address in automated emails sent during registration and new password requests, and other notifications. (Use an address ending in your site's domain to help prevent this email being flagged as spam.)"),
'#required' => TRUE,
- );
-
- $form['front_page'] = array(
+ ];
+ $form['front_page'] = [
'#type' => 'details',
'#title' => $this->t('Front page'),
'#open' => TRUE,
- );
+ ];
$front_page = $site_config->get('page.front') != '/user/login' ? $this->aliasManager->getAliasByPath($site_config->get('page.front')) : '';
-
$front_page = ($config->get($domain_id) != NULL) ? $config->get($domain_id . '.site_frontpage') : $front_page;
-
- $form['front_page']['site_frontpage'] = array(
+ $form['front_page']['site_frontpage'] = [
'#type' => 'textfield',
'#title' => $this->t('Default front page'),
'#default_value' => $front_page,
'#size' => 40,
'#description' => $this->t('Optionally, specify a relative URL to display as the front page. Leave blank to display the default front page.'),
'#field_prefix' => $this->requestContext->getCompleteBaseUrl(),
- );
- $form['error_page'] = array(
+ ];
+ $form['error_page'] = [
'#type' => 'details',
'#title' => $this->t('Error pages'),
'#open' => TRUE,
- );
- $form['error_page']['site_403'] = array(
+ ];
+ $form['error_page']['site_403'] = [
'#type' => 'textfield',
'#title' => $this->t('Default 403 (access denied) page'),
'#default_value' => ($config->get($domain_id) !== NULL) ? $config->get($domain_id . '.site_403') : $site_config->get('page.403'),
'#size' => 40,
'#description' => $this->t('This page is displayed when the requested document is denied to the current user. Leave blank to display a generic "access denied" page.'),
- );
- $form['error_page']['site_404'] = array(
+ ];
+ $form['error_page']['site_404'] = [
'#type' => 'textfield',
'#title' => $this->t('Default 404 (not found) page'),
'#default_value' => ($config->get($domain_id) !== NULL) ? $config->get($domain_id . '.site_404') : $site_config->get('page.404'),
'#size' => 40,
'#description' => $this->t('This page is displayed when no other content matches the requested document. Leave blank to display a generic "page not found" page.'),
- );
+ ];
$form['domain_id'] = [
'#type' => 'hidden',
'#title' => $this->t('Domain ID'),
@@ -185,7 +182,7 @@ class DomainConfigSettingsForm extends ConfigFormBase {
$form_state->setErrorByName('site_frontpage', $this->t("The path '%path' has to start with a slash.", ['%path' => $form_state->getValue('site_frontpage')]));
}
if (!$this->pathValidator->isValid($form_state->getValue('site_frontpage'))) {
- $form_state->setErrorByName('site_frontpage', $this->t("The path '%path' is either invalid or you do not have access to it.", array('%path' => $form_state->getValue('site_frontpage'))));
+ $form_state->setErrorByName('site_frontpage', $this->t("The path '%path' is either invalid or you do not have access to it.", ['%path' => $form_state->getValue('site_frontpage')]));
}
// Get the normal paths of both error pages.
if (!$form_state->isValueEmpty('site_403')) {
@@ -202,11 +199,11 @@ class DomainConfigSettingsForm extends ConfigFormBase {
}
// Validate 403 error path.
if (!$form_state->isValueEmpty('site_403') && !$this->pathValidator->isValid($form_state->getValue('site_403'))) {
- $form_state->setErrorByName('site_403', $this->t("The path '%path' is either invalid or you do not have access to it.", array('%path' => $form_state->getValue('site_403'))));
+ $form_state->setErrorByName('site_403', $this->t("The path '%path' is either invalid or you do not have access to it.", ['%path' => $form_state->getValue('site_403')]));
}
// Validate 404 error path.
if (!$form_state->isValueEmpty('site_404') && !$this->pathValidator->isValid($form_state->getValue('site_404'))) {
- $form_state->setErrorByName('site_404', $this->t("The path '%path' is either invalid or you do not have access to it.", array('%path' => $form_state->getValue('site_404'))));
+ $form_state->setErrorByName('site_404', $this->t("The path '%path' is either invalid or you do not have access to it.", ['%path' => $form_state->getValue('site_404')]));
}
parent::validateForm($form, $form_state);
diff --git a/sites/all/modules/contrib/admin/matomo/README.txt b/sites/all/modules/contrib/admin/matomo/README.txt
index dec0ab4b8..9d5dd11a2 100644
--- a/sites/all/modules/contrib/admin/matomo/README.txt
+++ b/sites/all/modules/contrib/admin/matomo/README.txt
@@ -1,6 +1,6 @@
Module: Matomo Analytics
-Author: Alexander Hass
+Author: Alexander Hass
Description
@@ -46,7 +46,7 @@ user with 'Administer Matomo' permission.
Like the blocks visibility settings in Drupal core, there is a choice for
"Add if the following PHP code returns TRUE." Sample PHP snippets that can be
used in this textarea can be found on the handbook page "Overview-approach to
-block visibility" at http://drupal.org/node/64135.
+block visibility" at https://drupal.org/node/64135.
Custom variables
=================
@@ -65,7 +65,7 @@ Value: [current-user:matomo-role-ids]
Scope: Visitor
More details about custom variables can be found in the Matomo API documentation
-at http://matomo.org/docs/javascript-tracking/#toc-custom-variables.
+at https://matomo.org/docs/javascript-tracking/#toc-custom-variables.
Advanced Settings
@@ -80,7 +80,7 @@ file locally.
Known issues
============
-Drupal requirements (http://drupal.org/requirements) tell you to configure
+Drupal requirements (https://drupal.org/requirements) tell you to configure
PHP with "session.save_handler = user", but your Matomo installation may
not work with this configuration and gives you a server error 500.
diff --git a/sites/all/modules/contrib/admin/matomo/composer.json b/sites/all/modules/contrib/admin/matomo/composer.json
index c946a4fb7..8799b1bfe 100644
--- a/sites/all/modules/contrib/admin/matomo/composer.json
+++ b/sites/all/modules/contrib/admin/matomo/composer.json
@@ -15,8 +15,10 @@
],
"support": {
"issues": "https://www.drupal.org/project/issues/matomo",
- "source": "http://git.drupal.org/project/matomo.git"
+ "source": "https://git.drupal.org/project/matomo.git"
},
"license": "GPL-2.0+",
- "require": {}
+ "require": {
+ "drupal/core": "~8.5"
+ }
}
diff --git a/sites/all/modules/contrib/admin/matomo/matomo.info.yml b/sites/all/modules/contrib/admin/matomo/matomo.info.yml
index 3b94f898b..4bc2bc4aa 100644
--- a/sites/all/modules/contrib/admin/matomo/matomo.info.yml
+++ b/sites/all/modules/contrib/admin/matomo/matomo.info.yml
@@ -4,12 +4,14 @@ description: "Adds Matomo javascript tracking code to all your site's pages."
package: Statistics
# core: 8.x
configure: matomo.admin_settings_form
+dependencies:
+ - drupal:system (>= 8.5)
test_dependencies:
- php:php
- token:token
-# Information added by Drupal.org packaging script on 2018-07-13
-version: '8.x-1.7'
+# Information added by Drupal.org packaging script on 2019-02-08
+version: '8.x-1.9'
core: '8.x'
project: 'matomo'
-datestamp: 1531470224
+datestamp: 1549615102
diff --git a/sites/all/modules/contrib/admin/matomo/matomo.install b/sites/all/modules/contrib/admin/matomo/matomo.install
index 324242621..b3f5a0b61 100644
--- a/sites/all/modules/contrib/admin/matomo/matomo.install
+++ b/sites/all/modules/contrib/admin/matomo/matomo.install
@@ -17,7 +17,8 @@ function matomo_install() {
$role->grantPermission('opt-in or out of matomo tracking');
$success = $role->save();
if ($success) {
- drupal_set_message(t('Module %module granted %permission permission to authenticated users.', ['%module' => 'Matomo Analytics', '%permission' => t('Opt-in or out of tracking')]), 'status');
+ $messenger = \Drupal::messenger();
+ $messenger->addMessage(t('Module %module granted %permission permission to authenticated users.', ['%module' => 'Matomo Analytics', '%permission' => t('Opt-in or out of tracking')]), 'status');
}
}
diff --git a/sites/all/modules/contrib/admin/matomo/matomo.module b/sites/all/modules/contrib/admin/matomo/matomo.module
index 380b66b34..2c422ff4d 100644
--- a/sites/all/modules/contrib/admin/matomo/matomo.module
+++ b/sites/all/modules/contrib/admin/matomo/matomo.module
@@ -7,7 +7,7 @@
* Adds the required Javascript to all your Drupal pages to allow tracking by
* the Matomo statistics package.
*
- * @author: Alexander Hass
+ * @author: Alexander Hass
*/
use Drupal\Component\Serialization\Json;
@@ -19,22 +19,18 @@ use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Site\Settings;
use Drupal\Core\Url;
+use Drupal\matomo\MatomoInterface;
use Drupal\node\NodeInterface;
use GuzzleHttp\Exception\RequestException;
use Drupal\matomo\Component\Render\MatomoJavaScriptSnippet;
-/**
- * Define the default file extension list that should be tracked as download.
- */
-define('MATOMO_TRACKFILES_EXTENSIONS', '7z|aac|arc|arj|asf|asx|avi|bin|csv|doc(x|m)?|dot(x|m)?|exe|flv|gif|gz|gzip|hqx|jar|jpe?g|js|mp(2|3|4|e?g)|mov(ie)?|msi|msp|pdf|phps|png|ppt(x|m)?|pot(x|m)?|pps(x|m)?|ppam|sld(x|m)?|thmx|qtm?|ra(m|r)?|sea|sit|tar|tgz|torrent|txt|wav|wma|wmv|wpd|xls(x|m|b)?|xlt(x|m)|xlam|xml|z|zip');
-
/**
* Implements hook_help().
*/
function matomo_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'matomo.admin_settings_form':
- return t('Matomo Analytics is an open source (GPL license) web analytics software. It gives interesting reports on your website visitors, your popular pages, the search engines keywords they used, the language they speak... and so much more. Matomo aims to be an open source alternative to Google Analytics.', [':pk_url' => 'http://www.matomo.org/']);
+ return t('Matomo Analytics is an open source (GPL license) web analytics software. It gives interesting reports on your website visitors, your popular pages, the search engines keywords they used, the language they speak... and so much more. Matomo aims to be an open source alternative to Google Analytics.', [':pk_url' => 'https://www.matomo.org/']);
}
}
@@ -114,7 +110,7 @@ function matomo_page_attachments(array &$page) {
'error' => t('Error message'),
];
- foreach (drupal_get_messages(NULL, FALSE) as $type => $messages) {
+ foreach (\Drupal::messenger()->all(NULL, FALSE) as $type => $messages) {
// Track only the selected message types.
if (in_array($type, $message_types)) {
foreach ($messages as $message) {
@@ -198,7 +194,7 @@ function matomo_page_attachments(array &$page) {
$codesnippet_after = $config->get('codesnippet.after');
// Build tracker code.
- // @see http://matomo.org/docs/javascript-tracking/#toc-asynchronous-tracking
+ // @see https://matomo.org/docs/javascript-tracking/#toc-asynchronous-tracking
$script = 'var _paq = _paq || [];';
$script .= '(function(){';
$script .= 'var u=(("https:" == document.location.protocol) ? "' . UrlHelper::filterBadProtocol($url_https) . '" : "' . UrlHelper::filterBadProtocol($url_http) . '");';
@@ -220,7 +216,7 @@ function matomo_page_attachments(array &$page) {
}
// Custom file download extensions.
- if ($config->get('track.files') && !($config->get('track.files_extensions') == MATOMO_TRACKFILES_EXTENSIONS)) {
+ if ($config->get('track.files') && !($config->get('track.files_extensions') == MatomoInterface::MATOMO_TRACKFILES_EXTENSIONS)) {
$script .= '_paq.push(["setDownloadExtensions", ' . Json::encode($config->get('track.files_extensions')) . ']);';
}
@@ -279,7 +275,7 @@ function matomo_page_attachments(array &$page) {
];
// Disable the download & outlink tracking for specific CSS classes.
// Custom code snippets with 'setIgnoreClasses' will override the value.
- // @see http://developer.matomo.org/api-reference/tracking-javascript#disable-the-download-amp-outlink-tracking-for-specific-css-classes
+ // @see https://developer.matomo.org/api-reference/tracking-javascript#disable-the-download-amp-outlink-tracking-for-specific-css-classes
$script .= '_paq.push(["setIgnoreClasses", ' . Json::encode($ignore_classes) . ']);';
// Enable download & outlink link tracking.
@@ -441,11 +437,12 @@ function matomo_user_profile_form_submit($form, FormStateInterface $form_state)
*/
function matomo_cron() {
$config = \Drupal::config('matomo.settings');
+ $request_time = \Drupal::time()->getRequestTime();
// Regenerate the piwik.js every day.
- if (REQUEST_TIME - \Drupal::state()->get('matomo.last_cache') >= 86400 && $config->get('cache')) {
+ if ($request_time - \Drupal::state()->get('matomo.last_cache') >= 86400 && $config->get('cache')) {
_matomo_cache($config->get('url_http') . 'piwik.js', TRUE);
- \Drupal::state()->set('matomo.last_cache', REQUEST_TIME);
+ \Drupal::state()->set('matomo.last_cache', $request_time);
}
}
diff --git a/sites/all/modules/contrib/admin/matomo/migration_templates/d6_matomo_settings.yml b/sites/all/modules/contrib/admin/matomo/migrations/d6_matomo_settings.yml
similarity index 100%
rename from sites/all/modules/contrib/admin/matomo/migration_templates/d6_matomo_settings.yml
rename to sites/all/modules/contrib/admin/matomo/migrations/d6_matomo_settings.yml
diff --git a/sites/all/modules/contrib/admin/matomo/migration_templates/d6_matomo_user_settings.yml b/sites/all/modules/contrib/admin/matomo/migrations/d6_matomo_user_settings.yml
similarity index 100%
rename from sites/all/modules/contrib/admin/matomo/migration_templates/d6_matomo_user_settings.yml
rename to sites/all/modules/contrib/admin/matomo/migrations/d6_matomo_user_settings.yml
diff --git a/sites/all/modules/contrib/admin/matomo/migration_templates/d7_matomo_settings.yml b/sites/all/modules/contrib/admin/matomo/migrations/d7_matomo_settings.yml
similarity index 100%
rename from sites/all/modules/contrib/admin/matomo/migration_templates/d7_matomo_settings.yml
rename to sites/all/modules/contrib/admin/matomo/migrations/d7_matomo_settings.yml
diff --git a/sites/all/modules/contrib/admin/matomo/migration_templates/d7_matomo_user_settings.yml b/sites/all/modules/contrib/admin/matomo/migrations/d7_matomo_user_settings.yml
similarity index 100%
rename from sites/all/modules/contrib/admin/matomo/migration_templates/d7_matomo_user_settings.yml
rename to sites/all/modules/contrib/admin/matomo/migrations/d7_matomo_user_settings.yml
diff --git a/sites/all/modules/contrib/admin/matomo/src/Form/MatomoAdminSettingsForm.php b/sites/all/modules/contrib/admin/matomo/src/Form/MatomoAdminSettingsForm.php
index a7a85e8ad..bd6e68722 100644
--- a/sites/all/modules/contrib/admin/matomo/src/Form/MatomoAdminSettingsForm.php
+++ b/sites/all/modules/contrib/admin/matomo/src/Form/MatomoAdminSettingsForm.php
@@ -4,15 +4,37 @@ namespace Drupal\matomo\Form;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\UrlHelper;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Extension\ModuleHandler;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\matomo\MatomoInterface;
use GuzzleHttp\Exception\RequestException;
+use GuzzleHttp\Client;
+use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Configure Matomo settings for this site.
*/
class MatomoAdminSettingsForm extends ConfigFormBase {
+ protected $moduleHandler;
+
+ protected $currentUser;
+
+ protected $httpClient;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(ConfigFactoryInterface $config_factory, AccountInterface $currentUser, ModuleHandler $moduleHandler, Client $httpClient) {
+ parent::__construct($config_factory);
+ $this->currentUser = $currentUser;
+ $this->moduleHandler = $moduleHandler;
+ $this->httpClient = $httpClient;
+ }
+
/**
* {@inheritdoc}
*/
@@ -117,7 +139,7 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
];
// Page specific visibility configurations.
- $account = \Drupal::currentUser();
+ $account = $this->currentUser;
$php_access = $account->hasPermission('use php for matomo tracking visibility');
$visibility_request_path_pages = $config->get('visibility.request_path_pages');
@@ -140,7 +162,7 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
];
$description = $this->t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", ['%blog' => '/blog', '%blog-wildcard' => '/blog/*', '%front' => '']);
- if (\Drupal::moduleHandler()->moduleExists('php') && $php_access) {
+ if ($this->moduleHandler->moduleExists('php') && $php_access) {
$options[] = $this->t('Pages on which this PHP code returns TRUE (experts only)');
$title = $this->t('Pages or PHP code');
$description .= ' ' . $this->t('If the PHP option is chosen, enter PHP code between %php. Note that executing incorrect PHP code can break your Drupal site.', ['%php' => '']);
@@ -207,13 +229,13 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
1 => $this->t('Tracking on by default, users with %permission permission can opt out', $t_permission),
2 => $this->t('Tracking off by default, users with %permission permission can opt in', $t_permission),
],
- '#default_value' => !empty($visibility_user_account_mode) ? $visibility_user_account_mode : 1,
+ '#default_value' => !empty($visibility_user_account_mode) ? $visibility_user_account_mode : 0,
];
$form['tracking']['user_visibility_settings']['matomo_trackuserid'] = [
'#type' => 'checkbox',
'#title' => $this->t('Track User ID'),
'#default_value' => $config->get('track.userid'),
- '#description' => $this->t('User ID enables the analysis of groups of sessions, across devices, using a unique, persistent, and non-personally identifiable ID string representing a user. Learn more about the benefits of using User ID.', [':url' => 'http://matomo.org/docs/user-id/']),
+ '#description' => $this->t('User ID enables the analysis of groups of sessions, across devices, using a unique, persistent, and non-personally identifiable ID string representing a user. Learn more about the benefits of using User ID.', [':url' => 'https://matomo.org/docs/user-id/']),
];
// Link specific configurations.
@@ -237,7 +259,7 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
'#title_display' => 'invisible',
'#type' => 'textfield',
'#default_value' => $config->get('track.files_extensions'),
- '#description' => $this->t('A file extension list separated by the | character that will be tracked as download when clicked. Regular expressions are supported. For example: @extensions', ['@extensions' => MATOMO_TRACKFILES_EXTENSIONS]),
+ '#description' => $this->t('A file extension list separated by the | character that will be tracked as download when clicked. Regular expressions are supported. For example: @extensions', ['@extensions' => MatomoInterface::MATOMO_TRACKFILES_EXTENSIONS]),
'#maxlength' => 500,
'#states' => [
'enabled' => [
@@ -251,7 +273,7 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
];
$colorbox_dependencies = '
';
$form['tracking']['search']['matomo_site_search'] = [
@@ -296,7 +318,7 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
'#title' => $this->t('Track internal search'),
'#description' => $this->t('If checked, internal search keywords are tracked.') . $site_search_dependencies,
'#default_value' => $config->get('track.site_search'),
- '#disabled' => (\Drupal::moduleHandler()->moduleExists('search') ? FALSE : TRUE),
+ '#disabled' => ($this->moduleHandler->moduleExists('search') ? FALSE : TRUE),
];
// Privacy specific configurations.
@@ -308,7 +330,7 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
$form['tracking']['privacy']['matomo_privacy_donottrack'] = [
'#type' => 'checkbox',
'#title' => $this->t('Universal web tracking opt-out'),
- '#description' => $this->t('If enabled and your Matomo server receives the Do-Not-Track header from the client browser, the Matomo server will not track the user. Compliance with Do Not Track could be purely voluntary, enforced by industry self-regulation, or mandated by state or federal law. Please accept your visitors privacy. If they have opt-out from tracking and advertising, you should accept their personal decision.'),
+ '#description' => $this->t('If enabled and your Matomo server receives the Do-Not-Track header from the client browser, the Matomo server will not track the user. Compliance with Do Not Track could be purely voluntary, enforced by industry self-regulation, or mandated by state or federal law. Please accept your visitors privacy. If they have opt-out from tracking and advertising, you should accept their personal decision.', [':donottrack' => 'https://www.eff.org/issues/do-not-track']),
'#default_value' => $config->get('privacy.donottrack'),
];
@@ -334,7 +356,7 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
// Custom variables.
$form['matomo_custom_var'] = [
- '#description' => $this->t('You can add Matomos Custom Variables here. These will be added to every page that Matomo tracking code appears on. Custom variable names and values are limited to 200 characters in length. Keep the names and values as short as possible and expect long values to get trimmed. You may use tokens in custom variable names and values. Global and user tokens are always available; on node pages, node tokens are also available.', [':custom_var_documentation' => 'http://matomo.org/docs/custom-variables/']),
+ '#description' => $this->t('You can add Matomos Custom Variables here. These will be added to every page that Matomo tracking code appears on. Custom variable names and values are limited to 200 characters in length. Keep the names and values as short as possible and expect long values to get trimmed. You may use tokens in custom variable names and values. Global and user tokens are always available; on node pages, node tokens are also available.', [':custom_var_documentation' => 'https://matomo.org/docs/custom-variables/']),
'#title' => $this->t('Custom variables'),
'#tree' => TRUE,
'#type' => 'details',
@@ -382,7 +404,7 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
'#element_validate' => [[get_class($this), 'tokenElementValidate']],
'#token_types' => ['node'],
];
- if (\Drupal::moduleHandler()->moduleExists('token')) {
+ if ($this->moduleHandler->moduleExists('token')) {
$form['matomo_custom_var']['slots'][$i]['value']['#element_validate'][] = 'token_element_validate';
}
$form['matomo_custom_var']['slots'][$i]['scope'] = [
@@ -402,7 +424,7 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
'#type' => 'item',
'#description' => $this->t("You can supplement Matomos' basic IP address tracking of visitors by segmenting users based on custom variables. Make sure you will not associate (or permit any third party to associate) any data gathered from your websites (or such third parties' websites) with any personally identifying information from any source as part of your use (or such third parties' use) of the Matomo' service."),
];
- if (\Drupal::moduleHandler()->moduleExists('token')) {
+ if ($this->moduleHandler->moduleExists('token')) {
$form['matomo_custom_var']['matomo_custom_var_token_tree'] = [
'#theme' => 'token_tree_link',
'#token_types' => ['node'],
@@ -424,7 +446,7 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
];
// Allow for tracking of the originating node when viewing translation sets.
- if (\Drupal::moduleHandler()->moduleExists('content_translation')) {
+ if ($this->moduleHandler->moduleExists('content_translation')) {
$form['advanced']['matomo_translation_set'] = [
'#type' => 'checkbox',
'#title' => $this->t('Track translation sets as one unit'),
@@ -439,7 +461,7 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
'#type' => 'details',
'#title' => $this->t('Custom JavaScript code'),
'#open' => TRUE,
- '#description' => $this->t('You can add custom Matomo code snippets here. These will be added to every page that Matomo appears on. Do not include the <script> tags, and always end your code with a semicolon (;).', [':snippets' => 'http://matomo.org/docs/javascript-tracking/']),
+ '#description' => $this->t('You can add custom Matomo code snippets here. These will be added to every page that Matomo appears on. Do not include the <script> tags, and always end your code with a semicolon (;).', [':snippets' => 'https://matomo.org/docs/javascript-tracking/']),
];
$form['advanced']['codesnippet']['matomo_codesnippet_before'] = [
'#type' => 'textarea',
@@ -496,7 +518,7 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
$url = $form_state->getValue('matomo_url_http') . 'piwik.php';
try {
- $result = \Drupal::httpClient()->get($url);
+ $result = $this->httpClient->get($url);
if ($result->getStatusCode() != 200 && $form_state->getValue('matomo_url_skiperror') == FALSE) {
$form_state->setErrorByName('matomo_url_http', $this->t('The validation of "@url" failed with error "@error" (HTTP code @code).', [
'@url' => UrlHelper::filterBadProtocol($url),
@@ -517,7 +539,7 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
if (!empty($matomo_url_https)) {
$url = $matomo_url_https . 'piwik.php';
try {
- $result = \Drupal::httpClient()->get($url);
+ $result = $this->httpClient->get($url);
if ($result->getStatusCode() != 200 && $form_state->getValue('matomo_url_skiperror') == FALSE) {
$form_state->setErrorByName('matomo_url_https', $this->t('The validation of "@url" failed with error "@error" (HTTP code @code).', [
'@url' => UrlHelper::filterBadProtocol($url),
@@ -714,4 +736,17 @@ class MatomoAdminSettingsForm extends ConfigFormBase {
return preg_match('/' . implode('|', array_map('preg_quote', $token_blacklist)) . '/i', $token_string);
}
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container) {
+ return new static(
+ // Load the service required to construct this class.
+ $container->get('config.factory'),
+ $container->get('current_user'),
+ $container->get('module_handler'),
+ $container->get('http_client')
+ );
+ }
+
}
diff --git a/sites/all/modules/contrib/admin/matomo/src/MatomoInterface.php b/sites/all/modules/contrib/admin/matomo/src/MatomoInterface.php
new file mode 100644
index 000000000..db12818d6
--- /dev/null
+++ b/sites/all/modules/contrib/admin/matomo/src/MatomoInterface.php
@@ -0,0 +1,15 @@
+randomMachineName(8);
// Create a node to search for.
- // Create a node.
$edit = [];
$edit['title[0][value]'] = 'This is a test title';
$edit['body[0][value]'] = 'This test content contains ' . $search['keys'] . ' string.';
diff --git a/sites/all/modules/contrib/admin/matomo/src/Tests/MatomoStatusMessagesTest.php b/sites/all/modules/contrib/admin/matomo/src/Tests/MatomoStatusMessagesTest.php
index bf3582f0c..2d4f0aa02 100644
--- a/sites/all/modules/contrib/admin/matomo/src/Tests/MatomoStatusMessagesTest.php
+++ b/sites/all/modules/contrib/admin/matomo/src/Tests/MatomoStatusMessagesTest.php
@@ -57,7 +57,11 @@ class MatomoStatusMessagesTest extends WebTestBase {
$this->assertRaw('_paq.push(["trackEvent", "Messages", "Error message", "Example error message with html tags and link."]);', '[testMatomoStatusMessages]: HTML has been stripped successful from Example error message with html tags and link.');
// Enable logging of status, warnings and errors.
- $this->config('matomo.settings')->set('track.messages', ['status' => 'status', 'warning' => 'warning', 'error' => 'error'])->save();
+ $this->config('matomo.settings')->set('track.messages', [
+ 'status' => 'status',
+ 'warning' => 'warning',
+ 'error' => 'error',
+ ])->save();
$this->drupalGet('matomo-test/drupal-messenger-add-message');
$this->assertRaw('_paq.push(["trackEvent", "Messages", "Status message", "Example status message."]);', '[testMatomoStatusMessages]: Example status message is enabled for tracking.');
diff --git a/sites/all/modules/contrib/admin/matomo/tests/modules/matomo_test/matomo_test.info.yml b/sites/all/modules/contrib/admin/matomo/tests/modules/matomo_test/matomo_test.info.yml
index 5abee1009..77399b4bd 100644
--- a/sites/all/modules/contrib/admin/matomo/tests/modules/matomo_test/matomo_test.info.yml
+++ b/sites/all/modules/contrib/admin/matomo/tests/modules/matomo_test/matomo_test.info.yml
@@ -4,8 +4,8 @@ description: 'Support module for Matomo testing.'
package: Testing
# core: 8.x
-# Information added by Drupal.org packaging script on 2018-07-13
-version: '8.x-1.7'
+# Information added by Drupal.org packaging script on 2019-02-08
+version: '8.x-1.9'
core: '8.x'
project: 'matomo'
-datestamp: 1531470224
+datestamp: 1549615102
diff --git a/sites/all/modules/contrib/admin/matomo/tests/modules/matomo_test/src/Controller/MatomoTestController.php b/sites/all/modules/contrib/admin/matomo/tests/modules/matomo_test/src/Controller/MatomoTestController.php
index 4a0e8801d..a37b78342 100644
--- a/sites/all/modules/contrib/admin/matomo/tests/modules/matomo_test/src/Controller/MatomoTestController.php
+++ b/sites/all/modules/contrib/admin/matomo/tests/modules/matomo_test/src/Controller/MatomoTestController.php
@@ -17,10 +17,10 @@ class MatomoTestController extends ControllerBase {
*/
public function drupalAddMessageTest() {
// Set some messages.
- drupal_set_message($this->t('Example status message.'), 'status');
- drupal_set_message($this->t('Example warning message.'), 'warning');
- drupal_set_message($this->t('Example error message.'), 'error');
- drupal_set_message($this->t('Example error message with html tags and link.'), 'error');
+ $this->messenger()->addMessage($this->t('Example status message.'), 'status');
+ $this->messenger()->addMessage($this->t('Example warning message.'), 'warning');
+ $this->messenger()->addMessage($this->t('Example error message.'), 'error');
+ $this->messenger()->addMessage($this->t('Example error message with html tags and link.'), 'error');
return [];
}
diff --git a/sites/all/modules/contrib/admin/path_alias_xt/path_alias_xt.info.yml b/sites/all/modules/contrib/admin/path_alias_xt/path_alias_xt.info.yml
index 24feddf9d..51fca7b7e 100644
--- a/sites/all/modules/contrib/admin/path_alias_xt/path_alias_xt.info.yml
+++ b/sites/all/modules/contrib/admin/path_alias_xt/path_alias_xt.info.yml
@@ -1,13 +1,16 @@
name: Extended Path Aliases
-type: module
description: 'Automatically extend path aliases to include tabs, like about-us/edit for node/123/edit. Allow these aliases to be entered in page specification wild-cards, about-us*, e.g for block visibility.'
-# core: 8.x
-configure: path_alias_xt.settings_form
-dependencies:
- - path
-# Information added by Drupal.org packaging script on 2017-07-14
+type: module
+# core: 8.x
+
+dependencies:
+ - drupal:path
+
+configure: path_alias_xt.settings_form
+
+# Information added by Drupal.org packaging script on 2019-01-30
version: '8.x-1.x-dev'
core: '8.x'
project: 'path_alias_xt'
-datestamp: 1500044946
+datestamp: 1548876484
diff --git a/sites/all/modules/contrib/admin/path_alias_xt/src/PathAliasXtProcessorAlias.php b/sites/all/modules/contrib/admin/path_alias_xt/src/PathAliasXtProcessorAlias.php
index cf1ea4c39..2d263a65f 100644
--- a/sites/all/modules/contrib/admin/path_alias_xt/src/PathAliasXtProcessorAlias.php
+++ b/sites/all/modules/contrib/admin/path_alias_xt/src/PathAliasXtProcessorAlias.php
@@ -57,7 +57,7 @@ class PathAliasXtProcessorAlias extends PathProcessorAlias {
// Validate the path.
// Injecting the service threw ServiceCircularReferenceException.
- if (\Drupal::service('path.validator')->isValid($return_path)) {
+ if (\Drupal::service('path.validator')->getUrlIfValidWithoutAccessCheck($return_path)) {
return $return_path;
}
}
diff --git a/sites/all/modules/contrib/admin/redirect/README.txt b/sites/all/modules/contrib/admin/redirect/README.txt
index 3ea2f179a..5ae8276ab 100644
--- a/sites/all/modules/contrib/admin/redirect/README.txt
+++ b/sites/all/modules/contrib/admin/redirect/README.txt
@@ -1,3 +1,61 @@
+CONTENTS OF THIS FILE
+---------------------
-This is the new module home for a unified redirection API (also replaces
+ * Introduction
+ * Requirements
+ * Installation
+ * Configuration
+ * Maintainers
+
+
+INTRODUCTION
+------------
+
+The Redirect module provides a unified redirection API (also replaces
path_redirect and globalredirect).
+
+
+ * For a full description of the module visit:
+ https://www.drupal.org/project/redirect
+
+ * To submit bug reports and feature suggestions, or to track changes visit:
+ https://www.drupal.org/project/issues/redirect
+
+
+REQUIREMENTS
+------------
+
+This module requires no modules outside of Drupal core.
+
+
+INSTALLATION
+------------
+
+ * Install the Redirect module as you would normally install a contributed
+ Drupal module. Visit https://www.drupal.org/node/1897420 for further
+ information.
+
+
+CONFIGURATION
+-------------
+
+ 1. Navigate to Administration > Extend and enable the module.
+ 2. Navigate to Administration > Configuration > Search and Metadata > URL
+ redirects for configuration.
+ 3. Select "Add redirect" and in the "Path" field add the old path.
+ 4. In the "To" field, start typing the title of a piece of content to select
+ it. You can also enter an internal path such as /node/add or an external
+ URL such as http://example.com. Enter to link to the front page.
+ 5. Select the Redirect status: 300 Multiple Choices, 301 Moved Permanently,
+ 302 Found, 303 See Other, 304 Not Modified, 305 Use Proxy, or 307
+ Temporary Redirect. Save.
+ 6. Once a redirect has been added, it will be listed in the URL Redirects
+ vertical tab group on the content's edit page.
+
+
+MAINTAINERS
+-----------
+
+Supporting organization for 8.x-1.x port:
+
+ * MD Systems - https://www.drupal.org/md-systems
diff --git a/sites/all/modules/contrib/admin/redirect/config/install/views.view.redirect.yml b/sites/all/modules/contrib/admin/redirect/config/install/views.view.redirect.yml
index 42555ccc3..6a1c65f55 100644
--- a/sites/all/modules/contrib/admin/redirect/config/install/views.view.redirect.yml
+++ b/sites/all/modules/contrib/admin/redirect/config/install/views.view.redirect.yml
@@ -38,7 +38,7 @@ display:
exposed_form:
type: basic
options:
- submit_button: Apply
+ submit_button: Filter
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
diff --git a/sites/all/modules/contrib/admin/redirect/modules/redirect_404/redirect_404.info.yml b/sites/all/modules/contrib/admin/redirect/modules/redirect_404/redirect_404.info.yml
index b1b96997b..1fbcea416 100644
--- a/sites/all/modules/contrib/admin/redirect/modules/redirect_404/redirect_404.info.yml
+++ b/sites/all/modules/contrib/admin/redirect/modules/redirect_404/redirect_404.info.yml
@@ -7,8 +7,8 @@ dependencies:
- redirect
- views
-# Information added by Drupal.org packaging script on 2018-05-04
-version: '8.x-1.2'
+# Information added by Drupal.org packaging script on 2018-10-16
+version: '8.x-1.3'
core: '8.x'
project: 'redirect'
-datestamp: 1525419807
+datestamp: 1539682690
diff --git a/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/EventSubscriber/Redirect404Subscriber.php b/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/EventSubscriber/Redirect404Subscriber.php
index 7a54e86db..f7cd1416a 100644
--- a/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/EventSubscriber/Redirect404Subscriber.php
+++ b/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/EventSubscriber/Redirect404Subscriber.php
@@ -2,7 +2,6 @@
namespace Drupal\redirect_404\EventSubscriber;
-use Drupal\Component\Utility\Unicode;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Path\PathMatcherInterface;
@@ -106,11 +105,11 @@ class Redirect404Subscriber implements EventSubscriberInterface {
$path = $this->currentPath->getPath();
// Ignore paths specified in the redirect settings.
- if ($pages = Unicode::strtolower($this->config->get('pages'))) {
+ if ($pages = mb_strtolower($this->config->get('pages'))) {
// Do not trim a trailing slash if that is the complete path.
$path_to_match = $path === '/' ? $path : rtrim($path, '/');
- if ($this->pathMatcher->matchPath(Unicode::strtolower($path_to_match), $pages)) {
+ if ($this->pathMatcher->matchPath(mb_strtolower($path_to_match), $pages)) {
return;
}
}
diff --git a/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/SqlRedirectNotFoundStorage.php b/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/SqlRedirectNotFoundStorage.php
index 8b425e9ba..98003ebae 100644
--- a/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/SqlRedirectNotFoundStorage.php
+++ b/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/SqlRedirectNotFoundStorage.php
@@ -51,7 +51,7 @@ class SqlRedirectNotFoundStorage implements RedirectNotFoundStorageInterface {
* {@inheritdoc}
*/
public function logRequest($path, $langcode) {
- if (Unicode::strlen($path) > static::MAX_PATH_LENGTH) {
+ if (mb_strlen($path) > static::MAX_PATH_LENGTH) {
// Don't attempt to log paths that would result in an exception. There is
// no point in logging truncated paths, as they cannot be used to build a
// new redirect.
diff --git a/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/Tests/Fix404RedirectUILanguageTest.php b/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/Tests/Fix404RedirectUILanguageTest.php
index c7657447c..89a14d2dc 100644
--- a/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/Tests/Fix404RedirectUILanguageTest.php
+++ b/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/Tests/Fix404RedirectUILanguageTest.php
@@ -2,6 +2,7 @@
namespace Drupal\redirect_404\Tests;
+use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;
use Drupal\language\Entity\ConfigurableLanguage;
@@ -88,14 +89,14 @@ class Fix404RedirectUILanguageTest extends Redirect404TestBase {
// Check if we generate correct Add redirect url and if the form is
// pre-filled.
$destination = Url::fromRoute('redirect_404.fix_404')->getInternalPath();
- $options = [
- 'query' => [
- 'source' => 'testing',
- 'language' => 'fr',
- 'destination' => $destination,
- ]
+ $expected_query = [
+ 'destination' => $destination,
+ 'language' => 'fr',
+ 'source' => 'testing',
];
- $this->assertUrl('admin/config/search/redirect/add', $options);
+ $parsed_url = UrlHelper::parse($this->getUrl());
+ $this->assertEqual(Url::fromRoute('redirect.add')->setAbsolute()->toString(), $parsed_url['path']);
+ $this->assertEqual($expected_query, $parsed_url['query']);
$this->assertFieldByName('redirect_source[0][path]', 'testing');
$this->assertOptionSelected('edit-language-0-value', 'fr');
// Save the redirect.
@@ -177,14 +178,14 @@ class Fix404RedirectUILanguageTest extends Redirect404TestBase {
// Assign a redirect to 'testing1'.
$this->clickLink('Add redirect');
- $options = [
- 'query' => [
- 'source' => 'testing1',
- 'language' => 'en',
- 'destination' => $destination,
- ]
+ $expected_query = [
+ 'destination' => $destination,
+ 'language' => 'en',
+ 'source' => 'testing1',
];
- $this->assertUrl('admin/config/search/redirect/add', $options);
+ $parsed_url = UrlHelper::parse($this->getUrl());
+ $this->assertEqual(Url::fromRoute('redirect.add')->setAbsolute()->toString(), $parsed_url['path']);
+ $this->assertEqual($expected_query, $parsed_url['query']);
$this->assertFieldByName('redirect_source[0][path]', 'testing1');
$this->assertOptionSelected('edit-language-0-value', 'en');
$edit = ['redirect_redirect[0][uri]' => '/node'];
diff --git a/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/Tests/Fix404RedirectUITest.php b/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/Tests/Fix404RedirectUITest.php
index 44b664459..088cbba47 100644
--- a/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/Tests/Fix404RedirectUITest.php
+++ b/sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/Tests/Fix404RedirectUITest.php
@@ -2,6 +2,7 @@
namespace Drupal\redirect_404\Tests;
+use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Url;
/**
@@ -26,14 +27,14 @@ class Fix404RedirectUITest extends Redirect404TestBase {
// Check if we generate correct Add redirect url and if the form is
// pre-filled.
$destination = Url::fromRoute('redirect_404.fix_404')->getInternalPath();
- $options = [
- 'query' => [
- 'source' => 'non-existing0',
- 'language' => 'en',
- 'destination' => $destination,
- ]
+ $expected_query = [
+ 'destination' => $destination,
+ 'language' => 'en',
+ 'source' => 'non-existing0',
];
- $this->assertUrl('admin/config/search/redirect/add', $options);
+ $parsed_url = UrlHelper::parse($this->getUrl());
+ $this->assertEqual(Url::fromRoute('redirect.add')->setAbsolute()->toString(), $parsed_url['path']);
+ $this->assertEqual($expected_query, $parsed_url['query']);
$this->assertFieldByName('redirect_source[0][path]', 'non-existing0');
// Save the redirect.
$edit = ['redirect_redirect[0][uri]' => '/node'];
@@ -97,14 +98,14 @@ class Fix404RedirectUITest extends Redirect404TestBase {
// Assign a redirect to 'non-existing2'.
$this->clickLink('Add redirect');
- $options = [
- 'query' => [
- 'source' => 'non-existing2',
- 'language' => 'en',
- 'destination' => $destination,
- ]
+ $expected_query = [
+ 'source' => 'non-existing2',
+ 'language' => 'en',
+ 'destination' => $destination,
];
- $this->assertUrl('admin/config/search/redirect/add', $options);
+ $parsed_url = UrlHelper::parse($this->getUrl());
+ $this->assertEqual(Url::fromRoute('redirect.add')->setAbsolute()->toString(), $parsed_url['path']);
+ $this->assertEqual($expected_query, $parsed_url['query']);
$this->assertFieldByName('redirect_source[0][path]', 'non-existing2');
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertUrl('admin/config/search/redirect/404');
diff --git a/sites/all/modules/contrib/admin/redirect/modules/redirect_domain/redirect_domain.info.yml b/sites/all/modules/contrib/admin/redirect/modules/redirect_domain/redirect_domain.info.yml
index a9c7ce006..aeb66d453 100644
--- a/sites/all/modules/contrib/admin/redirect/modules/redirect_domain/redirect_domain.info.yml
+++ b/sites/all/modules/contrib/admin/redirect/modules/redirect_domain/redirect_domain.info.yml
@@ -6,8 +6,8 @@ description: 'Allows users to redirect between domains.'
dependencies:
- redirect
-# Information added by Drupal.org packaging script on 2018-05-04
-version: '8.x-1.2'
+# Information added by Drupal.org packaging script on 2018-10-16
+version: '8.x-1.3'
core: '8.x'
project: 'redirect'
-datestamp: 1525419807
+datestamp: 1539682690
diff --git a/sites/all/modules/contrib/admin/redirect/modules/redirect_domain/src/Form/RedirectDomainForm.php b/sites/all/modules/contrib/admin/redirect/modules/redirect_domain/src/Form/RedirectDomainForm.php
index ec7b20f69..1bf5b9a87 100644
--- a/sites/all/modules/contrib/admin/redirect/modules/redirect_domain/src/Form/RedirectDomainForm.php
+++ b/sites/all/modules/contrib/admin/redirect/modules/redirect_domain/src/Form/RedirectDomainForm.php
@@ -133,7 +133,7 @@ class RedirectDomainForm extends ConfigFormBase {
if ($redirects = $form_state->getValue('redirects')) {
foreach ($redirects as $redirect) {
if (strpos($redirect['from'], '://') !== FALSE) {
- $form_state->setErrorByName('redirects', t('No protocol should be included in the redirect domain.'));
+ $form_state->setErrorByName('redirects', $this->t('No protocol should be included in the redirect domain.'));
}
}
}
@@ -160,6 +160,6 @@ class RedirectDomainForm extends ConfigFormBase {
}
$domain_config->set('domain_redirects', $domain_redirects);
$domain_config->save();
- drupal_set_message(t('The domain redirects have been saved.'));
+ drupal_set_message($this->t('The domain redirects have been saved.'));
}
}
diff --git a/sites/all/modules/contrib/admin/redirect/redirect.info.yml b/sites/all/modules/contrib/admin/redirect/redirect.info.yml
index 3472dab6e..a1e6eb15d 100644
--- a/sites/all/modules/contrib/admin/redirect/redirect.info.yml
+++ b/sites/all/modules/contrib/admin/redirect/redirect.info.yml
@@ -8,8 +8,8 @@ dependencies:
- drupal:link
- drupal:views
-# Information added by Drupal.org packaging script on 2018-05-04
-version: '8.x-1.2'
+# Information added by Drupal.org packaging script on 2018-10-16
+version: '8.x-1.3'
core: '8.x'
project: 'redirect'
-datestamp: 1525419807
+datestamp: 1539682690
diff --git a/sites/all/modules/contrib/admin/redirect/src/Entity/Redirect.php b/sites/all/modules/contrib/admin/redirect/src/Entity/Redirect.php
index ae54ec576..cb5d4c56d 100644
--- a/sites/all/modules/contrib/admin/redirect/src/Entity/Redirect.php
+++ b/sites/all/modules/contrib/admin/redirect/src/Entity/Redirect.php
@@ -3,7 +3,6 @@
namespace Drupal\redirect\Entity;
use Drupal\Component\Utility\Crypt;
-use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityStorageInterface;
@@ -25,7 +24,7 @@ use Drupal\link\LinkItemInterface;
* "delete" = "Drupal\redirect\Form\RedirectDeleteForm",
* "edit" = "Drupal\redirect\Form\RedirectForm"
* },
- * "views_data" = "Drupal\views\EntityViewsData",
+ * "views_data" = "Drupal\redirect\RedirectViewsData",
* "storage_schema" = "\Drupal\redirect\RedirectStorageSchema"
* },
* base_table = "redirect",
@@ -62,7 +61,7 @@ class Redirect extends ContentEntityBase {
*/
public static function generateHash($source_path, array $source_query, $language) {
$hash = array(
- 'source' => Unicode::strtolower($source_path),
+ 'source' => mb_strtolower($source_path),
'language' => $language,
);
@@ -86,7 +85,9 @@ class Redirect extends ContentEntityBase {
* {@inheritdoc}
*/
public function preSave(EntityStorageInterface $storage_controller) {
- $this->set('hash', Redirect::generateHash($this->redirect_source->path, (array) $this->redirect_source->query, $this->language()->getId()));
+ // Get the language code directly from the field as language() might not
+ // be up to date if the language was just changed.
+ $this->set('hash', Redirect::generateHash($this->redirect_source->path, (array) $this->redirect_source->query, $this->get('language')->value));
}
/**
@@ -205,7 +206,9 @@ class Redirect extends ContentEntityBase {
*/
public function setRedirect($url, array $query = array(), array $options = array()) {
$uri = $url . ($query ? '?' . UrlHelper::buildQuery($query) : '');
- $this->redirect_redirect->set(0, ['uri' => 'internal:/' . ltrim($uri, '/'), 'options' => $options]);
+ $external = UrlHelper::isValid($url, TRUE);
+ $uri = ($external ? $url : 'internal:/' . ltrim($uri, '/'));
+ $this->redirect_redirect->set(0, ['uri' => $uri, 'options' => $options]);
}
/**
diff --git a/sites/all/modules/contrib/admin/redirect/src/EventSubscriber/RedirectRequestSubscriber.php b/sites/all/modules/contrib/admin/redirect/src/EventSubscriber/RedirectRequestSubscriber.php
index 3161ccd42..87095deff 100644
--- a/sites/all/modules/contrib/admin/redirect/src/EventSubscriber/RedirectRequestSubscriber.php
+++ b/sites/all/modules/contrib/admin/redirect/src/EventSubscriber/RedirectRequestSubscriber.php
@@ -8,7 +8,7 @@ use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Logger\RfcLogLevel;
-use Drupal\Core\Path\AliasManager;
+use Drupal\Core\Path\AliasManagerInterface;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\Core\Url;
@@ -81,7 +81,7 @@ class RedirectRequestSubscriber implements EventSubscriberInterface {
* The language manager service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config
* The config.
- * @param \Drupal\Core\Path\AliasManager $alias_manager
+ * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
* The alias manager service.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler service.
@@ -92,7 +92,7 @@ class RedirectRequestSubscriber implements EventSubscriberInterface {
* @param \Symfony\Component\Routing\RequestContext
* Request context.
*/
- public function __construct(RedirectRepository $redirect_repository, LanguageManagerInterface $language_manager, ConfigFactoryInterface $config, AliasManager $alias_manager, ModuleHandlerInterface $module_handler, EntityManagerInterface $entity_manager, RedirectChecker $checker, RequestContext $context, InboundPathProcessorInterface $path_processor) {
+ public function __construct(RedirectRepository $redirect_repository, LanguageManagerInterface $language_manager, ConfigFactoryInterface $config, AliasManagerInterface $alias_manager, ModuleHandlerInterface $module_handler, EntityManagerInterface $entity_manager, RedirectChecker $checker, RequestContext $context, InboundPathProcessorInterface $path_processor) {
$this->redirectRepository = $redirect_repository;
$this->languageManager = $language_manager;
$this->config = $config->get('redirect.settings');
@@ -126,9 +126,19 @@ class RedirectRequestSubscriber implements EventSubscriberInterface {
// Get URL info and process it to be used for hash generation.
parse_str($request->getQueryString(), $request_query);
- // Do the inbound processing so that for example language prefixes are
- // removed.
- $path = $this->pathProcessor->processInbound($request->getPathInfo(), $request);
+ if (strpos($request->getPathInfo(), '/system/files/') === 0 && !$request->query->has('file')) {
+ // Private files paths are split by the inbound path processor and the
+ // relative file path is moved to the 'file' query string parameter. This
+ // is because the route system does not allow an arbitrary amount of
+ // parameters. We preserve the path as is returned by the request object.
+ // @see \Drupal\system\PathProcessor\PathProcessorFiles::processInbound()
+ $path = $request->getPathInfo();
+ }
+ else {
+ // Do the inbound processing so that for example language prefixes are
+ // removed.
+ $path = $this->pathProcessor->processInbound($request->getPathInfo(), $request);
+ }
$path = trim($path, '/');
$this->context->fromRequest($request);
diff --git a/sites/all/modules/contrib/admin/redirect/src/Form/RedirectDeleteForm.php b/sites/all/modules/contrib/admin/redirect/src/Form/RedirectDeleteForm.php
index ae3c2bcb7..eeee993d9 100644
--- a/sites/all/modules/contrib/admin/redirect/src/Form/RedirectDeleteForm.php
+++ b/sites/all/modules/contrib/admin/redirect/src/Form/RedirectDeleteForm.php
@@ -34,7 +34,7 @@ class RedirectDeleteForm extends ContentEntityConfirmFormBase {
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->entity->delete();
- drupal_set_message(t('The redirect %redirect has been deleted.', array('%redirect' => $this->entity->getRedirectUrl()->toString())));
+ drupal_set_message($this->t('The redirect %redirect has been deleted.', array('%redirect' => $this->entity->getRedirectUrl()->toString())));
$form_state->setRedirect('redirect.list');
}
diff --git a/sites/all/modules/contrib/admin/redirect/src/Form/RedirectDeleteMultipleForm.php b/sites/all/modules/contrib/admin/redirect/src/Form/RedirectDeleteMultipleForm.php
index 9e1ed222e..79c79467c 100644
--- a/sites/all/modules/contrib/admin/redirect/src/Form/RedirectDeleteMultipleForm.php
+++ b/sites/all/modules/contrib/admin/redirect/src/Form/RedirectDeleteMultipleForm.php
@@ -101,7 +101,7 @@ class RedirectDeleteMultipleForm extends ConfirmFormBase {
* {@inheritdoc}
*/
public function getConfirmText() {
- return t('Delete');
+ return $this->t('Delete');
}
/**
diff --git a/sites/all/modules/contrib/admin/redirect/src/Form/RedirectForm.php b/sites/all/modules/contrib/admin/redirect/src/Form/RedirectForm.php
index 573fa99d6..702e99158 100644
--- a/sites/all/modules/contrib/admin/redirect/src/Form/RedirectForm.php
+++ b/sites/all/modules/contrib/admin/redirect/src/Form/RedirectForm.php
@@ -50,7 +50,7 @@ class RedirectForm extends ContentEntityForm {
$redirect->setRedirect($redirect_url, $redirect_query, $redirect_options);
}
catch (MatchingRouteNotFoundException $e) {
- drupal_set_message(t('Invalid redirect URL %url provided.', array('%url' => $redirect_url)), 'warning');
+ drupal_set_message($this->t('Invalid redirect URL %url provided.', array('%url' => $redirect_url)), 'warning');
}
}
@@ -71,15 +71,15 @@ class RedirectForm extends ContentEntityForm {
foreach (\Drupal::languageManager()->getLanguages(LanguageInterface::STATE_CONFIGURABLE) as $langcode => $language) {
$form['language']['widget'][0]['value']['#options'][$langcode] = $language->getName();
}
- $form['language']['widget'][0]['value']['#options'][LanguageInterface::LANGCODE_NOT_SPECIFIED] = t('- All languages -');
+ $form['language']['widget'][0]['value']['#options'][LanguageInterface::LANGCODE_NOT_SPECIFIED] = $this->t('- All languages -');
}
$default_code = $redirect->getStatusCode() ? $redirect->getStatusCode() : \Drupal::config('redirect.settings')->get('default_status_code');
$form['status_code'] = array(
'#type' => 'select',
- '#title' => t('Redirect status'),
- '#description' => t('You can find more information about HTTP redirect status codes at @status-codes.', array('@status-codes' => 'http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_Redirection')),
+ '#title' => $this->t('Redirect status'),
+ '#description' => $this->t('You can find more information about HTTP redirect status codes at @status-codes.', array('@status-codes' => 'http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_Redirection')),
'#default_value' => $default_code,
'#options' => redirect_status_code_options(),
);
@@ -96,13 +96,13 @@ class RedirectForm extends ContentEntityForm {
$redirect = $form_state->getValue(array('redirect_redirect', 0));
if ($source['path'] == '') {
- $form_state->setErrorByName('redirect_source', t('It is not allowed to create a redirect from the front page.'));
+ $form_state->setErrorByName('redirect_source', $this->t('It is not allowed to create a redirect from the front page.'));
}
if (strpos($source['path'], '#') !== FALSE) {
- $form_state->setErrorByName('redirect_source', t('The anchor fragments are not allowed.'));
+ $form_state->setErrorByName('redirect_source', $this->t('The anchor fragments are not allowed.'));
}
if (strpos($source['path'], '/') === 0) {
- $form_state->setErrorByName('redirect_source', t('The url to redirect from should not start with a forward slash (/).'));
+ $form_state->setErrorByName('redirect_source', $this->t('The url to redirect from should not start with a forward slash (/).'));
}
try {
@@ -113,7 +113,7 @@ class RedirectForm extends ContentEntityForm {
// a valid route. Otherwise the validation will fail on the redirect path
// being an invalid route.
if ($source_url->toString() == $redirect_url->toString()) {
- $form_state->setErrorByName('redirect_redirect', t('You are attempting to redirect the page to itself. This will result in an infinite loop.'));
+ $form_state->setErrorByName('redirect_redirect', $this->t('You are attempting to redirect the page to itself. This will result in an infinite loop.'));
}
}
catch (\InvalidArgumentException $e) {
@@ -133,7 +133,7 @@ class RedirectForm extends ContentEntityForm {
if (!empty($redirects)) {
$redirect = array_shift($redirects);
if ($this->entity->isNew() || $redirect->id() != $this->entity->id()) {
- $form_state->setErrorByName('redirect_source', t('The source path %source is already being redirected. Do you want to edit the existing redirect?',
+ $form_state->setErrorByName('redirect_source', $this->t('The source path %source is already being redirected. Do you want to edit the existing redirect?',
array(
'%source' => $source['path'],
'@edit-page' => $redirect->url('edit-form'))));
@@ -146,7 +146,7 @@ class RedirectForm extends ContentEntityForm {
*/
public function save(array $form, FormStateInterface $form_state) {
$this->entity->save();
- drupal_set_message(t('The redirect has been saved.'));
+ drupal_set_message($this->t('The redirect has been saved.'));
$form_state->setRedirect('redirect.list');
}
}
diff --git a/sites/all/modules/contrib/admin/redirect/src/Form/RedirectSettingsForm.php b/sites/all/modules/contrib/admin/redirect/src/Form/RedirectSettingsForm.php
index f2b7d1b2f..029973dcc 100644
--- a/sites/all/modules/contrib/admin/redirect/src/Form/RedirectSettingsForm.php
+++ b/sites/all/modules/contrib/admin/redirect/src/Form/RedirectSettingsForm.php
@@ -58,7 +58,7 @@ class RedirectSettingsForm extends ConfigFormBase {
$form['globals']['redirect_route_normalizer_enabled'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Enforce clean and canonical URLs.'),
- '#description' => $this->t('Enabling this will automatically redirect to the canonical URL of any page. That includes redirecting to an alias if existing, removing trainling slashes, ensure the language prefix is set and similar clean-up.'),
+ '#description' => $this->t('Enabling this will automatically redirect to the canonical URL of any page. That includes redirecting to an alias if existing, removing trailing slashes, ensure the language prefix is set and similar clean-up.'),
'#default_value' => $config->get('route_normalizer_enabled'),
);
$form['globals']['redirect_ignore_admin_path'] = array(
@@ -87,7 +87,7 @@ class RedirectSettingsForm extends ConfigFormBase {
}
}
$config->save();
- drupal_set_message(t('Configuration was saved.'));
+ drupal_set_message($this->t('Configuration was saved.'));
}
}
diff --git a/sites/all/modules/contrib/admin/redirect/src/Plugin/Field/FieldWidget/RedirectSourceWidget.php b/sites/all/modules/contrib/admin/redirect/src/Plugin/Field/FieldWidget/RedirectSourceWidget.php
index 729abe45a..0a4341116 100644
--- a/sites/all/modules/contrib/admin/redirect/src/Plugin/Field/FieldWidget/RedirectSourceWidget.php
+++ b/sites/all/modules/contrib/admin/redirect/src/Plugin/Field/FieldWidget/RedirectSourceWidget.php
@@ -64,7 +64,7 @@ class RedirectSourceWidget extends WidgetBase {
// determine if we have a valid path.
try {
\Drupal::service('router')->match('/' . $form_state->getValue(array('redirect_source', 0, 'path')));
- $element['status_box'][]['#markup'] = '
' . t('The source path %path is likely a valid path. It is preferred to create URL aliases for existing paths rather than redirects.',
+ $element['status_box'][]['#markup'] = '
' . $this->t('The source path %path is likely a valid path. It is preferred to create URL aliases for existing paths rather than redirects.',
array('%path' => $source_path, '@url-alias' => Url::fromRoute('path.admin_add')->toString())) . '
' . t('The base source path %source is already being redirected. Do you want to edit the existing redirect?', array('%source' => $source_path, '@edit-page' => $redirect->url('edit-form'))) . '
';
+ $element['status_box'][]['#markup'] = '
' . $this->t('The base source path %source is already being redirected. Do you want to edit the existing redirect?', array('%source' => $source_path, '@edit-page' => $redirect->url('edit-form'))) . '
';
}
}
}
diff --git a/sites/all/modules/contrib/admin/redirect/src/RedirectRepository.php b/sites/all/modules/contrib/admin/redirect/src/RedirectRepository.php
index f8a1cea9a..236c927f6 100644
--- a/sites/all/modules/contrib/admin/redirect/src/RedirectRepository.php
+++ b/sites/all/modules/contrib/admin/redirect/src/RedirectRepository.php
@@ -112,10 +112,12 @@ class RedirectRepository {
*/
protected function findByRedirect(Redirect $redirect, $language) {
$uri = $redirect->getRedirectUrl();
- $baseUrl = \Drupal::request()->getBaseUrl();
- $path = ltrim(substr($uri->toString(), strlen($baseUrl)), '/');
+ $base_url = \Drupal::request()->getBaseUrl();
+ $generated_url = $uri->toString(TRUE);
+ $path = ltrim(substr($generated_url->getGeneratedUrl(), strlen($base_url)), '/');
$query = $uri->getOption('query') ?: [];
- return $this->findMatchingRedirect($path, $query, $language);
+ $return_value = $this->findMatchingRedirect($path, $query, $language);
+ return $return_value ? $return_value->addCacheableDependency($generated_url) : $return_value;
}
/**
diff --git a/sites/all/modules/contrib/admin/redirect/src/RedirectViewsData.php b/sites/all/modules/contrib/admin/redirect/src/RedirectViewsData.php
new file mode 100644
index 000000000..7e33ea51f
--- /dev/null
+++ b/sites/all/modules/contrib/admin/redirect/src/RedirectViewsData.php
@@ -0,0 +1,25 @@
+assertEqual($headers[0][':status'], $expected_ending_status);
}
+
+ /**
+ * @inheritdoc}
+ */
+ protected function drupalHead($path, array $options = [], array $headers = []) {
+ // Always just use getAbsolutePath() so that generating the link does not
+ // alter special requests.
+ $url = $this->getAbsoluteUrl($path);
+ $out = $this->curlExec([CURLOPT_NOBODY => TRUE, CURLOPT_URL => $url, CURLOPT_HTTPHEADER => $headers]);
+ // Ensure that any changes to variables in the other thread are picked up.
+ $this->refreshVariables();
+
+ if ($this->dumpHeaders) {
+ $this->verbose('GET request to: ' . $path .
+ 'Ending URL: ' . $this->getUrl() .
+ 'Headers: