فهرست منبع

contrib modules updates

Bachir Soussi Chiadmi 5 سال پیش
والد
کامیت
e3cf889820
100فایلهای تغییر یافته به همراه3772 افزوده شده و 709 حذف شده
  1. 18 0
      sites/all/modules/contrib/admin/admin_toolbar/CHANGELOG.txt
  2. 4 4
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.info.yml
  3. 16 0
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.install
  4. 3 3
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.info.yml
  5. 4 4
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.info.yml
  6. 0 21
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.links.menu.yml
  7. 108 38
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.module
  8. 1 1
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/composer.json
  9. 9 9
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/Controller/ToolbarController.php
  10. 3 3
      sites/all/modules/contrib/admin/config_update/config_update.info.yml
  11. 6 1
      sites/all/modules/contrib/admin/config_update/config_update_ui/config_update_ui.drush.inc
  12. 3 3
      sites/all/modules/contrib/admin/config_update/config_update_ui/config_update_ui.info.yml
  13. 0 0
      sites/all/modules/contrib/admin/config_update/config_update_ui/config_update_ui.module
  14. 1 1
      sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigDeleteConfirmForm.php
  15. 1 1
      sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigImportConfirmForm.php
  16. 1 1
      sites/all/modules/contrib/admin/config_update/config_update_ui/src/Form/ConfigRevertConfirmForm.php
  17. 14 10
      sites/all/modules/contrib/admin/config_update/config_update_ui/tests/src/Functional/ConfigProfileOverridesTest.php
  18. 121 98
      sites/all/modules/contrib/admin/config_update/config_update_ui/tests/src/Functional/ConfigUpdateTest.php
  19. 37 0
      sites/all/modules/contrib/admin/config_update/drupalci.yml
  20. 29 18
      sites/all/modules/contrib/admin/config_update/src/ConfigDiffer.php
  21. 1 1
      sites/all/modules/contrib/admin/config_update/src/ConfigLister.php
  22. 1 1
      sites/all/modules/contrib/admin/config_update/src/ConfigRevertInterface.php
  23. 54 27
      sites/all/modules/contrib/admin/config_update/src/ConfigReverter.php
  24. 79 25
      sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigDifferTest.php
  25. 173 145
      sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigListerTest.php
  26. 356 0
      sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigReverterTest.php
  27. 547 0
      sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigUpdateUnitTestBase.php
  28. 12 20
      sites/all/modules/contrib/admin/domain/.travis.yml
  29. 2 1
      sites/all/modules/contrib/admin/domain/CHANGELOG.md
  30. 2 11
      sites/all/modules/contrib/admin/domain/README.md
  31. 9 0
      sites/all/modules/contrib/admin/domain/composer.json
  32. 3 3
      sites/all/modules/contrib/admin/domain/domain/domain.info.yml
  33. 16 0
      sites/all/modules/contrib/admin/domain/domain/domain.module
  34. 5 0
      sites/all/modules/contrib/admin/domain/domain/drush.services.yml
  35. 3 3
      sites/all/modules/contrib/admin/domain/domain/src/Access/DomainAccessCheck.php
  36. 10 0
      sites/all/modules/contrib/admin/domain/domain/src/Commands/DomainCommandException.php
  37. 1368 0
      sites/all/modules/contrib/admin/domain/domain/src/Commands/DomainCommands.php
  38. 12 2
      sites/all/modules/contrib/admin/domain/domain/src/DomainElementManager.php
  39. 20 14
      sites/all/modules/contrib/admin/domain/domain/src/DomainNegotiator.php
  40. 1 2
      sites/all/modules/contrib/admin/domain/domain/src/DomainValidator.php
  41. 2 2
      sites/all/modules/contrib/admin/domain/domain/src/Entity/Domain.php
  42. 7 2
      sites/all/modules/contrib/admin/domain/domain/src/Plugin/Condition/Domain.php
  43. 3 3
      sites/all/modules/contrib/admin/domain/domain/tests/modules/domain_config_schema_test/domain_config_schema_test.info.yml
  44. 3 3
      sites/all/modules/contrib/admin/domain/domain/tests/modules/domain_test/domain_test.info.yml
  45. 3 3
      sites/all/modules/contrib/admin/domain/domain_access/domain_access.info.yml
  46. 5 0
      sites/all/modules/contrib/admin/domain/domain_access/drush.services.yml
  47. 79 0
      sites/all/modules/contrib/admin/domain/domain_access/src/Commands/DomainAccessCommands.php
  48. 3 3
      sites/all/modules/contrib/admin/domain/domain_access/tests/modules/domain_access_test/domain_access_test.info.yml
  49. 3 3
      sites/all/modules/contrib/admin/domain/domain_alias/domain_alias.info.yml
  50. 3 3
      sites/all/modules/contrib/admin/domain/domain_config/domain_config.info.yml
  51. 1 1
      sites/all/modules/contrib/admin/domain/domain_config/domain_config.services.yml
  52. 22 5
      sites/all/modules/contrib/admin/domain/domain_config/src/DomainConfigOverrider.php
  53. 24 0
      sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/domain_config_hook_test.info.yml
  54. 23 0
      sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/domain_config_hook_test.module
  55. 7 0
      sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/domain_config_hook_test.services.yml
  56. 47 0
      sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/src/PageCache/RequestPolicy/PageCacheRequestPolicy.php
  57. 3 3
      sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_middleware_test/domain_config_middleware_test.info.yml
  58. 3 3
      sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_test/domain_config_test.info.yml
  59. 30 0
      sites/all/modules/contrib/admin/domain/domain_config/tests/src/Functional/DomainConfigHookProblemTest.php
  60. 42 0
      sites/all/modules/contrib/admin/domain/domain_config/tests/src/Functional/DomainConfigHookTest.php
  61. 3 3
      sites/all/modules/contrib/admin/domain/domain_content/domain_content.info.yml
  62. 1 1
      sites/all/modules/contrib/admin/domain/domain_content/src/Controller/DomainContentController.php
  63. 3 3
      sites/all/modules/contrib/admin/domain/domain_source/domain_source.info.yml
  64. 14 0
      sites/all/modules/contrib/admin/domain/domain_source/domain_source.module
  65. 5 0
      sites/all/modules/contrib/admin/domain/domain_source/drush.services.yml
  66. 79 0
      sites/all/modules/contrib/admin/domain/domain_source/src/Commands/DomainSourceCommands.php
  67. 16 4
      sites/all/modules/contrib/admin/domain/domain_source/src/HttpKernel/DomainSourcePathProcessor.php
  68. 3 3
      sites/all/modules/contrib/admin/domain/domain_source/tests/modules/domain_source_test/domain_source_test.info.yml
  69. 40 0
      sites/all/modules/contrib/admin/domain/domain_source/tests/src/Functional/DomainSourceElementTest.php
  70. 0 58
      sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings-circular_dependency-2930391-7.patch
  71. 5 5
      sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.info.yml
  72. 0 1
      sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.links.menu.yml
  73. 1 1
      sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings.services.yml
  74. 18 7
      sites/all/modules/contrib/admin/domain_site_settings/src/Configuration/DomainConfigOverride.php
  75. 9 9
      sites/all/modules/contrib/admin/domain_site_settings/src/Controller/DomainSiteSettingsController.php
  76. 21 24
      sites/all/modules/contrib/admin/domain_site_settings/src/Form/DomainConfigSettingsForm.php
  77. 4 4
      sites/all/modules/contrib/admin/matomo/README.txt
  78. 4 2
      sites/all/modules/contrib/admin/matomo/composer.json
  79. 5 3
      sites/all/modules/contrib/admin/matomo/matomo.info.yml
  80. 2 1
      sites/all/modules/contrib/admin/matomo/matomo.install
  81. 10 13
      sites/all/modules/contrib/admin/matomo/matomo.module
  82. 0 0
      sites/all/modules/contrib/admin/matomo/migrations/d6_matomo_settings.yml
  83. 0 0
      sites/all/modules/contrib/admin/matomo/migrations/d6_matomo_user_settings.yml
  84. 0 0
      sites/all/modules/contrib/admin/matomo/migrations/d7_matomo_settings.yml
  85. 0 0
      sites/all/modules/contrib/admin/matomo/migrations/d7_matomo_user_settings.yml
  86. 31 10
      sites/all/modules/contrib/admin/matomo/src/Form/MatomoAdminSettingsForm.php
  87. 15 0
      sites/all/modules/contrib/admin/matomo/src/MatomoInterface.php
  88. 0 1
      sites/all/modules/contrib/admin/matomo/src/Tests/MatomoSearchTest.php
  89. 5 1
      sites/all/modules/contrib/admin/matomo/src/Tests/MatomoStatusMessagesTest.php
  90. 3 3
      sites/all/modules/contrib/admin/matomo/tests/modules/matomo_test/matomo_test.info.yml
  91. 4 4
      sites/all/modules/contrib/admin/matomo/tests/modules/matomo_test/src/Controller/MatomoTestController.php
  92. 8 5
      sites/all/modules/contrib/admin/path_alias_xt/path_alias_xt.info.yml
  93. 1 1
      sites/all/modules/contrib/admin/path_alias_xt/src/PathAliasXtProcessorAlias.php
  94. 59 1
      sites/all/modules/contrib/admin/redirect/README.txt
  95. 1 1
      sites/all/modules/contrib/admin/redirect/config/install/views.view.redirect.yml
  96. 3 3
      sites/all/modules/contrib/admin/redirect/modules/redirect_404/redirect_404.info.yml
  97. 2 3
      sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/EventSubscriber/Redirect404Subscriber.php
  98. 1 1
      sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/SqlRedirectNotFoundStorage.php
  99. 15 14
      sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/Tests/Fix404RedirectUILanguageTest.php
  100. 15 14
      sites/all/modules/contrib/admin/redirect/modules/redirect_404/src/Tests/Fix404RedirectUITest.php

