comparison core/modules/rest/src/Routing/ResourceRoutes.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 1fec387a4317
comparison
equal deleted inserted replaced
-1:000000000000 0:4c8ae668cc8c
1 <?php
2
3 namespace Drupal\rest\Routing;
4
5 use Drupal\Core\Entity\EntityTypeManagerInterface;
6 use Drupal\Core\Routing\RouteBuildEvent;
7 use Drupal\Core\Routing\RoutingEvents;
8 use Drupal\rest\Plugin\Type\ResourcePluginManager;
9 use Drupal\rest\RestResourceConfigInterface;
10 use Psr\Log\LoggerInterface;
11 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
12 use Symfony\Component\Routing\RouteCollection;
13
14 /**
15 * Subscriber for REST-style routes.
16 */
17 class ResourceRoutes implements EventSubscriberInterface {
18
19 /**
20 * The plugin manager for REST plugins.
21 *
22 * @var \Drupal\rest\Plugin\Type\ResourcePluginManager
23 */
24 protected $manager;
25
26 /**
27 * The REST resource config storage.
28 *
29 * @var \Drupal\Core\Entity\EntityManagerInterface
30 */
31 protected $resourceConfigStorage;
32
33 /**
34 * A logger instance.
35 *
36 * @var \Psr\Log\LoggerInterface
37 */
38 protected $logger;
39
40 /**
41 * Constructs a RouteSubscriber object.
42 *
43 * @param \Drupal\rest\Plugin\Type\ResourcePluginManager $manager
44 * The resource plugin manager.
45 * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
46 * The entity type manager
47 * @param \Psr\Log\LoggerInterface $logger
48 * A logger instance.
49 */
50 public function __construct(ResourcePluginManager $manager, EntityTypeManagerInterface $entity_type_manager, LoggerInterface $logger) {
51 $this->manager = $manager;
52 $this->resourceConfigStorage = $entity_type_manager->getStorage('rest_resource_config');
53 $this->logger = $logger;
54 }
55
56 /**
57 * Alters existing routes for a specific collection.
58 *
59 * @param \Drupal\Core\Routing\RouteBuildEvent $event
60 * The route build event.
61 * @return array
62 */
63 public function onDynamicRouteEvent(RouteBuildEvent $event) {
64 // Iterate over all enabled REST resource config entities.
65 /** @var \Drupal\rest\RestResourceConfigInterface[] $resource_configs */
66 $resource_configs = $this->resourceConfigStorage->loadMultiple();
67 foreach ($resource_configs as $resource_config) {
68 if ($resource_config->status()) {
69 $resource_routes = $this->getRoutesForResourceConfig($resource_config);
70 $event->getRouteCollection()->addCollection($resource_routes);
71 }
72 }
73 }
74
75 /**
76 * Provides all routes for a given REST resource config.
77 *
78 * This method determines where a resource is reachable, what path
79 * replacements are used, the required HTTP method for the operation etc.
80 *
81 * @param \Drupal\rest\RestResourceConfigInterface $rest_resource_config
82 * The rest resource config.
83 *
84 * @return \Symfony\Component\Routing\RouteCollection
85 * The route collection.
86 */
87 protected function getRoutesForResourceConfig(RestResourceConfigInterface $rest_resource_config) {
88 $plugin = $rest_resource_config->getResourcePlugin();
89 $collection = new RouteCollection();
90
91 foreach ($plugin->routes() as $name => $route) {
92 /** @var \Symfony\Component\Routing\Route $route */
93 // @todo: Are multiple methods possible here?
94 $methods = $route->getMethods();
95 // Only expose routes where the method is enabled in the configuration.
96 if ($methods && ($method = $methods[0]) && $supported_formats = $rest_resource_config->getFormats($method)) {
97 $route->setRequirement('_csrf_request_header_token', 'TRUE');
98
99 // Check that authentication providers are defined.
100 if (empty($rest_resource_config->getAuthenticationProviders($method))) {
101 $this->logger->error('At least one authentication provider must be defined for resource @id', [':id' => $rest_resource_config->id()]);
102 continue;
103 }
104
105 // Check that formats are defined.
106 if (empty($rest_resource_config->getFormats($method))) {
107 $this->logger->error('At least one format must be defined for resource @id', [':id' => $rest_resource_config->id()]);
108 continue;
109 }
110
111 // If the route has a format requirement, then verify that the
112 // resource has it.
113 $format_requirement = $route->getRequirement('_format');
114 if ($format_requirement && !in_array($format_requirement, $rest_resource_config->getFormats($method))) {
115 continue;
116 }
117
118 // The configuration has been validated, so we update the route to:
119 // - set the allowed request body content types/formats for methods that
120 // allow request bodies to be sent
121 // - set the allowed authentication providers
122 if (in_array($method, ['POST', 'PATCH', 'PUT'], TRUE)) {
123 // Restrict the incoming HTTP Content-type header to the allowed
124 // formats.
125 $route->addRequirements(['_content_type_format' => implode('|', $rest_resource_config->getFormats($method))]);
126 }
127 $route->setOption('_auth', $rest_resource_config->getAuthenticationProviders($method));
128 $route->setDefault('_rest_resource_config', $rest_resource_config->id());
129 $collection->add("rest.$name", $route);
130 }
131
132 }
133 return $collection;
134 }
135
136 /**
137 * {@inheritdoc}
138 */
139 public static function getSubscribedEvents() {
140 $events[RoutingEvents::DYNAMIC] = 'onDynamicRouteEvent';
141 return $events;
142 }
143
144 }