You are here

class PermissionHandler in Drupal 10

Same name and namespace in other branches
  1. 8 core/modules/user/src/PermissionHandler.php \Drupal\user\PermissionHandler
  2. 9 core/modules/user/src/PermissionHandler.php \Drupal\user\PermissionHandler

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):


# 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:
  # The callable should return an associative array with one or more
  # permissions. Each permission array can use the same keys as the example
  # permission defined above. Additionally, a dependencies key is supported.
  # For more information about permission dependencies see
  # PermissionHandlerInterface::getPermissions().
  - Drupal\filter\FilterPermissions::permissions

Hierarchy

Expanded class hierarchy of PermissionHandler

See also

\Drupal\user\PermissionHandlerInterface::getPermissions()

filter.permissions.yml

\Drupal\filter\FilterPermissions

User accounts, permissions, and roles

1 file declares its use of PermissionHandler
PermissionHandlerTest.php in core/modules/user/tests/src/Unit/PermissionHandlerTest.php
Contains \Drupal\Tests\user\Unit\PermissionHandlerTest.
1 string reference to 'PermissionHandler'
user.services.yml in core/modules/user/user.services.yml
core/modules/user/user.services.yml
1 service uses PermissionHandler
user.permissions in core/modules/user/user.services.yml
Drupal\user\PermissionHandler

File

core/modules/user/src/PermissionHandler.php, line 52

Namespace

Drupal\user
View source
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[]
   *   An array with the same structure as
   *   PermissionHandlerInterface::getPermissions().
   *
   * @see \Drupal\user\PermissionHandlerInterface::getPermissions()
   */
  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[]
   *   An array with the same structure as
   *   PermissionHandlerInterface::getPermissions().
   *
   * @see \Drupal\user\PermissionHandlerInterface::getPermissions()
   */
  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;
  }

}

Members