Chris@0: resourceStorage = $entity_storage; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public static function create(ContainerInterface $container) { Chris@0: return new static($container->get('entity_type.manager')->getStorage('rest_resource_config')); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Handles a web API request. Chris@0: * Chris@0: * @param \Drupal\Core\Routing\RouteMatchInterface $route_match Chris@0: * The route match. Chris@0: * @param \Symfony\Component\HttpFoundation\Request $request Chris@0: * The HTTP request object. Chris@0: * Chris@0: * @return \Symfony\Component\HttpFoundation\Response Chris@0: * The response object. Chris@0: */ Chris@0: public function handle(RouteMatchInterface $route_match, Request $request) { Chris@0: // Symfony is built to transparently map HEAD requests to a GET request. In Chris@0: // the case of the REST module's RequestHandler though, we essentially have Chris@0: // our own light-weight routing system on top of the Drupal/symfony routing Chris@0: // system. So, we have to respect the decision that the routing system made: Chris@0: // we look not at the request method, but at the route's method. All REST Chris@0: // routes are guaranteed to have _method set. Chris@0: // Response::prepare() will transform it to a HEAD response at the very last Chris@0: // moment. Chris@0: // @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4 Chris@0: // @see \Symfony\Component\Routing\Matcher\UrlMatcher::matchCollection() Chris@0: // @see \Symfony\Component\HttpFoundation\Response::prepare() Chris@0: $method = strtolower($route_match->getRouteObject()->getMethods()[0]); Chris@0: assert(count($route_match->getRouteObject()->getMethods()) === 1); Chris@0: Chris@0: Chris@0: $resource_config_id = $route_match->getRouteObject()->getDefault('_rest_resource_config'); Chris@0: /** @var \Drupal\rest\RestResourceConfigInterface $resource_config */ Chris@0: $resource_config = $this->resourceStorage->load($resource_config_id); Chris@0: $resource = $resource_config->getResourcePlugin(); Chris@0: Chris@0: // Deserialize incoming data if available. Chris@0: /** @var \Symfony\Component\Serializer\SerializerInterface $serializer */ Chris@0: $serializer = $this->container->get('serializer'); Chris@0: $received = $request->getContent(); Chris@0: $unserialized = NULL; Chris@0: if (!empty($received)) { Chris@0: $format = $request->getContentType(); Chris@0: Chris@0: $definition = $resource->getPluginDefinition(); Chris@0: Chris@0: // First decode the request data. We can then determine if the Chris@0: // serialized data was malformed. Chris@0: try { Chris@0: $unserialized = $serializer->decode($received, $format, ['request_method' => $method]); Chris@0: } Chris@0: catch (UnexpectedValueException $e) { Chris@0: // If an exception was thrown at this stage, there was a problem Chris@0: // decoding the data. Throw a 400 http exception. Chris@0: throw new BadRequestHttpException($e->getMessage()); Chris@0: } Chris@0: Chris@0: // Then attempt to denormalize if there is a serialization class. Chris@0: if (!empty($definition['serialization_class'])) { Chris@0: try { Chris@0: $unserialized = $serializer->denormalize($unserialized, $definition['serialization_class'], $format, ['request_method' => $method]); Chris@0: } Chris@0: // These two serialization exception types mean there was a problem Chris@0: // with the structure of the decoded data and it's not valid. Chris@0: catch (UnexpectedValueException $e) { Chris@0: throw new UnprocessableEntityHttpException($e->getMessage()); Chris@0: } Chris@0: catch (InvalidArgumentException $e) { Chris@0: throw new UnprocessableEntityHttpException($e->getMessage()); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: // Determine the request parameters that should be passed to the resource Chris@0: // plugin. Chris@0: $route_parameters = $route_match->getParameters(); Chris@0: $parameters = []; Chris@0: // Filter out all internal parameters starting with "_". Chris@0: foreach ($route_parameters as $key => $parameter) { Chris@0: if ($key{0} !== '_') { Chris@0: $parameters[] = $parameter; Chris@0: } Chris@0: } Chris@0: Chris@0: // Invoke the operation on the resource plugin. Chris@0: $response = call_user_func_array([$resource, $method], array_merge($parameters, [$unserialized, $request])); Chris@0: Chris@0: if ($response instanceof CacheableResponseInterface) { Chris@0: // Add rest config's cache tags. Chris@0: $response->addCacheableDependency($resource_config); Chris@0: } Chris@0: Chris@0: return $response; Chris@0: } Chris@0: Chris@0: }