annotate core/modules/user/src/PermissionHandler.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 4c8ae668cc8c
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\user;
Chris@0 4
Chris@0 5 use Drupal\Core\Discovery\YamlDiscovery;
Chris@0 6 use Drupal\Core\Controller\ControllerResolverInterface;
Chris@0 7 use Drupal\Core\Extension\ModuleHandlerInterface;
Chris@0 8 use Drupal\Core\StringTranslation\StringTranslationTrait;
Chris@0 9 use Drupal\Core\StringTranslation\TranslationInterface;
Chris@0 10
Chris@0 11 /**
Chris@0 12 * Provides the available permissions based on yml files.
Chris@0 13 *
Chris@0 14 * To define permissions you can use a $module.permissions.yml file. This file
Chris@0 15 * defines machine names, human-readable names, restrict access (if required for
Chris@0 16 * security warning), and optionally descriptions for each permission type. The
Chris@0 17 * machine names are the canonical way to refer to permissions for access
Chris@0 18 * checking.
Chris@0 19 *
Chris@0 20 * If your module needs to define dynamic permissions you can use the
Chris@0 21 * permission_callbacks key to declare a callable that will return an array of
Chris@0 22 * permissions, keyed by machine name. Each item in the array can contain the
Chris@0 23 * same keys as an entry in $module.permissions.yml.
Chris@0 24 *
Chris@0 25 * Here is an example from the core filter module (comments have been added):
Chris@0 26 * @code
Chris@0 27 * # The key is the permission machine name, and is required.
Chris@0 28 * administer filters:
Chris@0 29 * # (required) Human readable name of the permission used in the UI.
Chris@0 30 * title: 'Administer text formats and filters'
Chris@0 31 * # (optional) Additional description fo the permission used in the UI.
Chris@0 32 * description: 'Define how text is handled by combining filters into text formats.'
Chris@0 33 * # (optional) Boolean, when set to true a warning about site security will
Chris@0 34 * # be displayed on the Permissions page. Defaults to false.
Chris@0 35 * restrict access: false
Chris@0 36 *
Chris@0 37 * # An array of callables used to generate dynamic permissions.
Chris@0 38 * permission_callbacks:
Chris@0 39 * # Each item in the array should return an associative array with one or
Chris@0 40 * # more permissions following the same keys as the permission defined above.
Chris@0 41 * - Drupal\filter\FilterPermissions::permissions
Chris@0 42 * @endcode
Chris@0 43 *
Chris@0 44 * @see filter.permissions.yml
Chris@0 45 * @see \Drupal\filter\FilterPermissions
Chris@0 46 * @see user_api
Chris@0 47 */
Chris@0 48 class PermissionHandler implements PermissionHandlerInterface {
Chris@0 49
Chris@0 50 use StringTranslationTrait;
Chris@0 51
Chris@0 52 /**
Chris@0 53 * The module handler.
Chris@0 54 *
Chris@0 55 * @var \Drupal\Core\Extension\ModuleHandlerInterface
Chris@0 56 */
Chris@0 57 protected $moduleHandler;
Chris@0 58
Chris@0 59 /**
Chris@0 60 * The YAML discovery class to find all .permissions.yml files.
Chris@0 61 *
Chris@0 62 * @var \Drupal\Core\Discovery\YamlDiscovery
Chris@0 63 */
Chris@0 64 protected $yamlDiscovery;
Chris@0 65
Chris@0 66 /**
Chris@0 67 * The controller resolver.
Chris@0 68 *
Chris@0 69 * @var \Drupal\Core\Controller\ControllerResolverInterface
Chris@0 70 */
Chris@0 71 protected $controllerResolver;
Chris@0 72
Chris@0 73 /**
Chris@0 74 * Constructs a new PermissionHandler.
Chris@0 75 *
Chris@0 76 * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
Chris@0 77 * The module handler.
Chris@0 78 * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
Chris@0 79 * The string translation.
Chris@0 80 * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
Chris@0 81 * The controller resolver.
Chris@0 82 */
Chris@0 83 public function __construct(ModuleHandlerInterface $module_handler, TranslationInterface $string_translation, ControllerResolverInterface $controller_resolver) {
Chris@0 84 // @todo It would be nice if you could pull all module directories from the
Chris@0 85 // container.
Chris@0 86 $this->moduleHandler = $module_handler;
Chris@0 87 $this->stringTranslation = $string_translation;
Chris@0 88 $this->controllerResolver = $controller_resolver;
Chris@0 89 }
Chris@0 90
Chris@0 91 /**
Chris@0 92 * Gets the YAML discovery.
Chris@0 93 *
Chris@0 94 * @return \Drupal\Core\Discovery\YamlDiscovery
Chris@0 95 * The YAML discovery.
Chris@0 96 */
Chris@0 97 protected function getYamlDiscovery() {
Chris@0 98 if (!isset($this->yamlDiscovery)) {
Chris@0 99 $this->yamlDiscovery = new YamlDiscovery('permissions', $this->moduleHandler->getModuleDirectories());
Chris@0 100 }
Chris@0 101 return $this->yamlDiscovery;
Chris@0 102 }
Chris@0 103
Chris@0 104 /**
Chris@0 105 * {@inheritdoc}
Chris@0 106 */
Chris@0 107 public function getPermissions() {
Chris@0 108 $all_permissions = $this->buildPermissionsYaml();
Chris@0 109
Chris@0 110 return $this->sortPermissions($all_permissions);
Chris@0 111 }
Chris@0 112
Chris@0 113 /**
Chris@0 114 * {@inheritdoc}
Chris@0 115 */
Chris@0 116 public function moduleProvidesPermissions($module_name) {
Chris@0 117 // @TODO Static cache this information, see
Chris@0 118 // https://www.drupal.org/node/2339487
Chris@0 119 $permissions = $this->getPermissions();
Chris@0 120
Chris@0 121 foreach ($permissions as $permission) {
Chris@0 122 if ($permission['provider'] == $module_name) {
Chris@0 123 return TRUE;
Chris@0 124 }
Chris@0 125 }
Chris@0 126 return FALSE;
Chris@0 127 }
Chris@0 128
Chris@0 129 /**
Chris@0 130 * Builds all permissions provided by .permissions.yml files.
Chris@0 131 *
Chris@0 132 * @return array[]
Chris@0 133 * Each return permission is an array with the following keys:
Chris@0 134 * - title: The title of the permission.
Chris@0 135 * - description: The description of the permission, defaults to NULL.
Chris@0 136 * - provider: The provider of the permission.
Chris@0 137 */
Chris@0 138 protected function buildPermissionsYaml() {
Chris@0 139 $all_permissions = [];
Chris@0 140 $all_callback_permissions = [];
Chris@0 141
Chris@0 142 foreach ($this->getYamlDiscovery()->findAll() as $provider => $permissions) {
Chris@0 143 // The top-level 'permissions_callback' is a list of methods in controller
Chris@0 144 // syntax, see \Drupal\Core\Controller\ControllerResolver. These methods
Chris@0 145 // should return an array of permissions in the same structure.
Chris@0 146 if (isset($permissions['permission_callbacks'])) {
Chris@0 147 foreach ($permissions['permission_callbacks'] as $permission_callback) {
Chris@0 148 $callback = $this->controllerResolver->getControllerFromDefinition($permission_callback);
Chris@0 149 if ($callback_permissions = call_user_func($callback)) {
Chris@0 150 // Add any callback permissions to the array of permissions. Any
Chris@0 151 // defaults can then get processed below.
Chris@0 152 foreach ($callback_permissions as $name => $callback_permission) {
Chris@0 153 if (!is_array($callback_permission)) {
Chris@0 154 $callback_permission = [
Chris@0 155 'title' => $callback_permission,
Chris@0 156 ];
Chris@0 157 }
Chris@0 158
Chris@0 159 $callback_permission += [
Chris@0 160 'description' => NULL,
Chris@0 161 'provider' => $provider,
Chris@0 162 ];
Chris@0 163
Chris@0 164 $all_callback_permissions[$name] = $callback_permission;
Chris@0 165 }
Chris@0 166 }
Chris@0 167 }
Chris@0 168
Chris@0 169 unset($permissions['permission_callbacks']);
Chris@0 170 }
Chris@0 171
Chris@0 172 foreach ($permissions as &$permission) {
Chris@0 173 if (!is_array($permission)) {
Chris@0 174 $permission = [
Chris@0 175 'title' => $permission,
Chris@0 176 ];
Chris@0 177 }
Chris@0 178 $permission['title'] = $this->t($permission['title']);
Chris@0 179 $permission['description'] = isset($permission['description']) ? $this->t($permission['description']) : NULL;
Chris@0 180 $permission['provider'] = !empty($permission['provider']) ? $permission['provider'] : $provider;
Chris@0 181 }
Chris@0 182
Chris@0 183 $all_permissions += $permissions;
Chris@0 184 }
Chris@0 185
Chris@0 186 return $all_permissions + $all_callback_permissions;
Chris@0 187 }
Chris@0 188
Chris@0 189 /**
Chris@0 190 * Sorts the given permissions by provider name and title.
Chris@0 191 *
Chris@0 192 * @param array $all_permissions
Chris@0 193 * The permissions to be sorted.
Chris@0 194 *
Chris@0 195 * @return array[]
Chris@0 196 * Each return permission is an array with the following keys:
Chris@0 197 * - title: The title of the permission.
Chris@0 198 * - description: The description of the permission, defaults to NULL.
Chris@0 199 * - provider: The provider of the permission.
Chris@0 200 */
Chris@0 201 protected function sortPermissions(array $all_permissions = []) {
Chris@0 202 // Get a list of all the modules providing permissions and sort by
Chris@0 203 // display name.
Chris@0 204 $modules = $this->getModuleNames();
Chris@0 205
Chris@0 206 uasort($all_permissions, function (array $permission_a, array $permission_b) use ($modules) {
Chris@0 207 if ($modules[$permission_a['provider']] == $modules[$permission_b['provider']]) {
Chris@0 208 return $permission_a['title'] > $permission_b['title'];
Chris@0 209 }
Chris@0 210 else {
Chris@0 211 return $modules[$permission_a['provider']] > $modules[$permission_b['provider']];
Chris@0 212 }
Chris@0 213 });
Chris@0 214 return $all_permissions;
Chris@0 215 }
Chris@0 216
Chris@0 217 /**
Chris@0 218 * Returns all module names.
Chris@0 219 *
Chris@0 220 * @return string[]
Chris@0 221 * Returns the human readable names of all modules keyed by machine name.
Chris@0 222 */
Chris@0 223 protected function getModuleNames() {
Chris@0 224 $modules = [];
Chris@0 225 foreach (array_keys($this->moduleHandler->getModuleList()) as $module) {
Chris@0 226 $modules[$module] = $this->moduleHandler->getName($module);
Chris@0 227 }
Chris@0 228 asort($modules);
Chris@0 229 return $modules;
Chris@0 230 }
Chris@0 231
Chris@0 232 /**
Chris@0 233 * Wraps system_rebuild_module_data()
Chris@0 234 *
Chris@0 235 * @return \Drupal\Core\Extension\Extension[]
Chris@0 236 */
Chris@0 237 protected function systemRebuildModuleData() {
Chris@0 238 return system_rebuild_module_data();
Chris@0 239 }
Chris@0 240
Chris@0 241 }