+ 18 - 0
sites/all/modules/contrib/admin/admin_toolbar/CHANGELOG.txt

@@ -1,3 +1,21 @@
+Admin Toolbar 8.x-1.25, 2018-11-22
+----------------------------------
+Changes since 8.x-1.24:
+
+- #3012102 by tikaszvince, Jody Lynn, adriancid, grahl, jigarius: Provider
+  property missing on link definition.
+- #3010451 by epowelljr, adriancid: Improve the admin_toolbar module
+  description.
+- #2958415 by adriancid, romainj, Prashant.c, harshita29: Replace usages of the
+  deprecated drupal_set_message() function.
+- #2996485 by idebr, adriancid: Remove unused function 
+  admin_toolbar_tools_get_links().
+- #2989281 by JKerschner, adriancid: Consistently use $entityTypeManager.
+- #2985106 by Eli-T, adriancid, eme: Add ability to hide Drupal.org links
+  exposed by admin_toolbar_tools from certain users.
+- #2938884 by Spurlos, bdanin, romainj, purdy_nc, adriancid: A non-existent 
+  route breaks the site.
+
 Admin Toolbar 8.x-1.24, 2018-05-28
 ----------------------------------
 Changes since 8.x-1.23:

+ 4 - 4
sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.info.yml

@@ -1,5 +1,5 @@
 name: Admin Toolbar
-description: Provides a drop-down menu interface to the site Toolbar.
+description: Provides an improved drop-down menu interface to the site Toolbar.
 package: Administration
 
 type: module
@@ -8,8 +8,8 @@ type: module
 dependencies:
   - drupal:toolbar
 
-# Information added by Drupal.org packaging script on 2018-05-28
-version: '8.x-1.24'
+# Information added by Drupal.org packaging script on 2019-02-03
+version: '8.x-1.26'
 core: '8.x'
 project: 'admin_toolbar'
-datestamp: 1527522484
+datestamp: 1549218484

+ 16 - 0
sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.install

@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the Admin Toolbar module.
+ */
+
+/**
+ * Rebuild routes to mitigate issue 2938884.
+ *
+ * @see https://www.drupal.org/project/admin_toolbar/issues/2938884
+ */
+function admin_toolbar_update_8001() {
+  // Rebuilding the route cache.
+  \Drupal::service("router.builder")->rebuild();
+}

+ 3 - 3
sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.info.yml

@@ -8,8 +8,8 @@ type: module
 dependencies:
   - admin_toolbar:admin_toolbar
 
-# Information added by Drupal.org packaging script on 2018-05-28
-version: '8.x-1.24'
+# Information added by Drupal.org packaging script on 2019-02-03
+version: '8.x-1.26'
 core: '8.x'
 project: 'admin_toolbar'
-datestamp: 1527522484
+datestamp: 1549218484

+ 4 - 4
sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.info.yml

@@ -7,10 +7,10 @@ type: module
 
 dependencies:
   - admin_toolbar:admin_toolbar
-  - drupal:system (>=8.3)
+  - drupal:system (>=8.5)
 
-# Information added by Drupal.org packaging script on 2018-05-28
-version: '8.x-1.24'
+# Information added by Drupal.org packaging script on 2019-02-03
+version: '8.x-1.26'
 core: '8.x'
 project: 'admin_toolbar'
-datestamp: 1527522484
+datestamp: 1549218484

+ 0 - 21
sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.links.menu.yml

@@ -74,24 +74,3 @@ admin_toolbar_tools.flush_rendercache:
   route_name: admin_toolbar_tools.flush_rendercache
   parent: admin_toolbar_tools.flush
   menu_name: admin
-
-admin_toolbar_tools.drupalorg:
-  title: 'Drupal.org'
-  weight: -5
-  url: https://www.drupal.org
-  parent: admin_toolbar_tools.help
-  menu_name: admin
-
-admin_toolbar_tools.listchanges:
-  title: 'Change records for Drupal core'
-  weight: -6
-  url: https://www.drupal.org/list-changes
-  parent: admin_toolbar_tools.drupalorg
-  menu_name: admin
-
-admin_toolbar_tools.doc:
-  title: 'D8 API documentation'
-  weight: -5
-  url: https://api.drupal.org/api/drupal/8
-  parent: admin_toolbar_tools.drupalorg
-  menu_name: admin

+ 108 - 38
sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.module

@@ -48,13 +48,26 @@ function admin_toolbar_tools_help($route_name, RouteMatchInterface $route_match)
  * Implements hook_menu_links_discovered_alter().
  */
 function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
+  $languageManager = \Drupal::languageManager();
+  $config_override_language = $languageManager->getConfigOverrideLanguage();
+  $languageManager->setConfigOverrideLanguage($languageManager->getLanguage('en'));
+
   $moduleHandler = \Drupal::moduleHandler();
   $entityTypeManager = \Drupal::entityTypeManager();
   $routeProvider = \Drupal::service('router.route_provider');
-  $routes = [];
-  foreach ($routeProvider->getAllRoutes() as $route_name => $route) {
-    $routes[] = $route_name;
-  }
+
+  /**
+   * Determine if a route exists by name.
+   *
+   * @param $routeName
+   *   The name of the route to check.
+   *
+   * @return bool
+   *   Whether a route with that route name exists.
+   */
+  $routeExists = function ($routeName) use ($routeProvider) {
+    return (count($routeProvider->getRoutesByNames([$routeName])) === 1);
+  };
 
   $entityTypes = $entityTypeManager->getDefinitions();
   $content_entities = [];
