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