Mercurial > hg > isophonics-drupal-site
comparison core/modules/rest/src/RequestHandler.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 7a779792577d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\rest; | |
4 | |
5 use Drupal\Core\Cache\CacheableResponseInterface; | |
6 use Drupal\Core\DependencyInjection\ContainerInjectionInterface; | |
7 use Drupal\Core\Entity\EntityStorageInterface; | |
8 use Drupal\Core\Routing\RouteMatchInterface; | |
9 use Symfony\Component\DependencyInjection\ContainerAwareInterface; | |
10 use Symfony\Component\DependencyInjection\ContainerAwareTrait; | |
11 use Symfony\Component\DependencyInjection\ContainerInterface; | |
12 use Symfony\Component\HttpFoundation\Request; | |
13 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; | |
14 use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException; | |
15 use Symfony\Component\Serializer\Exception\UnexpectedValueException; | |
16 use Symfony\Component\Serializer\Exception\InvalidArgumentException; | |
17 | |
18 /** | |
19 * Acts as intermediate request forwarder for resource plugins. | |
20 * | |
21 * @see \Drupal\rest\EventSubscriber\ResourceResponseSubscriber | |
22 */ | |
23 class RequestHandler implements ContainerAwareInterface, ContainerInjectionInterface { | |
24 | |
25 use ContainerAwareTrait; | |
26 | |
27 /** | |
28 * The resource configuration storage. | |
29 * | |
30 * @var \Drupal\Core\Entity\EntityStorageInterface | |
31 */ | |
32 protected $resourceStorage; | |
33 | |
34 /** | |
35 * Creates a new RequestHandler instance. | |
36 * | |
37 * @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage | |
38 * The resource configuration storage. | |
39 */ | |
40 public function __construct(EntityStorageInterface $entity_storage) { | |
41 $this->resourceStorage = $entity_storage; | |
42 } | |
43 | |
44 /** | |
45 * {@inheritdoc} | |
46 */ | |
47 public static function create(ContainerInterface $container) { | |
48 return new static($container->get('entity_type.manager')->getStorage('rest_resource_config')); | |
49 } | |
50 | |
51 /** | |
52 * Handles a web API request. | |
53 * | |
54 * @param \Drupal\Core\Routing\RouteMatchInterface $route_match | |
55 * The route match. | |
56 * @param \Symfony\Component\HttpFoundation\Request $request | |
57 * The HTTP request object. | |
58 * | |
59 * @return \Symfony\Component\HttpFoundation\Response | |
60 * The response object. | |
61 */ | |
62 public function handle(RouteMatchInterface $route_match, Request $request) { | |
63 // Symfony is built to transparently map HEAD requests to a GET request. In | |
64 // the case of the REST module's RequestHandler though, we essentially have | |
65 // our own light-weight routing system on top of the Drupal/symfony routing | |
66 // system. So, we have to respect the decision that the routing system made: | |
67 // we look not at the request method, but at the route's method. All REST | |
68 // routes are guaranteed to have _method set. | |
69 // Response::prepare() will transform it to a HEAD response at the very last | |
70 // moment. | |
71 // @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4 | |
72 // @see \Symfony\Component\Routing\Matcher\UrlMatcher::matchCollection() | |
73 // @see \Symfony\Component\HttpFoundation\Response::prepare() | |
74 $method = strtolower($route_match->getRouteObject()->getMethods()[0]); | |
75 assert(count($route_match->getRouteObject()->getMethods()) === 1); | |
76 | |
77 | |
78 $resource_config_id = $route_match->getRouteObject()->getDefault('_rest_resource_config'); | |
79 /** @var \Drupal\rest\RestResourceConfigInterface $resource_config */ | |
80 $resource_config = $this->resourceStorage->load($resource_config_id); | |
81 $resource = $resource_config->getResourcePlugin(); | |
82 | |
83 // Deserialize incoming data if available. | |
84 /** @var \Symfony\Component\Serializer\SerializerInterface $serializer */ | |
85 $serializer = $this->container->get('serializer'); | |
86 $received = $request->getContent(); | |
87 $unserialized = NULL; | |
88 if (!empty($received)) { | |
89 $format = $request->getContentType(); | |
90 | |
91 $definition = $resource->getPluginDefinition(); | |
92 | |
93 // First decode the request data. We can then determine if the | |
94 // serialized data was malformed. | |
95 try { | |
96 $unserialized = $serializer->decode($received, $format, ['request_method' => $method]); | |
97 } | |
98 catch (UnexpectedValueException $e) { | |
99 // If an exception was thrown at this stage, there was a problem | |
100 // decoding the data. Throw a 400 http exception. | |
101 throw new BadRequestHttpException($e->getMessage()); | |
102 } | |
103 | |
104 // Then attempt to denormalize if there is a serialization class. | |
105 if (!empty($definition['serialization_class'])) { | |
106 try { | |
107 $unserialized = $serializer->denormalize($unserialized, $definition['serialization_class'], $format, ['request_method' => $method]); | |
108 } | |
109 // These two serialization exception types mean there was a problem | |
110 // with the structure of the decoded data and it's not valid. | |
111 catch (UnexpectedValueException $e) { | |
112 throw new UnprocessableEntityHttpException($e->getMessage()); | |
113 } | |
114 catch (InvalidArgumentException $e) { | |
115 throw new UnprocessableEntityHttpException($e->getMessage()); | |
116 } | |
117 } | |
118 } | |
119 | |
120 // Determine the request parameters that should be passed to the resource | |
121 // plugin. | |
122 $route_parameters = $route_match->getParameters(); | |
123 $parameters = []; | |
124 // Filter out all internal parameters starting with "_". | |
125 foreach ($route_parameters as $key => $parameter) { | |
126 if ($key{0} !== '_') { | |
127 $parameters[] = $parameter; | |
128 } | |
129 } | |
130 | |
131 // Invoke the operation on the resource plugin. | |
132 $response = call_user_func_array([$resource, $method], array_merge($parameters, [$unserialized, $request])); | |
133 | |
134 if ($response instanceof CacheableResponseInterface) { | |
135 // Add rest config's cache tags. | |
136 $response->addCacheableDependency($resource_config); | |
137 } | |
138 | |
139 return $response; | |
140 } | |
141 | |
142 } |