@@ -71,14 +84,16 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('views')) {
     $links['admin_toolbar_tools.flush_views'] = [
       'title' => t('Flush views cache'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'admin_toolbar_tools.flush_views',
       'menu_name' => 'admin',
       'parent' => 'admin_toolbar_tools.flush',
     ];
     // Adding a menu link to Files.
-    if ($moduleHandler->moduleExists('file') && in_array('view.files.page_1', $routes)) {
+    if ($moduleHandler->moduleExists('file') && $routeExists('view.files.page_1')) {
       $links['admin_toolbar_tools.view.files'] = [
         'title' => t('Files'),
+        'provider' => 'admin_toolbar_tools',
         'route_name' => 'view.files.page_1',
         'menu_name' => 'admin',
         'parent' => 'system.admin_content',
@@ -93,21 +108,23 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     foreach ($entityTypeManager->getStorage($content_entity_bundle)->loadMultiple() as $machine_name => $bundle) {
       // Normally, the edit form for the bundle would be its root link.
       $content_entity_bundle_root = NULL;
-      if (in_array('entity.' . $content_entity_bundle . '.overview_form', $routes)) {
+      if ($routeExists('entity.' . $content_entity_bundle . '.overview_form')) {
         // Some bundles have an overview/list form that make a better root link.
         $content_entity_bundle_root = 'entity.' . $content_entity_bundle . '.overview_form.' . $machine_name;
         $links[$content_entity_bundle_root] = [
           'title' => t($bundle->label()),
+          'provider' => 'admin_toolbar_tools',
           'route_name' => 'entity.' . $content_entity_bundle . '.overview_form',
           'menu_name' => 'admin',
           'parent' => 'entity.' . $content_entity_bundle . '.collection',
           'route_parameters' => [$content_entity_bundle => $machine_name],
         ];
       }
-      if (in_array('entity.' . $content_entity_bundle . '.edit_form', $routes)) {
+      if ($routeExists('entity.' . $content_entity_bundle . '.edit_form')) {
         $key = 'entity.' . $content_entity_bundle . '.edit_form.' . $machine_name;
         $links[$key] = [
           'title' => t($bundle->label()),
+          'provider' => 'admin_toolbar_tools',
           'route_name' => 'entity.' . $content_entity_bundle . '.edit_form',
           'menu_name' => 'admin',
           'parent' => 'entity.' . $content_entity_bundle . '.collection',
@@ -122,9 +139,10 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
         }
       }
       if ($moduleHandler->moduleExists('field_ui')) {
-        if (in_array('entity.' . $content_entity . '.field_ui_fields', $routes)) {
+        if ($routeExists('entity.' . $content_entity . '.field_ui_fields')) {
           $links['entity.' . $content_entity . '.field_ui_fields' . $machine_name] = [
             'title' => t('Manage fields'),
+            'provider' => 'admin_toolbar_tools',
             'route_name' => 'entity.' . $content_entity . '.field_ui_fields',
             'menu_name' => 'admin',
             'parent' => $content_entity_bundle_root,
@@ -132,9 +150,10 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
             'weight' => 1,
           ];
         }
-        if (in_array('entity.entity_form_display.' . $content_entity . '.default', $routes)) {
+        if ($routeExists('entity.entity_form_display.' . $content_entity . '.default')) {
           $links['entity.entity_form_display.' . $content_entity . '.default' . $machine_name] = [
             'title' => t('Manage form display'),
+            'provider' => 'admin_toolbar_tools',
             'route_name' => 'entity.entity_form_display.' . $content_entity . '.default',
             'menu_name' => 'admin',
             'parent' => $content_entity_bundle_root,
@@ -142,9 +161,10 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
             'weight' => 2,
           ];
         }
-        if (in_array('entity.entity_view_display.' . $content_entity . '.default', $routes)) {
+        if ($routeExists('entity.entity_view_display.' . $content_entity . '.default')) {
           $links['entity.entity_view_display.' . $content_entity . '.default.' . $machine_name] = [
             'title' => t('Manage display'),
+            'provider' => 'admin_toolbar_tools',
             'route_name' => 'entity.entity_view_display.' . $content_entity . '.default',
             'menu_name' => 'admin',
             'parent' => $content_entity_bundle_root,
@@ -153,9 +173,10 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
           ];
         }
       }
-      if ($moduleHandler->moduleExists('devel') && in_array('entity.' . $content_entity_bundle . '.devel_load', $routes)) {
+      if ($moduleHandler->moduleExists('devel') && $routeExists('entity.' . $content_entity_bundle . '.devel_load')) {
         $links['entity.' . $content_entity_bundle . '.devel_load.' . $machine_name] = [
           'title' => t('Devel'),
+          'provider' => 'admin_toolbar_tools',
           'route_name' => 'entity.' . $content_entity_bundle . '.devel_load',
           'menu_name' => 'admin',
           'parent' => $content_entity_bundle_root,
@@ -163,9 +184,10 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
           'weight' => 4,
         ];
       }
-      if (in_array('entity.' . $content_entity_bundle . '.delete_form', $routes)) {
+      if ($routeExists('entity.' . $content_entity_bundle . '.delete_form')) {
         $links['entity.' . $content_entity_bundle . '.delete_form.' . $machine_name] = [
           'title' => t('Delete'),
+          'provider' => 'admin_toolbar_tools',
           'route_name' => 'entity.' . $content_entity_bundle . '.delete_form',
           'menu_name' => 'admin',
           'parent' => $content_entity_bundle_root,
@@ -179,30 +201,35 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   // Add user links.
   $links['user.admin_create'] = [
     'title' => t('Add a new user'),
+    'provider' => 'admin_toolbar_tools',
     'route_name' => 'user.admin_create',
     'menu_name' => 'admin',
     'parent' => 'entity.user.collection',
   ];
   $links['user.admin_permissions'] = [
     'title' => t('Permissions'),
+    'provider' => 'admin_toolbar_tools',
     'route_name' => 'user.admin_permissions',
     'menu_name' => 'admin',
     'parent' => 'entity.user.collection',
   ];
   $links['entity.user_role.collection'] = [
     'title' => t('Roles'),
+    'provider' => 'admin_toolbar_tools',
     'route_name' => 'entity.user_role.collection',
     'menu_name' => 'admin',
     'parent' => 'entity.user.collection',
   ];
   $links['admin_toolbar_tools.user.logout'] = [
     'title' => t('Logout'),
+    'provider' => 'admin_toolbar_tools',
     'route_name' => 'user.logout',
     'parent' => 'admin_toolbar_tools.help',
     'weight' => 10,
   ];
   $links['user.role_add'] = [
     'title' => t('Add a new role'),
+    'provider' => 'admin_toolbar_tools',
     'route_name' => 'user.role_add',
     'menu_name' => 'admin',
     'parent' => 'entity.user_role.collection',
@@ -211,18 +238,21 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('field_ui')) {
     $links['entity.user.field_ui_fields_'] = [
       'title' => t('Manage fields'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'entity.user.field_ui_fields',
       'menu_name' => 'admin',
       'parent' => 'entity.user.admin_form',
     ];
     $links['entity.entity_form_display.user.default_'] = [
       'title' => t('Manage form display'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'entity.entity_form_display.user.default',
       'menu_name' => 'admin',
       'parent' => 'entity.user.admin_form',
     ];
     $links['entity.entity_view_display.user.default_'] = [
       'title' => t('Manage display'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'entity.entity_view_display.user.default',
       'menu_name' => 'admin',
       'parent' => 'entity.user.admin_form',
@@ -231,6 +261,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   foreach (user_roles() as $role) {
     $links['entity.user_role.edit_form.' . $role->id()] = [
       'title' => t($role->label()),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'entity.user_role.edit_form',
       'menu_name' => 'admin',
       'parent' => 'entity.user_role.collection',
@@ -238,6 +269,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     ];
     $links['entity.user_role.edit_permissions_form.' . $role->id()] = [
       'title' => t('Edit permissions'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'entity.user_role.edit_permissions_form',
       'menu_name' => 'admin',
       'parent' => 'entity.user_role.edit_form.' . $role->id(),
@@ -245,6 +277,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     ];
     $links['entity.user_role.delete_form.' . $role->id()] = [
       'title' => t('Delete'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'entity.user_role.delete_form',
       'menu_name' => 'admin',
       'parent' => 'entity.user_role.edit_form.' . $role->id(),
@@ -253,6 +286,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     if ($moduleHandler->moduleExists('devel')) {
       $links['entity.user_role.devel_load.' . $role->id()] = [
         'title' => t('Devel'),
+        'provider' => 'admin_toolbar_tools',
         'route_name' => 'entity.user_role.devel_load',
         'menu_name' => 'admin',
         'parent' => 'entity.user_role.edit_form.' . $role->id(),
@@ -266,6 +300,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     $links['admin_toolbar_tools.add_content']['parent'] = 'system.admin_content';
     $links['node.type_add'] = [
       'title' => t('Add content type'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'node.type_add',
       'menu_name' => 'admin',
       'parent' => 'entity.node_type.collection',
@@ -275,6 +310,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     foreach ($entityTypeManager->getStorage('node_type')->loadMultiple() as $type) {
       $links['node.add.' . $type->id()] = [
         'title' => t($type->label()),
+        'provider' => 'admin_toolbar_tools',
         'route_name' => 'node.add',
         'parent' => 'admin_toolbar_tools.add_content',
         'route_parameters' => ['node_type' => $type->id()],
@@ -285,12 +321,14 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('field_ui')) {
     $links['field_ui.entity_form_mode_add'] = [
       'title' => t('Add new form mode'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'field_ui.entity_form_mode_add',
       'menu_name' => 'admin',
       'parent' => 'entity.entity_form_mode.collection',
     ];
     $links['field_ui.entity_view_mode_add'] = [
       'title' => t('Add new view mode'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'field_ui.entity_view_mode_add',
       'menu_name' => 'admin',
       'parent' => 'entity.entity_view_mode.collection',
@@ -300,6 +338,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('taxonomy')) {
     $links['entity.taxonomy_vocabulary.add_form'] = [
       'title' => t('Add vocabulary'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'entity.taxonomy_vocabulary.add_form',
       'menu_name' => 'admin',
       'parent' => 'entity.taxonomy_vocabulary.collection',
@@ -310,6 +349,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('menu_ui')) {
     $links['entity.menu.add_form'] = [
       'title' => t('Add menu'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'entity.menu.add_form',
       'menu_name' => 'admin',
       'parent' => 'entity.menu.collection',
@@ -319,6 +359,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     foreach (menu_ui_get_menus() as $machine_name => $label) {
       $links['entity.menu.edit_form.' . $machine_name] = [
         'title' => t($label),
+        'provider' => 'admin_toolbar_tools',
         'route_name' => 'entity.menu.edit_form',
         'menu_name' => 'admin',
         'parent' => 'entity.menu.collection',
@@ -326,14 +367,16 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
       ];
       $links['entity.menu.delete_form.' . $machine_name] = [
         'title' => t('Delete'),
+        'provider' => 'admin_toolbar_tools',
         'route_name' => 'entity.menu.delete_form',
         'menu_name' => 'admin',
         'parent' => 'entity.menu.edit_form.' . $machine_name,
         'route_parameters' => ['menu' => $machine_name],
       ];
-      if ($moduleHandler->moduleExists('devel')) {
+      if ($moduleHandler->moduleExists('devel') && $routeExists('entity.menu.devel_load')) {
         $links['entity.menu.devel_load.' . $machine_name] = [
           'title' => t('Devel'),
+          'provider' => 'admin_toolbar_tools',
           'route_name' => 'entity.menu.devel_load',
           'menu_name' => 'admin',
           'parent' => 'entity.menu.edit_form.' . $machine_name,
@@ -342,6 +385,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
       }
       $links['entity.menu.add_link_form.' . $machine_name] = [
         'title' => t('Add link'),
+        'provider' => 'admin_toolbar_tools',
         'route_name' => 'entity.menu.add_link_form',
         'menu_name' => 'admin',
         'parent' => 'entity.menu.edit_form.' . $machine_name,
@@ -354,6 +398,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('block_content')) {
     $links['block_content.add_page'] = [
       'title' => t('Add custom block'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'block_content.add_page',
       'menu_name' => 'admin',
       'parent' => 'block.admin_display',
@@ -361,12 +406,14 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     ];
     $links['entity.block_content.collection'] = [
       'title' => t('Custom block library'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'entity.block_content.collection',
       'menu_name' => 'admin',
       'parent' => 'block.admin_display',
     ];
     $links['entity.block_content_type.collection'] = [
       'title' => t('Types'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'entity.block_content_type.collection',
       'menu_name' => 'admin',
       'parent' => 'block.admin_display',
@@ -377,6 +424,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('contact')) {
     $links['contact.form_add'] = [
       'title' => t('Add contact form'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'contact.form_add',
       'menu_name' => 'admin',
       'parent' => 'entity.contact_form.collection',
@@ -388,12 +436,14 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('update')) {
     $links['update.module_update'] = [
       'title' => t('Update'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'update.module_update',
       'menu_name' => 'admin',
       'parent' => 'system.modules_list',
     ];
     $links['update.module_install'] = [
       'title' => t('Install new module'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'update.module_install',
       'menu_name' => 'admin',
       'parent' => 'system.modules_list',
@@ -404,6 +454,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('devel')) {
     $links['admin_development'] = [
       'title' => t('Development'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'system.admin_config_development',
       'menu_name' => 'admin',
       'parent' => 'admin_toolbar_tools.help',
@@ -411,6 +462,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     ];
     $links['admin_toolbar_tools.devel.admin_settings'] = [
       'title' => t('Devel settings'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'devel.admin_settings',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
@@ -419,6 +471,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     if ($moduleHandler->moduleExists('webprofiler')) {
       $links['admin_toolbar_tools.devel.webprofiler'] = [
         'title' => t('Web Profiler settings'),
+        'provider' => 'admin_toolbar_tools',
         'route_name' => 'webprofiler.settings',
         'menu_name' => 'admin',
         'parent' => 'admin_development',
@@ -426,53 +479,55 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     }
     $links['admin_toolbar_tools.devel.configs_list'] = [
       'title' => t('Config editor'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'devel.configs_list',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
     ];
     $links['admin_toolbar_tools.devel.reinstall'] = [
       'title' => t('Reinstall modules'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'devel.reinstall',
       'parent' => 'admin_development',
     ];
     $links['admin_toolbar_tools.devel.menu_rebuild'] = [
       'title' => t('Rebuild menu'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'devel.menu_rebuild',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
     ];
     $links['admin_toolbar_tools.devel.state_system_page'] = [
       'title' => t('State editor'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'devel.state_system_page',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
     ];
     $links['admin_toolbar_tools.devel.theme_registry'] = [
       'title' => t('Theme registry'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'devel.theme_registry',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
     ];
     $links['admin_toolbar_tools.devel.entity_info_page'] = [
       'title' => t('Entity Info'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'devel.entity_info_page',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
     ];
-    $links['admin_toolbar_tools.devel.execute_php'] = [
-      'title' => t('Execute PHP Code'),
-      'route_name' => 'devel.execute_php',
-      'menu_name' => 'admin',
-      'parent' => 'admin_development',
-    ];
     $links['admin_toolbar_tools.devel.session'] = [
       'title' => t('Session viewer'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'devel.session',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
     ];
     $links['admin_toolbar_tools.devel.elements_page'] = [
       'title' => t('Form API field types'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'devel.elements_page',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
@@ -480,16 +535,35 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     // Menu link for the Toolbar module.
     $links['admin_toolbar_tools.toolbar.settings'] = [
       'title' => t('Toolbar settings'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'devel.toolbar.settings_form',
       'menu_name' => 'admin',
       'parent' => 'devel.admin_settings',
     ];
   }
-
+  // If module Devel PHP is enabled.
+  if ($moduleHandler->moduleExists('devel_php') && $routeExists('devel_php.execute_php')) {
+    $links['admin_toolbar_tools.devel_php.execute_php'] = [
+      'title' => t('Execute PHP Code'),
+      'route_name' => 'devel_php.execute_php',
+      'menu_name' => 'admin',
+      'parent' => 'admin_development',
+    ];
+  }
+  elseif ($moduleHandler->moduleExists('devel') && $routeExists('devel.execute_php')) {
+    $links['admin_toolbar_tools.devel.execute_php'] = [
+      'title' => t('Execute PHP Code'),
+      'provider' => 'admin_toolbar_tools',
+      'route_name' => 'devel.execute_php',
+      'menu_name' => 'admin',
+      'parent' => 'admin_development',
+    ];
+  }
   // If module Views Ui enabled.
   if ($moduleHandler->moduleExists('views_ui')) {
     $links['admin_toolbar_tools.views_ui.add'] = [
       'title' => t('Add new view'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'views_ui.add',
       'menu_name' => 'admin',
       'parent' => 'entity.view.collection',
@@ -497,6 +571,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     ];
     $links['admin_toolbar_tools.views_ui.field_list'] = [
       'title' => t('Used in views'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'views_ui.reports_fields',
       'menu_name' => 'admin',
       'parent' => 'entity.field_storage_config.collection',
@@ -505,6 +580,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
 
   $links['admin_toolbar_tools.system.theme_settings'] = [
     'title' => t('Settings'),
+    'provider' => 'admin_toolbar_tools',
     'route_name' => 'system.theme_settings',
     'menu_name' => 'admin',
     'parent' => 'system.themes_page',
@@ -513,6 +589,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('webprofiler')) {
     $links['admin_toolbar_tools.devel.webprofiler'] = [
       'title' => t('Webprofiler settings'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'webprofiler.settings',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
@@ -522,12 +599,14 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('update')) {
     $links['update.theme_install_'] = [
       'title' => t('Install new theme'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'update.theme_install',
       'menu_name' => 'admin',
       'parent' => 'system.themes_page',
     ];
     $links['update.theme_update_'] = [
       'title' => t('Update'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'update.theme_update',
       'menu_name' => 'admin',
       'parent' => 'system.themes_page',
@@ -537,6 +616,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     foreach ($installed_themes as $key_theme => $label_theme) {
       $links['system.theme_settings_theme.' . $key_theme] = [
         'title' => t($label_theme),
+        'provider' => 'admin_toolbar_tools',
         'route_name' => 'system.theme_settings_theme',
         'menu_name' => 'admin',
         'parent' => 'system.theme_settings_',
@@ -551,6 +631,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('language')) {
     $links['admin_toolbar_tools.language.negotiation'] = [
       'title' => t('Detection and selection'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'language.negotiation',
       'menu_name' => 'admin',
       'parent' => 'entity.configurable_language.collection',
@@ -561,14 +642,16 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('media')) {
     $links['admin_toolbar_tools.add_media'] = [
       'title' => t('Add media'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'entity.media.add_page',
       'menu_name' => 'admin',
       'parent' => 'system.admin_content',
     ];
     // Add node links for each media type.
-    foreach (\Drupal::entityTypeManager()->getStorage('media_type')->loadMultiple() as $type) {
+    foreach ($entityTypeManager->getStorage('media_type')->loadMultiple() as $type) {
       $links['media.add.' . $type->id()] = [
         'title' => t($type->label()),
+        'provider' => 'admin_toolbar_tools',
         'route_name' => 'entity.media.add_form',
         'parent' => 'admin_toolbar_tools.add_media',
         'route_parameters' => ['media_type' => $type->id()],
@@ -580,6 +663,7 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   if ($moduleHandler->moduleExists('config')) {
     $links['admin_toolbar_tools.config.import'] = [
       'title' => t('Import'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'config.import_full',
       'menu_name' => 'admin',
       'parent' => 'config.sync',
@@ -587,12 +671,15 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
     ];
     $links['admin_toolbar_tools.config.export'] = [
       'title' => t('Export'),
+      'provider' => 'admin_toolbar_tools',
       'route_name' => 'config.export_full',
       'menu_name' => 'admin',
       'parent' => 'config.sync',
       'weight' => 2,
     ];
   }
+
+  $languageManager->setConfigOverrideLanguage($config_override_language);
 }
 
 /**
@@ -613,20 +700,3 @@ function admin_toolbar_tools_installed_themes() {
 
   return $themes_installed;
 }
-
-/**
- * Get all links related to entity.
- *
- * @param string $entity_type_id
- *   The machine name for the entity type.
- *
- * @return array
- *   The links for the entity type.
- */
-function admin_toolbar_tools_get_links($entity_type_id) {
-  $entity = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
-  // Get all links related to entity.
-  $links = $entity->getLinkTemplates();
-
-  return $links;
-}

+ 1 - 1
sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/composer.json

@@ -34,6 +34,6 @@
   },
   "require": {
     "drupal/admin_toolbar": "^1",
-    "drupal/core": "~8.3"
+    "drupal/core": "~8.5"
   }
 }

+ 9 - 9
sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/Controller/ToolbarController.php

@@ -162,8 +162,8 @@ class ToolbarController extends ControllerBase {
    * Flushes all caches.
    */
   public function flushAll() {
+    $this->messenger()->addMessage($this->t('All caches cleared.'));
     drupal_flush_all_caches();
-    drupal_set_message($this->t('All caches cleared.'));
     return new RedirectResponse($this->reloadPage());
   }
 
@@ -173,7 +173,7 @@ class ToolbarController extends ControllerBase {
   public function flushJsCss() {
     $this->state()
       ->set('system.css_js_query_string', base_convert($this->time->getCurrentTime(), 10, 36));
-    drupal_set_message($this->t('CSS and JavaScript cache cleared.'));
+    $this->messenger()->addMessage($this->t('CSS and JavaScript cache cleared.'));
     return new RedirectResponse($this->reloadPage());
   }
 
@@ -182,7 +182,7 @@ class ToolbarController extends ControllerBase {
    */
   public function flushPlugins() {
     $this->pluginCacheClearer->clearCachedDefinitions();
-    drupal_set_message($this->t('Plugins cache cleared.'));
+    $this->messenger()->addMessage($this->t('Plugins cache cleared.'));
     return new RedirectResponse($this->reloadPage());
   }
 
@@ -191,7 +191,7 @@ class ToolbarController extends ControllerBase {
    */
   public function flushStatic() {
     drupal_static_reset();
-    drupal_set_message($this->t('Static cache cleared.'));
+    $this->messenger()->addMessage($this->t('Static cache cleared.'));
     return new RedirectResponse($this->reloadPage());
   }
 
@@ -204,7 +204,7 @@ class ToolbarController extends ControllerBase {
     $this->contextualLinkManager->clearCachedDefinitions();
     $this->localTaskLinkManager->clearCachedDefinitions();
     $this->localActionLinkManager->clearCachedDefinitions();
-    drupal_set_message($this->t('Routing and links cache cleared.'));
+    $this->messenger()->addMessage($this->t('Routing and links cache cleared.'));
     return new RedirectResponse($this->reloadPage());
   }
 
@@ -213,7 +213,7 @@ class ToolbarController extends ControllerBase {
    */
   public function flushViews() {
     views_invalidate_cache();
-    drupal_set_message($this->t('Views cache cleared.'));
+    $this->messenger()->addMessage($this->t('Views cache cleared.'));
     return new RedirectResponse($this->reloadPage());
   }
 
@@ -224,7 +224,7 @@ class ToolbarController extends ControllerBase {
     // @todo Update once Drupal 8.6 will be released.
     // @see https://www.drupal.org/node/2908461
     PhpStorageFactory::get('twig')->deleteAll();
-    drupal_set_message($this->t('Twig cache cleared.'));
+    $this->messenger()->addMessage($this->t('Twig cache cleared.'));
     return new RedirectResponse($this->reloadPage());
   }
 
@@ -233,7 +233,7 @@ class ToolbarController extends ControllerBase {
    */
   public function runCron() {
     $this->cron->run();
-    drupal_set_message($this->t('Cron ran successfully.'));
+    $this->messenger()->addMessage($this->t('Cron ran successfully.'));
     return new RedirectResponse($this->reloadPage());
   }
 
@@ -242,7 +242,7 @@ class ToolbarController extends ControllerBase {
    */
   public function cacheRender() {
     $this->cacheRender->invalidateAll();
-    drupal_set_message($this->t('Render cache cleared.'));
+    $this->messenger()->addMessage($this->t('Render cache cleared.'));
     return new RedirectResponse($this->reloadPage());
   }
 

+ 3 - 3
sites/all/modules/contrib/admin/config_update/config_update.info.yml

@@ -5,8 +5,8 @@ description: 'Provides basic revert and update functionality for other modules'
 dependencies:
   - drupal:config
 
-# Information added by Drupal.org packaging script on 2017-12-05
-version: '8.x-1.5'
+# Information added by Drupal.org packaging script on 2018-12-17
+version: '8.x-1.6'
 core: '8.x'
 project: 'config_update'
-datestamp: 1512514387
+datestamp: 1545090489

+ 6 - 1
sites/all/modules/contrib/admin/config_update/config_update_ui/config_update_ui.drush.inc

@@ -285,8 +285,13 @@ function drush_config_update_ui_config_revert($name) {
 
   // The revert command needs the type and the unprefixed name.
   $type = $lister->getTypeNameByConfigName($name);
+  // The lister gives NULL if simple configuration, but the reverter expects
+  // 'system.simple' so we convert it.
+  if ($type === NULL) {
+    $type = 'system.simple';
+  }
   $shortname = $name;
-  if ($type && $type != 'system.simple') {
+  if ($type != 'system.simple') {
     $definition = $manager->getDefinition($type);
     $prefix = $definition->getConfigPrefix() . '.';
     if (strpos($name, $prefix) === 0) {

+ 3 - 3
sites/all/modules/contrib/admin/config_update/config_update_ui/config_update_ui.info.yml

@@ -7,8 +7,8 @@ dependencies:
   - config_update:config_update
   - drupal:config
 
-# Information added by Drupal.org packaging script on 2017-12-05
-version: '8.x-1.5'
+# Information added by Drupal.org packaging script on 2018-12-17
+version: '8.x-1.6'
 core: '8.x'
 project: 'config_update'
-datestamp: 1512514387
+datestamp: 1545090489

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
sites/all/modules/contrib/admin/config_update/config_update_ui/config_update_ui.module


+ 1 - 1
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());
   }
 

+ 1 - 1
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());
   }
 

+ 1 - 1
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());
   }
 

+ 14 - 10
sites/all/modules/contrib/admin/config_update/config_update_ui/src/Tests/ConfigProfileOverridesTest.php → sites/all/modules/contrib/admin/config_update/config_update_ui/tests/src/Functional/ConfigProfileOverridesTest.php

@@ -1,15 +1,15 @@
 <?php
 
-namespace Drupal\config_update_ui\Tests;
+namespace Drupal\Tests\config_update_ui\Functional;
 
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Verify config reports, reverts, and diffs with profile overrides.
  *
- * @group config
+ * @group config_update
  */
-class ConfigProfileOverridesTest extends WebTestBase {
+class ConfigProfileOverridesTest extends BrowserTestBase {
 
   /**
    * Use the Standard profile, so that there are profile config overrides.
@@ -43,7 +43,7 @@ class ConfigProfileOverridesTest extends WebTestBase {
     parent::setUp();
 
     // Create user and log in.
-    $this->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');
   }
 
 }

+ 121 - 98
sites/all/modules/contrib/admin/config_update/config_update_ui/src/Tests/ConfigUpdateTest.php → sites/all/modules/contrib/admin/config_update/config_update_ui/tests/src/Functional/ConfigUpdateTest.php

@@ -1,15 +1,15 @@
 <?php
 
-namespace Drupal\config_update_ui\Tests;
+namespace Drupal\Tests\config_update_ui\Functional;
 
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Verify the config revert report and its links.
  *
- * @group config
+ * @group config_update
  */
-class ConfigUpdateTest extends WebTestBase {
+class ConfigUpdateTest extends BrowserTestBase {
 
   /**
    * Modules to enable.
@@ -46,7 +46,7 @@ class ConfigUpdateTest extends WebTestBase {
     parent::setUp();
 
     // Create user and log in.
-    $this->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');
-
-    // Grab the uuid and hash lines for the next test.
-    $text = $this->getTextContent();
+    $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 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');
   }
 
 }

+ 37 - 0
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

+ 29 - 18
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);
       }
     }
 

+ 1 - 1
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;

+ 1 - 1
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);
 

+ 54 - 27
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;
+    }
   }
 
 }

+ 79 - 25
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' => [
+            '_core' => 'do-not-use-this-key',
+            'd' => TRUE,
             'e' => FALSE,
-            '_core' => 'foo',
+            'empty' => [],
+          ],
+        ],
+        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' => [],
           ],
         ],
-        TRUE,
+        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',
           ],
         ],

+ 173 - 145
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();
 
-  /**
-   * 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'],
-    ];
+    $lister->method('getProfileName')
+      ->willReturn('standard');
 
-    $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;
+    $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));
 
-    $manager = $this->getMockBuilder('Drupal\Core\Entity\EntityTypeManagerInterface')->getMock();
-    $manager
-      ->method('getDefinitions')
-      ->willReturn($definitions);
-
-    return($manager);
+    $this->configLister = $lister;
   }
 
   /**
-   * 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;
+  }
+
 }

+ 356 - 0
sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigReverterTest.php

@@ -0,0 +1,356 @@
+<?php
+
+namespace Drupal\Tests\config_update\Unit;
+
+use Drupal\config_update\ConfigReverter;
+use Drupal\config_update\ConfigRevertInterface;
+use Drupal\config_update\ConfigDeleteInterface;
+
+/**
+ * Tests the \Drupal\config_update\ConfigReverter class.
+ *
+ * @group config_update
+ *
+ * @coversDefaultClass \Drupal\config_update\ConfigReverter
+ */
+class ConfigReverterTest extends ConfigUpdateUnitTestBase {
+
+  /**
+   * The config reverter to test.
+   *
+   * @var \Drupal\config_update\ConfigReverter
+   */
+  protected $configReverter;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->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,
+      ],
+    ];
+  }
+
+}

+ 547 - 0
sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigUpdateUnitTestBase.php

@@ -0,0 +1,547 @@
+<?php
+
+namespace Drupal\Tests\config_update\Unit;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Base class for unit testing in Config Update Manager.
+ *
+ * This class provides some mock classes for unit testing.
+ */
+abstract class ConfigUpdateUnitTestBase extends UnitTestCase {
+
+  /**
+   * The mocked entity definition information.
+   *
+   * They are not sorted, to test that the methods sort them. Also there are a
+   * couple with prefixes that are subsets of each other.
+   *
+   * @var string[]
+   *
+   * @see ConfigUpdateUnitTestBase::getEntityManagerMock().
+   */
+  protected $entityDefinitionInformation = [
+    ['prefix' => '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;
+  }
+
+}

+ 12 - 20
sites/all/modules/contrib/admin/domain/.travis.yml

@@ -4,22 +4,14 @@ 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
-      php: 7.1
-    - env: DRUPAL=8.5.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
       php: 7.1
     - env: DRUPAL=8.6.x
       php: 7.2
+    - env: DRUPAL=8.7.x
+      php: 7.1
+    - env: DRUPAL=8.7.x
+      php: 7.2
 
 addons:
   hosts:
@@ -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

+ 2 - 1
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

+ 2 - 11
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 [![Build Status](https://travis-ci.com/agentrickard/domain.svg?branch=8.x-1.x)](https://travis-ci.com/agentrickard/domain)
 ====
 
 @zerolab built a Travis definition file for automated testing! That means all pull requests will automatically run tests!
 
-[![Build Status](https://travis-ci.org/agentrickard/domain.svg?branch=8.x-1.x)](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.

+ 9 - 0
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"
+      }
+    }
   }
 }

+ 3 - 3
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

+ 16 - 0
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;
+}

+ 5 - 0
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 }

+ 3 - 3
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']);
     }
   }
 

+ 10 - 0
sites/all/modules/contrib/admin/domain/domain/src/Commands/DomainCommandException.php

@@ -0,0 +1,10 @@
+<?php
+/**
+ *
+ */
+
+namespace Drupal\domain\Commands;
+
+class DomainCommandException extends \Exception {
+
+}

+ 1368 - 0
sites/all/modules/contrib/admin/domain/domain/src/Commands/DomainCommands.php

@@ -0,0 +1,1368 @@
+<?php
+
+namespace Drupal\domain\Commands;
+
+use Consolidation\AnnotatedCommand\Events\CustomEventAwareInterface;
+use Consolidation\AnnotatedCommand\Events\CustomEventAwareTrait;
+use Consolidation\OutputFormatters\StructuredData\PropertyList;
+use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
+use Drupal\Core\Config\StorageException;
+use Drupal\Core\Entity\EntityStorageException;
+use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
+use Drupal\Component\Plugin\Exception\PluginException;
+use Drupal\Component\Plugin\Exception\PluginNotFoundException;
+use Drupal\Component\Utility\Html;
+use Drupal\domain\DomainInterface;
+use Drupal\domain\DomainStorageInterface;
+use Drush\Commands\DrushCommands;
+use Symfony\Component\Console\Input\InputOption;
+
+/**
+ * Drush commands for the domain module.
+ */
+class DomainCommands extends DrushCommands implements CustomEventAwareInterface {
+
+  use CustomEventAwareTrait;
+
+  /**
+   * The domain entity storage service.
+   *
+   * @var \Drupal\domain\DomainStorageInterface $domain_storage
+   */
+  protected $domain_storage = NULL;
+
+  /**
+   * Local cache of entity field map, kept for performance.
+   *
+   * @var array
+   */
+  protected $entity_field_map = NULL;
+
+  /**
+   * Flag set by the --dryrun cli option. If set prevents changes from
+   * being made by code in this class.
+   *
+   * @var bool
+   */
+  protected $is_dry_run = FALSE;
+
+  /**
+   * Static array of special-case policies for reassigning field data.
+   *
+   * @var string[]
+   * */
+  protected $reassignment_policies = ['prompt', 'default', 'ignore'];
+
+  /**
+   * List active domains for the site.
+   *
+   * @option inactive
+   *   Show only the domains that are inactive/disabled.
+   * @option active
+   *   Show only the domains that are active/enabled.
+   * @usage drush domain:list
+   *   List active domains for the site.
+   * @usage drush domains
+   *   List active domains for the site.
+   *
+   * @command domain:list
+   * @aliases domains,domain-list
+   *
+   * @field-labels
+   *   weight: Weight
+   *   name: Name
+   *   hostname: Hostname
+   *   response: HTTP Response
+   *   scheme: Scheme
+   *   status: Status
+   *   is_default: Default
+   *   domain_id: Domain Id
+   *   id: Machine name
+   * @default-fields id,name,hostname,scheme,status,is_default,response
+   *
+   * @param array $options
+   *
+   * @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
+   *
+   * @throws \Drupal\domain\Commands\DomainCommandException
+   */
+  public function listDomains(array $options) {
+    // Load all domains:
+    $domains = $this->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", <name>, Reassign user accounts
+   *   associated with the the domain being deleted to the default domain,
+   *   to the domain whose machine name is <name>, 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;
+  }
+
+}

+ 12 - 2
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.

+ 20 - 14
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;
+  }
+
 }

+ 1 - 2
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());

+ 2 - 2
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.

+ 7 - 2
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;
   }
 
   /**

+ 3 - 3
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

+ 3 - 3
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

+ 3 - 3
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

+ 5 - 0
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 }

+ 79 - 0
sites/all/modules/contrib/admin/domain/domain_access/src/Commands/DomainAccessCommands.php

@@ -0,0 +1,79 @@
+<?php
+
+namespace Drupal\domain_access\Commands;
+
+use Consolidation\AnnotatedCommand\AnnotationData;
+use Consolidation\AnnotatedCommand\CommandData;
+use Drupal\domain\Commands\DomainCommands;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+
+/**
+ * Drush commands for the domain access module.
+ *
+ * These commands mainly extend base Domain commands. See the documentation at
+ * https://github.com/consolidation/annotated-command for details.
+ */
+class DomainAccessCommands extends DomainCommands {
+
+  /**
+   * Registers additional information to domain:info.
+   *
+   * @hook init domain:info
+   */
+  public function initDomainInfo(InputInterface $input, AnnotationData $annotationData) {
+    // To add a field label, append to the 'field-labels' item.
+    // @TODO: watch https://github.com/consolidation/annotated-command/pull/174
+    $annotationData['field-labels'] .= "\n" . 'domain_access_entities: Domain access entities';
+  }
+
+  /**
+   * Provides additional information to domain:info.
+   *
+   * @hook alter domain:info
+   */
+  public function alterDomainInfo($result, CommandData $commandData) {
+    // Display which entities are enabled for domain by checking for the fields.
+    $result['domain_access_entities'] = $this->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);
+  }
+
+}

+ 3 - 3
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

+ 3 - 3
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

+ 3 - 3
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

+ 1 - 1
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

+ 22 - 5
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();
     }
+
   }
 
 }

+ 24 - 0
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

+ 23 - 0
sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/domain_config_hook_test.module

@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * @file
+ * Hook implementations for this module.
+ */
+
+/**
+ * Implements hook_user_login().
+ */
+function domain_config_hook_test_user_login($account) {
+  \Drupal::state()->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']);
+  }
+}

+ 7 - 0
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 }
+

+ 47 - 0
sites/all/modules/contrib/admin/domain/domain_config/tests/modules/domain_config_hook_test/src/PageCache/RequestPolicy/PageCacheRequestPolicy.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\domain_config_hook_test\PageCache\RequestPolicy;
+
+use Drupal\Core\Config\ConfigFactory;
+use Drupal\Core\PageCache\RequestPolicyInterface;
+use Drupal\Core\Session\SessionConfigurationInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * A page cache request policy.
+ *
+ * This service is not meant to DO anything, it's just meant to represent
+ * a service that might be present in the Drupal community. For example,
+ * persistent_login module has this same structure.
+ */
+class PageCacheRequestPolicy implements RequestPolicyInterface {
+
+  /**
+   * Drupal config factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactory
+   */
+  protected $configFactory;
+
+  /**
+   * Constructor.
+   *
+   * @param \Drupal\Core\Config\ConfigFactory $config_factory
+   *   Drupal config factory.
+   */
+  public function __construct(ConfigFactory $config_factory) {
+    $this->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;
+  }
+
+}

+ 3 - 3
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

+ 3 - 3
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

+ 30 - 0
sites/all/modules/contrib/admin/domain/domain_config/tests/src/Functional/DomainConfigHookProblemTest.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace Drupal\Tests\domain_config\Functional;
+
+/**
+ * Tests the domain config system.
+ *
+ * @group domain_config
+ */
+class DomainConfigHookProblemTest extends DomainConfigHookTest {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    // Adds the domain_config module.
+    'domain_config',
+  ];
+
+  /**
+   * Disabled config schema checking.
+   *
+   * Domain Config actually duplicates schemas provided by other modules,
+   * so it cannot define its own.
+   *
+   * @var bool
+   */
+  protected $strictConfigSchema = FALSE;
+
+}

+ 42 - 0
sites/all/modules/contrib/admin/domain/domain_config/tests/src/Functional/DomainConfigHookTest.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace Drupal\Tests\domain_config\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests the domain config system.
+ *
+ * @group domain_config
+ */
+class DomainConfigHookTest extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'domain',
+    // See module info file for description of what this module does.
+    'domain_config_hook_test',
+  ];
+
+  /**
+   * Test to ensure a domain_config_hook_test_user_login() does not run.
+   *
+   * This test serves as a control to show the domain_config_hook_test module
+   * functions correctly on it's own. Only when you add the domain_config
+   * module, does it fail.
+   */
+  public function testHookRuns() {
+    $this->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.');
+  }
+
+}

+ 3 - 3
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

+ 1 - 1
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.

+ 3 - 3
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

+ 14 - 0
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;
+}

+ 5 - 0
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 }

+ 79 - 0
sites/all/modules/contrib/admin/domain/domain_source/src/Commands/DomainSourceCommands.php

@@ -0,0 +1,79 @@
+<?php
+
+namespace Drupal\domain_source\Commands;
+
+use Consolidation\AnnotatedCommand\AnnotationData;
+use Consolidation\AnnotatedCommand\CommandData;
+use Drupal\domain\Commands\DomainCommands;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+
+/**
+ * Drush commands for the domain source module.
+ *
+ * These commands mainly extend base Domain commands. See the documentation at
+ * https://github.com/consolidation/annotated-command for details.
+ */
+class DomainSourceCommands extends DomainCommands {
+
+  /**
+   * Registers additional information to domain:info.
+   *
+   * @hook init domain:info
+   */
+  public function initDomainInfo(InputInterface $input, AnnotationData $annotationData) {
+    // To add a field label, append to the 'field-labels' item.
+    // @TODO: watch https://github.com/consolidation/annotated-command/pull/174
+    $annotationData['field-labels'] .= "\n" . 'domain_source_entities: Domain source entities';
+  }
+
+  /**
+   * Provides additional information to domain:info.
+   *
+   * @hook alter domain:info
+   */
+  public function alterDomainInfo($result, CommandData $commandData) {
+    // Display which entities are enabled for domain by checking for the fields.
+    $result['domain_source_entities'] = $this->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);
+  }
+
+}

+ 16 - 4
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;
+  }
+
 }

+ 3 - 3
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

+ 40 - 0
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);
+  }
+
 }

+ 0 - 58
sites/all/modules/contrib/admin/domain_site_settings/domain_site_settings-circular_dependency-2930391-7.patch

@@ -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');

+ 5 - 5
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

+ 0 - 1
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
-

+ 1 - 1
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}

+ 18 - 7
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,
+            ],
           ];
         }
       }

+ 9 - 9
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;
   }
 

+ 21 - 24
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 <em>From</em> 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);

+ 4 - 4
sites/all/modules/contrib/admin/matomo/README.txt

@@ -1,6 +1,6 @@
 
 Module: Matomo Analytics
-Author: Alexander Hass <http://drupal.org/user/85918>
+Author: Alexander Hass <https://drupal.org/user/85918>
 
 
 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.
 

+ 4 - 2
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"  
+  }
 }

+ 5 - 3
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

+ 2 - 1
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');
   }
 }
 

+ 10 - 13
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 <http://drupal.org/user/85918>
+ * @author: Alexander Hass <https://drupal.org/user/85918>
  */
 
 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('<a href=":pk_url">Matomo Analytics</a> 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('<a href=":pk_url">Matomo Analytics</a> 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);
   }
 }
 

+ 0 - 0
sites/all/modules/contrib/admin/matomo/migration_templates/d6_matomo_settings.yml → sites/all/modules/contrib/admin/matomo/migrations/d6_matomo_settings.yml


+ 0 - 0
sites/all/modules/contrib/admin/matomo/migration_templates/d6_matomo_user_settings.yml → sites/all/modules/contrib/admin/matomo/migrations/d6_matomo_user_settings.yml


+ 0 - 0
sites/all/modules/contrib/admin/matomo/migration_templates/d7_matomo_settings.yml → sites/all/modules/contrib/admin/matomo/migrations/d7_matomo_settings.yml


+ 0 - 0
sites/all/modules/contrib/admin/matomo/migration_templates/d7_matomo_user_settings.yml → sites/all/modules/contrib/admin/matomo/migrations/d7_matomo_user_settings.yml


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 31 - 10
sites/all/modules/contrib/admin/matomo/src/Form/MatomoAdminSettingsForm.php


+ 15 - 0
sites/all/modules/contrib/admin/matomo/src/MatomoInterface.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace Drupal\matomo;
+
+/**
+ * Provides an interface.
+ */
+interface MatomoInterface {
+
+  /**
+   * Define the default file extension list that should be tracked as download.
+   */
+  const 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';
+
+}

+ 0 - 1
sites/all/modules/contrib/admin/matomo/src/Tests/MatomoSearchTest.php

@@ -63,7 +63,6 @@ class MatomoSearchTest extends WebTestBase {
     $search['keys'] = $this->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.';

+ 5 - 1
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.');

+ 3 - 3
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

+ 4 - 4
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 <em>message</em> with html tags and <a href="http://example.com/">link</a>.'), '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 <em>message</em> with html tags and <a href="https://example.com/">link</a>.'), 'error');
 
     return [];
   }

+ 8 - 5
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 <em>about-us/edit</em> for <em>node/123/edit</em>.<br> Allow these aliases to be entered in page specification wild-cards, <em>about-us*</em>, e.g for block visibility.'
+
+type: module
 # core: 8.x
-configure: path_alias_xt.settings_form
+
 dependencies:
-  - path
+  - drupal:path
+
+configure: path_alias_xt.settings_form
 
-# Information added by Drupal.org packaging script on 2017-07-14
+# 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

+ 1 - 1
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;
         }
       }

+ 59 - 1
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 <front> 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

+ 1 - 1
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'

+ 3 - 3
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

+ 2 - 3
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;
         }
       }

+ 1 - 1
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.

+ 15 - 14
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'];

+ 15 - 14
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 نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است