diff --git a/core/modules/rest/src/NonCacheableResourceResponse.php b/core/modules/rest/src/NonCacheableResourceResponse.php new file mode 100644 index 0000000..e577718 --- /dev/null +++ b/core/modules/rest/src/NonCacheableResourceResponse.php @@ -0,0 +1,30 @@ +responseData = $data; + parent::__construct('', $status, $headers); + } +} diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php index a830d97..f31caa7 100644 --- a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php +++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php @@ -11,6 +11,7 @@ use Drupal\Core\Entity\EntityStorageException; use Drupal\rest\Plugin\ResourceBase; use Drupal\rest\ResourceResponse; +use Drupal\rest\NonCacheableResourceResponse; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\HttpException; @@ -39,7 +40,7 @@ class EntityResource extends ResourceBase { * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object. * - * @return \Drupal\rest\ResourceResponse + * @return \Drupal\rest\NonCacheableResourceResponse * The response containing the entity with its accessible fields. * * @throws \Symfony\Component\HttpKernel\Exception\HttpException @@ -115,9 +116,7 @@ public function post(EntityInterface $entity = NULL) { // 201 Created responses return the newly created entity in the response // body. $url = $entity->urlInfo('canonical', ['absolute' => TRUE])->toString(TRUE); - $response = new ResourceResponse($entity, 201, ['Location' => $url->getGeneratedUrl()]); - // Responses after creating an entity are not cacheable, so we add no - // cacheability metadata here. + $response = new NonCacheableResourceResponse($entity, 201, ['Location' => $url->getGeneratedUrl()]); return $response; } catch (EntityStorageException $e) { @@ -173,7 +172,7 @@ public function patch(EntityInterface $original_entity, EntityInterface $entity $this->logger->notice('Updated entity %type with ID %id.', array('%type' => $original_entity->getEntityTypeId(), '%id' => $original_entity->id())); // Update responses have an empty body. - return new ResourceResponse(NULL, 204); + return new NonCacheableResourceResponse(NULL, 204); } catch (EntityStorageException $e) { throw new HttpException(500, 'Internal Server Error', $e); @@ -200,7 +199,7 @@ public function delete(EntityInterface $entity) { $this->logger->notice('Deleted entity %type with ID %id.', array('%type' => $entity->getEntityTypeId(), '%id' => $entity->id())); // Delete responses have an empty body. - return new ResourceResponse(NULL, 204); + return new NonCacheableResourceResponse(NULL, 204); } catch (EntityStorageException $e) { throw new HttpException(500, 'Internal Server Error', $e); diff --git a/core/modules/rest/src/RequestHandler.php b/core/modules/rest/src/RequestHandler.php index d6b3dcf..27deab8 100644 --- a/core/modules/rest/src/RequestHandler.php +++ b/core/modules/rest/src/RequestHandler.php @@ -8,6 +8,7 @@ namespace Drupal\rest; use Drupal\Core\Render\RenderContext; +use Drupal\Core\Cache\CacheableResponseInterface; use Drupal\Core\Routing\RouteMatchInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerAwareTrait; @@ -102,27 +103,36 @@ public function handle(RouteMatchInterface $route_match, Request $request) { return new Response($content, $e->getStatusCode(), $headers); } - if ($response instanceof ResourceResponse) { + if ($response instanceof ResourceResponseInterface) { $data = $response->getResponseData(); - // 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. - // @todo Add test coverage for language negotiation contexts in - // https://www.drupal.org/node/2135829. - $context = new RenderContext(); - $output = $this->container->get('renderer')->executeInRenderContext($context, function() use ($serializer, $data, $format) { - return $serializer->serialize($data, $format); - }); - $response->setContent($output); - if (!$context->isEmpty()) { - $response->addCacheableDependency($context->pop()); - } + // Cacheable Response. + if ($response instanceof CacheableResponseInterface) { + // 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. + // @todo Add test coverage for language negotiation contexts in + // https://www.drupal.org/node/2135829. + $context = new RenderContext(); + $output = $this->container->get('renderer')->executeInRenderContext($context, function () use ($serializer, $data, $format) { + return $serializer->serialize($data, $format); + }); + $response->setContent($output); + if (!$context->isEmpty()) { + $response->addCacheableDependency($context->pop()); + } - $response->headers->set('Content-Type', $request->getMimeType($format)); - // Add rest settings config's cache tags. - $response->addCacheableDependency($this->container->get('config.factory')->get('rest.settings')); + $response->headers->set('Content-Type', $request->getMimeType($format)); + // Add rest settings config's cache tags. + $response->addCacheableDependency($this->container->get('config.factory')->get('rest.settings')); + } + else { + // Non-Cacheable Response. + $output = $serializer->serialize($data, $format); + $response->setContent($output); + $response->headers->set('Content-Type', $request->getMimeType($format)); + } } return $response; } diff --git a/core/modules/rest/src/ResourceResponse.php b/core/modules/rest/src/ResourceResponse.php index 2919fb1..045446e 100644 --- a/core/modules/rest/src/ResourceResponse.php +++ b/core/modules/rest/src/ResourceResponse.php @@ -19,16 +19,10 @@ * string or an object with a __toString() method, which is not a requirement * for data used here. */ -class ResourceResponse extends Response implements CacheableResponseInterface { +class ResourceResponse extends Response implements CacheableResponseInterface, ResourceResponseInterface { use CacheableResponseTrait; - - /** - * Response data that should be serialized. - * - * @var mixed - */ - protected $responseData; + use ResourceResponseTrait; /** * Constructor for ResourceResponse objects. @@ -45,13 +39,4 @@ public function __construct($data = NULL, $status = 200, $headers = array()) { parent::__construct('', $status, $headers); } - /** - * Returns response data that should be serialized. - * - * @return mixed - * Response data that should be serialized. - */ - public function getResponseData() { - return $this->responseData; - } } diff --git a/core/modules/rest/src/ResourceResponseInterface.php b/core/modules/rest/src/ResourceResponseInterface.php new file mode 100644 index 0000000..a889dae --- /dev/null +++ b/core/modules/rest/src/ResourceResponseInterface.php @@ -0,0 +1,23 @@ +responseData; + } + +}