Chris@0: formatProviders = $format_providers; Chris@0: $this->authProviders = $auth_providers; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public static function create(ContainerInterface $container) { Chris@0: return new static( Chris@0: $container->getParameter('serializer.format_providers'), Chris@0: $container->getParameter('authentication_providers') Chris@0: ); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Calculates dependencies of a specific rest resource configuration. Chris@0: * Chris@0: * This function returns dependencies in a non-sorted, non-unique manner. It Chris@0: * is therefore the caller's responsibility to sort and remove duplicates Chris@0: * from the result prior to saving it with the configuration or otherwise Chris@0: * using it in a way that requires that. For example, Chris@0: * \Drupal\rest\Entity\RestResourceConfig::calculateDependencies() does this Chris@0: * via its \Drupal\Core\Entity\DependencyTrait::addDependency() method. Chris@0: * Chris@0: * @param \Drupal\rest\RestResourceConfigInterface $rest_config Chris@0: * The rest configuration. Chris@0: * Chris@0: * @return string[][] Chris@0: * Dependencies keyed by dependency type. Chris@0: * Chris@0: * @see \Drupal\rest\Entity\RestResourceConfig::calculateDependencies() Chris@0: */ Chris@0: public function calculateDependencies(RestResourceConfigInterface $rest_config) { Chris@0: $granularity = $rest_config->get('granularity'); Chris@0: Chris@0: // Dependency calculation is the same for either granularity, the most Chris@0: // notable difference is that for the 'resource' granularity, the same Chris@0: // authentication providers and formats are supported for every method. Chris@0: switch ($granularity) { Chris@0: case RestResourceConfigInterface::METHOD_GRANULARITY: Chris@0: $methods = $rest_config->getMethods(); Chris@0: break; Chris@0: case RestResourceConfigInterface::RESOURCE_GRANULARITY: Chris@0: $methods = array_slice($rest_config->getMethods(), 0, 1); Chris@0: break; Chris@0: default: Chris@0: throw new \InvalidArgumentException('Invalid granularity specified.'); Chris@0: } Chris@0: Chris@0: // The dependency lists for authentication providers and formats Chris@0: // generated on container build. Chris@0: $dependencies = []; Chris@0: foreach ($methods as $request_method) { Chris@0: // Add dependencies based on the supported authentication providers. Chris@0: foreach ($rest_config->getAuthenticationProviders($request_method) as $auth) { Chris@0: if (isset($this->authProviders[$auth])) { Chris@0: $module_name = $this->authProviders[$auth]; Chris@0: $dependencies['module'][] = $module_name; Chris@0: } Chris@0: } Chris@0: // Add dependencies based on the supported authentication formats. Chris@0: foreach ($rest_config->getFormats($request_method) as $format) { Chris@0: if (isset($this->formatProviders[$format])) { Chris@0: $module_name = $this->formatProviders[$format]; Chris@0: $dependencies['module'][] = $module_name; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: return $dependencies; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Informs the entity that entities it depends on will be deleted. Chris@0: * Chris@0: * @param \Drupal\rest\RestResourceConfigInterface $rest_config Chris@0: * The rest configuration. Chris@0: * @param array $dependencies Chris@0: * An array of dependencies that will be deleted keyed by dependency type. Chris@0: * Dependency types are, for example, entity, module and theme. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE if the entity has been changed as a result, FALSE if not. Chris@0: * Chris@0: * @see \Drupal\Core\Config\Entity\ConfigEntityInterface::onDependencyRemoval() Chris@0: */ Chris@0: public function onDependencyRemoval(RestResourceConfigInterface $rest_config, array $dependencies) { Chris@0: $granularity = $rest_config->get('granularity'); Chris@0: switch ($granularity) { Chris@0: case RestResourceConfigInterface::METHOD_GRANULARITY: Chris@0: return $this->onDependencyRemovalForMethodGranularity($rest_config, $dependencies); Chris@0: case RestResourceConfigInterface::RESOURCE_GRANULARITY: Chris@0: return $this->onDependencyRemovalForResourceGranularity($rest_config, $dependencies); Chris@0: default: Chris@0: throw new \InvalidArgumentException('Invalid granularity specified.'); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Informs the entity that entities it depends on will be deleted. Chris@0: * Chris@0: * @param \Drupal\rest\RestResourceConfigInterface $rest_config Chris@0: * The rest configuration. Chris@0: * @param array $dependencies Chris@0: * An array of dependencies that will be deleted keyed by dependency type. Chris@0: * Dependency types are, for example, entity, module and theme. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE if the entity has been changed as a result, FALSE if not. Chris@0: */ Chris@0: protected function onDependencyRemovalForMethodGranularity(RestResourceConfigInterface $rest_config, array $dependencies) { Chris@0: $changed = FALSE; Chris@0: // Only module-related dependencies can be fixed. All other types of Chris@0: // dependencies cannot, because they were not generated based on supported Chris@0: // authentication providers or formats. Chris@0: if (isset($dependencies['module'])) { Chris@0: // Try to fix dependencies. Chris@0: $removed_auth = array_keys(array_intersect($this->authProviders, $dependencies['module'])); Chris@0: $removed_formats = array_keys(array_intersect($this->formatProviders, $dependencies['module'])); Chris@0: $configuration_before = $configuration = $rest_config->get('configuration'); Chris@0: if (!empty($removed_auth) || !empty($removed_formats)) { Chris@0: // Try to fix dependency problems by removing affected Chris@0: // authentication providers and formats. Chris@0: foreach (array_keys($rest_config->get('configuration')) as $request_method) { Chris@0: foreach ($removed_formats as $format) { Chris@0: if (in_array($format, $rest_config->getFormats($request_method), TRUE)) { Chris@0: $configuration[$request_method]['supported_formats'] = array_diff($configuration[$request_method]['supported_formats'], $removed_formats); Chris@0: } Chris@0: } Chris@0: foreach ($removed_auth as $auth) { Chris@0: if (in_array($auth, $rest_config->getAuthenticationProviders($request_method), TRUE)) { Chris@0: $configuration[$request_method]['supported_auth'] = array_diff($configuration[$request_method]['supported_auth'], $removed_auth); Chris@0: } Chris@0: } Chris@0: if (empty($configuration[$request_method]['supported_auth'])) { Chris@0: // Remove the key if there are no more authentication providers Chris@0: // supported by this request method. Chris@0: unset($configuration[$request_method]['supported_auth']); Chris@0: } Chris@0: if (empty($configuration[$request_method]['supported_formats'])) { Chris@0: // Remove the key if there are no more formats supported by this Chris@0: // request method. Chris@0: unset($configuration[$request_method]['supported_formats']); Chris@0: } Chris@0: if (empty($configuration[$request_method])) { Chris@0: // Remove the request method altogether if it no longer has any Chris@0: // supported authentication providers or formats. Chris@0: unset($configuration[$request_method]); Chris@0: } Chris@0: } Chris@0: } Chris@0: if ($configuration_before != $configuration && !empty($configuration)) { Chris@0: $rest_config->set('configuration', $configuration); Chris@0: // Only mark the dependencies problems as fixed if there is any Chris@0: // configuration left. Chris@0: $changed = TRUE; Chris@0: } Chris@0: } Chris@0: // If the dependency problems are not marked as fixed at this point they Chris@0: // should be related to the resource plugin and the config entity should Chris@0: // be deleted. Chris@0: return $changed; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Informs the entity that entities it depends on will be deleted. Chris@0: * Chris@0: * @param \Drupal\rest\RestResourceConfigInterface $rest_config Chris@0: * The rest configuration. Chris@0: * @param array $dependencies Chris@0: * An array of dependencies that will be deleted keyed by dependency type. Chris@0: * Dependency types are, for example, entity, module and theme. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE if the entity has been changed as a result, FALSE if not. Chris@0: */ Chris@0: protected function onDependencyRemovalForResourceGranularity(RestResourceConfigInterface $rest_config, array $dependencies) { Chris@0: $changed = FALSE; Chris@0: // Only module-related dependencies can be fixed. All other types of Chris@0: // dependencies cannot, because they were not generated based on supported Chris@0: // authentication providers or formats. Chris@0: if (isset($dependencies['module'])) { Chris@0: // Try to fix dependencies. Chris@0: $removed_auth = array_keys(array_intersect($this->authProviders, $dependencies['module'])); Chris@0: $removed_formats = array_keys(array_intersect($this->formatProviders, $dependencies['module'])); Chris@0: $configuration_before = $configuration = $rest_config->get('configuration'); Chris@0: if (!empty($removed_auth) || !empty($removed_formats)) { Chris@0: // All methods support the same formats and authentication providers, so Chris@0: // get those for whichever the first listed method is. Chris@0: $first_method = $rest_config->getMethods()[0]; Chris@0: Chris@0: // Try to fix dependency problems by removing affected Chris@0: // authentication providers and formats. Chris@0: foreach ($removed_formats as $format) { Chris@0: if (in_array($format, $rest_config->getFormats($first_method), TRUE)) { Chris@0: $configuration['formats'] = array_diff($configuration['formats'], $removed_formats); Chris@0: } Chris@0: } Chris@0: foreach ($removed_auth as $auth) { Chris@0: if (in_array($auth, $rest_config->getAuthenticationProviders($first_method), TRUE)) { Chris@0: $configuration['authentication'] = array_diff($configuration['authentication'], $removed_auth); Chris@0: } Chris@0: } Chris@0: if (empty($configuration['authentication'])) { Chris@0: // Remove the key if there are no more authentication providers Chris@0: // supported. Chris@0: unset($configuration['authentication']); Chris@0: } Chris@0: if (empty($configuration['formats'])) { Chris@0: // Remove the key if there are no more formats supported. Chris@0: unset($configuration['formats']); Chris@0: } Chris@0: if (empty($configuration['authentication']) || empty($configuration['formats'])) { Chris@0: // If there no longer are any supported authentication providers or Chris@0: // formats, this REST resource can no longer function, and so we Chris@0: // cannot fix this config entity to keep it working. Chris@0: $configuration = []; Chris@0: } Chris@0: } Chris@0: if ($configuration_before != $configuration && !empty($configuration)) { Chris@0: $rest_config->set('configuration', $configuration); Chris@0: // Only mark the dependencies problems as fixed if there is any Chris@0: // configuration left. Chris@0: $changed = TRUE; Chris@0: } Chris@0: } Chris@0: // If the dependency problems are not marked as fixed at this point they Chris@0: // should be related to the resource plugin and the config entity should Chris@0: // be deleted. Chris@0: return $changed; Chris@0: } Chris@0: Chris@0: }