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