فهرست منبع

updated contrib modules

Bachir Soussi Chiadmi 6 سال پیش
والد
کامیت
b32fe9ef14
100فایلهای تغییر یافته به همراه3456 افزوده شده و 682 حذف شده
  1. 3 3
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.info.yml
  2. 1 0
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.libraries.yml
  3. 1 1
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.module
  4. 3 3
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.info.yml
  5. 161 144
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.module
  6. 8 3
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/Controller/ToolbarController.php
  7. 1 0
      sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/Tests/AdminToolbarToolsAlterTest.php
  8. 15 12
      sites/all/modules/contrib/admin/admin_toolbar/css/admin.toolbar.css
  9. 15 2
      sites/all/modules/contrib/admin/admin_toolbar/js/admin_toolbar.js
  10. 158 0
      sites/all/modules/contrib/admin/admin_toolbar/js/jquery.hoverIntent.js
  11. 4 4
      sites/all/modules/contrib/admin/config_update/README.txt
  12. 3 3
      sites/all/modules/contrib/admin/config_update/config_update.info.yml
  13. 17 2
      sites/all/modules/contrib/admin/config_update/config_update_ui/config_update_ui.drush_testing.inc
  14. 3 3
      sites/all/modules/contrib/admin/config_update/config_update_ui/config_update_ui.info.yml
  15. 1 1
      sites/all/modules/contrib/admin/config_update/config_update_ui/config_update_ui.module
  16. 62 16
      sites/all/modules/contrib/admin/config_update/config_update_ui/src/Controller/ConfigUpdateController.php
  17. 97 0
      sites/all/modules/contrib/admin/config_update/config_update_ui/src/Tests/ConfigProfileOverridesTest.php
  18. 40 11
      sites/all/modules/contrib/admin/config_update/config_update_ui/src/Tests/ConfigUpdateTest.php
  19. 4 4
      sites/all/modules/contrib/admin/config_update/src/ConfigDiffInterface.php
  20. 8 8
      sites/all/modules/contrib/admin/config_update/src/ConfigDiffer.php
  21. 23 1
      sites/all/modules/contrib/admin/config_update/src/ConfigLister.php
  22. 3 7
      sites/all/modules/contrib/admin/config_update/src/ConfigListerWithProviders.php
  23. 308 0
      sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigDifferTest.php
  24. 0 0
      sites/all/modules/contrib/dev/config_devel/LICENSE.txt
  25. 8 0
      sites/all/modules/contrib/dev/config_devel/composer.json
  26. 2 0
      sites/all/modules/contrib/dev/config_devel/config/install/config_devel.settings.yml
  27. 23 0
      sites/all/modules/contrib/dev/config_devel/config/schema/config_devel.schema.yml
  28. 13 0
      sites/all/modules/contrib/dev/config_devel/config_devel.info.yml
  29. 5 0
      sites/all/modules/contrib/dev/config_devel/config_devel.links.menu.yml
  30. 7 0
      sites/all/modules/contrib/dev/config_devel/config_devel.routing.yml
  31. 11 0
      sites/all/modules/contrib/dev/config_devel/config_devel.services.yml
  32. 246 0
      sites/all/modules/contrib/dev/config_devel/drush/config_devel.drush.inc
  33. 26 0
      sites/all/modules/contrib/dev/config_devel/src/Event/ConfigDevelEvents.php
  34. 79 0
      sites/all/modules/contrib/dev/config_devel/src/Event/ConfigDevelSaveEvent.php
  35. 136 0
      sites/all/modules/contrib/dev/config_devel/src/EventSubscriber/ConfigDevelAutoExportSubscriber.php
  36. 83 0
      sites/all/modules/contrib/dev/config_devel/src/EventSubscriber/ConfigDevelAutoImportSubscriber.php
  37. 66 0
      sites/all/modules/contrib/dev/config_devel/src/EventSubscriber/ConfigDevelSubscriberBase.php
  38. 100 0
      sites/all/modules/contrib/dev/config_devel/src/Form/ConfigDevelSettingsForm.php
  39. 32 0
      sites/all/modules/contrib/dev/config_devel/tests/src/Kernel/ConfigDevelSubscriberEntityTest.php
  40. 25 0
      sites/all/modules/contrib/dev/config_devel/tests/src/Kernel/ConfigDevelSubscriberRawTest.php
  41. 65 0
      sites/all/modules/contrib/dev/config_devel/tests/src/Kernel/ConfigDevelSubscriberTestBase.php
  42. 53 0
      sites/all/modules/contrib/dev/config_devel/tests/src/Unit/ConfigDevelAutoExportSubscriberTest.php
  43. 44 0
      sites/all/modules/contrib/dev/config_devel/tests/src/Unit/ConfigDevelTestBase.php
  44. 3 3
      sites/all/modules/contrib/dev/devel/devel.info.yml
  45. 3 3
      sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.info.yml
  46. 2 1
      sites/all/modules/contrib/dev/devel/devel_generate/src/Commands/DevelGenerateCommands.php
  47. 4 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/DevelGenerateBase.php
  48. 9 9
      sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/ContentDevelGenerate.php
  49. 16 18
      sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/MenuDevelGenerate.php
  50. 5 14
      sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/TermDevelGenerate.php
  51. 17 4
      sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/UserDevelGenerate.php
  52. 3 3
      sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/VocabularyDevelGenerate.php
  53. 3 3
      sites/all/modules/contrib/dev/devel/devel_generate/tests/modules/devel_generate_example/devel_generate_example.info.yml
  54. 1 1
      sites/all/modules/contrib/dev/devel/drush.services.yml
  55. 3 3
      sites/all/modules/contrib/dev/devel/kint/kint.info.yml
  56. 71 41
      sites/all/modules/contrib/dev/devel/src/Commands/DevelCommands.php
  57. 3 3
      sites/all/modules/contrib/dev/devel/tests/modules/devel_dumper_test/devel_dumper_test.info.yml
  58. 3 3
      sites/all/modules/contrib/dev/devel/tests/modules/devel_entity_test/devel_entity_test.info.yml
  59. 3 3
      sites/all/modules/contrib/dev/devel/tests/modules/devel_test/devel_test.info.yml
  60. 10 10
      sites/all/modules/contrib/dev/devel/tests/src/Functional/DevelControllerTest.php
  61. 33 27
      sites/all/modules/contrib/dev/devel/tests/src/Functional/DevelDumperTest.php
  62. 3 3
      sites/all/modules/contrib/dev/devel/tests/src/Functional/DevelMenuLinksTest.php
  63. 8 8
      sites/all/modules/contrib/dev/devel/tests/src/Functional/DevelModulesReinstallTest.php
  64. 6 6
      sites/all/modules/contrib/dev/devel/tests/src/Functional/DevelSwitchUserTest.php
  65. 6 3
      sites/all/modules/contrib/dev/devel/webprofiler/src/DataCollector/DatabaseDataCollector.php
  66. 7 0
      sites/all/modules/contrib/dev/devel/webprofiler/src/Entity/Decorators/Config/ConfigEntityStorageDecorator.php
  67. 28 30
      sites/all/modules/contrib/dev/devel/webprofiler/src/EventDispatcher/TraceableEventDispatcher.php
  68. 1 1
      sites/all/modules/contrib/dev/devel/webprofiler/src/Form/ConfigForm.php
  69. 1 1
      sites/all/modules/contrib/dev/devel/webprofiler/src/Views/TraceableViewExecutable.php
  70. 3 3
      sites/all/modules/contrib/dev/devel/webprofiler/webprofiler.info.yml
  71. 1 1
      sites/all/modules/contrib/dev/entity/.travis.yml
  72. 1 1
      sites/all/modules/contrib/dev/entity/composer.json
  73. 4 4
      sites/all/modules/contrib/dev/entity/entity.info.yml
  74. 82 0
      sites/all/modules/contrib/dev/entity/entity.module
  75. 11 1
      sites/all/modules/contrib/dev/entity/entity.services.yml
  76. 1 1
      sites/all/modules/contrib/dev/entity/entity.views.inc
  77. 19 16
      sites/all/modules/contrib/dev/entity/src/Access/EntityRevisionRouteAccessChecker.php
  78. 27 0
      sites/all/modules/contrib/dev/entity/src/BundleFieldDefinition.php
  79. 102 0
      sites/all/modules/contrib/dev/entity/src/BundlePlugin/BundlePluginHandler.php
  80. 37 0
      sites/all/modules/contrib/dev/entity/src/BundlePlugin/BundlePluginHandlerInterface.php
  81. 94 0
      sites/all/modules/contrib/dev/entity/src/BundlePlugin/BundlePluginInstaller.php
  82. 34 0
      sites/all/modules/contrib/dev/entity/src/BundlePlugin/BundlePluginInstallerInterface.php
  83. 24 0
      sites/all/modules/contrib/dev/entity/src/BundlePlugin/BundlePluginInterface.php
  84. 76 0
      sites/all/modules/contrib/dev/entity/src/BundlePlugin/BundlePluginUninstallValidator.php
  85. 0 1
      sites/all/modules/contrib/dev/entity/src/Controller/RevisionOverviewController.php
  86. 57 19
      sites/all/modules/contrib/dev/entity/src/EntityAccessControlHandler.php
  87. 21 202
      sites/all/modules/contrib/dev/entity/src/EntityPermissionProvider.php
  88. 231 0
      sites/all/modules/contrib/dev/entity/src/EntityPermissionProviderBase.php
  89. 1 0
      sites/all/modules/contrib/dev/entity/src/EntityPermissions.php
  90. 1 1
      sites/all/modules/contrib/dev/entity/src/Plugin/Action/Derivative/DeleteActionDeriver.php
  91. 3 2
      sites/all/modules/contrib/dev/entity/src/Plugin/Derivative/RevisionsOverviewDeriver.php
  92. 0 1
      sites/all/modules/contrib/dev/entity/src/Revision/RevisionableContentEntityBase.php
  93. 138 0
      sites/all/modules/contrib/dev/entity/src/UncacheableEntityAccessControlHandler.php
  94. 143 0
      sites/all/modules/contrib/dev/entity/src/UncacheableEntityPermissionProvider.php
  95. 13 0
      sites/all/modules/contrib/dev/entity/tests/modules/entity_module_bundle_plugin_examples_test/entity_module_bundle_plugin_examples_test.info.yml
  96. 31 0
      sites/all/modules/contrib/dev/entity/tests/modules/entity_module_bundle_plugin_examples_test/src/Plugin/BundlePluginTest/Second.php
  97. 13 0
      sites/all/modules/contrib/dev/entity/tests/modules/entity_module_bundle_plugin_test/entity_module_bundle_plugin_test.info.yml
  98. 4 0
      sites/all/modules/contrib/dev/entity/tests/modules/entity_module_bundle_plugin_test/entity_module_bundle_plugin_test.services.yml
  99. 34 0
      sites/all/modules/contrib/dev/entity/tests/modules/entity_module_bundle_plugin_test/src/Annotation/BundlePluginTest.php
  100. 35 0
      sites/all/modules/contrib/dev/entity/tests/modules/entity_module_bundle_plugin_test/src/BundlePluginTestManager.php

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

@@ -6,8 +6,8 @@ type: module
 dependencies:
   - toolbar
 
-# Information added by Drupal.org packaging script on 2017-04-06
-version: '8.x-1.19'
+# Information added by Drupal.org packaging script on 2017-09-12
+version: '8.x-1.20'
 core: '8.x'
 project: 'admin_toolbar'
-datestamp: 1491487686
+datestamp: 1505199847

+ 1 - 0
sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.libraries.yml

@@ -3,6 +3,7 @@ toolbar.tree:
     theme:
       css/admin.toolbar.css: {}
   js:
+    js/jquery.hoverIntent.js: {}
     js/admin_toolbar.js: {}
   dependencies:
     - core/jquery

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


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

@@ -6,8 +6,8 @@ type: module
 dependencies:
   - admin_toolbar
 
-# Information added by Drupal.org packaging script on 2017-04-06
-version: '8.x-1.19'
+# Information added by Drupal.org packaging script on 2017-09-12
+version: '8.x-1.20'
 core: '8.x'
 project: 'admin_toolbar'
-datestamp: 1491487686
+datestamp: 1505199847

+ 161 - 144
sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.module

@@ -11,18 +11,17 @@ use Drupal\Core\Routing\RouteMatchInterface;
  * Implements hook_toolbar().
  */
 function admin_toolbar_tools_toolbar() {
-  $items = array();
-  $items['admin_toolbar_tools'] = array(
+  $items = [];
+  $items['admin_toolbar_tools'] = [
     '#type' => 'toolbar_item',
-    'tab' => array(
+    'tab' => [
       '#type' => 'link',
-      '#attributes' => array(
-        'class' => array('toolbar-icon', 'toolbar-icon-admin-toolbar-tools-help'),
-      ),
-    ),
-    '#attached' => array('library' => array('admin_toolbar_tools/toolbar.icon'),
-    ),
-  );
+      '#attributes' => [
+        'class' => ['toolbar-icon', 'toolbar-icon-admin-toolbar-tools-help'],
+      ],
+    ],
+    '#attached' => ['library' => ['admin_toolbar_tools/toolbar.icon']],
+  ];
 
   return $items;
 }
@@ -49,19 +48,19 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
   $moduleHandler = \Drupal::moduleHandler();
   $entityTypeManager = \Drupal::entityTypeManager();
   $routeProvider = \Drupal::service('router.route_provider');
-  $routes = array();
+  $routes = [];
   foreach ($routeProvider->getAllRoutes() as $route_name => $route) {
     $routes[] = $route_name;
   }
 
   $entityTypes = $entityTypeManager->getDefinitions();
-  $content_entities = array();
+  $content_entities = [];
   foreach ($entityTypes as $key => $entityType) {
     if ($entityType->getBundleEntityType() && ($entityType->get('field_ui_base_route') != '')) {
-      $content_entities[$key] = array(
+      $content_entities[$key] = [
         'content_entity' => $key,
         'content_entity_bundle' => $entityType->getBundleEntityType(),
-      );
+      ];
     }
   }
 
@@ -75,23 +74,23 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
       if (in_array('entity.' . $content_entity_bundle . '.overview_form', $routes)) {
         // 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] = array(
-          'title' => $bundle->label(),
+        $links[$content_entity_bundle_root] = [
+          'title' => t($bundle->label()),
           'route_name' => 'entity.' . $content_entity_bundle . '.overview_form',
           'menu_name' => 'admin',
           'parent' => 'entity.' . $content_entity_bundle . '.collection',
-          'route_parameters' => array($content_entity_bundle => $machine_name),
-        );
+          'route_parameters' => [$content_entity_bundle => $machine_name],
+        ];
       }
       if (in_array('entity.' . $content_entity_bundle . '.edit_form', $routes)) {
         $key = 'entity.' . $content_entity_bundle . '.edit_form.' . $machine_name;
-        $links[$key] = array(
-          'title' => $bundle->label(),
+        $links[$key] = [
+          'title' => t($bundle->label()),
           'route_name' => 'entity.' . $content_entity_bundle . '.edit_form',
           'menu_name' => 'admin',
           'parent' => 'entity.' . $content_entity_bundle . '.collection',
-          'route_parameters' => array($content_entity_bundle => $machine_name),
-        );
+          'route_parameters' => [$content_entity_bundle => $machine_name],
+        ];
         if (empty($content_entity_bundle_root)) {
           $content_entity_bundle_root = $key;
         }
@@ -102,396 +101,413 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
       }
       if ($moduleHandler->moduleExists('field_ui')) {
         if (in_array('entity.' . $content_entity . '.field_ui_fields', $routes)) {
-          $links['entity.' . $content_entity . '.field_ui_fields' . $machine_name] = array(
+          $links['entity.' . $content_entity . '.field_ui_fields' . $machine_name] = [
             'title' => t('Manage fields'),
             'route_name' => 'entity.' . $content_entity . '.field_ui_fields',
             'menu_name' => 'admin',
             'parent' => $content_entity_bundle_root,
-            'route_parameters' => array($content_entity_bundle => $machine_name),
+            'route_parameters' => [$content_entity_bundle => $machine_name],
             'weight' => 1,
-          );
+          ];
         }
         if (in_array('entity.entity_form_display.' . $content_entity . '.default', $routes)) {
-          $links['entity.entity_form_display.' . $content_entity . '.default' . $machine_name] = array(
+          $links['entity.entity_form_display.' . $content_entity . '.default' . $machine_name] = [
             'title' => t('Manage form display'),
             'route_name' => 'entity.entity_form_display.' . $content_entity . '.default',
             'menu_name' => 'admin',
             'parent' => $content_entity_bundle_root,
-            'route_parameters' => array($content_entity_bundle => $machine_name),
+            'route_parameters' => [$content_entity_bundle => $machine_name],
             'weight' => 2,
-          );
+          ];
         }
         if (in_array('entity.entity_view_display.' . $content_entity . '.default', $routes)) {
-          $links['entity.entity_view_display.' . $content_entity . '.default.' . $machine_name] = array(
+          $links['entity.entity_view_display.' . $content_entity . '.default.' . $machine_name] = [
             'title' => t('Manage display'),
             'route_name' => 'entity.entity_view_display.' . $content_entity . '.default',
             'menu_name' => 'admin',
             'parent' => $content_entity_bundle_root,
-            'route_parameters' => array($content_entity_bundle => $machine_name),
+            'route_parameters' => [$content_entity_bundle => $machine_name],
             'weight' => 3,
-          );
+          ];
         }
       }
       if ($moduleHandler->moduleExists('devel') && in_array('entity.' . $content_entity_bundle . '.devel_load', $routes)) {
-        $links['entity.' . $content_entity_bundle . '.devel_load.' . $machine_name] = array(
+        $links['entity.' . $content_entity_bundle . '.devel_load.' . $machine_name] = [
           'title' => t('Devel'),
           'route_name' => 'entity.' . $content_entity_bundle . '.devel_load',
           'menu_name' => 'admin',
           'parent' => $content_entity_bundle_root,
-          'route_parameters' => array($content_entity_bundle => $machine_name),
+          'route_parameters' => [$content_entity_bundle => $machine_name],
           'weight' => 4,
-        );
+        ];
       }
       if (in_array('entity.' . $content_entity_bundle . '.delete_form', $routes)) {
-        $links['entity.' . $content_entity_bundle . '.delete_form.' . $machine_name] = array(
+        $links['entity.' . $content_entity_bundle . '.delete_form.' . $machine_name] = [
           'title' => t('Delete'),
           'route_name' => 'entity.' . $content_entity_bundle . '.delete_form',
           'menu_name' => 'admin',
           'parent' => $content_entity_bundle_root,
-          'route_parameters' => array($content_entity_bundle => $machine_name),
+          'route_parameters' => [$content_entity_bundle => $machine_name],
           'weight' => 5,
-        );
+        ];
       }
     }
   }
 
   // Add user links.
-  $links['user.admin_create'] = array(
+  $links['user.admin_create'] = [
     'title' => t('Add a new user'),
     'route_name' => 'user.admin_create',
     'menu_name' => 'admin',
     'parent' => 'entity.user.collection',
-  );
-  $links['user.admin_permissions'] = array(
+  ];
+  $links['user.admin_permissions'] = [
     'title' => t('Permissions'),
     'route_name' => 'user.admin_permissions',
     'menu_name' => 'admin',
     'parent' => 'entity.user.collection',
-  );
-  $links['entity.user_role.collection'] = array(
+  ];
+  $links['entity.user_role.collection'] = [
     'title' => t('Roles'),
     'route_name' => 'entity.user_role.collection',
     'menu_name' => 'admin',
     'parent' => 'entity.user.collection',
-  );
-  $links['admin_toolbar_tools.user.logout'] = array(
+  ];
+  $links['admin_toolbar_tools.user.logout'] = [
     'title' => t('Logout'),
     'route_name' => 'user.logout',
     'parent' => 'admin_toolbar_tools.help',
     'weight' => 10,
-  );
-  $links['user.role_add'] = array(
+  ];
+  $links['user.role_add'] = [
     'title' => t('Add a new role'),
     'route_name' => 'user.role_add',
     'menu_name' => 'admin',
     'parent' => 'entity.user_role.collection',
     'weight' => -5,
-  );
+  ];
   if ($moduleHandler->moduleExists('field_ui')) {
-    $links['entity.user.field_ui_fields_'] = array(
+    $links['entity.user.field_ui_fields_'] = [
       'title' => t('Manage fields'),
       'route_name' => 'entity.user.field_ui_fields',
       'menu_name' => 'admin',
       'parent' => 'entity.user.admin_form',
-    );
-    $links['entity.entity_form_display.user.default_'] = array(
+    ];
+    $links['entity.entity_form_display.user.default_'] = [
       'title' => t('Manage form display'),
       'route_name' => 'entity.entity_form_display.user.default',
       'menu_name' => 'admin',
       'parent' => 'entity.user.admin_form',
-    );
-    $links['entity.entity_view_display.user.default_'] = array(
+    ];
+    $links['entity.entity_view_display.user.default_'] = [
       'title' => t('Manage display'),
       'route_name' => 'entity.entity_view_display.user.default',
       'menu_name' => 'admin',
       'parent' => 'entity.user.admin_form',
-    );
+    ];
   }
   foreach (user_roles() as $role) {
-    $links['entity.user_role.edit_form.' . $role->id()] = array(
-      'title' => $role->label(),
+    $links['entity.user_role.edit_form.' . $role->id()] = [
+      'title' => t($role->label()),
       'route_name' => 'entity.user_role.edit_form',
       'menu_name' => 'admin',
       'parent' => 'entity.user_role.collection',
-      'route_parameters' => array('user_role' => $role->id()),
-    );
-    $links['entity.user_role.edit_permissions_form.' . $role->id()] = array(
+      'route_parameters' => ['user_role' => $role->id()],
+    ];
+    $links['entity.user_role.edit_permissions_form.' . $role->id()] = [
       'title' => t('Edit permissions'),
       'route_name' => 'entity.user_role.edit_permissions_form',
       'menu_name' => 'admin',
       'parent' => 'entity.user_role.edit_form.' . $role->id(),
-      'route_parameters' => array('user_role' => $role->id()),
-    );
-    $links['entity.user_role.delete_form.' . $role->id()] = array(
+      'route_parameters' => ['user_role' => $role->id()],
+    ];
+    $links['entity.user_role.delete_form.' . $role->id()] = [
       'title' => t('Delete'),
       'route_name' => 'entity.user_role.delete_form',
       'menu_name' => 'admin',
       'parent' => 'entity.user_role.edit_form.' . $role->id(),
-      'route_parameters' => array('user_role' => $role->id()),
-    );
+      'route_parameters' => ['user_role' => $role->id()],
+    ];
     if ($moduleHandler->moduleExists('devel')) {
-      $links['entity.user_role.devel_load.' . $role->id()] = array(
+      $links['entity.user_role.devel_load.' . $role->id()] = [
         'title' => t('Devel'),
         'route_name' => 'entity.user_role.devel_load',
         'menu_name' => 'admin',
         'parent' => 'entity.user_role.edit_form.' . $role->id(),
-        'route_parameters' => array('user_role' => $role->id()),
-      );
+        'route_parameters' => ['user_role' => $role->id()],
+      ];
     }
   }
 
   if ($moduleHandler->moduleExists('node')) {
-    $links['node.add_page']['parent'] = 'system.admin_content';
-    $links['node.type_add'] = array(
+    $links['admin_toolbar_tools.add_content'] = $links['node.add_page'];
+    $links['admin_toolbar_tools.add_content']['parent'] = 'system.admin_content';
+    $links['node.type_add'] = [
       'title' => t('Add content type'),
       'route_name' => 'node.type_add',
       'menu_name' => 'admin',
       'parent' => 'entity.node_type.collection',
       'weight' => -5,
-    );
+    ];
     // Add node links for each content type.
     foreach (\Drupal::entityTypeManager()->getStorage('node_type')->loadMultiple() as $type) {
-      $links['node.add.' . $type->id()] = array(
+      $links['node.add.' . $type->id()] = [
         'title' => t($type->label()),
         'route_name' => 'node.add',
-        'parent' => 'node.add_page',
-        'route_parameters' => array('node_type' => $type->id()),
-      );
+        'parent' => 'admin_toolbar_tools.add_content',
+        'route_parameters' => ['node_type' => $type->id()],
+      ];
     }
   }
 
   if ($moduleHandler->moduleExists('field_ui')) {
-    $links['field_ui.entity_form_mode_add'] = array(
+    $links['field_ui.entity_form_mode_add'] = [
       'title' => t('Add new form mode'),
       'route_name' => 'field_ui.entity_form_mode_add',
       'menu_name' => 'admin',
       'parent' => 'entity.entity_form_mode.collection',
-    );
-    $links['field_ui.entity_view_mode_add'] = array(
+    ];
+    $links['field_ui.entity_view_mode_add'] = [
       'title' => t('Add new view mode'),
       'route_name' => 'field_ui.entity_view_mode_add',
       'menu_name' => 'admin',
       'parent' => 'entity.entity_view_mode.collection',
-    );
+    ];
   }
 
   if ($moduleHandler->moduleExists('taxonomy')) {
-    $links['entity.taxonomy_vocabulary.add_form'] = array(
+    $links['entity.taxonomy_vocabulary.add_form'] = [
       'title' => t('Add vocabulary'),
       'route_name' => 'entity.taxonomy_vocabulary.add_form',
       'menu_name' => 'admin',
       'parent' => 'entity.taxonomy_vocabulary.collection',
       'weight' => -5,
-    );
+    ];
   }
 
   if ($moduleHandler->moduleExists('menu_ui')) {
-    $links['entity.menu.add_form'] = array(
+    $links['entity.menu.add_form'] = [
       'title' => t('Add menu'),
       'route_name' => 'entity.menu.add_form',
       'menu_name' => 'admin',
       'parent' => 'entity.menu.collection',
       'weight' => -50,
-    );
+    ];
     // Adds links to /admin/structure/menu.
     foreach (menu_ui_get_menus() as $machine_name => $label) {
-      $links['entity.menu.edit_form.' . $machine_name] = array(
-        'title' => $label,
+      $links['entity.menu.edit_form.' . $machine_name] = [
+        'title' => t($label),
         'route_name' => 'entity.menu.edit_form',
         'menu_name' => 'admin',
         'parent' => 'entity.menu.collection',
-        'route_parameters' => array('menu' => $machine_name),
-      );
-      $links['entity.menu.delete_form.' . $machine_name] = array(
+        'route_parameters' => ['menu' => $machine_name],
+      ];
+      $links['entity.menu.delete_form.' . $machine_name] = [
         'title' => t('Delete'),
         'route_name' => 'entity.menu.delete_form',
         'menu_name' => 'admin',
         'parent' => 'entity.menu.edit_form.' . $machine_name,
-        'route_parameters' => array('menu' => $machine_name),
-      );
+        'route_parameters' => ['menu' => $machine_name],
+      ];
       if ($moduleHandler->moduleExists('devel')) {
-        $links['entity.menu.devel_load.' . $machine_name] = array(
+        $links['entity.menu.devel_load.' . $machine_name] = [
           'title' => t('Devel'),
           'route_name' => 'entity.menu.devel_load',
           'menu_name' => 'admin',
           'parent' => 'entity.menu.edit_form.' . $machine_name,
-          'route_parameters' => array('menu' => $machine_name),
-        );
+          'route_parameters' => ['menu' => $machine_name],
+        ];
       }
-      $links['entity.menu.add_link_form.' . $machine_name] = array(
+      $links['entity.menu.add_link_form.' . $machine_name] = [
         'title' => t('Add link'),
         'route_name' => 'entity.menu.add_link_form',
         'menu_name' => 'admin',
         'parent' => 'entity.menu.edit_form.' . $machine_name,
-        'route_parameters' => array('menu' => $machine_name),
-      );
+        'route_parameters' => ['menu' => $machine_name],
+      ];
     }
   }
 
   // If module block_content is enabled.
   if ($moduleHandler->moduleExists('block_content')) {
-    $links['block_content.add_page'] = array(
+    $links['block_content.add_page'] = [
       'title' => t('Add custom block'),
       'route_name' => 'block_content.add_page',
       'menu_name' => 'admin',
       'parent' => 'block.admin_display',
       'weight' => -100,
-    );
-    $links['entity.block_content.collection'] = array(
+    ];
+    $links['entity.block_content.collection'] = [
       'title' => t('Custom block library'),
       'route_name' => 'entity.block_content.collection',
       'menu_name' => 'admin',
       'parent' => 'block.admin_display',
-    );
-    $links['entity.block_content_type.collection'] = array(
+    ];
+    $links['entity.block_content_type.collection'] = [
       'title' => t('Types'),
       'route_name' => 'entity.block_content_type.collection',
       'menu_name' => 'admin',
       'parent' => 'block.admin_display',
-    );
+    ];
   }
 
   // If module Contact is enabled.
   if ($moduleHandler->moduleExists('contact')) {
-    $links['contact.form_add'] = array(
+    $links['contact.form_add'] = [
       'title' => t('Add contact form'),
       'route_name' => 'contact.form_add',
       'menu_name' => 'admin',
       'parent' => 'entity.contact_form.collection',
       'weight' => -5,
-    );
+    ];
   }
 
   // If module Update Manager is enabled.
   if ($moduleHandler->moduleExists('update')) {
-    $links['update.module_update'] = array(
+    $links['update.module_update'] = [
       'title' => t('Update'),
       'route_name' => 'update.module_update',
       'menu_name' => 'admin',
       'parent' => 'system.modules_list',
-    );
-    $links['update.module_install'] = array(
+    ];
+    $links['update.module_install'] = [
       'title' => t('Install new module'),
       'route_name' => 'update.module_install',
       'menu_name' => 'admin',
       'parent' => 'system.modules_list',
-    );
+    ];
   }
 
   // If module Devel is enabled.
   if ($moduleHandler->moduleExists('devel')) {
-    $links['admin_development'] = array(
+    $links['admin_development'] = [
       'title' => t('Development'),
       'route_name' => 'system.admin_config_development',
       'menu_name' => 'admin',
       'parent' => 'admin_toolbar_tools.help',
       'weight' => '-8',
-    );
-    $links['admin_toolbar_tools.devel.admin_settings'] = array(
+    ];
+    $links['admin_toolbar_tools.devel.admin_settings'] = [
       'title' => t('Devel settings'),
       'route_name' => 'devel.admin_settings',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
       'weight' => '-1',
-    );
-    $links['admin_toolbar_tools.devel.configs_list'] = array(
+    ];
+    if ($moduleHandler->moduleExists('webprofiler')) {
+      $links['admin_menu_tools.devel.webprofiler'] = [
+        'title' => t('Web Profiler settings'),
+        'route_name' => 'webprofiler.settings',
+        'menu_name' => 'admin',
+        'parent' => 'admin_development',
+      ];
+    }
+    $links['admin_toolbar_tools.devel.configs_list'] = [
       'title' => t('Config editor'),
       'route_name' => 'devel.configs_list',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
-    );
-    $links['admin_toolbar_tools.devel.reinstall'] = array(
+    ];
+    $links['admin_toolbar_tools.devel.reinstall'] = [
       'title' => t('Reinstall modules'),
       'route_name' => 'devel.reinstall',
       'parent' => 'admin_development',
-    );
-    $links['admin_toolbar_tools.devel.menu_rebuild'] = array(
+    ];
+    $links['admin_toolbar_tools.devel.menu_rebuild'] = [
       'title' => t('Rebuild menu'),
       'route_name' => 'devel.menu_rebuild',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
-    );
-    $links['admin_toolbar_tools.devel.state_system_page'] = array(
+    ];
+    $links['admin_toolbar_tools.devel.state_system_page'] = [
       'title' => t('State editor'),
       'route_name' => 'devel.state_system_page',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
-    );
-    $links['admin_toolbar_tools.devel.theme_registry'] = array(
+    ];
+    $links['admin_toolbar_tools.devel.theme_registry'] = [
       'title' => t('Theme registry'),
       'route_name' => 'devel.theme_registry',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
-    );
-    $links['admin_toolbar_tools.devel.entity_info_page'] = array(
+    ];
+    $links['admin_toolbar_tools.devel.entity_info_page'] = [
       'title' => t('Entity Info'),
       'route_name' => 'devel.entity_info_page',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
-    );
-    $links['admin_toolbar_tools.devel.execute_php'] = array(
+    ];
+    $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'] = array(
+    ];
+    $links['admin_toolbar_tools.devel.session'] = [
       'title' => t('Session viewer'),
       'route_name' => 'devel.session',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
-    );
-    $links['admin_toolbar_tools.devel.elements_page'] = array(
+    ];
+    $links['admin_toolbar_tools.devel.elements_page'] = [
       'title' => t('Form API field types'),
       'route_name' => 'devel.elements_page',
       'menu_name' => 'admin',
       'parent' => 'admin_development',
-    );
+    ];
   }
 
   // If module Views Ui enabled.
   if ($moduleHandler->moduleExists('views_ui')) {
-    $links['views_ui.add'] = array(
+    $links['views_ui.add'] = [
       'title' => t('Add new view'),
       'route_name' => 'views_ui.add',
       'menu_name' => 'admin',
       'parent' => 'entity.view.collection',
       'weight' => -5,
-    );
+    ];
   }
 
-  $links['system.theme_settings_'] = array(
+  $links['system.theme_settings_'] = [
     'title' => t('Settings'),
     'route_name' => 'system.theme_settings',
     'menu_name' => 'admin',
     'parent' => 'system.themes_page',
-  );
+  ];
 
+  if ($moduleHandler->moduleExists('webprofiler')) {
+    $links['admin_menu_tools.devel.webprofiler'] = [
+      'title' => t('Webprofiler settings'),
+      'route_name' => 'webprofiler.settings',
+      'menu_name' => 'admin',
+      'parent' => 'admin_development',
+    ];
+  }
   if ($moduleHandler->moduleExists('update')) {
-    $links['update.theme_install_'] = array(
+    $links['update.theme_install_'] = [
       'title' => t('Install new theme'),
       'route_name' => 'update.theme_install',
       'menu_name' => 'admin',
       'parent' => 'system.themes_page',
-    );
-    $links['update.theme_update_'] = array(
+    ];
+    $links['update.theme_update_'] = [
       'title' => t('Update'),
       'route_name' => 'update.theme_update',
       'menu_name' => 'admin',
       'parent' => 'system.themes_page',
-    );
+    ];
     // Lists installed themes.
     $installed_themes = admin_toolbar_tools_installed_themes();
     foreach ($installed_themes as $key_theme => $label_theme) {
-      $links['system.theme_settings_theme.' . $key_theme] = array(
+      $links['system.theme_settings_theme.' . $key_theme] = [
         'title' => t($label_theme),
         'route_name' => 'system.theme_settings_theme',
         'menu_name' => 'admin',
         'parent' => 'system.theme_settings_',
-        'route_parameters' => array(
+        'route_parameters' => [
           'theme' => $key_theme,
-        ),
-      );
+        ],
+      ];
     }
   }
 }
