/web/core/modules/user/src/PermissionHandler.php

https://gitlab.com/mohamed_hussein/prodt · PHP · 236 lines · 95 code · 25 blank · 116 comment · 10 complexity · 2aecc27316ce8a963f3fce9662b23bfd MD5 · raw file

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