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 }
|