3 namespace Drupal\rest\Routing;
5 use Drupal\Core\Entity\EntityTypeManagerInterface;
6 use Drupal\Core\Routing\RouteSubscriberBase;
7 use Drupal\rest\Plugin\Type\ResourcePluginManager;
8 use Drupal\rest\RestResourceConfigInterface;
9 use Psr\Log\LoggerInterface;
10 use Symfony\Component\Routing\RouteCollection;
13 * Subscriber for REST-style routes.
15 class ResourceRoutes extends RouteSubscriberBase {
18 * The plugin manager for REST plugins.
20 * @var \Drupal\rest\Plugin\Type\ResourcePluginManager
25 * The REST resource config storage.
27 * @var \Drupal\Core\Entity\EntityManagerInterface
29 protected $resourceConfigStorage;
34 * @var \Psr\Log\LoggerInterface
39 * Constructs a RouteSubscriber object.
41 * @param \Drupal\rest\Plugin\Type\ResourcePluginManager $manager
42 * The resource plugin manager.
43 * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
44 * The entity type manager
45 * @param \Psr\Log\LoggerInterface $logger
48 public function __construct(ResourcePluginManager $manager, EntityTypeManagerInterface $entity_type_manager, LoggerInterface $logger) {
49 $this->manager = $manager;
50 $this->resourceConfigStorage = $entity_type_manager->getStorage('rest_resource_config');
51 $this->logger = $logger;
55 * Alters existing routes for a specific collection.
57 * @param \Symfony\Component\Routing\RouteCollection $collection
58 * The route collection for adding routes.
61 protected function alterRoutes(RouteCollection $collection) {
62 // Iterate over all enabled REST resource config entities.
63 /** @var \Drupal\rest\RestResourceConfigInterface[] $resource_configs */
64 $resource_configs = $this->resourceConfigStorage->loadMultiple();
65 foreach ($resource_configs as $resource_config) {
66 if ($resource_config->status()) {
67 $resource_routes = $this->getRoutesForResourceConfig($resource_config);
68 $collection->addCollection($resource_routes);
74 * Provides all routes for a given REST resource config.
76 * This method determines where a resource is reachable, what path
77 * replacements are used, the required HTTP method for the operation etc.
79 * @param \Drupal\rest\RestResourceConfigInterface $rest_resource_config
80 * The rest resource config.
82 * @return \Symfony\Component\Routing\RouteCollection
83 * The route collection.
85 protected function getRoutesForResourceConfig(RestResourceConfigInterface $rest_resource_config) {
86 $plugin = $rest_resource_config->getResourcePlugin();
87 $collection = new RouteCollection();
89 foreach ($plugin->routes() as $name => $route) {
90 /** @var \Symfony\Component\Routing\Route $route */
91 // @todo: Are multiple methods possible here?
92 $methods = $route->getMethods();
93 // Only expose routes where the method is enabled in the configuration.
94 if ($methods && ($method = $methods[0]) && $supported_formats = $rest_resource_config->getFormats($method)) {
95 $route->setRequirement('_csrf_request_header_token', 'TRUE');
97 // Check that authentication providers are defined.
98 if (empty($rest_resource_config->getAuthenticationProviders($method))) {
99 $this->logger->error('At least one authentication provider must be defined for resource @id', [':id' => $rest_resource_config->id()]);
103 // Check that formats are defined.
104 if (empty($rest_resource_config->getFormats($method))) {
105 $this->logger->error('At least one format must be defined for resource @id', [':id' => $rest_resource_config->id()]);
109 // If the route has a format requirement, then verify that the
111 $format_requirement = $route->getRequirement('_format');
112 if ($format_requirement && !in_array($format_requirement, $rest_resource_config->getFormats($method))) {
116 // The configuration has been validated, so we update the route to:
117 // - set the allowed request body content types/formats for methods that
118 // allow request bodies to be sent
119 // - set the allowed authentication providers
120 if (in_array($method, ['POST', 'PATCH', 'PUT'], TRUE)) {
121 // Restrict the incoming HTTP Content-type header to the allowed
123 $route->addRequirements(['_content_type_format' => implode('|', $rest_resource_config->getFormats($method))]);
125 $route->setOption('_auth', $rest_resource_config->getAuthenticationProviders($method));
126 $route->setDefault('_rest_resource_config', $rest_resource_config->id());
127 $collection->add("rest.$name", $route);