@@ -503,11 +519,12 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) {
  *   An array of friendly theme names, keyed by the machine name.
  */
 function admin_toolbar_tools_installed_themes() {
-  $all_themes = \Drupal::service('theme_handler')->listInfo();
-  $themes_installed = array();
+  $themeHandler = \Drupal::service('theme_handler');
+  $all_themes = $themeHandler->listInfo();
+  $themes_installed = [];
   foreach ($all_themes as $key_theme => $theme) {
-    if (\Drupal::service('theme_handler')->hasUi($key_theme)) {
-      $themes_installed[$key_theme] = $theme->getName();
+    if ($themeHandler->hasUi($key_theme)) {
+      $themes_installed[$key_theme] = $themeHandler->getName($key_theme);
     }
   }
 

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

@@ -6,6 +6,7 @@ use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\CronInterface;
 use Drupal\Core\Routing\TrustedRedirectResponse;
+use Drupal\Component\Datetime\Time;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Drupal\Core\Menu\ContextualLinkManager;
@@ -31,6 +32,7 @@ class ToolbarController extends ControllerBase {
   protected $localTaskLinkManager;
   protected $localActionLinkManager;
   protected $cacheRender;
+  protected $time;
 
   /**
    * Constructs a CronController object.
@@ -43,13 +45,15 @@ class ToolbarController extends ControllerBase {
                               ContextualLinkManager $contextualLinkManager,
                               LocalTaskManager $localTaskLinkManager,
                               LocalActionManager $localActionLinkManager,
-                              CacheBackendInterface $cacheRender) {
+                              CacheBackendInterface $cacheRender,
+                              Time $time) {
     $this->cron = $cron;
     $this->menuLinkManager = $menuLinkManager;
     $this->contextualLinkManager = $contextualLinkManager;
     $this->localTaskLinkManager = $localTaskLinkManager;
     $this->localActionLinkManager = $localActionLinkManager;
     $this->cacheRender = $cacheRender;
+    $this->time = $time;
   }
 
   /**
@@ -62,7 +66,8 @@ class ToolbarController extends ControllerBase {
       $container->get('plugin.manager.menu.contextual_link'),
       $container->get('plugin.manager.menu.local_task'),
       $container->get('plugin.manager.menu.local_action'),
-      $container->get('cache.render')
+      $container->get('cache.render'),
+      $container->get('datetime.time')
     );
   }
 
@@ -93,7 +98,7 @@ class ToolbarController extends ControllerBase {
    */
   public function flush_js_css() {
     \Drupal::state()
-      ->set('system.css_js_query_string', base_convert(REQUEST_TIME, 10, 36));
+      ->set('system.css_js_query_string', base_convert($this->time->getCurrentTime(), 10, 36));
     drupal_set_message($this->t('CSS and JavaScript cache cleared.'));
     return new RedirectResponse($this->reload_page());
   }

+ 1 - 0
sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/Tests/AdminToolbarToolsAlterTest.php

@@ -34,6 +34,7 @@ class AdminToolbarToolsAlterTest extends WebTestBase {
     $this->adminUser = $this->drupalCreateUser([
       'access toolbar',
       'access administration pages',
+      'administer site configuration',
     ]);
     $this->drupalLogin($this->adminUser);
   }

+ 15 - 12
sites/all/modules/contrib/admin/admin_toolbar/css/admin.toolbar.css

@@ -1,4 +1,7 @@
 /*---------------------- menu horizontal hover---- Krout Fethi FrontEnd Developer-----*/
+#toolbar-bar {
+  z-index: 9999;
+}
 .toolbar-tray-horizontal .menu-item:hover {
   background: #fff;
 }
@@ -33,20 +36,20 @@
   border-top: 1px solid #dddddd;
 }
 
-.toolbar-tray-horizontal li.menu-item--expanded:hover ul ul,
-.toolbar-tray-horizontal li.menu-item--expanded:hover ul ul ul,
-.toolbar-tray-horizontal li.menu-item--expanded:hover ul ul ul ul,
-.toolbar-tray-horizontal li.menu-item--expanded:hover ul ul ul ul ul {
+.toolbar-tray-horizontal li.menu-item--expanded.hover-intent ul ul,
+.toolbar-tray-horizontal li.menu-item--expanded.hover-intent ul ul ul,
+.toolbar-tray-horizontal li.menu-item--expanded.hover-intent ul ul ul ul,
+.toolbar-tray-horizontal li.menu-item--expanded.hover-intent ul ul ul ul ul {
   display: none;
   left: -999em; /* LTR */
 }
 
 /* Lists nested under hovered list items */
-.toolbar-tray-horizontal li.menu-item--expanded:hover ul,
-.toolbar-tray-horizontal li li.menu-item--expanded:hover ul,
-.toolbar-tray-horizontal li li li.menu-item--expanded:hover ul,
-.toolbar-tray-horizontal li li li li.menu-item--expanded:hover ul,
-.toolbar-tray-horizontal li li li li li.menu-item--expanded:hover ul {
+.toolbar-tray-horizontal li.menu-item--expanded.hover-intent ul,
+.toolbar-tray-horizontal li li.menu-item--expanded.hover-intent ul,
+.toolbar-tray-horizontal li li li.menu-item--expanded.hover-intent ul,
+.toolbar-tray-horizontal li li li li.menu-item--expanded.hover-intent ul,
+.toolbar-tray-horizontal li li li li li.menu-item--expanded.hover-intent ul {
   display: block;
   left: auto; /* LTR */
 }
@@ -56,7 +59,7 @@
   padding: 12px 15px 12px 12px;
 }
 
-.toolbar-tray-horizontal ul li.menu-item--expanded:hover ul {
+.toolbar-tray-horizontal ul li.menu-item--expanded.hover-intent ul {
   display: block;
   position: absolute;
   width: 200px;
@@ -74,12 +77,12 @@
   background-repeat: no-repeat;
 }
 
-.toolbar-tray-horizontal ul li.menu-item--expanded .menu-item:hover ul {
+.toolbar-tray-horizontal ul li.menu-item--expanded .menu-item.hover-intent ul {
   display: block;
   margin: -40px 0 0 197px;
 }
 
-.toolbar-tray-horizontal li:hover ul li {
+.toolbar-tray-horizontal li.hover-intent ul li {
   float: none;
 }
 

+ 15 - 2
sites/all/modules/contrib/admin/admin_toolbar/js/admin_toolbar.js

@@ -1,5 +1,18 @@
-(function($) {
-  $(document).ready(function() {
+(function ($) {
+  $(document).ready(function () {
     $('a.toolbar-icon').removeAttr('title');
+
+    $('.toolbar-tray-horizontal li.menu-item--expanded, .toolbar-tray-horizontal ul li.menu-item--expanded .menu-item').hoverIntent({
+      over: function () {
+        // At the current depth, we should delete all "hover-intent" classes.
+        // Other wise we get unwanted behaviour where menu items are expanded while already in hovering other ones.
+        $(this).parent().find('li').removeClass('hover-intent');
+        $(this).addClass('hover-intent');
+      },
+      out: function () {
+        $(this).removeClass('hover-intent');
+      },
+      timeout: 500
+    });
   });
 })(jQuery);

+ 158 - 0
sites/all/modules/contrib/admin/admin_toolbar/js/jquery.hoverIntent.js

@@ -0,0 +1,158 @@
+/*!
+ * hoverIntent v1.8.1 // 2014.08.11 // jQuery v1.9.1+
+ * http://briancherne.github.io/jquery-hoverIntent/
+ *
+ * You may use hoverIntent under the terms of the MIT license. Basically that
+ * means you are free to use hoverIntent as long as this header is left intact.
+ * Copyright 2007, 2014 Brian Cherne
+ */
+
+/* hoverIntent is similar to jQuery's built-in "hover" method except that
+ * instead of firing the handlerIn function immediately, hoverIntent checks
+ * to see if the user's mouse has slowed down (beneath the sensitivity
+ * threshold) before firing the event. The handlerOut function is only
+ * called after a matching handlerIn.
+ *
+ * // basic usage ... just like .hover()
+ * .hoverIntent( handlerIn, handlerOut )
+ * .hoverIntent( handlerInOut )
+ *
+ * // basic usage ... with event delegation!
+ * .hoverIntent( handlerIn, handlerOut, selector )
+ * .hoverIntent( handlerInOut, selector )
+ *
+ * // using a basic configuration object
+ * .hoverIntent( config )
+ *
+ * @param  handlerIn   function OR configuration object
+ * @param  handlerOut  function OR selector for delegation OR undefined
+ * @param  selector    selector OR undefined
+ * @author Brian Cherne <brian(at)cherne(dot)net>
+ */
+
+;(function(factory) {
+  'use strict';
+  if (typeof define === 'function' && define.amd) {
+    define(['jquery'], factory);
+  } else if (jQuery && !jQuery.fn.hoverIntent) {
+    factory(jQuery);
+  }
+})(function($) {
+  'use strict';
+
+  // default configuration values
+  var _cfg = {
+    interval: 100,
+    sensitivity: 6,
+    timeout: 0
+  };
+
+  // counter used to generate an ID for each instance
+  var INSTANCE_COUNT = 0;
+
+  // current X and Y position of mouse, updated during mousemove tracking (shared across instances)
+  var cX, cY;
+
+  // saves the current pointer position coordinates based on the given mousemove event
+  var track = function(ev) {
+    cX = ev.pageX;
+    cY = ev.pageY;
+  };
+
+  // compares current and previous mouse positions
+  var compare = function(ev,$el,s,cfg) {
+    // compare mouse positions to see if pointer has slowed enough to trigger `over` function
+    if ( Math.sqrt( (s.pX-cX)*(s.pX-cX) + (s.pY-cY)*(s.pY-cY) ) < cfg.sensitivity ) {
+      $el.off(s.event,track);
+      delete s.timeoutId;
+      // set hoverIntent state as active for this element (permits `out` handler to trigger)
+      s.isActive = true;
+      // overwrite old mouseenter event coordinates with most recent pointer position
+      ev.pageX = cX; ev.pageY = cY;
+      // clear coordinate data from state object
+      delete s.pX; delete s.pY;
+      return cfg.over.apply($el[0],[ev]);
+    } else {
+      // set previous coordinates for next comparison
+      s.pX = cX; s.pY = cY;
+      // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)
+      s.timeoutId = setTimeout( function(){compare(ev, $el, s, cfg);} , cfg.interval );
+    }
+  };
+
+  // triggers given `out` function at configured `timeout` after a mouseleave and clears state
+  var delay = function(ev,$el,s,out) {
+    delete $el.data('hoverIntent')[s.id];
+    return out.apply($el[0],[ev]);
+  };
+
+  $.fn.hoverIntent = function(handlerIn,handlerOut,selector) {
+    // instance ID, used as a key to store and retrieve state information on an element
+    var instanceId = INSTANCE_COUNT++;
+
+    // extend the default configuration and parse parameters
+    var cfg = $.extend({}, _cfg);
+    if ( $.isPlainObject(handlerIn) ) {
+      cfg = $.extend(cfg, handlerIn);
+      if ( !$.isFunction(cfg.out) ) {
+        cfg.out = cfg.over;
+      }
+    } else if ( $.isFunction(handlerOut) ) {
+      cfg = $.extend(cfg, { over: handlerIn, out: handlerOut, selector: selector } );
+    } else {
+      cfg = $.extend(cfg, { over: handlerIn, out: handlerIn, selector: handlerOut } );
+    }
+
+    // A private function for handling mouse 'hovering'
+    var handleHover = function(e) {
+      // cloned event to pass to handlers (copy required for event object to be passed in IE)
+      var ev = $.extend({},e);
+
+      // the current target of the mouse event, wrapped in a jQuery object
+      var $el = $(this);
+
+      // read hoverIntent data from element (or initialize if not present)
+      var hoverIntentData = $el.data('hoverIntent');
+      if (!hoverIntentData) { $el.data('hoverIntent', (hoverIntentData = {})); }
+
+      // read per-instance state from element (or initialize if not present)
+      var state = hoverIntentData[instanceId];
+      if (!state) { hoverIntentData[instanceId] = state = { id: instanceId }; }
+
+      // state properties:
+      // id = instance ID, used to clean up data
+      // timeoutId = timeout ID, reused for tracking mouse position and delaying "out" handler
+      // isActive = plugin state, true after `over` is called just until `out` is called
+      // pX, pY = previously-measured pointer coordinates, updated at each polling interval
+      // event = string representing the namespaced event used for mouse tracking
+
+      // clear any existing timeout
+      if (state.timeoutId) { state.timeoutId = clearTimeout(state.timeoutId); }
+
+      // namespaced event used to register and unregister mousemove tracking
+      var mousemove = state.event = 'mousemove.hoverIntent.hoverIntent'+instanceId;
+
+      // handle the event, based on its type
+      if (e.type === 'mouseenter') {
+        // do nothing if already active
+        if (state.isActive) { return; }
+        // set "previous" X and Y position based on initial entry point
+        state.pX = ev.pageX; state.pY = ev.pageY;
+        // update "current" X and Y position based on mousemove
+        $el.off(mousemove,track).on(mousemove,track);
+        // start polling interval (self-calling timeout) to compare mouse coordinates over time
+        state.timeoutId = setTimeout( function(){compare(ev,$el,state,cfg);} , cfg.interval );
+      } else { // "mouseleave"
+        // do nothing if not already active
+        if (!state.isActive) { return; }
+        // unbind expensive mousemove event
+        $el.off(mousemove,track);
+        // if hoverIntent state is true, then call the mouseOut function after the specified delay
+        state.timeoutId = setTimeout( function(){delay(ev,$el,state,cfg.out);} , cfg.timeout );
+      }
+    };
+
+    // listen for mouseenter and mouseleave
+    return this.on({'mouseenter.hoverIntent':handleHover,'mouseleave.hoverIntent':handleHover}, cfg.selector);
+  };
+});

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

@@ -7,7 +7,7 @@ Configuration Update Base: A base module providing functionality related to
   updating and computing differences between configuration versions. No
   user interface; used by other modules such as Features.
 
-Configuration Update Reports (in the config_ui sub-directory of this project):
-  Adds an updates report and revert functionality to configuration management.
-  Depends on Configuration Update Base. For more information, see the
-  README.txt file in the subdirectory.
+Configuration Update Reports (in the config_update_ui sub-directory of this
+  project): Adds an updates report and revert functionality to configuration
+  management.  Depends on Configuration Update Base. For more information, see
+  the README.txt file in the subdirectory.

+ 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-01-18
-version: '8.x-1.3'
+# Information added by Drupal.org packaging script on 2017-09-18
+version: '8.x-1.4'
 core: '8.x'
 project: 'config_update'
-datestamp: 1484770686
+datestamp: 1505755746

+ 17 - 2
sites/all/modules/contrib/admin/config_update/config_update_ui/config_update_ui.drush_testing.inc

@@ -8,9 +8,24 @@
  */
 
 if (!function_exists('drush_print')) {
-  function drush_print() {}
+
+  /**
+   * Stub for drush_print() function for testing.
+   */
+  function drush_print() {
+  }
+
 }
+
 if (!function_exists('dt')) {
-  function dt($text) { return $text; }
+
+  /**
+   * Stub for dt() function for testing.
+   */
+  function dt($text) {
+    return $text;
+  }
+
 }
+
 defined('STDERR') or define('STDERR', 25);

+ 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-01-18
-version: '8.x-1.3'
+# Information added by Drupal.org packaging script on 2017-09-18
+version: '8.x-1.4'
 core: '8.x'
 project: 'config_update'
-datestamp: 1484770686
+datestamp: 1505755746

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


+ 62 - 16
sites/all/modules/contrib/admin/config_update/config_update_ui/src/Controller/ConfigUpdateController.php

@@ -3,6 +3,7 @@
 namespace Drupal\config_update_ui\Controller;
 
 use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Diff\DiffFormatter;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Extension\ThemeHandlerInterface;
@@ -60,6 +61,13 @@ class ConfigUpdateController extends ControllerBase {
    */
   protected $themeHandler;
 
+  /**
+   * The config factory.
+   *
+   * @var \Drupal\Core\config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
   /**
    * Constructs a ConfigUpdateController object.
    *
@@ -75,8 +83,10 @@ class ConfigUpdateController extends ControllerBase {
    *   The module handler.
    * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
    *   The theme handler.
+   * @param \drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
    */
-  public function __construct(ConfigDiffInterface $config_diff, ConfigListByProviderInterface $config_list, ConfigRevertInterface $config_update, DiffFormatter $diff_formatter, ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler) {
+  public function __construct(ConfigDiffInterface $config_diff, ConfigListByProviderInterface $config_list, ConfigRevertInterface $config_update, DiffFormatter $diff_formatter, ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler, ConfigFactoryInterface $config_factory) {
     $this->configDiff = $config_diff;
     $this->configList = $config_list;
     $this->configRevert = $config_update;
@@ -84,6 +94,7 @@ class ConfigUpdateController extends ControllerBase {
     $this->diffFormatter->show_header = FALSE;
     $this->moduleHandler = $module_handler;
     $this->themeHandler = $theme_handler;
+    $this->configFactory = $config_factory;
   }
 
   /**
@@ -96,7 +107,8 @@ class ConfigUpdateController extends ControllerBase {
       $container->get('config_update.config_update'),
       $container->get('diff.formatter'),
       $container->get('module_handler'),
-      $container->get('theme_handler')
+      $container->get('theme_handler'),
+      $container->get('config.factory')
     );
   }
 
@@ -238,6 +250,22 @@ class ConfigUpdateController extends ControllerBase {
       '#rows' => [],
     ];
 
+    // Full report of all configuration.
+    $links['report_full'] = [
+      'title' => $this->t('Everything'),
+      'url' => Url::fromRoute('config_update_ui.report', ['report_type' => 'type', 'name' => 'system.all']),
+    ];
+    $build['links']['#rows'][] = [
+      $this->t('Full report'),
+      [
+        'data' => [
+          '#type' => 'operations',
+          '#links' => $links,
+        ],
+      ],
+    ];
+
+    // Reports by configuration type.
     $definitions = $this->configList->listTypes();
     $links = [];
     foreach ($definitions as $entity_type => $definition) {
@@ -250,10 +278,6 @@ class ConfigUpdateController extends ControllerBase {
     uasort($links, [$this, 'sortLinks']);
 
     $links = [
-      'report_type_all' => [
-        'title' => $this->t('All types'),
-        'url' => Url::fromRoute('config_update_ui.report', ['report_type' => 'type', 'name' => 'system.all']),
-      ],
       'report_type_system.simple' => [
         'title' => $this->t('Simple configuration'),
         'url' => Url::fromRoute('config_update_ui.report', ['report_type' => 'type', 'name' => 'system.simple']),
@@ -261,7 +285,7 @@ class ConfigUpdateController extends ControllerBase {
     ] + $links;
 
     $build['links']['#rows'][] = [
-      $this->t('Configuration type'),
+      $this->t('Single configuration type'),
       [
         'data' => [
           '#type' => 'operations',
@@ -271,7 +295,7 @@ class ConfigUpdateController extends ControllerBase {
     ];
 
     // Make a list of installed modules.
-    $profile = Settings::get('install_profile');
+    $profile = $this->getProfileName();
     $modules = $this->moduleHandler->getModuleList();
     $links = [];
     foreach ($modules as $machine_name => $module) {
@@ -285,7 +309,7 @@ class ConfigUpdateController extends ControllerBase {
     uasort($links, [$this, 'sortLinks']);
 
     $build['links']['#rows'][] = [
-      $this->t('Module'),
+      $this->t('Single module'),
       [
         'data' => [
           '#type' => 'operations',
@@ -308,7 +332,7 @@ class ConfigUpdateController extends ControllerBase {
     uasort($links, [$this, 'sortLinks']);
 
     $build['links']['#rows'][] = [
-      $this->t('Theme'),
+      $this->t('Single theme'),
       [
         'data' => [
           '#type' => 'operations',
@@ -393,7 +417,7 @@ class ConfigUpdateController extends ControllerBase {
         break;
 
       case 'profile':
-        $profile = Settings::get('install_profile');
+        $profile = $this->getProfileName();
         $label = $this->t('@name profile', ['@name' => $this->moduleHandler->getName($profile)]);
         break;
 
@@ -449,7 +473,8 @@ class ConfigUpdateController extends ControllerBase {
     $build['different'] = [
       '#caption' => $this->t('Changed configuration items'),
       '#empty' => $this->t('None: no active configuration items differ from their current provided versions.'),
-    ] + $this->makeReportTable($different, 'active', ['diff', 'export', 'revert']);
+    ] + $this->makeReportTable($different, 'active',
+      ['diff', 'export', 'revert']);
 
     return $build;
   }
@@ -468,13 +493,13 @@ class ConfigUpdateController extends ControllerBase {
    *   - revert
    *   - export
    *   - import
-   *   - delete
+   *   - delete.
    *
    * @return array
    *   Render array for the table, not including the #empty and #prefix
    *   properties.
    */
-  protected function makeReportTable($names, $storage, $actions) {
+  protected function makeReportTable(array $names, $storage, array $actions) {
     $build = [];
 
     $build['#type'] = 'table';
@@ -544,7 +569,7 @@ class ConfigUpdateController extends ControllerBase {
       $provider = $this->configList->getConfigProvider($name);
       $provider_name = '';
       if (!empty($provider)) {
-        switch($provider[0]) {
+        switch ($provider[0]) {
           case 'profile':
             $provider_name = $this->moduleHandler->getName($provider[1]);
             if ($provider_name) {
@@ -574,7 +599,6 @@ class ConfigUpdateController extends ControllerBase {
               $provider_name = '';
             }
             break;
-            break;
         }
       }
       $row[] = $provider_name;
@@ -627,4 +651,26 @@ class ConfigUpdateController extends ControllerBase {
     return ($title1 < $title2) ? -1 : 1;
   }
 
+  /**
+   * Returns the name of the install profile.
+   *
+   * For backwards compatibility with pre/post 8.3.x, tries to get it from
+   * either configuration or settings.
+   *
+   * @return string
+   *   The name of the install profile.
+   */
+  protected function getProfileName() {
+    // Code adapted from DrupalKernel::getInstalProfile() in Core.
+    // In Core 8.3.x or later, read from config.
+    $profile = $this->configFactory->get('core.extension')->get('profile');
+    if (!empty($profile)) {
+      return $profile;
+    }
+    else {
+      // If system_update_8300() has not yet run, use settings.
+      return Settings::get('install_profile');
+    }
+  }
+
 }

+ 97 - 0
sites/all/modules/contrib/admin/config_update/config_update_ui/src/Tests/ConfigProfileOverridesTest.php

@@ -0,0 +1,97 @@
+<?php
+
+namespace Drupal\config_update_ui\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Verify config reports, reverts, and diffs with profile overrides.
+ *
+ * @group config
+ */
+class ConfigProfileOverridesTest extends WebTestBase {
+
+  /**
+   * Use the Standard profile, so that there are profile config overrides.
+   *
+   * @var string
+   */
+  protected $profile = 'standard';
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = [
+    'config',
+    'config_update',
+    'config_update_ui',
+  ];
+
+  /**
+   * The admin user that will be created.
+   *
+   * @var object
+   */
+  protected $adminUser;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Create user and log in.
+    $this->adminUser = $this->drupalCreateUser([
+      'access administration pages',
+      'administer themes',
+      'view config updates report',
+      'synchronize configuration',
+      'export configuration',
+      'import configuration',
+      'revert configuration',
+      'delete configuration',
+    ]);
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Tests that config overrides work as expected.
+   */
+  public function testConfigOverrides() {
+
+    // The Standard install profile contains a system.theme.yml file that
+    // sets up bartik/seven as the default/admin theme. The default config
+    // from the System module has no admin theme and stark as the default
+    // theme. So first, run the report on simple configuration and verify
+    // 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');
+
+    // 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,
+    // since it is now overridden.
+    $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');
+
+    // 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');
+
+    // 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');
+  }
+
+}

+ 40 - 11
sites/all/modules/contrib/admin/config_update/config_update_ui/src/Tests/ConfigUpdateTest.php

@@ -17,12 +17,25 @@ class ConfigUpdateTest extends WebTestBase {
    * Use the Search module because it has two included config items in its
    * config/install, assuming node and user are also enabled.
    *
-   * @var array.
+   * @var array
    */
-  public static $modules = ['config', 'config_update', 'config_update_ui', 'search', 'node', 'user', 'block', 'text', 'field', 'filter'];
+  public static $modules = [
+    'config',
+    'config_update',
+    'config_update_ui',
+    'search',
+    'node',
+    'user',
+    'block',
+    'text',
+    'field',
+    'filter',
+  ];
 
   /**
    * The admin user that will be created.
+   *
+   * @var object
    */
   protected $adminUser;
 
@@ -33,7 +46,17 @@ class ConfigUpdateTest extends WebTestBase {
     parent::setUp();
 
     // Create user and log in.
-    $this->adminUser = $this->drupalCreateUser(['access administration pages', 'administer search', 'view config updates report', 'synchronize configuration', 'export configuration', 'import configuration', 'revert configuration', 'delete configuration', 'administer filters']);
+    $this->adminUser = $this->drupalCreateUser([
+      'access administration pages',
+      'administer search',
+      'view config updates report',
+      'synchronize configuration',
+      'export configuration',
+      'import configuration',
+      'revert configuration',
+      'delete configuration',
+      'administer filters',
+    ]);
     $this->drupalLogin($this->adminUser);
 
     // Make sure local tasks and page title are showing.
@@ -99,7 +122,13 @@ class ConfigUpdateTest extends WebTestBase {
     $this->drupalGet('admin/config/development/configuration/report/module/user');
     $this->assertReport('User module', [], [], [], $inactive, ['added', 'changed']);
     $this->assertDrushReports('module', 'user', [], [], [],
-      ['rdf.mapping.user.user', 'search.page.user_search', 'views.view.user_admin_people', 'views.view.who_s_new', 'views.view.who_s_online' ], ['changed']);
+      [
+        'rdf.mapping.user.user',
+        'search.page.user_search',
+        'views.view.user_admin_people',
+        'views.view.who_s_new',
+        'views.view.who_s_online',
+      ], ['changed']);
 
     // Use the import link to get it back. Do this from the search page
     // report to make sure we are importing the right config.
@@ -314,7 +343,7 @@ class ConfigUpdateTest extends WebTestBase {
    * @param string[] $skip
    *   Array of report sections to skip checking.
    */
-  protected function assertReport($title, $missing, $added, $changed, $inactive, $skip = []) {
+  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');
 
@@ -393,7 +422,7 @@ class ConfigUpdateTest extends WebTestBase {
    * @param string[] $skip
    *   Array of report sections to skip checking.
    */
-  protected function assertDrushReports($type, $name, $missing, $added, $changed, $inactive, $skip = []) {
+  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');
@@ -442,9 +471,10 @@ class ConfigUpdateTest extends WebTestBase {
    */
   protected function assertNoReport() {
     $this->assertText('Report type');
-    $this->assertText('Configuration type');
-    $this->assertText('Module');
-    $this->assertText('Theme');
+    $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');
@@ -454,7 +484,6 @@ class ConfigUpdateTest extends WebTestBase {
 
     // 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');
@@ -469,7 +498,7 @@ class ConfigUpdateTest extends WebTestBase {
     $this->assertLink('Testing');
 
     // Configuration types.
-    $this->assertLink('All types');
+    $this->assertLink('Everything');
     $this->assertLink('Simple configuration');
     $this->assertLink('Search page');
   }

+ 4 - 4
sites/all/modules/contrib/admin/config_update/src/ConfigDiffInterface.php

@@ -14,9 +14,9 @@ interface ConfigDiffInterface {
    * have the same keys and values. It is up to the particular implementing
    * class to decide what normalizing means.
    *
-   * @param array $source
+   * @param array|null $source
    *   Source config.
-   * @param array $target
+   * @param array|null $target
    *   Target config.
    *
    * @return bool
@@ -32,9 +32,9 @@ interface ConfigDiffInterface {
    * differences. It is up to the particular implementing class to decide what
    * normalizing means.
    *
-   * @param array $source
+   * @param array|null $source
    *   Source config.
-   * @param array $target
+   * @param array|null $target
    *   Target config.
    *
    * @return \Drupal\Component\Diff\Diff

+ 8 - 8
sites/all/modules/contrib/admin/config_update/src/ConfigDiffer.php

@@ -43,7 +43,7 @@ class ConfigDiffer implements ConfigDiffInterface {
   /**
    * Constructs a ConfigDiffer.
    *
-   * @param TranslationInterface $translation
+   * @param \Drupal\Core\StringTranslation\TranslationInterface $translation
    *   String translation service.
    * @param string[] $ignore
    *   Config components to ignore.
@@ -52,7 +52,7 @@ class ConfigDiffer implements ConfigDiffInterface {
    * @param string $value_prefix
    *   Prefix to use in diffs for array value.
    */
-  public function __construct(TranslationInterface $translation, $ignore = ['uuid', '_core'], $hierarchy_prefix = '::', $value_prefix = ' : ') {
+  public function __construct(TranslationInterface $translation, array $ignore = ['uuid', '_core'], $hierarchy_prefix = '::', $value_prefix = ' : ') {
     $this->stringTranslation = $translation;
     $this->hierarchyPrefix = $hierarchy_prefix;
     $this->valuePrefix = $value_prefix;
@@ -66,7 +66,7 @@ class ConfigDiffer implements ConfigDiffInterface {
    * as well as empty array values, and sorts at each level by array key, so
    * that config from different storage can be compared meaningfully.
    *
-   * @param array $config
+   * @param array|null $config
    *   Configuration array to normalize.
    *
    * @return array
@@ -109,7 +109,7 @@ class ConfigDiffer implements ConfigDiffInterface {
   public function same($source, $target) {
     $source = $this->normalize($source);
     $target = $this->normalize($target);
-    return $source == $target;
+    return $source === $target;
   }
 
   /**
@@ -136,15 +136,15 @@ class ConfigDiffer implements ConfigDiffInterface {
    *   (optional) When called recursively, the prefix to put on each line. Omit
    *   when initially calling this function.
    *
-   * @return string[] Array of config lines formatted so that a line-by-line
-   *   diff will show the context in each line, and meaningful differences will
-   *   be computed.
+   * @return string[]
+   *   Array of config lines formatted so that a line-by-line diff will show the
+   *   context in each line, and meaningful differences will be computed.
    *
    * @see ConfigDiffer::normalize()
    * @see ConfigDiffer::$hierarchyPrefix
    * @see ConfigDiffer::$valuePrefix
    */
-  protected function format($config, $prefix = '') {
+  protected function format(array $config, $prefix = '') {
     $lines = [];
 
     foreach ($config as $key => $value) {

+ 23 - 1
sites/all/modules/contrib/admin/config_update/src/ConfigLister.php

@@ -164,7 +164,7 @@ class ConfigLister implements ConfigListInterface {
         break;
 
       case 'profile':
-        $name = Settings::get('install_profile');
+        $name = $this->getProfileName();
         // Intentional fall-through here to the 'module' or 'theme' case.
       case 'module':
       case 'theme':
@@ -220,4 +220,26 @@ class ConfigLister implements ConfigListInterface {
     return array_values($list);
   }
 
+  /**
+   * Returns the name of the install profile.
+   *
+   * For backwards compatibility with pre/post 8.3.x, tries to get it from
+   * either configuration or settings.
+   *
+   * @return string
+   *   The name of the install profile.
+   */
+  protected function getProfileName() {
+    // Code adapted from DrupalKernel::getInstalProfile() in Core.
+    // In Core 8.3.x or later, read from config.
+    $config = $this->activeConfigStorage->read('core.extension');
+    if (!empty($config['profile'])) {
+      return $config['profile'];
+    }
+    else {
+      // If system_update_8300() has not yet run, use settings.
+      return Settings::get('install_profile');
+    }
+  }
+
 }

+ 3 - 7
sites/all/modules/contrib/admin/config_update/src/ConfigListerWithProviders.php

@@ -7,8 +7,6 @@ use Drupal\Core\Config\StorageInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Extension\ThemeHandlerInterface;
-use Drupal\Core\Site\Settings;
-use Drupal\Core\Extension\Extension;
 
 /**
  * Provides methods related to config listing, including provider calculation.
@@ -88,12 +86,10 @@ class ConfigListerWithProviders extends ConfigLister implements ConfigListByProv
     }
 
     // Calculate if it hasn't been set up yet.
-
     // List all of the profile, modules, and themes.
     $extensionsToDo = [];
-    $profile = Settings::get('install_profile');
+    $profile = $this->getProfileName();
     $extensionsToDo[] = ['profile', $profile];
-
     $modules = $this->moduleHandler->getModuleList();
     foreach ($modules as $machine_name => $module) {
       if ($machine_name != $profile) {
@@ -114,14 +110,14 @@ class ConfigListerWithProviders extends ConfigLister implements ConfigListByProv
       'theme' => [],
     ];
 
-    foreach($extensionsToDo as $item) {
+    foreach ($extensionsToDo as $item) {
       $type = $item[0];
       $name = $item[1];
       $configs = array_merge($this->listProvidedItems($type, $name),
         $this->listProvidedItems($type, $name, TRUE));
       if (!empty($configs)) {
         $this->extensionsWithConfig[$type][$name] = $name;
-        foreach($configs as $config) {
+        foreach ($configs as $config) {
           $this->providers[$config] = [$type, $name];
         }
       }

+ 308 - 0
sites/all/modules/contrib/admin/config_update/tests/src/Unit/ConfigDifferTest.php

@@ -0,0 +1,308 @@
+<?php
+
+namespace Drupal\Tests\config_update\Unit;
+
+use Drupal\config_update\ConfigDiffer;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests the \Drupal\config_update\ConfigDiffer class.
+ *
+ * @group config_update
+ *
+ * @coversDefaultClass \Drupal\config_update\ConfigDiffer
+ */
+class ConfigDifferTest extends UnitTestCase {
+
+  /**
+   * The mock translation object.
+   *
+   * @var \Drupal\Core\StringTranslation\TranslationInterface
+   */
+  protected $stringTranslation;
+
+  /**
+   * The config differ to test.
+   *
+   * @var \Drupal\config_update\ConfigDiffer
+   */
+  protected $configDiffer;
+
+  /**
+   * {@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);
+  }
+
+  /**
+   * @covers \Drupal\config_update\ConfigDiffer::same
+   * @dataProvider sameProvider
+   */
+  public function testSame($a, $b, $expected) {
+    $this->assertEquals($expected, $this->configDiffer->same($a, $b));
+  }
+
+  /**
+   * Data provider for self:testSame().
+   */
+  public function sameProvider() {
+    $base = [
+      'uuid' => 'bar',
+      'a' => 'a',
+      'b' => 0,
+      'c' => [
+        'd' => TRUE,
+        'e' => FALSE,
+      ],
+    ];
+
+    return [
+      [$base, $base, TRUE],
+
+      // Add _core, omit uuid. Should match.
+      [
+        $base,
+        [
+          '_core' => 'foo',
+          'a' => 'a',
+          'b' => 0,
+          'c' => [
+            'd' => TRUE,
+            'e' => FALSE,
+          ],
+        ],
+        TRUE,
+      ],
+
+      // Change order. Should match.
+      [
+        $base,
+        [
+          'a' => 'a',
+          'uuid' => 'bar',
+          'b' => 0,
+          'c' => [
+            'd' => TRUE,
+            'e' => FALSE,
+          ],
+        ],
+        TRUE,
+      ],
+
+      // Change order and add _core in deeper level. Should match.
+      [
+        $base,
+        [
+          'uuid' => 'bar',
+          'a' => 'a',
+          'b' => 0,
+          'c' => [
+            'e' => FALSE,
+            '_core' => 'foo',
+            'd' => TRUE,
+          ],
+        ],
+        TRUE,
+      ],
+
+      // Omit a component. Should not match.
+      [
+        $base,
+        [
+          'uuid' => 'bar',
+          'a' => 'a',
+          'c' => [
+            'd' => TRUE,
+            'e' => FALSE,
+          ],
+        ],
+        FALSE,
+      ],
+
+      // Add a component. Should not match.
+      [
+        $base,
+        [
+          'uuid' => 'bar',
+          'a' => 'a',
+          'b' => 0,
+          'c' => [
+            'd' => TRUE,
+            'e' => FALSE,
+          ],
+          'f' => 'f',
+        ],
+        FALSE,
+      ],
+
+      // 0 should not match a string.
+      [
+        $base,
+        [
+          '_core' => 'foo',
+          'uuid' => 'bar',
+          'a' => 'a',
+          'b' => 'b',
+          'c' => [
+            'd' => TRUE,
+            'e' => FALSE,
+          ],
+        ],
+        FALSE,
+      ],
+
+      // FALSE should not match a string.
+      [
+        $base,
+        [
+          '_core' => 'foo',
+          'uuid' => 'bar',
+          'a' => 'a',
+          'b' => 0,
+          'c' => [
+            'd' => TRUE,
+            'e' => 'e',
+          ],
+        ],
+        FALSE,
+      ],
+
+      // TRUE should not match a string.
+      [
+        $base,
+        [
+          '_core' => 'foo',
+          'uuid' => 'bar',
+          'a' => 'a',
+          'b' => 0,
+          'c' => [
+            'd' => 'd',
+            'e' => FALSE,
+          ],
+        ],
+        FALSE,
+      ],
+    ];
+  }
+
+  /**
+   * @covers \Drupal\config_update\ConfigDiffer::diff
+   */
+  public function testDiff() {
+    $configOne = [
+      'uuid' => '1234-5678-90',
+      'id' => 'test.config.id',
+      'id_to_remove' => 'test.remove.id',
+      'type' => 'old_type',
+      'true_value' => TRUE,
+      'nested_array' => [
+        'flat_array' => [
+          'value2',
+          'value1',
+          'value3',
+        ],
+        'custom_key' => 'value',
+      ],
+    ];
+
+    $configTwo = [
+      'uuid' => '09-8765-4321',
+      'id' => 'test.config.id',
+      'type' => 'new_type',
+      'true_value' => FALSE,
+      'nested_array' => [
+        'flat_array' => [
+          'value2',
+          'value3',
+        ],
+        'custom_key' => 'value',
+        'custom_key_2' => 'value2',
+      ],
+    ];
+
+    $edits = $this->configDiffer->diff($configOne, $configTwo)->getEdits();
+
+    $expectedEdits = [
+      [
+        'copy' => [
+          'orig' => [
+            'id : test.config.id',
+          ],
+          'closing' => [
+            'id : test.config.id',
+          ],
+        ],
+      ],
+      [
+        'delete' => [
+          'orig' => [
+            'id_to_remove : test.remove.id',
+          ],
+          'closing' => FALSE,
+        ],
+      ],
+      [
+        'copy' => [
+          'orig' => [
+            'nested_array',
+            'nested_array::custom_key : value',
+          ],
+          'closing' => [
+            'nested_array',
+            'nested_array::custom_key : value',
+          ],
+        ],
+      ],
+      [
+        'add' => [
+          'orig' => FALSE,
+          'closing' => [
+            'nested_array::custom_key_2 : value2',
+          ],
+        ],
+      ],
+      [
+        'copy' => [
+          'orig' => [
+            'nested_array::flat_array',
+            'nested_array::flat_array::0 : value2',
+          ],
+          'closing' => [
+            'nested_array::flat_array',
+            'nested_array::flat_array::0 : value2',
+          ],
+        ],
+      ],
+      [
+        'change' => [
+          'orig' => [
+            'nested_array::flat_array::1 : value1',
+            'nested_array::flat_array::2 : value3',
+            'true_value : 1',
+            'type : old_type',
+          ],
+          'closing' => [
+            'nested_array::flat_array::1 : value3',
+            'true_value : ',
+            'type : new_type',
+          ],
+        ],
+      ],
+    ];
+
+    $this->assertEquals(count($expectedEdits), count($edits));
+
+    /** @var \Drupal\Component\Diff\Engine\DiffOp $diffOp */
+    foreach ($edits as $index => $diffOp) {
+      $this->assertEquals($expectedEdits[$index][$diffOp->type]['orig'], $diffOp->orig);
+      $this->assertEquals($expectedEdits[$index][$diffOp->type]['closing'], $diffOp->closing);
+    }
+  }
+
+}

+ 0 - 0
sites/all/modules/contrib/migrate/migrate_plus/LICENSE.txt → sites/all/modules/contrib/dev/config_devel/LICENSE.txt


+ 8 - 0
sites/all/modules/contrib/dev/config_devel/composer.json

@@ -0,0 +1,8 @@
+{
+  "name": "drupal/config_devel",
+  "description": "Helps developers work with configuration.",
+  "type": "drupal-module",
+  "license": "GPL-2.0+",
+  "minimum-stability": "dev",
+  "require": { }
+}

+ 2 - 0
sites/all/modules/contrib/dev/config_devel/config/install/config_devel.settings.yml

@@ -0,0 +1,2 @@
+auto_import: []
+auto_export: []

+ 23 - 0
sites/all/modules/contrib/dev/config_devel/config/schema/config_devel.schema.yml

@@ -0,0 +1,23 @@
+config_devel.settings:
+  type: config_object
+  label: config devel settings
+  mapping:
+    auto_import:
+      type: sequence
+      sequence:
+        - type: mapping
+          mapping:
+            filename:
+              type: string
+            hash:
+              type: string
+    auto_export:
+      type: sequence
+      sequence:
+        - type: string
+config_devel.test:
+  type: config_object
+  label: config devel test
+  mapping:
+    label:
+      type: label

+ 13 - 0
sites/all/modules/contrib/dev/config_devel/config_devel.info.yml

@@ -0,0 +1,13 @@
+name: Configuration development module
+type: module
+description: 'Helps developers work with configuration.'
+package: Configuration
+# version: VERSION
+# core: 8.x
+configure: config_devel.settings
+
+# Information added by Drupal.org packaging script on 2017-09-11
+version: '8.x-1.1'
+core: '8.x'
+project: 'config_devel'
+datestamp: 1505141047

+ 5 - 0
sites/all/modules/contrib/dev/config_devel/config_devel.links.menu.yml

@@ -0,0 +1,5 @@
+config_devel.settings:
+  title: Config devel
+  description: 'Specify which configuration objects to automatically import/export.'
+  route_name: config_devel.settings
+  parent: system.admin_config_development

+ 7 - 0
sites/all/modules/contrib/dev/config_devel/config_devel.routing.yml

@@ -0,0 +1,7 @@
+config_devel.settings:
+  path: '/admin/config/development/config_devel'
+  defaults:
+    _form: 'Drupal\config_devel\Form\ConfigDevelSettingsForm'
+    _title: 'Config Devel'
+  requirements:
+    _permission: 'import configuration'

+ 11 - 0
sites/all/modules/contrib/dev/config_devel/config_devel.services.yml

@@ -0,0 +1,11 @@
+services:
+  config_devel.writeback_subscriber:
+    class: Drupal\config_devel\EventSubscriber\ConfigDevelAutoExportSubscriber
+    arguments: ['@config.factory', '@config.manager', '@event_dispatcher']
+    tags:
+      - { name: event_subscriber }
+  config_devel.auto_import_subscriber:
+    class: Drupal\config_devel\EventSubscriber\ConfigDevelAutoImportSubscriber
+    arguments: ['@config.factory', '@config.manager']
+    tags:
+      - { name: event_subscriber }

+ 246 - 0
sites/all/modules/contrib/dev/config_devel/drush/config_devel.drush.inc

@@ -0,0 +1,246 @@
+<?php
+
+/**
+ * @file
+ * Configuration development module drush integration.
+ */
+
+use Drupal\Core\Config\InstallStorage;
+
+/**
+ * Implements hook_drush_command().
+ */
+function config_devel_drush_command() {
+  $items = array();
+
+  $description = '';
+  $description .= "List which configuration settings you want to export in the\n";
+  $description .= "module's info file by listing them under 'config_devel', as shown below:\n";
+  $description .= "\n";
+  $description .= "config_devel:\n";
+  $description .= "  install:\n";
+  $description .= "    - entity.view_display.node.article.default\n";
+  $description .= "    - entity.view_display.node.article.teaser\n";
+  $description .= "    - field.instance.node.article.body\n";
+  $description .= "  optional:\n";
+  $description .= "    - field.instance.node.article.tags\n";
+
+  $items['config-devel-export'] = array(
+    'description' => "Write back configuration to module's config directory.\n" . $description,
+    'arguments' => array(
+      'module' => 'Module machine name.',
+    ),
+    'options' => array(
+    ),
+    'required-arguments' => TRUE,
+    'examples' => array(
+      'drush config-devel-export MODULE_NAME' => 'Write back configuration to the specified module, based on .info file.',
+    ),
+    'aliases' => array('cde', 'cd-em'),
+  );
+
+  $items['config-devel-import'] = array(
+    'description' => "Import configuration from module's config directory to active storage.\n" . $description,
+    'arguments' => array(
+      'module' => 'Module machine name.',
+    ),
+    'options' => array(
+    ),
+    'required-arguments' => TRUE,
+    'examples' => array(
+      'drush config-devel-import MODULE_NAME' => 'Import configuration from the specified module into the active storage, based on .info file.',
+    ),
+    'aliases' => array('cdi', 'cd-im'),
+  );
+
+  $items['config-devel-import-one'] = array(
+    'description' => "Import a single configuration item from module's config directory to active storage.\n" . $description,
+    'arguments' => array(
+      'path' => 'Config file name.',
+    ),
+    'options' => array(
+    ),
+    'required-arguments' => TRUE,
+    'examples' => array(
+      'drush config-devel-import-one system.site.yml' => 'Import the contents of system.site.yml into the config object system.site.',
+      'drush config-devel-import-one system.site' => 'Import the standard input into the config object system.site. Helpful for scripting copying to remote',
+    ),
+    'aliases' => array('cdi1', 'cd-i1'),
+  );
+
+  return $items;
+}
+
+/**
+ * Drush command callback.
+ */
+function drush_config_devel_export($extension) {
+  // Determine the type of extension we're dealing with.
+  $type = drush_config_devel_get_type($extension);
+
+  if ($type) {
+    // Get the config
+    $config = drush_config_devel_get_config($type, $extension);
+
+    // Process config
+    if (isset($config['install'])) {
+      drush_config_devel_process_config($config['install'], $type, $extension, InstallStorage::CONFIG_INSTALL_DIRECTORY);
+    }
+
+    // If we have any optional configuration, process that as well.
+    if (isset($config['optional'])) {
+      drush_config_devel_process_config($config['optional'], $type, $extension, InstallStorage::CONFIG_OPTIONAL_DIRECTORY);
+    }
+  }
+  else {
+    drush_set_error("Couldn't export configuration. The '$extension' extension is not enabled.");
+  }
+}
+
+/**
+ * Drush command callback.
+ */
+function drush_config_devel_import($extension) {
+  // Determine the type of extension we're dealing with.
+  $type = drush_config_devel_get_type($extension);
+
+  if ($type) {
+    // Get the config
+    $config = drush_config_devel_get_config($type, $extension);
+
+    // Import config
+    if (isset($config['install'])) {
+      drush_config_devel_import_config($config['install'], $type, $extension, InstallStorage::CONFIG_INSTALL_DIRECTORY);
+    }
+
+    // Import optional config
+    if (isset($config['optional'])) {
+      drush_config_devel_import_config($config['optional'], $type, $extension, InstallStorage::CONFIG_OPTIONAL_DIRECTORY);
+    }
+  }
+  else {
+    drush_set_error("Couldn't import configuration. The '$extension' extension is not enabled.");
+  }
+}
+
+/**
+ * Drush command callback.
+ */
+function drush_config_devel_import_one($path) {
+  $contents = '';
+  if (!file_exists($path)) {
+    if (substr($path, -4) != '.yml') {
+      $contents = file_get_contents('php://stdin');
+    }
+    elseif (!empty($_SERVER['PWD'])) {
+      $path = $_SERVER['PWD'] . '/' . trim($path, '/');
+    }
+  }
+  if ($contents || file_exists($path)) {
+    \Drupal::service('config_devel.auto_import_subscriber')->importOne($path, '', $contents);
+  }
+  else {
+    drush_log("file '$path' not found", 'error');
+    exit;
+  }
+}
+
+/**
+ * Exports a list of configuration entities.
+ *
+ * @param array $config_list
+ *   An array of configuration entities.
+ * @param string $type
+ *   The type of extension we're exporting, one of module or theme.
+ * @param string $extension
+ *   The module, theme or install profile we're exporting.
+ * @param string $directory
+ *   The directory we're exporting to.
+ */
+function drush_config_devel_process_config($config_list, $type, $extension, $directory) {
+  $config_path = drupal_get_path($type, $extension) . "/$directory";
+  foreach ($config_list as $name) {
+    $config = \Drupal::config($name);
+    $file_names = array($config_path . '/' . $name . '.yml');
+
+    \Drupal::service('config_devel.writeback_subscriber')->writeBackConfig($config, $file_names);
+  }
+}
+
+/**
+ * Imports a list of configuration entities
+ *
+ * @param array $config_list
+ *   An array of configuration entities.
+ * @param string $type
+ *   The type of extension we're exporting, one of module or theme.
+ * @param string $extension
+ *   The module, theme or install profile we're exporting.
+ * @param string $directory
+ *   The directory we're exporting to.
+ */
+function drush_config_devel_import_config($config_list, $type, $extension, $directory) {
+  $config_path = drupal_get_path($type, $extension) . "/$directory";
+  foreach ($config_list as $name) {
+    $file_name = $config_path . '/' . $name . '.yml';
+    drush_config_devel_import_one($file_name);
+  }
+}
+
+/**
+ * Gets the config.
+ *
+ * @param  string $type
+ *   module, theme or profile
+ * @param  string $extension
+ *   extension name
+ * @return array
+ *   An array containing install and optional config
+ */
+function drush_config_devel_get_config($type, $extension) {
+  $filename = drupal_get_path($type, $extension) . '/' . $extension .'.info.yml';
+  $info = \Drupal::service('info_parser')->parse($filename);
+
+  $config = array();
+  if (isset($info['config_devel'])) {
+    // Keep backwards compatibility for the old format. This has config names
+    // listed directly beneath 'config_devel', rather than an intermediate level
+    // for 'install' and 'optional'.
+    // Detect the old format based on whether there's neither of these two keys.
+    if (!isset($info['config_devel']['install']) && !isset($info['config_devel']['optional'])) {
+      $info['config_devel']['install'] = $info['config_devel'];
+    }
+
+    $config['install'] = $info['config_devel']['install'];
+
+    // If we have any optional configuration, fetch that as well.
+    if (isset($info['config_devel']['optional'])) {
+      $config['optional'] = $info['config_devel']['optional'];
+    }
+  }
+
+  return $config;
+}
+
+/**
+ * Gets the type for the given extension.
+ *
+ * @param  string $extension
+ *   extension name
+ * @return string
+ *   module, theme, profile, or FALSE if no valid extension provided.
+ */
+function drush_config_devel_get_type($extension) {
+  $type = NULL;
+  if (\Drupal::moduleHandler()->moduleExists($extension)) {
+    $type = 'module';
+  }
+  elseif (\Drupal::service('theme_handler')->themeExists($extension)) {
+    $type = 'theme';
+  }
+  elseif (drupal_get_profile() === $extension) {
+    $type = 'profile';
+  }
+
+  return $type;
+}

+ 26 - 0
sites/all/modules/contrib/dev/config_devel/src/Event/ConfigDevelEvents.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\config_devel\Event;
+
+/**
+ * Defines events for config devel.
+ *
+ * @see \Drupal\config_devel\Event\ConfigDevelSaveEvent
+ */
+final class ConfigDevelEvents {
+
+  /**
+   * Name of the event fired when saving a config entity to disk.
+   *
+   * This event allows other modules to impact the configuration that is being
+   * written to disk
+   *
+   * @Event
+   *
+   * @see \Drupal\config_devel\Event\ConfigDevelSaveEvent
+   *
+   * @var string
+   */
+  const SAVE = 'config_devel.save';
+
+}

+ 79 - 0
sites/all/modules/contrib/dev/config_devel/src/Event/ConfigDevelSaveEvent.php

@@ -0,0 +1,79 @@
+<?php
+
+namespace Drupal\config_devel\Event;
+
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * The ConfigDevelSaveEvent class.
+ */
+class ConfigDevelSaveEvent extends Event {
+
+  /**
+   * An array of files names that will  be written.
+   *
+   * @var array
+   */
+  protected $fileNames = [];
+
+  /**
+   * An array representing the config object to be written.
+   *
+   * @var array
+   */
+  protected $data;
+
+  /**
+   * ConfigDevelSaveEvent constructor.
+   *
+   * @param array $file_names
+   *   The config file names.
+   * @param array $data
+   *   The config data.
+   */
+  public function __construct(array $file_names, array $data) {
+    $this->fileNames = $file_names;
+    $this->data = $data;
+  }
+
+  /**
+   * Gets the filenames that will be saved.
+   *
+   * @return array
+   *   An array of file names.
+   */
+  public function getFileNames() {
+    return $this->fileNames;
+  }
+
+  /**
+   * Sets the file names.
+   *
+   * @param array $file_names
+   *   An array of file names to be written out
+   */
+  public function setFileNames(array $file_names) {
+    $this->fileNames = $file_names;
+  }
+
+  /**
+   * Gets the data representing the config object.
+   *
+   * @return array
+   *   An array of config data.
+   */
+  public function getData() {
+    return $this->data;
+  }
+
+  /**
+   * Sets the data for the config object.
+   *
+   * @param array $data
+   *   The config data.
+   */
+  public function setData(array $data) {
+    $this->data = $data;
+  }
+
+}

+ 136 - 0
sites/all/modules/contrib/dev/config_devel/src/EventSubscriber/ConfigDevelAutoExportSubscriber.php

@@ -0,0 +1,136 @@
+<?php
+
+namespace Drupal\config_devel\EventSubscriber;
+
+use Drupal\config_devel\Event\ConfigDevelEvents;
+use Drupal\config_devel\Event\ConfigDevelSaveEvent;
+use Drupal\Core\Config\Config;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Config\ConfigManagerInterface;
+use Drupal\Core\Config\FileStorage;
+use Drupal\Core\Config\InstallStorage;
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\Yaml\Exception\DumpException;
+use Drupal\Core\Config\ConfigCrudEvent;
+use Drupal\Core\Config\ConfigRenameEvent;
+use Drupal\Core\Config\ConfigEvents;
+
+/**
+ * ConfigDevelAutoExportSubscriber subscriber for configuration CRUD events.
+ */
+class ConfigDevelAutoExportSubscriber extends ConfigDevelSubscriberBase implements EventSubscriberInterface {
+
+  /**
+   * The event dispatcher.
+   *
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  protected $eventDispatcher;
+
+  /**
+   * Constructs the ConfigDevelAutoExportSubscriber object.
+   *
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The configuration factory.
+   * @param \Drupal\Core\Config\ConfigManagerInterface $config_manager
+   *   The configuration manager.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
+   */
+  public function __construct(ConfigFactoryInterface $config_factory, ConfigManagerInterface $config_manager, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct($config_factory, $config_manager);
+    $this->configFactory = $config_factory;
+    $this->configManager = $config_manager;
+    $this->eventDispatcher = $event_dispatcher;
+  }
+
+  /**
+   * The files to automatically export.
+   *
+   * @var array
+   */
+  protected $autoExportFiles;
+
+  /**
+   * React to configuration ConfigEvent::SAVE events.
+   *
+   * @param \Drupal\Core\Config\ConfigCrudEvent $event
+   *   The event to process.
+   */
+  public function onConfigSave(ConfigCrudEvent $event) {
+    $this->autoExportConfig($event->getConfig());
+  }
+
+  /**
+   * React to configuration ConfigEvent::RENAME events.
+   *
+   * @param \Drupal\Core\Config\ConfigRenameEvent $event
+   *   The event to process.
+   */
+  public function onConfigRename(ConfigRenameEvent $event) {
+    $this->autoExportConfig($event->getConfig());
+  }
+
+  /**
+   * Automatically export configuration.
+   *
+   * @param Config $config
+   *   The config object.
+   */
+  protected function autoExportConfig(Config $config) {
+    $config_name = $config->getName();
+    $file_names = array_filter($this->getSettings()->get('auto_export') ?: [], function ($file_name) use ($config_name) {
+      return basename($file_name, '.' . FileStorage::getFileExtension()) == $config_name;
+    });
+    $this->writeBackConfig($config, $file_names);
+  }
+
+  /**
+   * write configuration back to files.
+   *
+   * @param \Drupal\Core\Config\Config $config
+   *   The config object.
+   * @param array $file_names
+   *   The file names to which the configuration should be written.
+   */
+  public function writeBackConfig(Config $config, array $file_names) {
+    if ($file_names) {
+      $data = $config->get();
+      $config_name = $config->getName();
+      unset($data['_core']);
+      if ($entity_type_id = $this->configManager->getEntityTypeIdByName($config_name)) {
+        unset($data['uuid']);
+      }
+
+      // Let everyone else have a change to update the exported data.
+      $event = new ConfigDevelSaveEvent($file_names, $data);
+      $this->eventDispatcher->dispatch(ConfigDevelEvents::SAVE, $event);
+      $data = $event->getData();
+      $file_names = $event->getFileNames();
+
+      foreach ($file_names as $file_name) {
+        try {
+          file_put_contents($file_name, (new InstallStorage())->encode($data));
+        }
+        catch (DumpException $e) {
+          // Do nothing. What could we do?
+        }
+      }
+    }
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  static function getSubscribedEvents() {
+    $events[ConfigEvents::SAVE][] = array('onConfigSave', 10);
+    $events[ConfigEvents::RENAME][] = array('onConfigRename', 10);
+    return $events;
+  }
+
+}

+ 83 - 0
sites/all/modules/contrib/dev/config_devel/src/EventSubscriber/ConfigDevelAutoImportSubscriber.php

@@ -0,0 +1,83 @@
+<?php
+
+namespace Drupal\config_devel\EventSubscriber;
+
+use Drupal\Component\Utility\Crypt;
+use Drupal\Core\Config\InstallStorage;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpKernel\KernelEvents;
+
+class ConfigDevelAutoImportSubscriber extends ConfigDevelSubscriberBase implements EventSubscriberInterface {
+
+  /**
+   * Reinstall changed config files.
+   */
+  public function autoImportConfig() {
+    $config = $this->getSettings();
+    $changed = FALSE;
+    foreach ($config->get('auto_import') as $key => $file) {
+      if ($new_hash = $this->importOne($file['filename'], $file['hash'])) {
+        $config->set("auto_import.$key.hash", $new_hash);
+        $changed = TRUE;
+      }
+    }
+    if ($changed) {
+      $config->save();
+    }
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('autoImportConfig', 20);
+    return $events;
+  }
+
+  /**
+   * @param string $filename
+   * @param string $original_hash
+   * @return bool
+   */
+  public function importOne($filename, $original_hash = '', $contents = '') {
+    $hash = '';
+    if (!$contents && (!$contents = @file_get_contents($filename))) {
+      return $hash;
+    }
+    $needs_import = TRUE;
+    if ($original_hash) {
+      $hash = Crypt::hashBase64($contents);
+      if ($hash == $original_hash) {
+        $needs_import = FALSE;
+      }
+    }
+    if ($needs_import) {
+      $data = (new InstallStorage())->decode($contents);
+      $config_name = basename($filename, '.yml');
+      $entity_type_id = $this->configManager->getEntityTypeIdByName($config_name);
+      if ($entity_type_id) {
+        $entity_storage = $this->getStorage($entity_type_id);
+        $entity_id = $this->getEntityId($entity_storage, $config_name);
+        $entity_type = $entity_storage->getEntityType();
+        $id_key = $entity_type->getKey('id');
+        $data[$id_key] = $entity_id;
+        /** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $entity */
+        $entity = $entity_storage->create($data);
+        if ($existing_entity = $entity_storage->load($entity_id)) {
+          $entity
+            ->set('uuid', $existing_entity->uuid())
+            ->enforceIsNew(FALSE);
+        }
+        $entity_storage->save($entity);
+      }
+      else {
+        $this->configFactory->getEditable($config_name)->setData($data)->save();
+      }
+    }
+    return $hash;
+  }
+
+}

+ 66 - 0
sites/all/modules/contrib/dev/config_devel/src/EventSubscriber/ConfigDevelSubscriberBase.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace Drupal\config_devel\EventSubscriber;
+
+
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Config\ConfigManagerInterface;
+use Drupal\Core\Config\Entity\ConfigEntityStorageInterface;
+
+class ConfigDevelSubscriberBase {
+
+  /**
+   * The configuration factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * The configuration manager.
+   *
+   * @var \Drupal\Core\Config\ConfigManagerInterface
+   */
+  protected $configManager;
+
+  /**
+   * Constructs the ConfigDevelAutoExportSubscriber object.
+   *
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The configuration factory.
+   * @param \Drupal\Core\Config\ConfigManagerInterface $config_manager
+   *   The configuration manager.
+   */
+  public function __construct(ConfigFactoryInterface $config_factory, ConfigManagerInterface $config_manager) {
+    $this->configFactory = $config_factory;
+    $this->configManager = $config_manager;
+  }
+
+  /**
+   * @param string $entity_type_id
+   *
+   * @return \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
+   */
+  protected function getStorage($entity_type_id) {
+    return $this->configManager->getEntityManager()->getStorage($entity_type_id);
+  }
+
+  /**
+   * @param \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $entity_storage
+   * @param string $config_name
+   *
+   * @return string
+   */
+  protected function getEntityId(ConfigEntityStorageInterface $entity_storage, $config_name) {
+    // getIDFromConfigName adds a dot but getConfigPrefix has a dot already.
+    return $entity_storage::getIDFromConfigName($config_name, $entity_storage->getEntityType()->getConfigPrefix());
+  }
+
+  /**
+   * @return \Drupal\Core\Config\Config
+   */
+  protected function getSettings() {
+    return $this->configFactory->getEditable('config_devel.settings');
+  }
+
+}

+ 100 - 0
sites/all/modules/contrib/dev/config_devel/src/Form/ConfigDevelSettingsForm.php

@@ -0,0 +1,100 @@
+<?php
+
+namespace Drupal\config_devel\Form;
+
+use Drupal\Core\Config\FileStorage;
+use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Settings form for config devel.
+ */
+class ConfigDevelSettingsForm extends ConfigFormBase {
+
+  /**
+   * Name of the config being edited.
+   */
+  const CONFIGNAME = 'config_devel.settings';
+
+  /**
+   * @var array
+   */
+  protected $keys;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    $default_value = '';
+    foreach ($this->config(static::CONFIGNAME)->get('auto_import') as $file) {
+      $default_value .= $file['filename'] . "\n";
+    }
+    $form['auto_import'] = array(
+      '#type' => 'textarea',
+      '#title' => $this->t('Auto import'),
+      '#default_value' => $default_value,
+      '#description' => $this->t('When these files change, they will be automatically imported at the beginning of the next request.') . '<br>' .
+        $this->t('Enter one item per line. Each item should consist of a path relative to the Drupal root and a filename in the same form as a config YML file.') . '<br>' .
+        $this->t('For example: "modules/mymodule/config/install/node.type.mytype.yml".'),
+    );
+    $form['auto_export'] = array(
+      '#type' => 'textarea',
+      '#title' => $this->t('Auto export'),
+      '#default_value' => implode("\n", $this->config(static::CONFIGNAME)->get('auto_export')),
+      '#description' => $this->t('Automatically export to the files specified when the corresponding config item is changed in the admin UI.') . '<br>' .
+        $this->t('Enter one item per line. Each item should consist of a path relative to the Drupal root and a filename in the same form as a config YML file.') . '<br>' .
+        $this->t('For example: "modules/mymodule/config/install/node.type.mytype.yml".'),
+    );
+    return parent::buildForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state) {
+    foreach (array('auto_import', 'auto_export') as $key) {
+      $form_state->setValue($key, array_filter(preg_split("/\r\n/", $form_state->getValues()[$key])));
+    }
+    foreach ($form_state->getValues()['auto_import'] as $file) {
+      $name = basename($file, '.' . FileStorage::getFileExtension());
+      if (in_array($name, array('system.site', 'core.extension', 'simpletest.settings'))) {
+        $form_state->setErrorByName('auto_import', $this->t('@name is not compatible with this module', array('@name' => $name)));
+      }
+    }
+    parent::validateForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    $auto_import = array();
+    foreach ($form_state->getValues()['auto_import'] as $file) {
+      $auto_import[] = array(
+        'filename' => $file,
+        'hash' => '',
+      );
+    }
+    $this->config(static::CONFIGNAME)
+      ->set('auto_import', $auto_import)
+      ->set('auto_export', $form_state->getValues()['auto_export'])
+      ->save();
+    parent::submitForm($form, $form_state);
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'config_devel_settings';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['config_devel.settings'];
+  }
+
+}

+ 32 - 0
sites/all/modules/contrib/dev/config_devel/tests/src/Kernel/ConfigDevelSubscriberEntityTest.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace Drupal\Tests\config_devel\Kernel;
+
+/**
+ * Tests the automated importer for config entities.
+ *
+ * @group config_devel
+ */
+class ConfigDevelSubscriberEntityTest extends ConfigDevelSubscriberTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = array('config_test');
+
+  /**
+   * {@inheritdoc}
+   */
+  const CONFIGNAME = 'config_test.dynamic.test';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doAssert(array $data, array $exported_data) {
+    $entity = entity_load('config_test', 'test', TRUE);
+    $this->assertIdentical($data['label'], $entity->get('label'));
+    $this->assertIdentical($exported_data['label'], $data['label']);
+    $this->assertIdentical($exported_data['id'], 'test');
+    $this->assertFalse(isset($exported_data['uuid']));
+  }
+}

+ 25 - 0
sites/all/modules/contrib/dev/config_devel/tests/src/Kernel/ConfigDevelSubscriberRawTest.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace Drupal\Tests\config_devel\Kernel;
+
+/**
+ * Tests the automated importer for raw config objects.
+ *
+ * @group config_devel
+ */
+class ConfigDevelSubscriberRawTest extends ConfigDevelSubscriberTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  const CONFIGNAME = 'config_devel.test';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doAssert(array $data, array $exported_data) {
+    $this->assertIdentical($data, $this->storage->read(static::CONFIGNAME));
+    $this->assertIdentical($data, $exported_data);
+  }
+
+}

+ 65 - 0
sites/all/modules/contrib/dev/config_devel/tests/src/Kernel/ConfigDevelSubscriberTestBase.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace Drupal\Tests\config_devel\Kernel;
+
+use Drupal\Component\Serialization\Yaml;
+use Drupal\KernelTests\KernelTestBase;
+
+abstract class ConfigDevelSubscriberTestBase extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = array('config_devel');
+
+  /**
+   * Name of the config object.
+   */
+  const CONFIGNAME = '';
+
+  /**
+   * @var \Drupal\Core\Config\StorageInterface
+   */
+  protected $storage;
+
+  /**
+   * Test the import subscriber.
+   */
+  public function testSubscribers() {
+    // Without this the config exporter breaks.
+    \Drupal::service('config.installer')->installDefaultConfig('module', 'config_devel');
+    $filename = 'public://'. static::CONFIGNAME . '.yml';
+    drupal_mkdir('public://exported');
+    $exported_filename = 'public://exported/' . static::CONFIGNAME . '.yml';
+    \Drupal::configFactory()->getEditable('config_devel.settings')
+      ->set('auto_import', array(array(
+        'filename' => $filename,
+        'hash' => '',
+      )))
+      ->set('auto_export', array(
+        $exported_filename,
+      ))
+      ->save();
+    $this->storage = \Drupal::service('config.storage');
+    $this->assertFalse($this->storage->exists(static::CONFIGNAME));
+    $subscriber = \Drupal::service('config_devel.auto_import_subscriber');
+    for ($i = 2; $i; $i--) {
+      $data['label'] = $this->randomString();
+      file_put_contents($filename, Yaml::encode($data));
+      // The import fires an export too.
+      $subscriber->autoImportConfig();
+      $this->doAssert($data, Yaml::decode(file_get_contents($exported_filename)));
+    }
+  }
+
+  /**
+   * Assert that the config import succeeded.
+   *
+   * @param array $writen_data
+   *   The config data as written.
+   * @param array $exported_data
+   *   The config data exported.
+   */
+  abstract protected function doAssert(array $data, array $exported_data);
+
+}

+ 53 - 0
sites/all/modules/contrib/dev/config_devel/tests/src/Unit/ConfigDevelAutoExportSubscriberTest.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace Drupal\Tests\config_devel\Unit;
+
+use org\bovigo\vfs\vfsStream;
+use Drupal\Component\Serialization\Yaml;
+
+use Drupal\config_devel\EventSubscriber\ConfigDevelAutoExportSubscriber;
+
+/**
+ * @coversDefaultClass \Drupal\config_devel\EventSubscriber\ConfigDevelAutoExportSubscriber
+ * @group config_devel
+ */
+class ConfigDevelAutoExportSubscriberTest extends ConfigDevelTestBase {
+
+  /**
+   * Test ConfigDevelAutoExportSubscriber::writeBackConfig().
+   */
+  public function testWriteBackConfig() {
+    $config_data = array(
+      'id' => $this->randomMachineName(),
+      'langcode' => 'en',
+      'uuid' => '836769f4-6791-402d-9046-cc06e20be87f',
+    );
+
+    $config = $this->getMockBuilder('\Drupal\Core\Config\Config')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $config->expects($this->any())
+      ->method('getName')
+      ->will($this->returnValue($this->randomMachineName()));
+    $config->expects($this->any())
+      ->method('get')
+      ->will($this->returnValue($config_data));
+
+    $file_names = array(
+      vfsStream::url('public://' . $this->randomMachineName() . '.yml'),
+      vfsStream::url('public://' . $this->randomMachineName() . '.yml'),
+    );
+
+    $configDevelSubscriber = new ConfigDevelAutoExportSubscriber($this->configFactory, $this->configManager, $this->eventDispatcher);
+    $configDevelSubscriber->writeBackConfig($config, $file_names);
+
+    $data = $config_data;
+    unset($data['uuid']);
+    unset($data['_core']);
+
+    foreach ($file_names as $file_name) {
+      $this->assertEquals($data, Yaml::decode(file_get_contents($file_name)));
+    }
+  }
+
+}

+ 44 - 0
sites/all/modules/contrib/dev/config_devel/tests/src/Unit/ConfigDevelTestBase.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace Drupal\Tests\config_devel\Unit;
+
+use org\bovigo\vfs\vfsStream;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Helper class with mock objects.
+ */
+abstract class ConfigDevelTestBase extends UnitTestCase {
+
+  /**
+   * @var \Drupal\Core\Config\ConfigFactoryInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $configFactory;
+
+  /**
+   * @var \Drupal\Core\Config\ConfigManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $configManager;
+
+  /**
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  protected $eventDispatcher;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+    $this->configFactory = $this->getMock('Drupal\Core\Config\ConfigFactoryInterface');
+
+    $this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
+
+    $this->configManager = $this->getMock('Drupal\Core\Config\ConfigManagerInterface');
+    $this->configManager->expects($this->any())
+      ->method('getEntityTypeIdByName')
+      ->will($this->returnArgument(0));
+
+    vfsStream::setup('public://');
+  }
+}

+ 3 - 3
sites/all/modules/contrib/dev/devel/devel.info.yml

@@ -7,8 +7,8 @@ configure: devel.admin_settings
 tags:
  - developer
 
-# Information added by Drupal.org packaging script on 2017-08-14
-version: '8.x-1.0'
+# Information added by Drupal.org packaging script on 2017-10-05
+version: '8.x-1.2'
 core: '8.x'
 project: 'devel'
-datestamp: 1502732047
+datestamp: 1507197848

+ 3 - 3
sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.info.yml

@@ -6,8 +6,8 @@ package: Development
 tags:
  - developer
 
-# Information added by Drupal.org packaging script on 2017-08-14
-version: '8.x-1.0'
+# Information added by Drupal.org packaging script on 2017-10-05
+version: '8.x-1.2'
 core: '8.x'
 project: 'devel'
-datestamp: 1502732047
+datestamp: 1507197848

+ 2 - 1
sites/all/modules/contrib/dev/devel/devel_generate/src/Commands/DevelGenerateCommands.php

@@ -141,6 +141,7 @@ class DevelGenerateCommands extends DrushCommands {
    * @param $max_width Max width of first level of links.
    * @option kill Delete all content before generating new content.
    * @aliases genm
+   * @validate-module-enabled menu_link_content
    */
   public function menus($number_menus = 2, $number_links = 50, $max_depth = 3, $max_width = 8, $options = ['kill' => FALSE]) {
     $this->generate();
@@ -179,7 +180,7 @@ class DevelGenerateCommands extends DrushCommands {
     /** @var DevelGenerateBaseInterface $instance */
     $instance = $manager->createInstance($commandData->annotationData()->get('pluginId'), array());
     $this->setPluginInstance($instance);
-    $parameters = $instance->validateDrushParams($args);
+    $parameters = $instance->validateDrushParams($args, $commandData->input()->getOptions());
     $this->setParameters($parameters);
   }
 

+ 4 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/DevelGenerateBase.php

@@ -165,4 +165,8 @@ abstract class DevelGenerateBase extends PluginBase implements DevelGenerateBase
     }
     return $this->random;
   }
+
+  protected function isDrush8() {
+    return function_exists('drush_drupal_load_autoloader');
+  }
 }

+ 9 - 9
sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/ContentDevelGenerate.php

@@ -316,7 +316,7 @@ class ContentDevelGenerate extends DevelGenerateBase implements ContainerFactory
       $start = time();
       for ($i = 1; $i <= $values['num']; $i++) {
         $this->develGenerateContentAddNode($values);
-        if (function_exists('drush_log') && $i % drush_get_option('feedback', 1000) == 0) {
+        if ($this->isDrush8() && function_exists('drush_log') && $i % drush_get_option('feedback', 1000) == 0) {
           $now = time();
           drush_log(dt('Completed @feedback nodes (@rate nodes/min)', array('@feedback' => drush_get_option('feedback', 1000), '@rate' => (drush_get_option('feedback', 1000) * 60) / ($now - $start))), 'ok');
           $start = $now;
@@ -372,8 +372,8 @@ class ContentDevelGenerate extends DevelGenerateBase implements ContainerFactory
   /**
    * {@inheritdoc}
    */
-  public function validateDrushParams($args) {
-    $add_language = drush_get_option('languages');
+  public function validateDrushParams($args, $options = []) {
+    $add_language = $this->isDrush8() ? drush_get_option('languages') : $options['languages'];
     if (!empty($add_language)) {
       $add_language = explode(',', str_replace(' ', '', $add_language));
       // Intersect with the enabled languages to make sure the language args
@@ -381,17 +381,17 @@ class ContentDevelGenerate extends DevelGenerateBase implements ContainerFactory
       $values['values']['add_language'] = array_intersect($add_language, array_keys($this->languageManager->getLanguages(LanguageInterface::STATE_ALL)));
     }
 
-    $values['kill'] = drush_get_option('kill');
+    $values['kill'] = $this->isDrush8() ? drush_get_option('kill') : $options['kill'];
     $values['title_length'] = 6;
     $values['num'] = array_shift($args);
     $values['max_comments'] = array_shift($args);
     $all_types = array_keys(node_type_get_names());
     $default_types = array_intersect(array('page', 'article'), $all_types);
-    $selected_types = StringUtils::csvToArray(drush_get_option('types', $default_types));
-
-    // Validates the input format for content types option.
-    if (drush_get_option('types', $default_types) === TRUE) {
-      throw new \Exception(dt('Wrong syntax or no content type selected. The correct syntax uses "=", eg.: --types=page,article'));
+    if ($this->isDrush8()) {
+      $selected_types = _convert_csv_to_array(drush_get_option('types', $default_types));
+    }
+    else {
+      $selected_types = StringUtils::csvToArray($options['types'] ?: $default_types);
     }
 
     if (empty($selected_types)) {

+ 16 - 18
sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/MenuDevelGenerate.php

@@ -221,14 +221,14 @@ class MenuDevelGenerate extends DevelGenerateBase implements ContainerFactoryPlu
   /**
    * {@inheritdoc}
    */
-  public function validateDrushParams($args) {
+  public function validateDrushParams($args, $options = []) {
 
     $link_types = array('node', 'front', 'external');
     $values = array(
       'num_menus' => array_shift($args),
       'num_links' => array_shift($args),
-      'kill' => drush_get_option('kill'),
-      'pipe' => drush_get_option('pipe'),
+      'kill' => $this->isDrush8() ? drush_get_option('kill') : $options['kill'],
+      'pipe' => $this->isDrush8() ? drush_get_option('pipe') : $options['pipe'],
       'link_types' => array_combine($link_types, $link_types),
     );
 
@@ -240,16 +240,16 @@ class MenuDevelGenerate extends DevelGenerateBase implements ContainerFactoryPlu
     $values['existing_menus']['__new-menu__'] = TRUE;
 
     if ($this->isNumber($values['num_menus']) == FALSE) {
-      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid number of menus'));
+      throw new \Exception(dt('Invalid number of menus'));
     }
     if ($this->isNumber($values['num_links']) == FALSE) {
-      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid number of links'));
+      throw new \Exception(dt('Invalid number of links'));
     }
     if ($this->isNumber($values['max_depth']) == FALSE || $values['max_depth'] > 9 || $values['max_depth'] < 1) {
-      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid maximum link depth. Use a value between 1 and 9'));
+      throw new \Exception(dt('Invalid maximum link depth. Use a value between 1 and 9'));
     }
     if ($this->isNumber($values['max_width']) == FALSE || $values['max_width'] < 1) {
-      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid maximum menu width. Use a positive numeric value.'));
+      throw new \Exception(dt('Invalid maximum menu width. Use a positive numeric value.'));
     }
 
     return $values;
@@ -300,19 +300,17 @@ class MenuDevelGenerate extends DevelGenerateBase implements ContainerFactoryPlu
   protected function generateMenus($num_menus, $title_length = 12) {
     $menus = array();
 
-    if ($this->moduleHandler->moduleExists('menu_ui')) {
-      for ($i = 1; $i <= $num_menus; $i++) {
-        $name = $this->getRandom()->word(mt_rand(2, max(2, $title_length)));
+    for ($i = 1; $i <= $num_menus; $i++) {
+      $name = $this->getRandom()->word(mt_rand(2, max(2, $title_length)));
 
-        $menu = $this->menuStorage->create(array(
-          'label' => $name,
-          'id' => 'devel-' . Unicode::strtolower($name),
-          'description' => $this->t('Description of @name', array('@name' => $name)),
-        ));
+      $menu = $this->menuStorage->create(array(
+        'label' => $name,
+        'id' => 'devel-' . Unicode::strtolower($name),
+        'description' => $this->t('Description of @name', array('@name' => $name)),
+      ));
 
-        $menu->save();
-        $menus[$menu->id()] = $menu->label();
-      }
+      $menu->save();
+      $menus[$menu->id()] = $menu->label();
     }
 
     return $menus;

+ 5 - 14
sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/TermDevelGenerate.php

@@ -210,15 +210,6 @@ class TermDevelGenerate extends DevelGenerateBase implements ContainerFactoryPlu
 
       $max++;
 
-      if (function_exists('drush_log')) {
-        $feedback = drush_get_option('feedback', 1000);
-        if ($i % $feedback == 0) {
-          $now = time();
-          drush_log(dt('Completed @feedback terms (@rate terms/min)', array('@feedback' => $feedback, '@rate' => $feedback * 60 / ($now - $start))), 'ok');
-          $start = $now;
-        }
-      }
-
       // Limit memory usage. Only report first 20 created terms.
       if ($i < 20) {
         $terms[] = $term->label();
@@ -233,7 +224,7 @@ class TermDevelGenerate extends DevelGenerateBase implements ContainerFactoryPlu
   /**
    * {@inheritdoc}
    */
-  public function validateDrushParams($args) {
+  public function validateDrushParams($args, $options = []) {
     $vocabulary_name = array_shift($args);
     $number = array_shift($args);
 
@@ -242,21 +233,21 @@ class TermDevelGenerate extends DevelGenerateBase implements ContainerFactoryPlu
     }
 
     if (!$vocabulary_name) {
-      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Please provide a vocabulary machine name.'));
+      throw new \Exception(dt('Please provide a vocabulary machine name.'));
     }
 
     if (!$this->isNumber($number)) {
-      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid number of terms: @num', array('@num' => $number)));
+      throw new \Exception(dt('Invalid number of terms: @num', array('@num' => $number)));
     }
 
     // Try to convert machine name to a vocabulary id.
     if (!$vocabulary = $this->vocabularyStorage->load($vocabulary_name)) {
-      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid vocabulary name: @name', array('@name' => $vocabulary_name)));
+      throw new \Exception(dt('Invalid vocabulary name: @name', array('@name' => $vocabulary_name)));
     }
 
     $values = [
       'num' => $number,
-      'kill' => drush_get_option('kill'),
+      'kill' => $this->isDrush8() ? drush_get_option('kill') : $options['kill'],
       'title_length' => 12,
       'vids' => [$vocabulary->id()],
     ];

+ 17 - 4
sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/UserDevelGenerate.php

@@ -7,6 +7,7 @@ use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\devel_generate\DevelGenerateBase;
+use Drush\Utils\StringUtils;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -177,14 +178,26 @@ class UserDevelGenerate extends DevelGenerateBase implements ContainerFactoryPlu
   /**
    * {@inheritdoc}
    */
-  public function validateDrushParams($args) {
+  public function validateDrushParams($args, $options = []) {
     $values = array(
       'num' => array_shift($args),
-      'roles' => drush_get_option('roles') ? explode(',', drush_get_option('roles')) : array(),
-      'kill' => drush_get_option('kill'),
-      'pass' => drush_get_option('pass', NULL),
       'time_range' => 0,
     );
+
+    if ($this->isDrush8()) {
+      $values += [
+        'roles' => explode(',', drush_get_option('roles', '')),
+        'kill' => drush_get_option('kill'),
+        'pass' => drush_get_option('pass', NULL),
+      ];
+    }
+    else {
+      $values += [
+        'roles' => StringUtils::csvToArray($options['roles']),
+        'kill' => $options['kill'],
+        'pass' => $options['pass'],
+      ];
+    }
     return $values;
   }
 

+ 3 - 3
sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/VocabularyDevelGenerate.php

@@ -158,15 +158,15 @@ class VocabularyDevelGenerate extends DevelGenerateBase implements ContainerFact
   /**
    * {@inheritdoc}
    */
-  public function validateDrushParams($args) {
+  public function validateDrushParams($args, $options = []) {
     $values = array(
       'num' => array_shift($args),
-      'kill' => drush_get_option('kill'),
+      'kill' => $this->isDrush8() ? drush_get_option('kill') : $options['kill'],
       'title_length' => 12,
     );
 
     if ($this->isNumber($values['num']) == FALSE) {
-      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid number of vocabularies: @num.', array('@num' => $values['num'])));
+      throw new \Exception(dt('Invalid number of vocabularies: @num.', array('@num' => $values['num'])));
     }
 
     return $values;

+ 3 - 3
sites/all/modules/contrib/dev/devel/devel_generate/tests/modules/devel_generate_example/devel_generate_example.info.yml

@@ -7,8 +7,8 @@ configure: admin/config/development/generate
 tags:
  - developer
 
-# Information added by Drupal.org packaging script on 2017-08-14
-version: '8.x-1.0'
+# Information added by Drupal.org packaging script on 2017-10-05
+version: '8.x-1.2'
 core: '8.x'
 project: 'devel'
-datestamp: 1502732047
+datestamp: 1507197848

+ 1 - 1
sites/all/modules/contrib/dev/devel/drush.services.yml

@@ -1,6 +1,6 @@
 services:
   devel.command:
     class: Drupal\devel\Commands\DevelCommands
-    arguments: ['@token', '@service_container', '@event_dispatcher']
+    arguments: ['@token', '@service_container', '@event_dispatcher', '@module_handler']
     tags:
       -  { name: drush.command }

+ 3 - 3
sites/all/modules/contrib/dev/devel/kint/kint.info.yml

@@ -6,8 +6,8 @@ package: Development
 tags:
  - developer
 
-# Information added by Drupal.org packaging script on 2017-08-14
-version: '8.x-1.0'
+# Information added by Drupal.org packaging script on 2017-10-05
+version: '8.x-1.2'
 core: '8.x'
 project: 'devel'
-datestamp: 1502732047
+datestamp: 1507197848

+ 71 - 41
sites/all/modules/contrib/dev/devel/src/Commands/DevelCommands.php

@@ -5,6 +5,9 @@ use Drupal\Component\Uuid\Php;
 use Drupal\Core\Utility\Token;
 use Drush\Commands\DrushCommands;
 use Drush\Exceptions\UserAbortException;
+use Drush\Utils\StringUtils;
+use Symfony\Component\Console\Input\Input;
+use Symfony\Component\Console\Output\Output;
 
 /**
  * For commands that are parts of modules, Drush expects to find commandfiles in
@@ -21,11 +24,21 @@ class DevelCommands extends DrushCommands {
 
   protected $eventDispatcher;
 
-  public function __construct(Token $token, $container, $eventDispatcher) {
+  protected $moduleHandler;
+
+  public function __construct(Token $token, $container, $eventDispatcher, $moduleHandler) {
     parent::__construct();
     $this->token = $token;
     $this->container = $container;
     $this->eventDispatcher = $eventDispatcher;
+    $this->moduleHandler = $moduleHandler;
+  }
+
+  /**
+   * @return \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  public function getModuleHandler() {
+    return $this->moduleHandler;
   }
 
   /**
@@ -50,93 +63,110 @@ class DevelCommands extends DrushCommands {
   }
 
   /**
-   * Uninstall, and Install a list of modules.
+   * Uninstall, and Install modules.
 
-   * @command devel-reinstall
+   * @command devel:reinstall
    * @param $modules A comma-separated list of module names.
-   * @aliases dre
+   * @aliases dre,devel-reinstall
    * @allow-additional-options pm-uninstall,pm-enable
    */
-  public function reinstall($projects) {
-    $projects = _convert_csv_to_array($projects);
+  public function reinstall($modules) {
+    $modules = StringUtils::csvToArray($modules);
 
-    // This is faster than 3 separate bootstraps.
-    $args = array_merge(array('pm-uninstall'), $projects);
-    // @todo. Use $application dispatch instead of drush_invoke().
-    call_user_func_array('drush_invoke', $args);
-
-    $args = array_merge(array('pm-enable'), $projects);
-    call_user_func_array('drush_invoke', $args);
+    $modules_str = implode(',', $modules);
+    drush_invoke_process('@self', 'pm:uninstall', [$modules_str], []);
+    drush_invoke_process('@self', 'pm:enable', [$modules_str], []);
   }
 
   /**
    * List implementations of a given hook and optionally edit one.
    *
-   * @command devel-hook
+   * @command devel:hook
    * @param $hook The name of the hook to explore.
+   * @param $implementation The name of the implementation to edit. Usually omitted.
    * @usage devel-hook cron
    *   List implementations of hook_cron().
-   * @aliases fnh,fn-hook,hook
+   * @aliases fnh,fn-hook,hook,devel-hook
+   * @optionset_get_editor
    */
-  function hook($hook) {
+  function hook($hook, $implementation) {
     // Get implementations in the .install files as well.
     include_once './core/includes/install.inc';
     drupal_load_updates();
+    $info = $this->codeLocate($implementation . "_$hook");
+    $exec = drush_get_editor();
+    drush_shell_exec_interactive($exec, $info['file']);
+  }
 
-    if ($hook_implementations = \Drupal::moduleHandler()->getImplementations($hook)) {
-      if ($choice = drush_choice(array_combine($hook_implementations, $hook_implementations), 'Enter the number of the hook implementation you wish to view.')) {
-        $info= $this->codeLocate($choice . "_$hook");
-        $exec = drush_get_editor();
-        drush_shell_exec_interactive($exec, $info['file']);
+  /**
+   * @hook interact hook
+   */
+  public function hookInteract(Input $input, Output $output) {
+    if (!$input->getArgument('implementation')) {
+      if ($hook_implementations = $this->getModuleHandler()->getImplementations($input->getArgument('hook'))) {
+        if (!$choice = $this->io()->choice('Enter the number of the hook implementation you wish to view.', array_combine($hook_implementations, $hook_implementations))) {
+          throw new UserAbortException();
+        }
+        $input->setArgument('implementation', $choice);
+      }
+      else {
+        throw new \Exception(dt('No implementations'));
       }
-    }
-    else {
-      $this->logger()->success(dt('No implementations.'));
     }
   }
 
   /**
    * List implementations of a given event and optionally edit one.
    *
-   * @command devel-event
+   * @command devel:event
    * @param $event The name of the event to explore. If omitted, a list of events is shown.
+   * @param $implementation The name of the implementation to show. Usually omitted.
    * @usage devel-event
    *   Pick a Kernel event, then pick an implementation, and then view its source code.
    * @usage devel-event kernel.terminate
-   *   Pick a terminate subscribers and view its source code.
+   *   Pick a terminate subscribers implementation and view its source code.
    * @aliases fne,fn-event,event
    */
-  function event($event) {
+  function event($event, $implementation) {
+    $info= $this->codeLocate($implementation);
+    $exec = drush_get_editor();
+    drush_shell_exec_interactive($exec, $info['file']);
+  }
+
+  /**
+   * @hook interact devel:event
+   */
+  public function interactEvent(Input $input, Output $output) {
     $dispatcher = $this->getEventDispatcher();
-    if (empty($event)) {
-      // @todo Expand this list and move to interact().
+    if (!$input->getArgument('event')) {
+      // @todo Expand this list.
       $events = array('kernel.controller', 'kernel.exception', 'kernel.request', 'kernel.response', 'kernel.terminate', 'kernel.view');
       $events = array_combine($events, $events);
-      if (!$event = drush_choice($events, 'Enter the event you wish to explore.')) {
+      if (!$event = $this->io()->choice('Enter the event you wish to explore.', $events)) {
         throw new UserAbortException();
       }
+      $input->setArgument('event', $event);
     }
     if ($implementations = $dispatcher->getListeners($event)) {
       foreach ($implementations as $implementation) {
         $callable = get_class($implementation[0]) . '::' . $implementation[1];
         $choices[$callable] = $callable;
       }
-      if ($choice = drush_choice($choices, 'Enter the number of the implementation you wish to view.')) {
-        $info= $this->codeLocate($choice);
-        $exec = drush_get_editor();
-        drush_shell_exec_interactive($exec, $info['file']);
+      if (!$choice = $this->io()->choice('Enter the number of the implementation you wish to view.', $choices)) {
+        throw new UserAbortException();
       }
+      $input->setArgument('implementation', $choice);
     }
     else {
-      $this->logger()->success(dt('No implementations.'));
+      throw new \Exception(dt('No implementations.'));
     }
   }
 
   /**
    * List available tokens.
    *
-   * @command devel-token
-   * @aliases token
+   * @command devel:token
+   * @aliases token,devel-token
    * @field-labels
    *   group: Group
    *   token: Token
@@ -162,8 +192,8 @@ class DevelCommands extends DrushCommands {
   /**
    * Generate a UUID.
    *
-   * @command devel-uuid
-   * @aliases uuid
+   * @command devel:uuid
+   * @aliases uuid,devel-uuid
    * @usage drush devel-uuid
    *   Outputs a Universally Unique Identifier.
    *
@@ -203,9 +233,9 @@ class DevelCommands extends DrushCommands {
   /**
    * Get a list of available container services.
    *
-   * @command devel-services
+   * @command devel:services
    * @param $prefix A prefix to filter the service list by.
-   * @aliases devel-container-services,dcs
+   * @aliases devel-container-services,dcs,devel-services
    * @usage drush devel-services
    *   Gets a list of all available container services
    * @usage drush dcs plugin.manager

+ 3 - 3
sites/all/modules/contrib/dev/devel/tests/modules/devel_dumper_test/devel_dumper_test.info.yml

@@ -5,8 +5,8 @@ package: Testing
 # version: VERSION
 # core: 8.x
 
-# Information added by Drupal.org packaging script on 2017-08-14
-version: '8.x-1.0'
+# Information added by Drupal.org packaging script on 2017-10-05
+version: '8.x-1.2'
 core: '8.x'
 project: 'devel'
-datestamp: 1502732047
+datestamp: 1507197848

+ 3 - 3
sites/all/modules/contrib/dev/devel/tests/modules/devel_entity_test/devel_entity_test.info.yml

@@ -9,8 +9,8 @@ dependencies:
   - text
   - entity_test
 
-# Information added by Drupal.org packaging script on 2017-08-14
-version: '8.x-1.0'
+# Information added by Drupal.org packaging script on 2017-10-05
+version: '8.x-1.2'
 core: '8.x'
 project: 'devel'
-datestamp: 1502732047
+datestamp: 1507197848

+ 3 - 3
sites/all/modules/contrib/dev/devel/tests/modules/devel_test/devel_test.info.yml

@@ -5,8 +5,8 @@ package: Testing
 # version: VERSION
 # core: 8.x
 
-# Information added by Drupal.org packaging script on 2017-08-14
-version: '8.x-1.0'
+# Information added by Drupal.org packaging script on 2017-10-05
+version: '8.x-1.2'
 core: '8.x'
 project: 'devel'
-datestamp: 1502732047
+datestamp: 1507197848

+ 10 - 10
sites/all/modules/contrib/dev/devel/src/Tests/DevelControllerTest.php → sites/all/modules/contrib/dev/devel/tests/src/Functional/DevelControllerTest.php

@@ -1,22 +1,22 @@
 <?php
 
-namespace Drupal\devel\Tests;
+namespace Drupal\Tests\devel\Functional;
 
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests Devel controller.
  *
  * @group devel
  */
-class DevelControllerTest extends WebTestBase {
+class DevelControllerTest extends BrowserTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = array('devel', 'node', 'entity_test', 'devel_entity_test', 'block');
+  public static $modules = ['devel', 'node', 'entity_test', 'devel_entity_test', 'block'];
 
   /**
    * {@inheritdoc}
@@ -26,35 +26,35 @@ class DevelControllerTest extends WebTestBase {
 
     // Create a test entity.
     $random_label = $this->randomMachineName();
-    $data = array('type' => 'entity_test', 'name' => $random_label);
+    $data = ['type' => 'entity_test', 'name' => $random_label];
     $this->entity = entity_create('entity_test', $data);
     $this->entity->save();
 
     // Create a test entity with only canonical route.
     $random_label = $this->randomMachineName();
-    $data = array('type' => 'devel_entity_test_canonical', 'name' => $random_label);
+    $data = ['type' => 'devel_entity_test_canonical', 'name' => $random_label];
     $this->entity_canonical = entity_create('devel_entity_test_canonical', $data);
     $this->entity_canonical->save();
 
     // Create a test entity with only edit route.
     $random_label = $this->randomMachineName();
-    $data = array('type' => 'devel_entity_test_edit', 'name' => $random_label);
+    $data = ['type' => 'devel_entity_test_edit', 'name' => $random_label];
     $this->entity_edit = entity_create('devel_entity_test_edit', $data);
     $this->entity_edit->save();
 
     // Create a test entity with no routes.
     $random_label = $this->randomMachineName();
-    $data = array('type' => 'devel_entity_test_no_links', 'name' => $random_label);
+    $data = ['type' => 'devel_entity_test_no_links', 'name' => $random_label];
     $this->entity_no_links = entity_create('devel_entity_test_no_links', $data);
     $this->entity_no_links->save();
 
     $this->drupalPlaceBlock('local_tasks_block');
 
-    $web_user = $this->drupalCreateUser(array(
+    $web_user = $this->drupalCreateUser([
       'view test entity',
       'administer entity_test content',
       'access devel information',
-    ));
+    ]);
     $this->drupalLogin($web_user);
   }
 

+ 33 - 27
sites/all/modules/contrib/dev/devel/src/Tests/DevelDumperTest.php → sites/all/modules/contrib/dev/devel/tests/src/Functional/DevelDumperTest.php

@@ -1,16 +1,16 @@
 <?php
 
-namespace Drupal\devel\Tests;
+namespace Drupal\Tests\devel\Functional;
 
 use Drupal\Component\Render\FormattableMarkup;
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests pluggable dumper feature.
  *
  * @group devel
  */
-class DevelDumperTest extends WebTestBase {
+class DevelDumperTest extends BrowserTestBase {
 
   /**
    * Modules to enable.
@@ -36,36 +36,42 @@ class DevelDumperTest extends WebTestBase {
     $this->drupalGet('admin/config/development/devel');
 
     // Ensures that the dumper input is present on the config page.
-    $this->assertFieldByName('dumper');
+    $this->assertSession()->fieldExists('dumper');
 
     // Ensures that the 'default' dumper is enabled by default.
-    $this->assertFieldChecked('edit-dumper-default');
+    $this->assertSession()->checkboxChecked('edit-dumper-default');
 
     // Ensures that all dumpers declared by devel are present on the config page
     // and that only the available dumpers are selectable.
-    $dumpers = ['default', 'drupal_variable', 'firephp', 'chromephp', 'var_dumper'];
+    $dumpers = [
+      'default',
+      'drupal_variable',
+      'firephp',
+      'chromephp',
+      'var_dumper',
+    ];
     $available_dumpers = ['default', 'drupal_variable'];
 
     foreach ($dumpers as $dumper) {
-      $this->assertFieldByXPath('//input[@type="radio" and @name="dumper"]', $dumper, new FormattableMarkup('Radio button for @dumper found.', ['@dumper' => $dumper]));
+      $this->assertFieldByXPath('//input[@type="radio" and @name="dumper"]', $dumper);
       if (in_array($dumper, $available_dumpers)) {
-        $this->assertFieldByXPath('//input[@name="dumper" and not(@disabled="disabled")]', $dumper, new FormattableMarkup('Dumper @dumper is available.', ['@dumper' => $dumper]));
+        $this->assertFieldByXPath('//input[@name="dumper" and not(@disabled="disabled")]', $dumper);
       }
       else {
-        $this->assertFieldByXPath('//input[@name="dumper" and @disabled="disabled"]', $dumper, new FormattableMarkup('Dumper @dumper is disabled.', ['@dumper' => $dumper]));
+        $this->assertFieldByXPath('//input[@name="dumper" and @disabled="disabled"]', $dumper);
       }
     }
 
     // Ensures that dumper plugins declared by other modules are present on the
     // config page and that only the available dumpers are selectable.
-    $this->assertFieldByName('dumper', 'available_test_dumper');
-    $this->assertText('Available test dumper.', 'Available dumper label is present');
-    $this->assertText('Drupal dumper for testing purposes (available).', 'Available dumper description is present');
+    $this->assertFieldByXPath('//input[@name="dumper"]', 'available_test_dumper');
+    $this->assertSession()->pageTextContains('Available test dumper.');
+    $this->assertSession()->pageTextContains('Drupal dumper for testing purposes (available).');
     $this->assertFieldByXPath('//input[@name="dumper" and not(@disabled="disabled")]', 'available_test_dumper', 'Available dumper input not is disabled.');
 
-    $this->assertFieldByName('dumper', 'not_available_test_dumper');
-    $this->assertText('Not available test dumper.', 'Non available dumper label is present');
-    $this->assertText('Drupal dumper for testing purposes (not available).Not available. You may need to install external dependencies for use this plugin.', 'Non available dumper description is present');
+    $this->assertFieldByXPath('//input[@name="dumper"]', 'not_available_test_dumper');
+    $this->assertSession()->pageTextContains('Not available test dumper.');
+    $this->assertSession()->pageTextContains('Drupal dumper for testing purposes (not available).Not available. You may need to install external dependencies for use this plugin.');
     $this->assertFieldByXPath('//input[@name="dumper" and @disabled="disabled"]', 'not_available_test_dumper', 'Non available dumper input is disabled.');
 
     // Ensures that saving of the dumpers configuration works as expected.
@@ -73,10 +79,10 @@ class DevelDumperTest extends WebTestBase {
       'dumper' => 'drupal_variable',
     ];
     $this->drupalPostForm('admin/config/development/devel', $edit, t('Save configuration'));
-    $this->assertText(t('The configuration options have been saved.'));
+    $this->assertSession()->pageTextContains(t('The configuration options have been saved.'));
 
     $config = \Drupal::config('devel.settings')->get('devel_dumper');
-    $this->assertEqual('drupal_variable', $config, 'The configuration options have been properly saved');
+    $this->assertEquals('drupal_variable', $config, 'The configuration options have been properly saved');
 
     // Ensure that if the chosen dumper is not available (e.g. the module that
     // provide it is uninstalled) the 'default' dumper appears selected in the
@@ -84,22 +90,22 @@ class DevelDumperTest extends WebTestBase {
     \Drupal::service('module_installer')->install(['kint']);
 
     $this->drupalGet('admin/config/development/devel');
-    $this->assertFieldByName('dumper', 'kint');
+    $this->assertFieldByXPath('//input[@name="dumper"]', 'kint');
 
     $edit = [
       'dumper' => 'kint',
     ];
     $this->drupalPostForm('admin/config/development/devel', $edit, t('Save configuration'));
-    $this->assertText(t('The configuration options have been saved.'));
+    $this->assertSession()->pageTextContains(t('The configuration options have been saved.'));
 
     $config = \Drupal::config('devel.settings')->get('devel_dumper');
-    $this->assertEqual('kint', $config, 'The configuration options have been properly saved');
+    $this->assertEquals('kint', $config, 'The configuration options have been properly saved');
 
     \Drupal::service('module_installer')->uninstall(['kint']);
 
     $this->drupalGet('admin/config/development/devel');
-    $this->assertNoFieldByName('dumper', 'kint');
-    $this->assertFieldChecked('edit-dumper-default');
+    $this->assertNoFieldByXPath('//input[@name="dumper"]', 'kint');
+    $this->assertSession()->checkboxChecked('edit-dumper-default');
   }
 
   /**
@@ -110,7 +116,7 @@ class DevelDumperTest extends WebTestBase {
       'dumper' => 'available_test_dumper',
     ];
     $this->drupalPostForm('admin/config/development/devel', $edit, t('Save configuration'));
-    $this->assertText(t('The configuration options have been saved.'));
+    $this->assertSession()->pageTextContains(t('The configuration options have been saved.'));
 
     $this->drupalGet('devel_dumper_test/dump');
     $elements = $this->xpath('//body/pre[contains(text(), :message)]', [':message' => 'AvailableTestDumper::dump() Test output']);
@@ -129,8 +135,8 @@ class DevelDumperTest extends WebTestBase {
     $this->assertTrue(!empty($elements), 'Dumped message is present.');
     // Ensures that plugins can add libraries to the page when the
     // ::exportAsRenderable() method is used.
-    $this->assertRaw('devel_dumper_test/css/devel_dumper_test.css');
-    $this->assertRaw('devel_dumper_test/js/devel_dumper_test.js');
+    $this->assertSession()->responseContains('devel_dumper_test/css/devel_dumper_test.css');
+    $this->assertSession()->responseContains('devel_dumper_test/js/devel_dumper_test.js');
 
     $debug_filename = file_directory_temp() . '/drupal_debug.txt';
 
@@ -140,7 +146,7 @@ class DevelDumperTest extends WebTestBase {
 <pre>AvailableTestDumper::export() Test output</pre>
 
 EOF;
-    $this->assertEqual($file_content, $expected, 'Dumped message is present.');
+    $this->assertEquals($file_content, $expected, 'Dumped message is present.');
 
     // Ensures that the DevelDumperManager::debug() is not access checked and
     // that the dump is written in the debug file even if the user has not the
@@ -153,7 +159,7 @@ EOF;
 <pre>AvailableTestDumper::export() Test output</pre>
 
 EOF;
-    $this->assertEqual($file_content, $expected, 'Dumped message is present.');
+    $this->assertEquals($file_content, $expected, 'Dumped message is present.');
   }
 
 }

+ 3 - 3
sites/all/modules/contrib/dev/devel/src/Tests/DevelMenuLinksTest.php → sites/all/modules/contrib/dev/devel/tests/src/Functional/DevelMenuLinksTest.php

@@ -1,16 +1,16 @@
 <?php
 
-namespace Drupal\devel\Tests;
+namespace Drupal\Tests\devel\Functional;
 
 use Drupal\Core\Url;
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests devel menu links.
  *
  * @group devel
  */
-class DevelMenuLinksTest extends WebTestBase {
+class DevelMenuLinksTest extends BrowserTestBase {
 
   /**
    * Modules to enable.

+ 8 - 8
sites/all/modules/contrib/dev/devel/src/Tests/DevelReinstallTest.php → sites/all/modules/contrib/dev/devel/tests/src/Functional/DevelModulesReinstallTest.php

@@ -1,22 +1,22 @@
 <?php
 
-namespace Drupal\devel\Tests;
+namespace Drupal\Tests\devel\Functional;
 
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests reinstall modules.
  *
  * @group devel
  */
-class DevelReinstallTest extends WebTestBase {
+class DevelModulesReinstallTest extends BrowserTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = array('devel');
+  public static $modules = ['devel'];
 
   /**
    * The profile to install as a basis for testing.
@@ -31,7 +31,7 @@ class DevelReinstallTest extends WebTestBase {
   protected function setUp() {
     parent::setUp();
 
-    $web_user = $this->drupalCreateUser(array('administer site configuration'));
+    $web_user = $this->drupalCreateUser(['administer site configuration']);
     $this->drupalLogin($web_user);
   }
 
@@ -40,7 +40,7 @@ class DevelReinstallTest extends WebTestBase {
    */
   public function testDevelReinstallModules() {
     // Minimal profile enables only dblog, block and node.
-    $modules = array('dblog', 'block');
+    $modules = ['dblog', 'block'];
 
     // Needed for compare correctly the message.
     sort($modules);
@@ -48,13 +48,13 @@ class DevelReinstallTest extends WebTestBase {
     $this->drupalGet('devel/reinstall');
 
     // Prepare field data in an associative array
-    $edit = array();
+    $edit = [];
     foreach ($modules as $module) {
       $edit["reinstall[$module]"] = TRUE;
     }
 
     $this->drupalPostForm('devel/reinstall', $edit, t('Reinstall'));
-    $this->assertText(t('Uninstalled and installed: @names.', array('@names' => implode(', ', $modules))));
+    $this->assertText(t('Uninstalled and installed: @names.', ['@names' => implode(', ', $modules)]));
   }
 
 }

+ 6 - 6
sites/all/modules/contrib/dev/devel/src/Tests/DevelSwitchUserTest.php → sites/all/modules/contrib/dev/devel/tests/src/Functional/DevelSwitchUserTest.php

@@ -1,16 +1,16 @@
 <?php
 
-namespace Drupal\devel\Tests;
+namespace Drupal\Tests\devel\Functional;
 
 use Drupal\Component\Render\FormattableMarkup;
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests switch user.
  *
  * @group devel
  */
-class DevelSwitchUserTest extends WebTestBase {
+class DevelSwitchUserTest extends BrowserTestBase {
 
   /**
    * Modules to enable.
@@ -276,12 +276,12 @@ class DevelSwitchUserTest extends WebTestBase {
    */
   protected function assertSessionByUid($uid) {
     $query = \Drupal::database()->select('sessions');
-    $query->fields('sessions', array('uid'));
+    $query->fields('sessions', ['uid']);
     $query->condition('uid', $uid);
     $result = $query->execute()->fetchAll();
 
     if (empty($result)) {
-      $this->fail(new FormattableMarkup('No session found for uid @uid', array('@uid' => $uid)));
+      $this->fail(new FormattableMarkup('No session found for uid @uid', ['@uid' => $uid]));
     }
     elseif (count($result) > 1) {
       // If there is more than one session, then that must be unexpected.
@@ -304,7 +304,7 @@ class DevelSwitchUserTest extends WebTestBase {
    */
   protected function assertNoSessionByUid($uid) {
     $query = \Drupal::database()->select('sessions');
-    $query->fields('sessions', array('uid'));
+    $query->fields('sessions', ['uid']);
     $query->condition('uid', $uid);
     $result = $query->execute()->fetchAll();
     $this->assert(empty($result), "No session for uid $uid found.");

+ 6 - 3
sites/all/modules/contrib/dev/devel/webprofiler/src/DataCollector/DatabaseDataCollector.php

@@ -56,7 +56,7 @@ class DatabaseDataCollector extends DataCollector implements DrupalDataCollector
         unset($query['caller']['args']);
 
         // Remove query args element if empty.
-        if (empty($query['args'])) {
+        if (isset($query['args']) && empty($query['args'])) {
           unset($query['args']);
         }
 
@@ -223,8 +223,11 @@ class DatabaseDataCollector extends DataCollector implements DrupalDataCollector
       $query['type'] = $type;
 
       $quoted = [];
-      foreach ((array) $query['args'] as $key => $val) {
-        $quoted[$key] = is_null($val) ? 'NULL' : $conn->quote($val);
+
+      if (isset($query['args'])) {
+        foreach ((array) $query['args'] as $key => $val) {
+          $quoted[$key] = is_null($val) ? 'NULL' : $conn->quote($val);
+        }
       }
 
       $query['query_args'] = strtr($query['query'], $quoted);

+ 7 - 0
sites/all/modules/contrib/dev/devel/webprofiler/src/Entity/Decorators/Config/ConfigEntityStorageDecorator.php

@@ -108,6 +108,13 @@ class ConfigEntityStorageDecorator extends EntityDecorator implements ConfigEnti
     return $this->getOriginalObject()->save($entity);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function hasData() {
+    return $this->getOriginalObject()->hasData();
+  }
+
   /**
    * {@inheritdoc}
    */

+ 28 - 30
sites/all/modules/contrib/dev/devel/webprofiler/src/EventDispatcher/TraceableEventDispatcher.php

@@ -4,6 +4,7 @@ namespace Drupal\webprofiler\EventDispatcher;
 
 use Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher;
 use Drupal\webprofiler\Stopwatch;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\EventDispatcher\Event;
 use Symfony\Component\HttpKernel\KernelEvents;
 
@@ -29,10 +30,19 @@ class TraceableEventDispatcher extends ContainerAwareEventDispatcher implements
   protected $notCalledListeners;
 
   /**
-   * @param \Drupal\webprofiler\Stopwatch $stopwatch
+   * {@inheritdoc}
    */
-  public function setStopwatch(Stopwatch $stopwatch) {
-    $this->stopwatch = $stopwatch;
+  public function __construct(ContainerInterface $container, array $listeners = []) {
+    parent::__construct($container, $listeners);
+    $this->notCalledListeners = $listeners;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addListener($event_name, $listener, $priority = 0) {
+    parent::addListener($event_name, $listener, $priority);
+    $this->notCalledListeners[$event_name][$priority][] = ['callable' => $listener];
   }
 
   /**
@@ -97,6 +107,13 @@ class TraceableEventDispatcher extends ContainerAwareEventDispatcher implements
     return $this->notCalledListeners;
   }
 
+  /**
+   * @param \Drupal\webprofiler\Stopwatch $stopwatch
+   */
+  public function setStopwatch(Stopwatch $stopwatch) {
+    $this->stopwatch = $stopwatch;
+  }
+
   /**
    * Called before dispatching the event.
    *
@@ -158,38 +175,19 @@ class TraceableEventDispatcher extends ContainerAwareEventDispatcher implements
       'method' => $definition['callable'][1],
     ];
 
-    // Remove this listener from the $notCalledListeners array.
-    if (!$this->notCalledListeners) {
-      $this->notCalledListeners = $this->cloneListeners($this->listeners);
-    }
-
     foreach ($this->notCalledListeners[$event_name][$priority] as $key => $listener) {
-      if ($listener['service'][0] == $definition['service'][0] && $listener['service'][1] == $definition['service'][1]) {
-        unset($this->notCalledListeners[$event_name][$priority][$key]);
+      if (isset($listener['service'])) {
+        if ($listener['service'][0] == $definition['service'][0] && $listener['service'][1] == $definition['service'][1]) {
+          unset($this->notCalledListeners[$event_name][$priority][$key]);
+        }
       }
-    }
-  }
-
-  /**
-   * @param $listeners
-   *
-   * @return array
-   */
-  private function cloneListeners($listeners) {
-    $clone = [];
-
-    foreach ($listeners as $eventName => $events) {
-      foreach ($events as $priorityValue => $priorities) {
-        foreach ($priorities as $key => $listener) {
-          $clone[$eventName][$priorityValue][$key]['service'] = [
-            $listener['service'][0],
-            $listener['service'][1]
-          ];
+      else {
+        if (get_class($listener['callable'][0]) == get_class($definition['callable'][0]) && $listener['callable'][1] == $definition['callable'][1]) {
+          unset($this->notCalledListeners[$event_name][$priority][$key]);
         }
       }
-    }
 
-    return $clone;
+    }
   }
 
 }

+ 1 - 1
sites/all/modules/contrib/dev/devel/webprofiler/src/Form/ConfigForm.php

@@ -134,7 +134,7 @@ class ConfigForm extends ConfigFormBase {
       '#states' => array(
         'visible' => array(
           array(
-            ':input[name="active_toolbar_items[database]' => array('checked' => TRUE),
+            'input[name="active_toolbar_items[database]"]' => array('checked' => TRUE),
           ),
         ),
       ),

+ 1 - 1
sites/all/modules/contrib/dev/devel/webprofiler/src/Views/TraceableViewExecutable.php

@@ -31,7 +31,7 @@ class TraceableViewExecutable extends ViewExecutable {
    * @return float
    */
   public function getExecuteTime() {
-    return $this->execute_time;
+    return property_exists($this, 'execute_time') ? $this->execute_time : 0.0;
   }
 
   /**

+ 3 - 3
sites/all/modules/contrib/dev/devel/webprofiler/webprofiler.info.yml

@@ -9,8 +9,8 @@ tags:
 dependencies:
  - devel
 
-# Information added by Drupal.org packaging script on 2017-08-14
-version: '8.x-1.0'
+# Information added by Drupal.org packaging script on 2017-10-05
+version: '8.x-1.2'
 core: '8.x'
 project: 'devel'
-datestamp: 1502732047
+datestamp: 1507197848

+ 1 - 1
sites/all/modules/contrib/dev/entity/.travis.yml

@@ -38,7 +38,7 @@ before_script:
   # Export database variable for kernel tests.
   - export SIMPLETEST_DB=mysql://root:@127.0.0.1/entity
   # Download Drupal 8 core.
-  - travis_retry git clone --branch 8.1.x --depth 1 http://git.drupal.org/project/drupal.git
+  - travis_retry git clone --branch 8.3.x --depth 1 http://git.drupal.org/project/drupal.git
   - cd drupal
   - composer self-update
   - composer install -n

+ 1 - 1
sites/all/modules/contrib/dev/entity/composer.json

@@ -5,6 +5,6 @@
   "homepage": "http://drupal.org/project/entity",
   "license": "GPL-2.0+",
   "require": {
-    "drupal/core": "~8.1"
+    "drupal/core": "~8.3"
   }
 }

+ 4 - 4
sites/all/modules/contrib/dev/entity/entity.info.yml

@@ -3,10 +3,10 @@ description: Provides expanded entity APIs, which will be moved to Drupal core o
 type: module
 # core: 8.x
 dependencies:
-  - system (>=8.1.0)
+  - drupal:system (>=8.3.0)
 
-# Information added by Drupal.org packaging script on 2016-12-08
-version: '8.x-1.0-alpha4'
+# Information added by Drupal.org packaging script on 2017-09-20
+version: '8.x-1.0-beta1'
 core: '8.x'
 project: 'entity'
-datestamp: 1481194986
+datestamp: 1505895847

+ 82 - 0
sites/all/modules/contrib/dev/entity/entity.module

@@ -4,3 +4,85 @@
  * @file
  * Provides expanded entity APIs.
  */
+
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\entity\BundlePlugin\BundlePluginHandler;
+
+/**
+ * Gets the entity types which use bundle plugins.
+ *
+ * @return \Drupal\Core\Entity\EntityTypeInterface[]
+ *   The entity types.
+ */
+function entity_get_bundle_plugin_entity_types() {
+  $entity_types = \Drupal::entityTypeManager()->getDefinitions();
+  $entity_types = array_filter($entity_types, function (EntityTypeInterface $entity_type) {
+    return $entity_type->hasHandlerClass('bundle_plugin');
+  });
+
+  return $entity_types;
+}
+
+/**
+ * Implements hook_entity_type_build().
+ */
+function entity_entity_type_build(array &$entity_types) {
+  foreach ($entity_types as $entity_type) {
+    if ($entity_type->get('bundle_plugin_type')) {
+      $entity_type->setHandlerClass('bundle_plugin', BundlePluginHandler::class);
+    }
+  }
+}
+
+/**
+ * Implements hook_entity_bundle_info().
+ */
+function entity_entity_bundle_info() {
+  $bundles = [];
+  foreach (entity_get_bundle_plugin_entity_types() as $entity_type) {
+    /** @var \Drupal\entity\BundlePlugin\BundlePluginHandler $bundle_handler */
+    $bundle_handler = \Drupal::entityTypeManager()->getHandler($entity_type->id(), 'bundle_plugin');
+    $bundles[$entity_type->id()] = $bundle_handler->getBundleInfo();
+  }
+  return $bundles;
+}
+
+/**
+ * Implements hook_entity_field_storage_info().
+ */
+function entity_entity_field_storage_info(EntityTypeInterface $entity_type) {
+  if ($entity_type->hasHandlerClass('bundle_plugin')) {
+    /** @var \Drupal\entity\BundlePlugin\BundlePluginHandler $bundle_handler */
+    $bundle_handler = \Drupal::entityTypeManager()->getHandler($entity_type->id(), 'bundle_plugin');
+    return $bundle_handler->getFieldStorageDefinitions();
+  }
+}
+
+/**
+ * Implements hook_entity_bundle_field_info().
+ */
+function entity_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle) {
+  if ($entity_type->hasHandlerClass('bundle_plugin')) {
+    /** @var \Drupal\entity\BundlePlugin\BundlePluginHandler $bundle_handler */
+    $bundle_handler = \Drupal::entityTypeManager()->getHandler($entity_type->id(), 'bundle_plugin');
+    return $bundle_handler->getFieldDefinitions($bundle);
+  }
+}
+
+/**
+ * Implements hook_modules_installed().
+ */
+function entity_modules_installed($modules) {
+  foreach (entity_get_bundle_plugin_entity_types() as $entity_type) {
+    \Drupal::service('entity.bundle_plugin_installer')->installBundles($entity_type, $modules);
+  }
+}
+
+/**
+ * Implements hook_module_preuninstall().
+ */
+function entity_module_preuninstall($module) {
+  foreach (entity_get_bundle_plugin_entity_types() as $entity_type) {
+    \Drupal::service('entity.bundle_plugin_installer')->uninstallBundles($entity_type, [$module]);
+  }
+}

+ 11 - 1
sites/all/modules/contrib/dev/entity/entity.services.yml

@@ -1,6 +1,16 @@
 services:
   access_checker.entity_revision:
     class: \Drupal\entity\Access\EntityRevisionRouteAccessChecker
-    arguments: ['@entity_type.manager', '@request_stack']
+    arguments: ['@entity_type.manager', '@current_route_match']
     tags:
       - { name: access_check, applies_to: _entity_access_revision }
+
+  entity.bundle_plugin_installer:
+    class: Drupal\entity\BundlePlugin\BundlePluginInstaller
+    arguments: ['@entity_type.manager', '@entity_bundle.listener', '@field_storage_definition.listener', '@field_definition.listener']
+
+  entity.bundle_plugin.uninstall_validator:
+    class: \Drupal\entity\BundlePlugin\BundlePluginUninstallValidator
+    tags:
+      - { name: module_install.uninstall_validator }
+    arguments: ['@entity_type.manager', '@string_translation']

+ 1 - 1
sites/all/modules/contrib/dev/entity/entity.views.inc

@@ -9,7 +9,7 @@ use Drupal\Core\Entity\EntityTypeInterface;
 function entity_views_data() {
   $entity_types = \Drupal::entityTypeManager()->getDefinitions();
   $entity_types = array_filter($entity_types, function (EntityTypeInterface $entity_type) {
-    return $entity_type->isSubclassOf(ContentEntityInterface::class);
+    return $entity_type->entityClassImplements(ContentEntityInterface::class);
   });
 
   $data = [];

+ 19 - 16
sites/all/modules/contrib/dev/entity/src/Access/EntityRevisionRouteAccessChecker.php

@@ -7,9 +7,8 @@ use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Routing\Access\AccessInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Session\AccountInterface;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpFoundation\RequestStack;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -30,42 +29,42 @@ class EntityRevisionRouteAccessChecker implements AccessInterface {
   protected $accessCache = array();
 
   /**
-   * The request stack.
+   * The currently active route match object.
    *
-   * @var \Symfony\Component\HttpFoundation\RequestStack
+   * @var \Drupal\Core\Routing\RouteMatchInterface
    */
-  protected $requestStack;
+  protected $routeMatch;
 
   /**
    * Creates a new EntityRevisionRouteAccessChecker instance.
    *
    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
    *   The entity manager.
-   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
-   *   The request stack.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The currently active route match object.
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, RequestStack $request_stack) {
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, RouteMatchInterface $route_match) {
     $this->entityTypeManager = $entity_type_manager;
-    $this->requestStack = $request_stack;
+    $this->routeMatch = $route_match;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function access(Route $route, AccountInterface $account, Request $request = NULL) {
-    if (empty($request)) {
-      $request = $this->requestStack->getCurrentRequest();
+  public function access(Route $route, AccountInterface $account, RouteMatchInterface $route_match = NULL) {
+    if (empty($route_match)) {
+      $route_match = $this->routeMatch;
     }
 
     $operation = $route->getRequirement('_entity_access_revision');
-    list(, $operation) = explode('.', $operation, 2);
+    list($entity_type_id, $operation) = explode('.', $operation, 2);
 
     if ($operation === 'list') {
-      $_entity = $request->attributes->get('_entity', $request->attributes->get($route->getOption('entity_type_id')));
+      $_entity = $route_match->getParameter($entity_type_id);
       return AccessResult::allowedIf($this->checkAccess($_entity, $account, $operation))->cachePerPermissions();
     }
     else {
-      $_entity_revision = $request->attributes->get('_entity_revision');
+      $_entity_revision = $route_match->getParameter($entity_type_id . '_revision');
       return AccessResult::allowedIf($_entity_revision && $this->checkAccess($_entity_revision, $account, $operation))->cachePerPermissions();
     }
   }
@@ -104,8 +103,10 @@ class EntityRevisionRouteAccessChecker implements AccessInterface {
     $cid = $entity->getRevisionId() . ':' . $langcode . ':' . $account->id() . ':' . $operation;
 
     if (!isset($this->accessCache[$cid])) {
+      $admin_permission = $entity_type->getAdminPermission();
+
       // Perform basic permission checks first.
-      if (!$account->hasPermission($map[$operation]) && !$account->hasPermission($type_map[$operation]) && !$account->hasPermission('administer nodes')) {
+      if (!$account->hasPermission($map[$operation]) && !$account->hasPermission($type_map[$operation]) && ($admin_permission && !$account->hasPermission($admin_permission))) {
         $this->accessCache[$cid] = FALSE;
         return FALSE;
       }
@@ -114,6 +115,8 @@ class EntityRevisionRouteAccessChecker implements AccessInterface {
         $this->accessCache[$cid] = TRUE;
       }
       else {
+        // Entity access handlers are generally not aware of the "list" operation.
+        $operation = $operation == 'list' ? 'view' : $operation;
         // First check the access to the default revision and finally, if the
         // node passed in is not the default revision then access to that, too.
         $this->accessCache[$cid] = $entity_access->access($entity_storage->load($entity->id()), $operation, $account) && ($entity->isDefaultRevision() || $entity_access->access($entity, $operation, $account));

+ 27 - 0
sites/all/modules/contrib/dev/entity/src/BundleFieldDefinition.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace Drupal\entity;
+
+use Drupal\Core\Field\BaseFieldDefinition;
+
+/**
+ * Provides a field definition class for bundle fields.
+ *
+ * Core currently doesn't provide one, the hook_entity_bundle_field_info()
+ * example uses BaseFieldDefinition, which is wrong. Tracked in #2346347.
+ *
+ * Note that this class implements both FieldStorageDefinitionInterface and
+ * FieldDefinitionInterface. This is a simplification for DX reasons,
+ * allowing code to return just the bundle definitions instead of having to
+ * return both storage definitions and bundle definitions.
+ */
+class BundleFieldDefinition extends BaseFieldDefinition {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isBaseField() {
+    return FALSE;
+  }
+
+}

+ 102 - 0
sites/all/modules/contrib/dev/entity/src/BundlePlugin/BundlePluginHandler.php

@@ -0,0 +1,102 @@
+<?php
+
+namespace Drupal\entity\BundlePlugin;
+
+use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+class BundlePluginHandler implements BundlePluginHandlerInterface {
+
+  /**
+   * The entity type.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeInterface
+   */
+  protected $entityType;
+
+  /**
+   * The bundle plugin manager.
+   *
+   * @var \Drupal\Component\Plugin\PluginManagerInterface
+   */
+  protected $pluginManager;
+
+  /**
+   * Constructs a new BundlePluginHandler object.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type.
+   * @param \Drupal\Component\Plugin\PluginManagerInterface $plugin_manager
+   *   The bundle plugin manager.
+   */
+  public function __construct(EntityTypeInterface $entity_type, PluginManagerInterface $plugin_manager) {
+    $this->entityType = $entity_type;
+    $this->pluginManager = $plugin_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
+    return new static(
+      $entity_type,
+      $container->get('plugin.manager.' . $entity_type->get('bundle_plugin_type'))
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getBundleInfo() {
+    $bundles = [];
+    foreach ($this->pluginManager->getDefinitions() as $plugin_id => $definition) {
+      $bundles[$plugin_id] = [
+        'label' => $definition['label'],
+        'description' => isset($definition['description']) ? $definition['description'] : '',
+        'translatable' => $this->entityType->isTranslatable(),
+        'provider' => $definition['provider'],
+      ];
+    }
+    return $bundles;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFieldStorageDefinitions() {
+    $definitions = [];
+    foreach (array_keys($this->pluginManager->getDefinitions()) as $plugin_id) {
+      /** @var \Drupal\entity\BundlePlugin\BundlePluginInterface $plugin */
+      $plugin = $this->pluginManager->createInstance($plugin_id);
+      $definitions += $plugin->buildFieldDefinitions();
+    }
+    // Ensure the presence of required keys which aren't set by the plugin.
+    foreach ($definitions as $field_name => $definition) {
+      $definition->setName($field_name);
+      $definition->setTargetEntityTypeId($this->entityType->id());
+      $definitions[$field_name] = $definition;
+    }
+
+    return $definitions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFieldDefinitions($bundle) {
+    /** @var \Drupal\entity\BundlePlugin\BundlePluginInterface $plugin */
+    $plugin = $this->pluginManager->createInstance($bundle);
+    $definitions = $plugin->buildFieldDefinitions();
+    // Ensure the presence of required keys which aren't set by the plugin.
+    foreach ($definitions as $field_name => $definition) {
+      $definition->setName($field_name);
+      $definition->setTargetEntityTypeId($this->entityType->id());
+      $definition->setTargetBundle($bundle);
+      $definitions[$field_name] = $definition;
+    }
+
+    return $definitions;
+  }
+
+}

+ 37 - 0
sites/all/modules/contrib/dev/entity/src/BundlePlugin/BundlePluginHandlerInterface.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace Drupal\entity\BundlePlugin;
+
+use Drupal\Core\Entity\EntityHandlerInterface;
+
+/**
+ * Handles plugin-provided bundles.
+ */
+interface BundlePluginHandlerInterface extends EntityHandlerInterface {
+
+  /**
+   * Gets the bundle info.
+   *
+   * @return array
+   *   An array of bundle information keyed by the bundle name.
+   *   The format expected by hook_entity_bundle_info().
+   */
+  public function getBundleInfo();
+
+  /**
+   * Gets the field storage definitions.
+   */
+  public function getFieldStorageDefinitions();
+
+  /**
+   * Gets the field definitions for a specific bundle.
+   *
+   * @param string $bundle
+   *   The bundle name.
+   *
+   * @return \Drupal\entity\BundleFieldDefinition[]
+   *   An array of bundle field definitions, keyed by field name.
+   */
+  public function getFieldDefinitions($bundle);
+
+}

+ 94 - 0
sites/all/modules/contrib/dev/entity/src/BundlePlugin/BundlePluginInstaller.php

@@ -0,0 +1,94 @@
+<?php
+
+namespace Drupal\entity\BundlePlugin;
+
+use Drupal\Core\Entity\EntityBundleListenerInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Field\FieldDefinitionListenerInterface;
+use Drupal\Core\Field\FieldStorageDefinitionListenerInterface;
+
+class BundlePluginInstaller implements BundlePluginInstallerInterface {
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The entity bundle listener.
+   *
+   * @var \Drupal\Core\Entity\EntityBundleListenerInterface
+   */
+  protected $entityBundleListener;
+
+  /**
+   * The field storage definition listener.
+   *
+   * @var \Drupal\Core\Field\FieldStorageDefinitionListenerInterface
+   */
+  protected $fieldStorageDefinitionListener;
+
+  /**
+   * The field definition listener.
+   *
+   * @var \Drupal\Core\Field\FieldDefinitionListenerInterface
+   */
+  protected $fieldDefinitionListener;
+
+  /**
+   * Constructs a new BundlePluginInstaller object.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   * @param \Drupal\Core\Entity\EntityBundleListenerInterface $entity_bundle_listener
+   *   The entity bundle listener.
+   * @param \Drupal\Core\Field\FieldStorageDefinitionListenerInterface $field_storage_definition_listener
+   *   The field storage definition listener.
+   * @param \Drupal\Core\Field\FieldDefinitionListenerInterface $field_definition_listener
+   *   The field definition listener.
+   */
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityBundleListenerInterface $entity_bundle_listener, FieldStorageDefinitionListenerInterface $field_storage_definition_listener, FieldDefinitionListenerInterface $field_definition_listener) {
+    $this->entityTypeManager = $entity_type_manager;
+    $this->entityBundleListener = $entity_bundle_listener;
+    $this->fieldStorageDefinitionListener = $field_storage_definition_listener;
+    $this->fieldDefinitionListener = $field_definition_listener;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function installBundles(EntityTypeInterface $entity_type, array $modules) {
+    $bundle_handler = $this->entityTypeManager->getHandler($entity_type->id(), 'bundle_plugin');
+    $bundles = array_filter($bundle_handler->getBundleInfo(), function ($bundle_info) use ($modules) {
+      return in_array($bundle_info['provider'], $modules, TRUE);
+    });
+    foreach (array_keys($bundles) as $bundle) {
+      $this->entityBundleListener->onBundleCreate($bundle, $entity_type->id());
+      foreach ($bundle_handler->getFieldDefinitions($bundle) as $definition) {
+        $this->fieldStorageDefinitionListener->onFieldStorageDefinitionCreate($definition);
+        $this->fieldDefinitionListener->onFieldDefinitionCreate($definition);
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function uninstallBundles(EntityTypeInterface $entity_type, array $modules) {
+    $bundle_handler = $this->entityTypeManager->getHandler($entity_type->id(), 'bundle_plugin');
+    $bundles = array_filter($bundle_handler->getBundleInfo(), function ($bundle_info) use ($modules) {
+      return in_array($bundle_info['provider'], $modules, TRUE);
+    });
+    foreach (array_keys($bundles) as $bundle) {
+      $this->entityBundleListener->onBundleDelete($bundle, $entity_type->id());
+      foreach ($bundle_handler->getFieldDefinitions($bundle) as $definition) {
+        $this->fieldDefinitionListener->onFieldDefinitionDelete($definition);
+        $this->fieldStorageDefinitionListener->onFieldStorageDefinitionDelete($definition);
+      }
+    }
+  }
+
+}

+ 34 - 0
sites/all/modules/contrib/dev/entity/src/BundlePlugin/BundlePluginInstallerInterface.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\entity\BundlePlugin;
+
+use Drupal\Core\Entity\EntityTypeInterface;
+
+/**
+ * Installs and uninstalls bundle plugins.
+ *
+ * Ensures that the fields provided by the bundle plugins are created/deleted.
+ */
+interface BundlePluginInstallerInterface {
+
+  /**
+   * Installs the bundle plugins provided by the specified modules.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type.
+   * @param array $modules
+   *   The modules.
+   */
+  public function installBundles(EntityTypeInterface $entity_type, array $modules);
+
+  /**
+   * Uninstalls the bundle plugins provided by the specified modules.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type.
+   * @param array $modules
+   *   The modules.
+   */
+  public function uninstallBundles(EntityTypeInterface $entity_type, array $modules);
+
+}

+ 24 - 0
sites/all/modules/contrib/dev/entity/src/BundlePlugin/BundlePluginInterface.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace Drupal\entity\BundlePlugin;
+
+use Drupal\Component\Plugin\PluginInspectionInterface;
+
+/**
+ * Interface for plugins which act as entity bundles.
+ */
+interface BundlePluginInterface extends PluginInspectionInterface {
+
+  /**
+   * Builds the field definitions for entities of this bundle.
+   *
+   * Important:
+   * Field names must be unique across all bundles.
+   * It is recommended to prefix them with the bundle name (plugin ID).
+   *
+   * @return \Drupal\entity\BundleFieldDefinition[]
+   *   An array of bundle field definitions, keyed by field name.
+   */
+  public function buildFieldDefinitions();
+
+}

+ 76 - 0
sites/all/modules/contrib/dev/entity/src/BundlePlugin/BundlePluginUninstallValidator.php

@@ -0,0 +1,76 @@
+<?php
+
+namespace Drupal\entity\BundlePlugin;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Extension\ModuleUninstallValidatorInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\StringTranslation\TranslationInterface;
+
+/**
+ * Prevents uninstalling modules with bundle plugins in case of found data.
+ */
+class BundlePluginUninstallValidator implements ModuleUninstallValidatorInterface {
+
+  use StringTranslationTrait;
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * Constructs the object.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
+   *   The string translation service.
+   */
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, TranslationInterface $string_translation) {
+    $this->entityTypeManager = $entity_type_manager;
+    $this->stringTranslation = $string_translation;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validate($module) {
+    $reasons = [];
+
+    foreach (entity_get_bundle_plugin_entity_types() as $entity_type) {
+      /** @var \Drupal\entity\BundlePlugin\BundlePluginHandler $bundle_handler */
+      $bundle_handler = $this->entityTypeManager->getHandler($entity_type->id(), 'bundle_plugin');
+      $bundles = $bundle_handler->getBundleInfo();
+
+      // We find all bundles which have to be removed due to the uninstallation.
+      $bundles_filtered_by_module = array_filter($bundles, function ($bundle_info) use ($module) {
+        return $module === $bundle_info['provider'];
+      });
+
+      if (!empty($bundles_filtered_by_module)) {
+        $bundle_keys_with_content = array_filter(array_keys($bundles_filtered_by_module), function ($bundle) use ($entity_type) {
+          $result = $this->entityTypeManager->getStorage($entity_type->id())->getQuery()
+            ->condition($entity_type->getKey('bundle'), $bundle)
+            ->range(0, 1)
+            ->execute();
+          return !empty($result);
+        });
+
+        $bundles_with_content = array_intersect_key($bundles_filtered_by_module, array_flip($bundle_keys_with_content));
+  
+        foreach ($bundles_with_content as $bundle) {
+          $reasons[] = $this->t('There is data for the bundle @bundle on the entity type @entity_type. Please remove all content before uninstalling the module.', [
+            '@bundle' => $bundle['label'],
+            '@entity_type' => $entity_type->getLabel(),
+          ]);
+        }
+      }
+    }
+
+    return $reasons;
+  }
+
+}

+ 0 - 1
sites/all/modules/contrib/dev/entity/src/Controller/RevisionOverviewController.php

@@ -11,7 +11,6 @@ use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Entity\RevisionLogInterface;
-use Drupal\user\EntityOwnerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**

+ 57 - 19
sites/all/modules/contrib/dev/entity/src/EntityAccessControlHandler.php

@@ -5,16 +5,30 @@ namespace Drupal\entity;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Entity\EntityAccessControlHandler as CoreEntityAccessControlHandler;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityPublishedInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\user\EntityOwnerInterface;
 
 /**
  * Controls access based on the generic entity permissions.
  *
- * @see \Drupal\entity\EntityPermissionProvider
+ * @see \Drupal\entity\UncacheableEntityPermissionProvider
  */
 class EntityAccessControlHandler extends CoreEntityAccessControlHandler {
 
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(EntityTypeInterface $entity_type) {
+    parent::__construct($entity_type);
+
+    if (!$entity_type->hasHandlerClass('permission_provider') || !is_a($entity_type->getHandlerClass('permission_provider'), EntityPermissionProvider::class, TRUE)) {
+      throw new \Exception("This entity access control handler requires the entity permissions provider: {EntityPermissionProvider::class}");
+    }
+  }
+
+
   /**
    * {@inheritdoc}
    */
@@ -51,10 +65,18 @@ class EntityAccessControlHandler extends CoreEntityAccessControlHandler {
    *   The access result.
    */
   protected function checkEntityPermissions(EntityInterface $entity, $operation, AccountInterface $account) {
-    return AccessResult::allowedIfHasPermissions($account, [
-      "$operation {$entity->getEntityTypeId()}",
-      "$operation {$entity->bundle()} {$entity->getEntityTypeId()}",
-    ], 'OR');
+    if ($operation === 'view') {
+      $permissions = [
+        "view {$entity->getEntityTypeId()}"
+      ];
+    }
+    else {
+      $permissions = [
+        "$operation {$entity->getEntityTypeId()}",
+        "$operation {$entity->bundle()} {$entity->getEntityTypeId()}",
+      ];
+    }
+    return AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
   }
 
   /**
@@ -72,23 +94,39 @@ class EntityAccessControlHandler extends CoreEntityAccessControlHandler {
    *   The access result.
    */
   protected function checkEntityOwnerPermissions(EntityInterface $entity, $operation, AccountInterface $account) {
-    /** @var \Drupal\Core\Entity\EntityInterface|\Drupal\user\EntityOwnerInterface $entity */
-    if (($account->id() == $entity->getOwnerId())) {
-      $result = AccessResult::allowedIfHasPermissions($account, [
-        "$operation own {$entity->getEntityTypeId()}",
-        "$operation any {$entity->getEntityTypeId()}",
-        "$operation own {$entity->bundle()} {$entity->getEntityTypeId()}",
-        "$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
-      ], 'OR');
+    if ($operation === 'view') {
+      if ($entity instanceof EntityPublishedInterface && !$entity->isPublished()) {
+        if (($account->id() == $entity->getOwnerId())) {
+          $permissions = [
+            "view own unpublished {$entity->getEntityTypeId()}",
+          ];
+          return AccessResult::allowedIfHasPermissions($account, $permissions)->cachePerUser();
+        }
+        return AccessResult::neutral()->cachePerUser();
+      }
+      else {
+        return AccessResult::allowedIfHasPermissions($account, [
+          "view {$entity->getEntityTypeId()}",
+        ]);
+      }
     }
     else {
-      $result = AccessResult::allowedIfHasPermissions($account, [
-        "$operation any {$entity->getEntityTypeId()}",
-        "$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
-      ], 'OR');
+     if (($account->id() == $entity->getOwnerId())) {
+        $result = AccessResult::allowedIfHasPermissions($account, [
+          "$operation own {$entity->getEntityTypeId()}",
+          "$operation any {$entity->getEntityTypeId()}",
+          "$operation own {$entity->bundle()} {$entity->getEntityTypeId()}",
+          "$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
+        ], 'OR');
+      }
+      else {
+        $result = AccessResult::allowedIfHasPermissions($account, [
+          "$operation any {$entity->getEntityTypeId()}",
+          "$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
+        ], 'OR');
+      }
+      return $result;
     }
-
-    return $result->cachePerUser();
   }
 
   /**

+ 21 - 202
sites/all/modules/contrib/dev/entity/src/EntityPermissionProvider.php

@@ -2,8 +2,8 @@
 
 namespace Drupal\entity;
 
-use Drupal\Core\Entity\ContentEntityTypeInterface;
 use Drupal\Core\Entity\EntityHandlerInterface;
+use Drupal\Core\Entity\EntityPublishedInterface;
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
@@ -11,10 +11,21 @@ use Drupal\user\EntityOwnerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * Provides generic entity permissions.
+ * Provides generic entity permissions which are still cacheable.
  *
- * Supports both entity_type and bundle granularities.
- * Supports entity ownership (own/any permissions).
+ * This includes:
+ *
+ * - administer $entity_type
+ * - access $entity_type overview
+ * - view $entity_type
+ * - view own unpublished $entity_type
+ * - update (own|any) ($bundle) $entity_type
+ * - delete (own|any) ($bundle) $entity_type
+ * - create $bundle $entity_type
+ *
+ * This class does not support "view own ($bundle) $entity_type", because this
+ * results in caching per user. If you need this use case, please use
+ * \Drupal\entity\UncacheableEntityPermissionProvider instead.
  *
  * Intended for content entity types, since config entity types usually rely
  * on a single "administer" permission.
@@ -29,218 +40,26 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  * @see \Drupal\entity\EntityAccessControlHandler
  * @see \Drupal\entity\EntityPermissions
  */
-class EntityPermissionProvider implements EntityPermissionProviderInterface, EntityHandlerInterface {
-
-  use StringTranslationTrait;
-
-  /**
-   * The entity type bundle info.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
-   */
-  protected $entityTypeBundleInfo;
-
-  /**
-   * Constructs a new EntityPermissionProvider object.
-   *
-   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
-   *   The entity type bundle info.
-   */
-  public function __construct(EntityTypeBundleInfoInterface $entity_type_bundle_info) {
-    $this->entityTypeBundleInfo = $entity_type_bundle_info;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
-    return new static(
-      $container->get('entity_type.bundle.info')
-    );
-  }
+class EntityPermissionProvider extends EntityPermissionProviderBase {
 
   /**
    * {@inheritdoc}
    */
   public function buildPermissions(EntityTypeInterface $entity_type) {
     $entity_type_id = $entity_type->id();
-    $has_owner = $entity_type->isSubclassOf(EntityOwnerInterface::class);
-    $singular_label = $entity_type->getSingularLabel();
     $plural_label = $entity_type->getPluralLabel();
 
-    $permissions = [];
-    $permissions["administer {$entity_type_id}"] = [
-      'title' => $this->t('Administer @type', ['@type' => $plural_label]),
-      'restrict access' => TRUE,
-    ];
-    $permissions["access {$entity_type_id} overview"] = [
-      'title' => $this->t('Access the @type overview page', ['@type' => $plural_label]),
-    ];
-    // View permissions are the same for both granularities.
-    if ($has_owner) {
-      $permissions["view any {$entity_type_id}"] = [
-        'title' => $this->t('View any @type', [
-          '@type' => $singular_label,
-        ]),
-      ];
-      $permissions["view own {$entity_type_id}"] = [
-        'title' => $this->t('View own @type', [
-          '@type' => $plural_label,
-        ]),
-      ];
-    }
-    else {
-      $permissions["view {$entity_type_id}"] = [
-        'title' => $this->t('View @type', [
-          '@type' => $plural_label,
-        ]),
-      ];
-    }
-    // Generate the other permissions based on granularity.
-    if ($entity_type->getPermissionGranularity() == 'entity_type') {
-      $permissions += $this->buildEntityTypePermissions($entity_type);
-    }
-    else {
-      $permissions += $this->buildBundlePermissions($entity_type);
-    }
+    $permissions = parent::buildPermissions($entity_type);
 
-    foreach ($permissions as $name => $permission) {
-      // Permissions are grouped by provider on admin/people/permissions.
-      $permissions[$name]['provider'] = $entity_type->getProvider();
-      // TranslatableMarkup objects don't sort properly.
-      $permissions[$name]['title'] = (string) $permission['title'];
-    }
-
-    return $permissions;
-  }
-
-  /**
-   * Builds permissions for the entity_type granularity.
-   *
-   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
-   *   The entity type.
-   *
-   * @return array
-   *   The permissions.
-   */
-  protected function buildEntityTypePermissions(EntityTypeInterface $entity_type) {
-    $entity_type_id = $entity_type->id();
-    $has_owner = $entity_type->isSubclassOf(EntityOwnerInterface::class);
-    $singular_label = $entity_type->getSingularLabel();
-    $plural_label = $entity_type->getPluralLabel();
-
-    $permissions = [];
-    $permissions["create {$entity_type_id}"] = [
-      'title' => $this->t('Create @type', [
+    // View permissions are the same for both granularities.
+    $permissions["view {$entity_type_id}"] = [
+      'title' => $this->t('View @type', [
         '@type' => $plural_label,
       ]),
     ];
-    if ($has_owner) {
-      $permissions["update any {$entity_type_id}"] = [
-        'title' => $this->t('Update any @type', [
-          '@type' => $singular_label,
-        ]),
-      ];
-      $permissions["update own {$entity_type_id}"] = [
-        'title' => $this->t('Update own @type', [
-          '@type' => $plural_label,
-        ]),
-      ];
-      $permissions["delete any {$entity_type_id}"] = [
-        'title' => $this->t('Delete any @type', [
-          '@type' => $singular_label,
-        ]),
-      ];
-      $permissions["delete own {$entity_type_id}"] = [
-        'title' => $this->t('Delete own @type', [
-          '@type' => $plural_label,
-        ]),
-      ];
-    }
-    else {
-      $permissions["update {$entity_type_id}"] = [
-        'title' => $this->t('Update @type', [
-          '@type' => $plural_label,
-        ]),
-      ];
-      $permissions["delete {$entity_type_id}"] = [
-        'title' => $this->t('Delete @type', [
-          '@type' => $plural_label,
-        ]),
-      ];
-    }
 
-    return $permissions;
+    return $this->processPermissions($permissions, $entity_type);
   }
 
-  /**
-   * Builds permissions for the bundle granularity.
-   *
-   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
-   *   The entity type.
-   *
-   * @return array
-   *   The permissions.
-   */
-  protected function buildBundlePermissions(EntityTypeInterface $entity_type) {
-    $entity_type_id = $entity_type->id();
-    $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id);
-    $has_owner = $entity_type->isSubclassOf(EntityOwnerInterface::class);
-    $singular_label = $entity_type->getSingularLabel();
-    $plural_label = $entity_type->getPluralLabel();
-
-    $permissions = [];
-    foreach ($bundles as $bundle_name => $bundle_info) {
-      $permissions["create {$bundle_name} {$entity_type_id}"] = [
-        'title' => $this->t('@bundle: Create @type', [
-          '@bundle' => $bundle_info['label'],
-          '@type' => $plural_label,
-        ]),
-      ];
-
-      if ($has_owner) {
-        $permissions["update any {$bundle_name} {$entity_type_id}"] = [
-          'title' => $this->t('@bundle: Update any @type', [
-            '@bundle' => $bundle_info['label'],
-            '@type' => $singular_label,
-          ]),
-        ];
-        $permissions["update own {$bundle_name} {$entity_type_id}"] = [
-          'title' => $this->t('@bundle: Update own @type', [
-            '@bundle' => $bundle_info['label'],
-            '@type' => $plural_label,
-          ]),
-        ];
-        $permissions["delete any {$bundle_name} {$entity_type_id}"] = [
-          'title' => $this->t('@bundle: Delete any @type', [
-            '@bundle' => $bundle_info['label'],
-            '@type' => $singular_label,
-          ]),
-        ];
-        $permissions["delete own {$bundle_name} {$entity_type_id}"] = [
-          'title' => $this->t('@bundle: Delete own @type', [
-            '@bundle' => $bundle_info['label'],
-            '@type' => $plural_label,
-          ]),
-        ];
-      }
-      else {
-        $permissions["update {$bundle_name} {$entity_type_id}"] = [
-          'title' => $this->t('@bundle: Update @type', [
-            '@bundle' => $bundle_info['label'],
-            '@type' => $plural_label,
-          ]),
-        ];
-        $permissions["delete {$bundle_name} {$entity_type_id}"] = [
-          'title' => $this->t('@bundle: Delete @type', [
-            '@bundle' => $bundle_info['label'],
-            '@type' => $plural_label,
-          ]),
-        ];
-      }
-    }
-
-    return $permissions;
-  }
 
 }

+ 231 - 0
sites/all/modules/contrib/dev/entity/src/EntityPermissionProviderBase.php

@@ -0,0 +1,231 @@
+<?php
+
+namespace Drupal\entity;
+
+use Drupal\Core\Entity\EntityHandlerInterface;
+use Drupal\Core\Entity\EntityPublishedInterface;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\user\EntityOwnerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * @internal
+ */
+class EntityPermissionProviderBase implements EntityPermissionProviderInterface, EntityHandlerInterface {
+
+  use StringTranslationTrait;
+
+  /**
+   * The entity type bundle info.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
+   */
+  protected $entityTypeBundleInfo;
+
+  /**
+   * Constructs a new EntityPermissionProvider object.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
+   *   The entity type bundle info.
+   */
+  public function __construct(EntityTypeBundleInfoInterface $entity_type_bundle_info) {
+    $this->entityTypeBundleInfo = $entity_type_bundle_info;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
+    return new static(
+      $container->get('entity_type.bundle.info')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildPermissions(EntityTypeInterface $entity_type) {
+    $entity_type_id = $entity_type->id();
+    $has_owner = $entity_type->entityClassImplements(EntityOwnerInterface::class);
+    $plural_label = $entity_type->getPluralLabel();
+
+    $permissions = [];
+    $permissions["administer {$entity_type_id}"] = [
+      'title' => $this->t('Administer @type', ['@type' => $plural_label]),
+      'restrict access' => TRUE,
+    ];
+    $permissions["access {$entity_type_id} overview"] = [
+      'title' => $this->t('Access the @type overview page', ['@type' => $plural_label]),
+    ];
+    if ($has_owner && $entity_type->entityClassImplements(EntityPublishedInterface::class)) {
+      $permissions["view own unpublished {$entity_type_id}"] = [
+        'title' => $this->t('View own unpublished @type', [
+          '@type' => $plural_label,
+        ]),
+      ];
+    }
+
+    // Generate the other permissions based on granularity.
+    if ($entity_type->getPermissionGranularity() === 'entity_type') {
+      $permissions += $this->buildEntityTypePermissions($entity_type);
+    }
+    else {
+      $permissions += $this->buildBundlePermissions($entity_type);
+    }
+
+    return $this->processPermissions($permissions, $entity_type);
+  }
+
+  /**
+   * Adds the provider and converts the titles to strings to allow sorting.
+   *
+   * @param array $permissions
+   *   The array of permissions
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type.
+   *
+   * @return array
+   *   An array of processed permissions.
+   */
+  protected function processPermissions(array $permissions, EntityTypeInterface $entity_type) {
+    foreach ($permissions as $name => $permission) {
+      // Permissions are grouped by provider on admin/people/permissions.
+      $permissions[$name]['provider'] = $entity_type->getProvider();
+      // TranslatableMarkup objects don't sort properly.
+      $permissions[$name]['title'] = (string) $permission['title'];
+    }
+    return $permissions;
+  }
+
+  /**
+   * Builds permissions for the entity_type granularity.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type.
+   *
+   * @return array
+   *   The permissions.
+   */
+  protected function buildEntityTypePermissions(EntityTypeInterface $entity_type) {
+    $entity_type_id = $entity_type->id();
+    $has_owner = $entity_type->entityClassImplements(EntityOwnerInterface::class);
+    $singular_label = $entity_type->getSingularLabel();
+    $plural_label = $entity_type->getPluralLabel();
+
+    $permissions = [];
+    $permissions["create {$entity_type_id}"] = [
+      'title' => $this->t('Create @type', [
+        '@type' => $plural_label,
+      ]),
+    ];
+    if ($has_owner) {
+      $permissions["update any {$entity_type_id}"] = [
+        'title' => $this->t('Update any @type', [
+          '@type' => $singular_label,
+        ]),
+      ];
+      $permissions["update own {$entity_type_id}"] = [
+        'title' => $this->t('Update own @type', [
+          '@type' => $plural_label,
+        ]),
+      ];
+      $permissions["delete any {$entity_type_id}"] = [
+        'title' => $this->t('Delete any @type', [
+          '@type' => $singular_label,
+        ]),
+      ];
+      $permissions["delete own {$entity_type_id}"] = [
+        'title' => $this->t('Delete own @type', [
+          '@type' => $plural_label,
+        ]),
+      ];
+    }
+    else {
+      $permissions["update {$entity_type_id}"] = [
+        'title' => $this->t('Update @type', [
+          '@type' => $plural_label,
+        ]),
+      ];
+      $permissions["delete {$entity_type_id}"] = [
+        'title' => $this->t('Delete @type', [
+          '@type' => $plural_label,
+        ]),
+      ];
+    }
+
+    return $permissions;
+  }
+
+  /**
+   * Builds permissions for the bundle granularity.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type.
+   *
+   * @return array
+   *   The permissions.
+   */
+  protected function buildBundlePermissions(EntityTypeInterface $entity_type) {
+    $entity_type_id = $entity_type->id();
+    $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id);
+    $has_owner = $entity_type->entityClassImplements(EntityOwnerInterface::class);
+    $singular_label = $entity_type->getSingularLabel();
+    $plural_label = $entity_type->getPluralLabel();
+
+    $permissions = [];
+    foreach ($bundles as $bundle_name => $bundle_info) {
+      $permissions["create {$bundle_name} {$entity_type_id}"] = [
+        'title' => $this->t('@bundle: Create @type', [
+          '@bundle' => $bundle_info['label'],
+          '@type' => $plural_label,
+        ]),
+      ];
+
+      if ($has_owner) {
+        $permissions["update any {$bundle_name} {$entity_type_id}"] = [
+          'title' => $this->t('@bundle: Update any @type', [
+            '@bundle' => $bundle_info['label'],
+            '@type' => $singular_label,
+          ]),
+        ];
+        $permissions["update own {$bundle_name} {$entity_type_id}"] = [
+          'title' => $this->t('@bundle: Update own @type', [
+            '@bundle' => $bundle_info['label'],
+            '@type' => $plural_label,
+          ]),
+        ];
+        $permissions["delete any {$bundle_name} {$entity_type_id}"] = [
+          'title' => $this->t('@bundle: Delete any @type', [
+            '@bundle' => $bundle_info['label'],
+            '@type' => $singular_label,
+          ]),
+        ];
+        $permissions["delete own {$bundle_name} {$entity_type_id}"] = [
+          'title' => $this->t('@bundle: Delete own @type', [
+            '@bundle' => $bundle_info['label'],
+            '@type' => $plural_label,
+          ]),
+        ];
+      }
+      else {
+        $permissions["update {$bundle_name} {$entity_type_id}"] = [
+          'title' => $this->t('@bundle: Update @type', [
+            '@bundle' => $bundle_info['label'],
+            '@type' => $plural_label,
+          ]),
+        ];
+        $permissions["delete {$bundle_name} {$entity_type_id}"] = [
+          'title' => $this->t('@bundle: Delete @type', [
+            '@bundle' => $bundle_info['label'],
+            '@type' => $plural_label,
+          ]),
+        ];
+      }
+    }
+
+    return $permissions;
+  }
+
+}

+ 1 - 0
sites/all/modules/contrib/dev/entity/src/EntityPermissions.php

@@ -10,6 +10,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  * Generates entity permissions via their permission providers.
  *
  * @see \Drupal\entity\EntityPermissionProvider
+ * @see \Drupal\entity\UncacheableEntityPermissionProvider
  */
 class EntityPermissions implements ContainerInjectionInterface {
 

+ 1 - 1
sites/all/modules/contrib/dev/entity/src/Plugin/Action/Derivative/DeleteActionDeriver.php

@@ -69,7 +69,7 @@ class DeleteActionDeriver extends DeriverBase implements ContainerDeriverInterfa
   protected function getParticipatingEntityTypes() {
     $entity_types = $this->entityTypeManager->getDefinitions();
     $entity_types = array_filter($entity_types, function (EntityTypeInterface $entity_type) {
-      return $entity_type->isSubclassOf(ContentEntityInterface::class) && $entity_type->hasLinkTemplate('delete-multiple-form');
+      return $entity_type->entityClassImplements(ContentEntityInterface::class) && $entity_type->hasLinkTemplate('delete-multiple-form');
     });
 
     return $entity_types;

+ 3 - 2
sites/all/modules/contrib/dev/entity/src/Plugin/Derivative/RevisionsOverviewDeriver.php

@@ -3,6 +3,7 @@
 namespace Drupal\entity\Plugin\Derivative;
 
 use Drupal\Component\Plugin\Derivative\DeriverBase;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -24,7 +25,7 @@ class RevisionsOverviewDeriver extends DeriverBase implements ContainerDeriverIn
    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
    *   The entity type manager.
    */
-  public function __construct(\Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager) {
+  public function __construct(EntityTypeManagerInterface $entityTypeManager) {
     $this->entityTypeManager = $entityTypeManager;
   }
 
@@ -55,7 +56,7 @@ class RevisionsOverviewDeriver extends DeriverBase implements ContainerDeriverIn
 
       $this->derivatives[$entity_type_id] = [
         'route_name' => "entity.$entity_type_id.version_history",
-        'title' => 'Revisions',
+        'title' => t('Revisions'),
         'base_route' => "entity.$entity_type_id.canonical",
         'weight' => 20,
       ] + $base_plugin_definition;

+ 0 - 1
sites/all/modules/contrib/dev/entity/src/Revision/RevisionableContentEntityBase.php

@@ -3,7 +3,6 @@
 namespace Drupal\entity\Revision;
 
 use Drupal\Core\Entity\RevisionableContentEntityBase as BaseRevisionableContentEntityBase;
-use Drupal\Core\Entity\ContentEntityBase;
 
 /**
  * Improves the url route handling of core's revisionable content entity base.

+ 138 - 0
sites/all/modules/contrib/dev/entity/src/UncacheableEntityAccessControlHandler.php

@@ -0,0 +1,138 @@
+<?php
+
+namespace Drupal\entity;
+
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Entity\EntityAccessControlHandler as CoreEntityAccessControlHandler;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityPublishedInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\user\EntityOwnerInterface;
+
+/**
+ * Controls access based on the uncacheable entity permissions.
+ *
+ * @see \Drupal\entity\UncacheableEntityPermissionProvider
+ *
+ * Note: this access control handler will cause pages to be cached per user.
+ */
+class UncacheableEntityAccessControlHandler extends CoreEntityAccessControlHandler {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(EntityTypeInterface $entity_type) {
+    parent::__construct($entity_type);
+
+    if (!$entity_type->hasHandlerClass('permission_provider') || !is_a($entity_type->getHandlerClass('permission_provider'), UncacheableEntityPermissionProvider::class, TRUE)) {
+      throw new \Exception("This entity access control handler requires the entity permissions provider: {EntityPermissionProvider::class}");
+    }
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
+    $account = $this->prepareUser($account);
+    /** @var \Drupal\Core\Access\AccessResult $result */
+    $result = parent::checkAccess($entity, $operation, $account);
+
+    if ($result->isNeutral()) {
+      if ($entity instanceof EntityOwnerInterface) {
+        $result = $this->checkEntityOwnerPermissions($entity, $operation, $account);
+      }
+      else {
+        $result = $this->checkEntityPermissions($entity, $operation, $account);
+      }
+    }
+
+    // Ensure that access is evaluated again when the entity changes.
+    return $result->addCacheableDependency($entity);
+  }
+
+  /**
+   * Checks the entity operation and bundle permissions.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity for which to check access.
+   * @param string $operation
+   *   The entity operation. Usually one of 'view', 'view label', 'update' or
+   *   'delete'.
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   The user for which to check access.
+   *
+   * @return \Drupal\Core\Access\AccessResultInterface
+   *   The access result.
+   */
+  protected function checkEntityPermissions(EntityInterface $entity, $operation, AccountInterface $account) {
+    return AccessResult::allowedIfHasPermissions($account, [
+      "$operation {$entity->getEntityTypeId()}",
+      "$operation {$entity->bundle()} {$entity->getEntityTypeId()}",
+    ], 'OR');
+  }
+
+  /**
+   * Checks the entity operation and bundle permissions, with owners.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity for which to check access.
+   * @param string $operation
+   *   The entity operation. Usually one of 'view', 'view label', 'update' or
+   *   'delete'.
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   The user for which to check access.
+   *
+   * @return \Drupal\Core\Access\AccessResultInterface
+   *   The access result.
+   */
+  protected function checkEntityOwnerPermissions(EntityInterface $entity, $operation, AccountInterface $account) {
+    /** @var \Drupal\Core\Entity\EntityInterface|\Drupal\user\EntityOwnerInterface $entity */
+    if (($account->id() == $entity->getOwnerId())) {
+      if ($operation === 'view' && $entity instanceof EntityPublishedInterface && !$entity->isPublished()) {
+        $permissions = [
+          "view own unpublished {$entity->getEntityTypeId()}",
+        ];
+      }
+      else {
+        $permissions = [
+          "$operation own {$entity->getEntityTypeId()}",
+          "$operation any {$entity->getEntityTypeId()}",
+          "$operation own {$entity->bundle()} {$entity->getEntityTypeId()}",
+          "$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
+        ];
+      }
+      $result = AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
+    }
+    else {
+      $result = AccessResult::allowedIfHasPermissions($account, [
+        "$operation any {$entity->getEntityTypeId()}",
+        "$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
+      ], 'OR');
+    }
+
+    return $result->cachePerUser();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
+    $result = parent::checkCreateAccess($account, $context, $entity_bundle);
+    if ($result->isNeutral()) {
+      $permissions = [
+        'administer ' . $this->entityTypeId,
+        'create ' . $this->entityTypeId,
+      ];
+      if ($entity_bundle) {
+        $permissions[] = 'create ' . $entity_bundle . ' ' . $this->entityTypeId;
+      }
+
+      $result = AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
+    }
+
+    return $result;
+  }
+
+}

+ 143 - 0
sites/all/modules/contrib/dev/entity/src/UncacheableEntityPermissionProvider.php

@@ -0,0 +1,143 @@
+<?php
+
+namespace Drupal\entity;
+
+use Drupal\Core\Entity\EntityHandlerInterface;
+use Drupal\Core\Entity\EntityPublishedInterface;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\user\EntityOwnerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides generic entity permissions which are cached per user.
+ *
+ * This includes:
+ *
+ * - administer $entity_type
+ * - access $entity_type overview
+ * - view an ($bundle) $entity_type
+ * - view own ($bundle) $entity_type
+ * - view own unpublished $entity_type
+ * - update (own|any) ($bundle) $entity_type
+ * - delete (own|any) ($bundle) $entity_type
+ * - create $bundle $entity_type
+ *
+ * As this class supports "view own ($bundle) $entity_type" it is just cacheable
+ * per user, which might harm performance of sites. Given that please use 
+ * \Drupal\entity\EntityPermissionProvider unless you need the feature, or your
+ * entity type is not really user facing (commerce orders for example).
+ *
+ * Intended for content entity types, since config entity types usually rely
+ * on a single "administer" permission.
+ * Example annotation:
+ * @code
+ *  handlers = {
+ *    "access" = "Drupal\entity\UncacheableEntityAccessControlHandler",
+ *    "permission_provider" = "Drupal\entity\UncacheableEntityPermissionProvider",
+ *  }
+ * @endcode
+ *
+ * @see \Drupal\entity\EntityAccessControlHandler
+ * @see \Drupal\entity\EntityPermissions
+ */
+class UncacheableEntityPermissionProvider extends EntityPermissionProviderBase {
+
+  /**
+   * Builds permissions for the entity_type granularity.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type.
+   *
+   * @return array
+   *   The permissions.
+   */
+  protected function buildEntityTypePermissions(EntityTypeInterface $entity_type) {
+    $permissions = parent::buildEntityTypePermissions($entity_type);
+
+    $entity_type_id = $entity_type->id();
+    $has_owner = $entity_type->entityClassImplements(EntityOwnerInterface::class);
+    $plural_label = $entity_type->getPluralLabel();
+
+    if ($has_owner) {
+      $permissions["view any {$entity_type_id}"] = [
+        'title' => $this->t('View any @type', [
+          '@type' => $plural_label,
+        ]),
+      ];
+      $permissions["view own {$entity_type_id}"] = [
+        'title' => $this->t('View own @type', [
+          '@type' => $plural_label,
+        ]),
+      ];
+    }
+    else {
+      $permissions["view any {$entity_type_id}"] = [
+        'title' => $this->t('View any @type', [
+          '@type' => $plural_label,
+        ]),
+      ];
+    }
+
+    return $permissions;
+  }
+
+  /**
+   * Builds permissions for the bundle granularity.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type.
+   *
+   * @return array
+   *   The permissions.
+   */
+  protected function buildBundlePermissions(EntityTypeInterface $entity_type) {
+    $permissions = parent::buildBundlePermissions($entity_type);
+    $entity_type_id = $entity_type->id();
+    $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id);
+    $has_owner = $entity_type->entityClassImplements(EntityOwnerInterface::class);
+    $plural_label = $entity_type->getPluralLabel();
+
+    $permissions["view any {$entity_type_id}"] = [
+      'title' => $this->t('View any @type', [
+        '@type' => $plural_label,
+      ]),
+    ];
+    if ($has_owner) {
+      $permissions["view own {$entity_type_id}"] = [
+        'title' => $this->t('View own @type', [
+          '@type' => $plural_label,
+        ]),
+      ];
+    }
+
+    foreach ($bundles as $bundle_name => $bundle_info) {
+      if ($has_owner) {
+        $permissions["view any {$bundle_name} {$entity_type_id}"] = [
+          'title' => $this->t('@bundle: View any @type', [
+            '@bundle' => $bundle_info['label'],
+            '@type' => $plural_label,
+          ]),
+        ];
+        $permissions["view own {$bundle_name} {$entity_type_id}"] = [
+          'title' => $this->t('@bundle: View own @type', [
+            '@bundle' => $bundle_info['label'],
+            '@type' => $plural_label,
+          ]),
+        ];
+      }
+      else {
+        $permissions["view any {$bundle_name} {$entity_type_id}"] = [
+          'title' => $this->t('@bundle: View any @type', [
+            '@bundle' => $bundle_info['label'],
+            '@type' => $plural_label,
+          ]),
+        ];
+      }
+    }
+
+    return $permissions;
+  }
+
+}

+ 13 - 0
sites/all/modules/contrib/dev/entity/tests/modules/entity_module_bundle_plugin_examples_test/entity_module_bundle_plugin_examples_test.info.yml

@@ -0,0 +1,13 @@
+name: 'Entity bundle plugin examples test'
+type: module
+description: 'Module for testing bundle plugins.'
+package: Testing
+# core: 8.x
+dependencies:
+  - entity
+
+# Information added by Drupal.org packaging script on 2017-09-20
+version: '8.x-1.0-beta1'
+core: '8.x'
+project: 'entity'
+datestamp: 1505895847

+ 31 - 0
sites/all/modules/contrib/dev/entity/tests/modules/entity_module_bundle_plugin_examples_test/src/Plugin/BundlePluginTest/Second.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace Drupal\entity_module_bundle_plugin_examples_test\Plugin\BundlePluginTest;
+
+use Drupal\entity\BundleFieldDefinition;
+use Drupal\Core\Plugin\PluginBase;
+use Drupal\entity_module_bundle_plugin_test\Plugin\BundlePluginTest\BundlePluginTestInterface;
+
+/**
+ * Provides the second bundle plugin.
+ *
+ * @BundlePluginTest(
+ *   id = "second",
+ *   label = @Translation("Second"),
+ * )
+ */
+class Second extends PluginBase implements BundlePluginTestInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildFieldDefinitions() {
+    $fields = [];
+    $fields['second_mail'] = BundleFieldDefinition::create('email')
+      ->setLabel(t('Email'))
+      ->setRequired(TRUE);
+
+    return $fields;
+  }
+
+}

+ 13 - 0
sites/all/modules/contrib/dev/entity/tests/modules/entity_module_bundle_plugin_test/entity_module_bundle_plugin_test.info.yml

@@ -0,0 +1,13 @@
+name: 'Entity bundle plugin test'
+type: module
+description: 'Module for testing bundle plugins.'
+package: Testing
+# core: 8.x
+dependencies:
+  - entity
+
+# Information added by Drupal.org packaging script on 2017-09-20
+version: '8.x-1.0-beta1'
+core: '8.x'
+project: 'entity'
+datestamp: 1505895847

+ 4 - 0
sites/all/modules/contrib/dev/entity/tests/modules/entity_module_bundle_plugin_test/entity_module_bundle_plugin_test.services.yml

@@ -0,0 +1,4 @@
+services:
+  plugin.manager.bundle_plugin_test:
+    class: Drupal\entity_module_bundle_plugin_test\BundlePluginTestManager
+    parent: default_plugin_manager

+ 34 - 0
sites/all/modules/contrib/dev/entity/tests/modules/entity_module_bundle_plugin_test/src/Annotation/BundlePluginTest.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\entity_module_bundle_plugin_test\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines the BundlePluginTest annotation object.
+ *
+ * Plugin namespace: Plugin\BundlePluginTest.
+ *
+ * @see plugin_api
+ *
+ * @Annotation
+ */
+class BundlePluginTest extends Plugin {
+
+  /**
+   * The plugin ID.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The plugin label.
+   *
+   * @ingroup plugin_translatable
+   *
+   * @var \Drupal\Core\Annotation\Translation
+   */
+  public $label;
+
+}

+ 35 - 0
sites/all/modules/contrib/dev/entity/tests/modules/entity_module_bundle_plugin_test/src/BundlePluginTestManager.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace Drupal\entity_module_bundle_plugin_test;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+
+/**
+ * Manages discovery and instantiation of BundlePluginTest plugins.
+ *
+ * @see \Drupal\entity_module_bundle_plugin_test\Annotation\BundlePluginTest
+ * @see plugin_api
+ */
+class BundlePluginTestManager extends DefaultPluginManager {
+
+  /**
+   * Constructs a new BundlePluginTestManager object.
+   *
+   * @param \Traversable $namespaces
+   *   An object that implements \Traversable which contains the root paths
+   *   keyed by the corresponding namespace to look for plugin implementations.
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+   *   The cache backend.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   */
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Plugin/BundlePluginTest', $namespaces, $module_handler, 'Drupal\entity_module_bundle_plugin_test\Plugin\BundlePluginTest\BundlePluginTestInterface', 'Drupal\entity_module_bundle_plugin_test\Annotation\BundlePluginTest');
+
+    $this->alterInfo('bundle_plugin_test_info');
+    $this->setCacheBackend($cache_backend, 'bundle_plugin_test_plugins');
+  }
+
+}

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است