diff core/modules/user/src/PermissionHandler.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/user/src/PermissionHandler.php	Wed Nov 29 16:09:58 2017 +0000
@@ -0,0 +1,241 @@
+<?php
+
+namespace Drupal\user;
+
+use Drupal\Core\Discovery\YamlDiscovery;
+use Drupal\Core\Controller\ControllerResolverInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\StringTranslation\TranslationInterface;
+
+/**
+ * Provides the available permissions based on yml files.
+ *
+ * To define permissions you can use a $module.permissions.yml file. This file
+ * defines machine names, human-readable names, restrict access (if required for
+ * security warning), and optionally descriptions for each permission type. The
+ * machine names are the canonical way to refer to permissions for access
+ * checking.
+ *
+ * If your module needs to define dynamic permissions you can use the
+ * permission_callbacks key to declare a callable that will return an array of
+ * permissions, keyed by machine name. Each item in the array can contain the
+ * same keys as an entry in $module.permissions.yml.
+ *
+ * Here is an example from the core filter module (comments have been added):
+ * @code
+ * # The key is the permission machine name, and is required.
+ * administer filters:
+ *   # (required) Human readable name of the permission used in the UI.
+ *   title: 'Administer text formats and filters'
+ *   # (optional) Additional description fo the permission used in the UI.
+ *   description: 'Define how text is handled by combining filters into text formats.'
+ *   # (optional) Boolean, when set to true a warning about site security will
+ *   # be displayed on the Permissions page. Defaults to false.
+ *   restrict access: false
+ *
+ * # An array of callables used to generate dynamic permissions.
+ * permission_callbacks:
+ *   # Each item in the array should return an associative array with one or
+ *   # more permissions following the same keys as the permission defined above.
+ *   - Drupal\filter\FilterPermissions::permissions
+ * @endcode
+ *
+ * @see filter.permissions.yml
+ * @see \Drupal\filter\FilterPermissions
+ * @see user_api
+ */
+class PermissionHandler implements PermissionHandlerInterface {
+
+  use StringTranslationTrait;
+
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * The YAML discovery class to find all .permissions.yml files.
+   *
+   * @var \Drupal\Core\Discovery\YamlDiscovery
+   */
+  protected $yamlDiscovery;
+
+  /**
+   * The controller resolver.
+   *
+   * @var \Drupal\Core\Controller\ControllerResolverInterface
+   */
+  protected $controllerResolver;
+
+  /**
+   * Constructs a new PermissionHandler.
+   *
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
+   *   The string translation.
+   * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
+   *   The controller resolver.
+   */
+  public function __construct(ModuleHandlerInterface $module_handler, TranslationInterface $string_translation, ControllerResolverInterface $controller_resolver) {
+    // @todo It would be nice if you could pull all module directories from the
+    //   container.
+    $this->moduleHandler = $module_handler;
+    $this->stringTranslation = $string_translation;
+    $this->controllerResolver = $controller_resolver;
+  }
+
+  /**
+   * Gets the YAML discovery.
+   *
+   * @return \Drupal\Core\Discovery\YamlDiscovery
+   *   The YAML discovery.
+   */
+  protected function getYamlDiscovery() {
+    if (!isset($this->yamlDiscovery)) {
+      $this->yamlDiscovery = new YamlDiscovery('permissions', $this->moduleHandler->getModuleDirectories());
+    }
+    return $this->yamlDiscovery;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPermissions() {
+    $all_permissions = $this->buildPermissionsYaml();
+
+    return $this->sortPermissions($all_permissions);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function moduleProvidesPermissions($module_name) {
+    // @TODO Static cache this information, see
+    // https://www.drupal.org/node/2339487
+    $permissions = $this->getPermissions();
+
+    foreach ($permissions as $permission) {
+      if ($permission['provider'] == $module_name) {
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+
+  /**
+   * Builds all permissions provided by .permissions.yml files.
+   *
+   * @return array[]
+   *   Each return permission is an array with the following keys:
+   *   - title: The title of the permission.
+   *   - description: The description of the permission, defaults to NULL.
+   *   - provider: The provider of the permission.
+   */
+  protected function buildPermissionsYaml() {
+    $all_permissions = [];
+    $all_callback_permissions = [];
+
+    foreach ($this->getYamlDiscovery()->findAll() as $provider => $permissions) {
+      // The top-level 'permissions_callback' is a list of methods in controller
+      // syntax, see \Drupal\Core\Controller\ControllerResolver. These methods
+      // should return an array of permissions in the same structure.
+      if (isset($permissions['permission_callbacks'])) {
+        foreach ($permissions['permission_callbacks'] as $permission_callback) {
+          $callback = $this->controllerResolver->getControllerFromDefinition($permission_callback);
+          if ($callback_permissions = call_user_func($callback)) {
+            // Add any callback permissions to the array of permissions. Any
+            // defaults can then get processed below.
+            foreach ($callback_permissions as $name => $callback_permission) {
+              if (!is_array($callback_permission)) {
+                $callback_permission = [
+                  'title' => $callback_permission,
+                ];
+              }
+
+              $callback_permission += [
+                'description' => NULL,
+                'provider' => $provider,
+              ];
+
+              $all_callback_permissions[$name] = $callback_permission;
+            }
+          }
+        }
+
+        unset($permissions['permission_callbacks']);
+      }
+
+      foreach ($permissions as &$permission) {
+        if (!is_array($permission)) {
+          $permission = [
+            'title' => $permission,
+          ];
+        }
+        $permission['title'] = $this->t($permission['title']);
+        $permission['description'] = isset($permission['description']) ? $this->t($permission['description']) : NULL;
+        $permission['provider'] = !empty($permission['provider']) ? $permission['provider'] : $provider;
+      }
+
+      $all_permissions += $permissions;
+    }
+
+    return $all_permissions + $all_callback_permissions;
+  }
+
+  /**
+   * Sorts the given permissions by provider name and title.
+   *
+   * @param array $all_permissions
+   *   The permissions to be sorted.
+   *
+   * @return array[]
+   *   Each return permission is an array with the following keys:
+   *   - title: The title of the permission.
+   *   - description: The description of the permission, defaults to NULL.
+   *   - provider: The provider of the permission.
+   */
+  protected function sortPermissions(array $all_permissions = []) {
+    // Get a list of all the modules providing permissions and sort by
+    // display name.
+    $modules = $this->getModuleNames();
+
+    uasort($all_permissions, function (array $permission_a, array $permission_b) use ($modules) {
+      if ($modules[$permission_a['provider']] == $modules[$permission_b['provider']]) {
+        return $permission_a['title'] > $permission_b['title'];
+      }
+      else {
+        return $modules[$permission_a['provider']] > $modules[$permission_b['provider']];
+      }
+    });
+    return $all_permissions;
+  }
+
+  /**
+   * Returns all module names.
+   *
+   * @return string[]
+   *   Returns the human readable names of all modules keyed by machine name.
+   */
+  protected function getModuleNames() {
+    $modules = [];
+    foreach (array_keys($this->moduleHandler->getModuleList()) as $module) {
+      $modules[$module] = $this->moduleHandler->getName($module);
+    }
+    asort($modules);
+    return $modules;
+  }
+
+  /**
+   * Wraps system_rebuild_module_data()
+   *
+   * @return \Drupal\Core\Extension\Extension[]
+   */
+  protected function systemRebuildModuleData() {
+    return system_rebuild_module_data();
+  }
+
+}