Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\rest\Entity;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
Chris@0
|
6 use Drupal\rest\RestResourceConfigInterface;
|
Chris@0
|
7 use Symfony\Component\DependencyInjection\ContainerInterface;
|
Chris@0
|
8
|
Chris@0
|
9 /**
|
Chris@0
|
10 * Calculates rest resource config dependencies.
|
Chris@0
|
11 *
|
Chris@0
|
12 * @internal
|
Chris@0
|
13 */
|
Chris@0
|
14 class ConfigDependencies implements ContainerInjectionInterface {
|
Chris@0
|
15
|
Chris@0
|
16 /**
|
Chris@0
|
17 * The serialization format providers, keyed by format.
|
Chris@0
|
18 *
|
Chris@0
|
19 * @var string[]
|
Chris@0
|
20 */
|
Chris@0
|
21 protected $formatProviders;
|
Chris@0
|
22
|
Chris@0
|
23 /**
|
Chris@0
|
24 * The authentication providers, keyed by ID.
|
Chris@0
|
25 *
|
Chris@0
|
26 * @var string[]
|
Chris@0
|
27 */
|
Chris@0
|
28 protected $authProviders;
|
Chris@0
|
29
|
Chris@0
|
30 /**
|
Chris@0
|
31 * Creates a new ConfigDependencies instance.
|
Chris@0
|
32 *
|
Chris@0
|
33 * @param string[] $format_providers
|
Chris@0
|
34 * The serialization format providers, keyed by format.
|
Chris@0
|
35 * @param string[] $auth_providers
|
Chris@0
|
36 * The authentication providers, keyed by ID.
|
Chris@0
|
37 */
|
Chris@0
|
38 public function __construct(array $format_providers, array $auth_providers) {
|
Chris@0
|
39 $this->formatProviders = $format_providers;
|
Chris@0
|
40 $this->authProviders = $auth_providers;
|
Chris@0
|
41 }
|
Chris@0
|
42
|
Chris@0
|
43 /**
|
Chris@0
|
44 * {@inheritdoc}
|
Chris@0
|
45 */
|
Chris@0
|
46 public static function create(ContainerInterface $container) {
|
Chris@0
|
47 return new static(
|
Chris@0
|
48 $container->getParameter('serializer.format_providers'),
|
Chris@0
|
49 $container->getParameter('authentication_providers')
|
Chris@0
|
50 );
|
Chris@0
|
51 }
|
Chris@0
|
52
|
Chris@0
|
53 /**
|
Chris@0
|
54 * Calculates dependencies of a specific rest resource configuration.
|
Chris@0
|
55 *
|
Chris@0
|
56 * This function returns dependencies in a non-sorted, non-unique manner. It
|
Chris@0
|
57 * is therefore the caller's responsibility to sort and remove duplicates
|
Chris@0
|
58 * from the result prior to saving it with the configuration or otherwise
|
Chris@0
|
59 * using it in a way that requires that. For example,
|
Chris@0
|
60 * \Drupal\rest\Entity\RestResourceConfig::calculateDependencies() does this
|
Chris@0
|
61 * via its \Drupal\Core\Entity\DependencyTrait::addDependency() method.
|
Chris@0
|
62 *
|
Chris@0
|
63 * @param \Drupal\rest\RestResourceConfigInterface $rest_config
|
Chris@0
|
64 * The rest configuration.
|
Chris@0
|
65 *
|
Chris@0
|
66 * @return string[][]
|
Chris@0
|
67 * Dependencies keyed by dependency type.
|
Chris@0
|
68 *
|
Chris@0
|
69 * @see \Drupal\rest\Entity\RestResourceConfig::calculateDependencies()
|
Chris@0
|
70 */
|
Chris@0
|
71 public function calculateDependencies(RestResourceConfigInterface $rest_config) {
|
Chris@0
|
72 $granularity = $rest_config->get('granularity');
|
Chris@0
|
73
|
Chris@0
|
74 // Dependency calculation is the same for either granularity, the most
|
Chris@0
|
75 // notable difference is that for the 'resource' granularity, the same
|
Chris@0
|
76 // authentication providers and formats are supported for every method.
|
Chris@0
|
77 switch ($granularity) {
|
Chris@0
|
78 case RestResourceConfigInterface::METHOD_GRANULARITY:
|
Chris@0
|
79 $methods = $rest_config->getMethods();
|
Chris@0
|
80 break;
|
Chris@0
|
81 case RestResourceConfigInterface::RESOURCE_GRANULARITY:
|
Chris@0
|
82 $methods = array_slice($rest_config->getMethods(), 0, 1);
|
Chris@0
|
83 break;
|
Chris@0
|
84 default:
|
Chris@0
|
85 throw new \InvalidArgumentException('Invalid granularity specified.');
|
Chris@0
|
86 }
|
Chris@0
|
87
|
Chris@0
|
88 // The dependency lists for authentication providers and formats
|
Chris@0
|
89 // generated on container build.
|
Chris@0
|
90 $dependencies = [];
|
Chris@0
|
91 foreach ($methods as $request_method) {
|
Chris@0
|
92 // Add dependencies based on the supported authentication providers.
|
Chris@0
|
93 foreach ($rest_config->getAuthenticationProviders($request_method) as $auth) {
|
Chris@0
|
94 if (isset($this->authProviders[$auth])) {
|
Chris@0
|
95 $module_name = $this->authProviders[$auth];
|
Chris@0
|
96 $dependencies['module'][] = $module_name;
|
Chris@0
|
97 }
|
Chris@0
|
98 }
|
Chris@0
|
99 // Add dependencies based on the supported authentication formats.
|
Chris@0
|
100 foreach ($rest_config->getFormats($request_method) as $format) {
|
Chris@0
|
101 if (isset($this->formatProviders[$format])) {
|
Chris@0
|
102 $module_name = $this->formatProviders[$format];
|
Chris@0
|
103 $dependencies['module'][] = $module_name;
|
Chris@0
|
104 }
|
Chris@0
|
105 }
|
Chris@0
|
106 }
|
Chris@0
|
107
|
Chris@0
|
108 return $dependencies;
|
Chris@0
|
109 }
|
Chris@0
|
110
|
Chris@0
|
111 /**
|
Chris@0
|
112 * Informs the entity that entities it depends on will be deleted.
|
Chris@0
|
113 *
|
Chris@0
|
114 * @param \Drupal\rest\RestResourceConfigInterface $rest_config
|
Chris@0
|
115 * The rest configuration.
|
Chris@0
|
116 * @param array $dependencies
|
Chris@0
|
117 * An array of dependencies that will be deleted keyed by dependency type.
|
Chris@0
|
118 * Dependency types are, for example, entity, module and theme.
|
Chris@0
|
119 *
|
Chris@0
|
120 * @return bool
|
Chris@0
|
121 * TRUE if the entity has been changed as a result, FALSE if not.
|
Chris@0
|
122 *
|
Chris@0
|
123 * @see \Drupal\Core\Config\Entity\ConfigEntityInterface::onDependencyRemoval()
|
Chris@0
|
124 */
|
Chris@0
|
125 public function onDependencyRemoval(RestResourceConfigInterface $rest_config, array $dependencies) {
|
Chris@0
|
126 $granularity = $rest_config->get('granularity');
|
Chris@0
|
127 switch ($granularity) {
|
Chris@0
|
128 case RestResourceConfigInterface::METHOD_GRANULARITY:
|
Chris@0
|
129 return $this->onDependencyRemovalForMethodGranularity($rest_config, $dependencies);
|
Chris@0
|
130 case RestResourceConfigInterface::RESOURCE_GRANULARITY:
|
Chris@0
|
131 return $this->onDependencyRemovalForResourceGranularity($rest_config, $dependencies);
|
Chris@0
|
132 default:
|
Chris@0
|
133 throw new \InvalidArgumentException('Invalid granularity specified.');
|
Chris@0
|
134 }
|
Chris@0
|
135 }
|
Chris@0
|
136
|
Chris@0
|
137 /**
|
Chris@0
|
138 * Informs the entity that entities it depends on will be deleted.
|
Chris@0
|
139 *
|
Chris@0
|
140 * @param \Drupal\rest\RestResourceConfigInterface $rest_config
|
Chris@0
|
141 * The rest configuration.
|
Chris@0
|
142 * @param array $dependencies
|
Chris@0
|
143 * An array of dependencies that will be deleted keyed by dependency type.
|
Chris@0
|
144 * Dependency types are, for example, entity, module and theme.
|
Chris@0
|
145 *
|
Chris@0
|
146 * @return bool
|
Chris@0
|
147 * TRUE if the entity has been changed as a result, FALSE if not.
|
Chris@0
|
148 */
|
Chris@0
|
149 protected function onDependencyRemovalForMethodGranularity(RestResourceConfigInterface $rest_config, array $dependencies) {
|
Chris@0
|
150 $changed = FALSE;
|
Chris@0
|
151 // Only module-related dependencies can be fixed. All other types of
|
Chris@0
|
152 // dependencies cannot, because they were not generated based on supported
|
Chris@0
|
153 // authentication providers or formats.
|
Chris@0
|
154 if (isset($dependencies['module'])) {
|
Chris@0
|
155 // Try to fix dependencies.
|
Chris@0
|
156 $removed_auth = array_keys(array_intersect($this->authProviders, $dependencies['module']));
|
Chris@0
|
157 $removed_formats = array_keys(array_intersect($this->formatProviders, $dependencies['module']));
|
Chris@0
|
158 $configuration_before = $configuration = $rest_config->get('configuration');
|
Chris@0
|
159 if (!empty($removed_auth) || !empty($removed_formats)) {
|
Chris@0
|
160 // Try to fix dependency problems by removing affected
|
Chris@0
|
161 // authentication providers and formats.
|
Chris@0
|
162 foreach (array_keys($rest_config->get('configuration')) as $request_method) {
|
Chris@0
|
163 foreach ($removed_formats as $format) {
|
Chris@0
|
164 if (in_array($format, $rest_config->getFormats($request_method), TRUE)) {
|
Chris@0
|
165 $configuration[$request_method]['supported_formats'] = array_diff($configuration[$request_method]['supported_formats'], $removed_formats);
|
Chris@0
|
166 }
|
Chris@0
|
167 }
|
Chris@0
|
168 foreach ($removed_auth as $auth) {
|
Chris@0
|
169 if (in_array($auth, $rest_config->getAuthenticationProviders($request_method), TRUE)) {
|
Chris@0
|
170 $configuration[$request_method]['supported_auth'] = array_diff($configuration[$request_method]['supported_auth'], $removed_auth);
|
Chris@0
|
171 }
|
Chris@0
|
172 }
|
Chris@0
|
173 if (empty($configuration[$request_method]['supported_auth'])) {
|
Chris@0
|
174 // Remove the key if there are no more authentication providers
|
Chris@0
|
175 // supported by this request method.
|
Chris@0
|
176 unset($configuration[$request_method]['supported_auth']);
|
Chris@0
|
177 }
|
Chris@0
|
178 if (empty($configuration[$request_method]['supported_formats'])) {
|
Chris@0
|
179 // Remove the key if there are no more formats supported by this
|
Chris@0
|
180 // request method.
|
Chris@0
|
181 unset($configuration[$request_method]['supported_formats']);
|
Chris@0
|
182 }
|
Chris@0
|
183 if (empty($configuration[$request_method])) {
|
Chris@0
|
184 // Remove the request method altogether if it no longer has any
|
Chris@0
|
185 // supported authentication providers or formats.
|
Chris@0
|
186 unset($configuration[$request_method]);
|
Chris@0
|
187 }
|
Chris@0
|
188 }
|
Chris@0
|
189 }
|
Chris@0
|
190 if ($configuration_before != $configuration && !empty($configuration)) {
|
Chris@0
|
191 $rest_config->set('configuration', $configuration);
|
Chris@0
|
192 // Only mark the dependencies problems as fixed if there is any
|
Chris@0
|
193 // configuration left.
|
Chris@0
|
194 $changed = TRUE;
|
Chris@0
|
195 }
|
Chris@0
|
196 }
|
Chris@0
|
197 // If the dependency problems are not marked as fixed at this point they
|
Chris@0
|
198 // should be related to the resource plugin and the config entity should
|
Chris@0
|
199 // be deleted.
|
Chris@0
|
200 return $changed;
|
Chris@0
|
201 }
|
Chris@0
|
202
|
Chris@0
|
203 /**
|
Chris@0
|
204 * Informs the entity that entities it depends on will be deleted.
|
Chris@0
|
205 *
|
Chris@0
|
206 * @param \Drupal\rest\RestResourceConfigInterface $rest_config
|
Chris@0
|
207 * The rest configuration.
|
Chris@0
|
208 * @param array $dependencies
|
Chris@0
|
209 * An array of dependencies that will be deleted keyed by dependency type.
|
Chris@0
|
210 * Dependency types are, for example, entity, module and theme.
|
Chris@0
|
211 *
|
Chris@0
|
212 * @return bool
|
Chris@0
|
213 * TRUE if the entity has been changed as a result, FALSE if not.
|
Chris@0
|
214 */
|
Chris@0
|
215 protected function onDependencyRemovalForResourceGranularity(RestResourceConfigInterface $rest_config, array $dependencies) {
|
Chris@0
|
216 $changed = FALSE;
|
Chris@0
|
217 // Only module-related dependencies can be fixed. All other types of
|
Chris@0
|
218 // dependencies cannot, because they were not generated based on supported
|
Chris@0
|
219 // authentication providers or formats.
|
Chris@0
|
220 if (isset($dependencies['module'])) {
|
Chris@0
|
221 // Try to fix dependencies.
|
Chris@0
|
222 $removed_auth = array_keys(array_intersect($this->authProviders, $dependencies['module']));
|
Chris@0
|
223 $removed_formats = array_keys(array_intersect($this->formatProviders, $dependencies['module']));
|
Chris@0
|
224 $configuration_before = $configuration = $rest_config->get('configuration');
|
Chris@0
|
225 if (!empty($removed_auth) || !empty($removed_formats)) {
|
Chris@0
|
226 // All methods support the same formats and authentication providers, so
|
Chris@0
|
227 // get those for whichever the first listed method is.
|
Chris@0
|
228 $first_method = $rest_config->getMethods()[0];
|
Chris@0
|
229
|
Chris@0
|
230 // Try to fix dependency problems by removing affected
|
Chris@0
|
231 // authentication providers and formats.
|
Chris@0
|
232 foreach ($removed_formats as $format) {
|
Chris@0
|
233 if (in_array($format, $rest_config->getFormats($first_method), TRUE)) {
|
Chris@0
|
234 $configuration['formats'] = array_diff($configuration['formats'], $removed_formats);
|
Chris@0
|
235 }
|
Chris@0
|
236 }
|
Chris@0
|
237 foreach ($removed_auth as $auth) {
|
Chris@0
|
238 if (in_array($auth, $rest_config->getAuthenticationProviders($first_method), TRUE)) {
|
Chris@0
|
239 $configuration['authentication'] = array_diff($configuration['authentication'], $removed_auth);
|
Chris@0
|
240 }
|
Chris@0
|
241 }
|
Chris@0
|
242 if (empty($configuration['authentication'])) {
|
Chris@0
|
243 // Remove the key if there are no more authentication providers
|
Chris@0
|
244 // supported.
|
Chris@0
|
245 unset($configuration['authentication']);
|
Chris@0
|
246 }
|
Chris@0
|
247 if (empty($configuration['formats'])) {
|
Chris@0
|
248 // Remove the key if there are no more formats supported.
|
Chris@0
|
249 unset($configuration['formats']);
|
Chris@0
|
250 }
|
Chris@0
|
251 if (empty($configuration['authentication']) || empty($configuration['formats'])) {
|
Chris@0
|
252 // If there no longer are any supported authentication providers or
|
Chris@0
|
253 // formats, this REST resource can no longer function, and so we
|
Chris@0
|
254 // cannot fix this config entity to keep it working.
|
Chris@0
|
255 $configuration = [];
|
Chris@0
|
256 }
|
Chris@0
|
257 }
|
Chris@0
|
258 if ($configuration_before != $configuration && !empty($configuration)) {
|
Chris@0
|
259 $rest_config->set('configuration', $configuration);
|
Chris@0
|
260 // Only mark the dependencies problems as fixed if there is any
|
Chris@0
|
261 // configuration left.
|
Chris@0
|
262 $changed = TRUE;
|
Chris@0
|
263 }
|
Chris@0
|
264 }
|
Chris@0
|
265 // If the dependency problems are not marked as fixed at this point they
|
Chris@0
|
266 // should be related to the resource plugin and the config entity should
|
Chris@0
|
267 // be deleted.
|
Chris@0
|
268 return $changed;
|
Chris@0
|
269 }
|
Chris@0
|
270
|
Chris@0
|
271 }
|