241 lines
8.1 KiB
PHP
241 lines
8.1 KiB
PHP
<?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 = array();
|
|
$all_callback_permissions = array();
|
|
|
|
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 = array(
|
|
'title' => $callback_permission,
|
|
);
|
|
}
|
|
|
|
$callback_permission += array(
|
|
'description' => NULL,
|
|
'provider' => $provider,
|
|
);
|
|
|
|
$all_callback_permissions[$name] = $callback_permission;
|
|
}
|
|
}
|
|
}
|
|
|
|
unset($permissions['permission_callbacks']);
|
|
}
|
|
|
|
foreach ($permissions as &$permission) {
|
|
if (!is_array($permission)) {
|
|
$permission = array(
|
|
'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 = array()) {
|
|
// 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 = array();
|
|
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();
|
|
}
|
|
|
|
}
|