annotate core/modules/rest/src/Entity/ConfigDependencies.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\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 }