Issue #2910211 by tedbow, Wim Leers: Allow computed exposed properties in ComplexData to support cacheability
parent
33818be2d8
commit
52a598e2bf
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\Tests\hal\Functional\EntityResource\EntityTest;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
|
||||
|
@ -82,4 +83,18 @@ class EntityTestHalJsonInternalPropertyNormalizerTest extends EntityTestHalJsonA
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return Cache::mergeContexts(parent::getExpectedCacheContexts(), ['request_format']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheTags() {
|
||||
return Cache::mergeTags(parent::getExpectedCacheTags(), ['you_are_it', 'no_tag_backs']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\rest\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Cache\CacheableResponse;
|
||||
use Drupal\Core\Cache\CacheableResponseInterface;
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
|
@ -20,6 +21,15 @@ use Symfony\Component\Serializer\SerializerInterface;
|
|||
*/
|
||||
class ResourceResponseSubscriber implements EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* Name of key for bubbling cacheability metadata via serialization context.
|
||||
*
|
||||
* @see \Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize()
|
||||
* @see \Symfony\Component\Serializer\SerializerInterface::serialize()
|
||||
* @see \Drupal\rest\EventSubscriber\ResourceResponseSubscriber::renderResponseBody()
|
||||
*/
|
||||
const SERIALIZATION_CONTEXT_CACHEABILITY = 'cacheability';
|
||||
|
||||
/**
|
||||
* The serializer.
|
||||
*
|
||||
|
@ -128,11 +138,19 @@ class ResourceResponseSubscriber implements EventSubscriberInterface {
|
|||
/**
|
||||
* 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.
|
||||
* During serialization, encoders and normalizers are able to explicitly
|
||||
* bubble cacheability metadata via the 'cacheability' key-value pair in the
|
||||
* received context. This bubbled cacheability metadata will be applied to the
|
||||
* the response.
|
||||
*
|
||||
* In versions of Drupal prior to 8.5, implicit bubbling of cacheability
|
||||
* metadata was allowed because there was no explicit cacheability metadata
|
||||
* bubbling API. To maintain backwards compatibility, we continue to support
|
||||
* this, but support for this will be dropped in Drupal 9.0.0. This is
|
||||
* especially useful when interacting with APIs that implicitly invoke
|
||||
* rendering (for example: generating URLs): this allows those to "leak", and
|
||||
* we collect their bubbled cacheability metadata automatically in a render
|
||||
* context.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The request object.
|
||||
|
@ -152,14 +170,25 @@ class ResourceResponseSubscriber implements EventSubscriberInterface {
|
|||
|
||||
// If there is data to send, serialize and set it as the response body.
|
||||
if ($data !== NULL) {
|
||||
$serialization_context = [
|
||||
'request' => $request,
|
||||
static::SERIALIZATION_CONTEXT_CACHEABILITY => new CacheableMetadata(),
|
||||
];
|
||||
|
||||
// @deprecated In Drupal 8.5.0, will be removed before Drupal 9.0.0. Use
|
||||
// explicit cacheability metadata bubbling instead. (The wrapping call to
|
||||
// executeInRenderContext() will be removed before Drupal 9.0.0.)
|
||||
$context = new RenderContext();
|
||||
$output = $this->renderer
|
||||
->executeInRenderContext($context, function () use ($serializer, $data, $format) {
|
||||
return $serializer->serialize($data, $format);
|
||||
->executeInRenderContext($context, function () use ($serializer, $data, $format, $serialization_context) {
|
||||
return $serializer->serialize($data, $format, $serialization_context);
|
||||
});
|
||||
|
||||
if ($response instanceof CacheableResponseInterface && !$context->isEmpty()) {
|
||||
$response->addCacheableDependency($context->pop());
|
||||
if ($response instanceof CacheableResponseInterface) {
|
||||
if (!$context->isEmpty()) {
|
||||
@trigger_error('Implicit cacheability metadata bubbling (onto the global render context) in normalizers is deprecated since Drupal 8.5.0 and will be removed in Drupal 9.0.0. Use the "cacheability" serialization context instead, for explicit cacheability metadata bubbling. See https://www.drupal.org/node/2918937', E_USER_DEPRECATED);
|
||||
$response->addCacheableDependency($context->pop());
|
||||
}
|
||||
$response->addCacheableDependency($serialization_context[static::SERIALIZATION_CONTEXT_CACHEABILITY]);
|
||||
}
|
||||
|
||||
$response->setContent($output);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTest;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
@ -84,4 +85,18 @@ class EntityTestJsonInternalPropertyNormalizerTest extends EntityTestResourceTes
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return Cache::mergeContexts(parent::getExpectedCacheContexts(), ['request_format']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheTags() {
|
||||
return Cache::mergeTags(parent::getExpectedCacheTags(), ['you_are_it', 'no_tag_backs']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\rest\EventSubscriber\ResourceResponseSubscriber;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\SerializerAwareNormalizer;
|
||||
|
||||
|
@ -81,4 +83,18 @@ abstract class NormalizerBase extends SerializerAwareNormalizer implements Norma
|
|||
return in_array($format, (array) $this->format, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds cacheability if applicable.
|
||||
*
|
||||
* @param array $context
|
||||
* Context options for the normalizer.
|
||||
* @param $data
|
||||
* The data that might have cacheability information.
|
||||
*/
|
||||
protected function addCacheableDependency(array $context, $data) {
|
||||
if ($data instanceof CacheableDependencyInterface && isset($context[ResourceResponseSubscriber::SERIALIZATION_CONTEXT_CACHEABILITY])) {
|
||||
$context[ResourceResponseSubscriber::SERIALIZATION_CONTEXT_CACHEABILITY]->addCacheableDependency($data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ class TypedDataNormalizer extends NormalizerBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
$this->addCacheableDependency($context, $object);
|
||||
return $object->getValue();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
namespace Drupal\entity_test\TypedData;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\TypedData\TypedData;
|
||||
|
||||
/**
|
||||
* A computed property for test strings.
|
||||
*/
|
||||
class ComputedString extends TypedData {
|
||||
class ComputedString extends TypedData implements CacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -27,4 +29,25 @@ class ComputedString extends TypedData {
|
|||
return $this->getString();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return ['you_are_it', 'no_tag_backs'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return ['request_format'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue