Upgraded drupal core with security updates
[yaffs-website] / web / core / modules / rest / src / Routing / ResourceRoutes.php
1 <?php
2
3 namespace Drupal\rest\Routing;
4
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;
11
12 /**
13  * Subscriber for REST-style routes.
14  */
15 class ResourceRoutes extends RouteSubscriberBase {
16
17   /**
18    * The plugin manager for REST plugins.
19    *
20    * @var \Drupal\rest\Plugin\Type\ResourcePluginManager
21    */
22   protected $manager;
23
24   /**
25    * The REST resource config storage.
26    *
27    * @var \Drupal\Core\Entity\EntityManagerInterface
28    */
29   protected $resourceConfigStorage;
30
31   /**
32    * A logger instance.
33    *
34    * @var \Psr\Log\LoggerInterface
35    */
36   protected $logger;
37
38   /**
39    * Constructs a RouteSubscriber object.
40    *
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
46    *   A logger instance.
47    */
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;
52   }
53
54   /**
55    * Alters existing routes for a specific collection.
56    *
57    * @param \Symfony\Component\Routing\RouteCollection $collection
58    *   The route collection for adding routes.
59    * @return array
60    */
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);
69       }
70     }
71   }
72
73   /**
74    * Provides all routes for a given REST resource config.
75    *
76    * This method determines where a resource is reachable, what path
77    * replacements are used, the required HTTP method for the operation etc.
78    *
79    * @param \Drupal\rest\RestResourceConfigInterface $rest_resource_config
80    *   The rest resource config.
81    *
82    * @return \Symfony\Component\Routing\RouteCollection
83    *   The route collection.
84    */
85   protected function getRoutesForResourceConfig(RestResourceConfigInterface $rest_resource_config) {
86     $plugin = $rest_resource_config->getResourcePlugin();
87     $collection = new RouteCollection();
88
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');
96
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()]);
100           continue;
101         }
102
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()]);
106           continue;
107         }
108
109         // If the route has a format requirement, then verify that the
110         // resource has it.
111         $format_requirement = $route->getRequirement('_format');
112         if ($format_requirement && !in_array($format_requirement, $rest_resource_config->getFormats($method))) {
113           continue;
114         }
115
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
122           // formats.
123           $route->addRequirements(['_content_type_format' => implode('|', $rest_resource_config->getFormats($method))]);
124         }
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);
128       }
129
130     }
131     return $collection;
132   }
133
134 }