Chris@0: manager = $manager; Chris@0: $this->resourceConfigStorage = $entity_type_manager->getStorage('rest_resource_config'); Chris@0: $this->logger = $logger; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Alters existing routes for a specific collection. Chris@0: * Chris@0: * @param \Drupal\Core\Routing\RouteBuildEvent $event Chris@0: * The route build event. Chris@0: * @return array Chris@0: */ Chris@0: public function onDynamicRouteEvent(RouteBuildEvent $event) { Chris@0: // Iterate over all enabled REST resource config entities. Chris@0: /** @var \Drupal\rest\RestResourceConfigInterface[] $resource_configs */ Chris@0: $resource_configs = $this->resourceConfigStorage->loadMultiple(); Chris@0: foreach ($resource_configs as $resource_config) { Chris@0: if ($resource_config->status()) { Chris@0: $resource_routes = $this->getRoutesForResourceConfig($resource_config); Chris@0: $event->getRouteCollection()->addCollection($resource_routes); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Provides all routes for a given REST resource config. Chris@0: * Chris@0: * This method determines where a resource is reachable, what path Chris@0: * replacements are used, the required HTTP method for the operation etc. Chris@0: * Chris@0: * @param \Drupal\rest\RestResourceConfigInterface $rest_resource_config Chris@0: * The rest resource config. Chris@0: * Chris@0: * @return \Symfony\Component\Routing\RouteCollection Chris@0: * The route collection. Chris@0: */ Chris@0: protected function getRoutesForResourceConfig(RestResourceConfigInterface $rest_resource_config) { Chris@0: $plugin = $rest_resource_config->getResourcePlugin(); Chris@0: $collection = new RouteCollection(); Chris@0: Chris@0: foreach ($plugin->routes() as $name => $route) { Chris@0: /** @var \Symfony\Component\Routing\Route $route */ Chris@0: // @todo: Are multiple methods possible here? Chris@0: $methods = $route->getMethods(); Chris@14: // Only expose routes Chris@14: // - that have an explicit method and allow >=1 format for that method Chris@14: // - that exist for BC Chris@14: // @see \Drupal\rest\RouteProcessor\RestResourceGetRouteProcessorBC Chris@14: if (($methods && ($method = $methods[0]) && $supported_formats = $rest_resource_config->getFormats($method)) || $route->hasOption('bc_route')) { Chris@0: $route->setRequirement('_csrf_request_header_token', 'TRUE'); Chris@0: Chris@0: // Check that authentication providers are defined. Chris@0: if (empty($rest_resource_config->getAuthenticationProviders($method))) { Chris@18: $this->logger->error('At least one authentication provider must be defined for resource @id', ['@id' => $rest_resource_config->id()]); Chris@0: continue; Chris@0: } Chris@0: Chris@0: // Check that formats are defined. Chris@0: if (empty($rest_resource_config->getFormats($method))) { Chris@18: $this->logger->error('At least one format must be defined for resource @id', ['@id' => $rest_resource_config->id()]); Chris@0: continue; Chris@0: } Chris@0: Chris@14: // Remove BC routes for unsupported formats. Chris@14: if ($route->getOption('bc_route') === TRUE) { Chris@14: $format_requirement = $route->getRequirement('_format'); Chris@14: if ($format_requirement && !in_array($format_requirement, $rest_resource_config->getFormats($method))) { Chris@14: continue; Chris@14: } Chris@0: } Chris@0: Chris@0: // The configuration has been validated, so we update the route to: Chris@14: // - set the allowed response body content types/formats for methods Chris@17: // that may send response bodies (unless hardcoded by the plugin) Chris@0: // - set the allowed request body content types/formats for methods that Chris@17: // allow request bodies to be sent (unless hardcoded by the plugin) Chris@0: // - set the allowed authentication providers Chris@17: if (in_array($method, ['GET', 'HEAD', 'POST', 'PUT', 'PATCH'], TRUE) && !$route->hasRequirement('_format')) { Chris@14: $route->addRequirements(['_format' => implode('|', $rest_resource_config->getFormats($method))]); Chris@14: } Chris@17: if (in_array($method, ['POST', 'PATCH', 'PUT'], TRUE) && !$route->hasRequirement('_content_type_format')) { Chris@0: $route->addRequirements(['_content_type_format' => implode('|', $rest_resource_config->getFormats($method))]); Chris@0: } Chris@0: $route->setOption('_auth', $rest_resource_config->getAuthenticationProviders($method)); Chris@0: $route->setDefault('_rest_resource_config', $rest_resource_config->id()); Chris@14: $parameters = $route->getOption('parameters') ?: []; Chris@14: $route->setOption('parameters', $parameters + [ Chris@14: '_rest_resource_config' => [ Chris@14: 'type' => 'entity:' . $rest_resource_config->getEntityTypeId(), Chris@14: ], Chris@14: ]); Chris@0: $collection->add("rest.$name", $route); Chris@0: } Chris@0: Chris@0: } Chris@0: return $collection; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public static function getSubscribedEvents() { Chris@0: $events[RoutingEvents::DYNAMIC] = 'onDynamicRouteEvent'; Chris@0: return $events; Chris@0: } Chris@0: Chris@0: }