Update core 8.3.0
This commit is contained in:
parent
da7a7918f8
commit
cd7a898e66
6144 changed files with 132297 additions and 87747 deletions
|
|
@ -0,0 +1,204 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\rest\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Cache\CacheableResponse;
|
||||
use Drupal\Core\Cache\CacheableResponseInterface;
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\rest\ResourceResponseInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
/**
|
||||
* Response subscriber that serializes and removes ResourceResponses' data.
|
||||
*/
|
||||
class ResourceResponseSubscriber implements EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* The serializer.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\SerializerInterface
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* The renderer.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* The current route match.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteMatchInterface
|
||||
*/
|
||||
protected $routeMatch;
|
||||
|
||||
/**
|
||||
* Constructs a ResourceResponseSubscriber object.
|
||||
*
|
||||
* @param \Symfony\Component\Serializer\SerializerInterface $serializer
|
||||
* The serializer.
|
||||
* @param \Drupal\Core\Render\RendererInterface $renderer
|
||||
* The renderer.
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The current route match.
|
||||
*/
|
||||
public function __construct(SerializerInterface $serializer, RendererInterface $renderer, RouteMatchInterface $route_match) {
|
||||
$this->serializer = $serializer;
|
||||
$this->renderer = $renderer;
|
||||
$this->routeMatch = $route_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes ResourceResponse responses' data, and removes that data.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
|
||||
* The event to process.
|
||||
*/
|
||||
public function onResponse(FilterResponseEvent $event) {
|
||||
$response = $event->getResponse();
|
||||
if (!$response instanceof ResourceResponseInterface) {
|
||||
return;
|
||||
}
|
||||
|
||||
$request = $event->getRequest();
|
||||
$format = $this->getResponseFormat($this->routeMatch, $request);
|
||||
$this->renderResponseBody($request, $response, $this->serializer, $format);
|
||||
$event->setResponse($this->flattenResponse($response));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the format to respond in.
|
||||
*
|
||||
* Respects the requested format if one is specified. However, it is common to
|
||||
* forget to specify a request format in case of a POST or PATCH. Rather than
|
||||
* simply throwing an error, we apply the robustness principle: when POSTing
|
||||
* or PATCHing using a certain format, you probably expect a response in that
|
||||
* same format.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The current route match.
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
*
|
||||
* @return string
|
||||
* The response format.
|
||||
*/
|
||||
public function getResponseFormat(RouteMatchInterface $route_match, Request $request) {
|
||||
$route = $route_match->getRouteObject();
|
||||
$acceptable_request_formats = $route->hasRequirement('_format') ? explode('|', $route->getRequirement('_format')) : [];
|
||||
$acceptable_content_type_formats = $route->hasRequirement('_content_type_format') ? explode('|', $route->getRequirement('_content_type_format')) : [];
|
||||
$acceptable_formats = $request->isMethodSafe() ? $acceptable_request_formats : $acceptable_content_type_formats;
|
||||
|
||||
$requested_format = $request->getRequestFormat();
|
||||
$content_type_format = $request->getContentType();
|
||||
|
||||
// If an acceptable format is requested, then use that. Otherwise, including
|
||||
// and particularly when the client forgot to specify a format, then use
|
||||
// heuristics to select the format that is most likely expected.
|
||||
if (in_array($requested_format, $acceptable_formats)) {
|
||||
return $requested_format;
|
||||
}
|
||||
// If a request body is present, then use the format corresponding to the
|
||||
// request body's Content-Type for the response, if it's an acceptable
|
||||
// format for the request.
|
||||
elseif (!empty($request->getContent()) && in_array($content_type_format, $acceptable_content_type_formats)) {
|
||||
return $content_type_format;
|
||||
}
|
||||
// Otherwise, use the first acceptable format.
|
||||
elseif (!empty($acceptable_formats)) {
|
||||
return $acceptable_formats[0];
|
||||
}
|
||||
// Sometimes, there are no acceptable formats, e.g. DELETE routes.
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a resource response body.
|
||||
*
|
||||
* Serialization can invoke rendering (e.g., generating URLs), but the
|
||||
* serialization API does not provide a mechanism to collect the
|
||||
* bubbleable metadata associated with that (e.g., language and other
|
||||
* contexts), so instead, allow those to "leak" and collect them here in
|
||||
* a render context.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The request object.
|
||||
* @param \Drupal\rest\ResourceResponseInterface $response
|
||||
* The response from the REST resource.
|
||||
* @param \Symfony\Component\Serializer\SerializerInterface $serializer
|
||||
* The serializer to use.
|
||||
* @param string|null $format
|
||||
* The response format, or NULL in case the response does not need a format,
|
||||
* for example for the response to a DELETE request.
|
||||
*
|
||||
* @todo Add test coverage for language negotiation contexts in
|
||||
* https://www.drupal.org/node/2135829.
|
||||
*/
|
||||
protected function renderResponseBody(Request $request, ResourceResponseInterface $response, SerializerInterface $serializer, $format) {
|
||||
$data = $response->getResponseData();
|
||||
|
||||
// If there is data to send, serialize and set it as the response body.
|
||||
if ($data !== NULL) {
|
||||
$context = new RenderContext();
|
||||
$output = $this->renderer
|
||||
->executeInRenderContext($context, function () use ($serializer, $data, $format) {
|
||||
return $serializer->serialize($data, $format);
|
||||
});
|
||||
|
||||
if ($response instanceof CacheableResponseInterface && !$context->isEmpty()) {
|
||||
$response->addCacheableDependency($context->pop());
|
||||
}
|
||||
|
||||
$response->setContent($output);
|
||||
$response->headers->set('Content-Type', $request->getMimeType($format));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens a fully rendered resource response.
|
||||
*
|
||||
* Ensures that complex data structures in ResourceResponse::getResponseData()
|
||||
* are not serialized. Not doing this means that caching this response object
|
||||
* requires unserializing the PHP data when reading this response object from
|
||||
* cache, which can be very costly, and is unnecessary.
|
||||
*
|
||||
* @param \Drupal\rest\ResourceResponseInterface $response
|
||||
* A fully rendered resource response.
|
||||
*
|
||||
* @return \Drupal\Core\Cache\CacheableResponse|\Symfony\Component\HttpFoundation\Response
|
||||
* The flattened response.
|
||||
*/
|
||||
protected function flattenResponse(ResourceResponseInterface $response) {
|
||||
$final_response = ($response instanceof CacheableResponseInterface) ? new CacheableResponse() : new Response();
|
||||
$final_response->setContent($response->getContent());
|
||||
$final_response->setStatusCode($response->getStatusCode());
|
||||
$final_response->setProtocolVersion($response->getProtocolVersion());
|
||||
$final_response->setCharset($response->getCharset());
|
||||
$final_response->headers = clone $response->headers;
|
||||
if ($final_response instanceof CacheableResponseInterface) {
|
||||
$final_response->addCacheableDependency($response->getCacheableMetadata());
|
||||
}
|
||||
return $final_response;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
// Run shortly before \Drupal\Core\EventSubscriber\FinishResponseSubscriber.
|
||||
$events[KernelEvents::RESPONSE][] = ['onResponse', 5];
|
||||
return $events;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\rest\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Config\ConfigCrudEvent;
|
||||
use Drupal\Core\Config\ConfigEvents;
|
||||
use Drupal\Core\Routing\RouteBuilderInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
/**
|
||||
* A subscriber triggering a route rebuild when certain configuration changes.
|
||||
*/
|
||||
class RestConfigSubscriber implements EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* The router builder.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteBuilderInterface
|
||||
*/
|
||||
protected $routerBuilder;
|
||||
|
||||
/**
|
||||
* Constructs the RestConfigSubscriber.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
|
||||
* The router builder service.
|
||||
*/
|
||||
public function __construct(RouteBuilderInterface $router_builder) {
|
||||
$this->routerBuilder = $router_builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs the router builder a rebuild is needed when necessary.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigCrudEvent $event
|
||||
* The Event to process.
|
||||
*/
|
||||
public function onSave(ConfigCrudEvent $event) {
|
||||
$saved_config = $event->getConfig();
|
||||
if ($saved_config->getName() === 'rest.settings' && $event->isChanged('bc_entity_resource_permissions')) {
|
||||
$this->routerBuilder->setRebuildNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
$events[ConfigEvents::SAVE][] = ['onSave'];
|
||||
return $events;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in a new issue