Commit fde6ee35 authored by catch's avatar catch
Browse files

Issue #3379984 by kristiaanvandeneynde, bbrala, quietone: Refactor...

Issue #3379984 by kristiaanvandeneynde, bbrala, quietone: Refactor ResourceObjectNormalizationCacher to use VariationCache
parent 13dbb104
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -50,7 +50,8 @@ services:
  jsonapi.normalization_cacher:
    class: Drupal\jsonapi\EventSubscriber\ResourceObjectNormalizationCacher
    calls:
      - ['setRenderCache', ['@render_cache']]
      - ['setVariationCache', ['@variation_cache.jsonapi_normalizations']]
      - ['setRequestStack', ['@request_stack']]
    tags:
      - { name: event_subscriber }
  serializer.normalizer.content_entity.jsonapi:
@@ -144,6 +145,10 @@ services:
      - { name: cache.bin }
    factory: ['@cache_factory', 'get']
    arguments: [jsonapi_normalizations]
  variation_cache.jsonapi_normalizations:
    class: Drupal\Core\Cache\VariationCacheInterface
    factory: ['@variation_cache_factory', 'get']
    arguments: [jsonapi_normalizations]

  # Route filter.
  jsonapi.route_filter.format_setter:
+50 −43
Original line number Diff line number Diff line
@@ -3,9 +3,10 @@
namespace Drupal\jsonapi\EventSubscriber;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Render\RenderCacheInterface;
use Drupal\Core\Cache\VariationCacheInterface;
use Drupal\jsonapi\JsonApiResource\ResourceObject;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
use Symfony\Component\HttpKernel\KernelEvents;

@@ -14,7 +15,6 @@
 *
 * @internal
 * @see \Drupal\jsonapi\Normalizer\ResourceObjectNormalizer::getNormalization()
 * @todo Refactor once https://www.drupal.org/node/2551419 lands.
 */
class ResourceObjectNormalizationCacher implements EventSubscriberInterface {

@@ -40,11 +40,18 @@ class ResourceObjectNormalizationCacher implements EventSubscriberInterface {
  const RESOURCE_CACHE_SUBSET_FIELDS = 'fields';

  /**
   * The render cache.
   * The variation cache.
   *
   * @var \Drupal\Core\Render\RenderCacheInterface
   * @var \Drupal\Core\Cache\VariationCacheInterface
   */
  protected $renderCache;
  protected $variationCache;

  /**
   * The request stack.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;

  /**
   * The things to cache after the response has been sent.
@@ -54,13 +61,23 @@ class ResourceObjectNormalizationCacher implements EventSubscriberInterface {
  protected $toCache = [];

  /**
   * Sets the render cache service.
   * Sets the variation cache.
   *
   * @param \Drupal\Core\Cache\VariationCacheInterface $variation_cache
   *   The variation cache.
   */
  public function setVariationCache(VariationCacheInterface $variation_cache) {
    $this->variationCache = $variation_cache;
  }

  /**
   * Sets the request stack.
   *
   * @param \Drupal\Core\Render\RenderCacheInterface $render_cache
   *   The render cache.
   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
   *   The request stack.
   */
  public function setRenderCache(RenderCacheInterface $render_cache) {
    $this->renderCache = $render_cache;
  public function setRequestStack(RequestStack $request_stack) {
    $this->requestStack = $request_stack;
  }

  /**
@@ -78,8 +95,14 @@ public function setRenderCache(RenderCacheInterface $render_cache) {
   * @see \Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber::renderArrayToResponse()
   */
  public function get(ResourceObject $object) {
    $cached = $this->renderCache->get(static::generateLookupRenderArray($object));
    return $cached ? $cached['#data'] : FALSE;
    // @todo Investigate whether to cache POST and PATCH requests.
    // @todo Follow up on https://www.drupal.org/project/drupal/issues/3381898.
    if (!$this->requestStack->getCurrentRequest()->isMethodCacheable()) {
      return FALSE;
    }

    $cached = $this->variationCache->get($this->generateCacheKeys($object), new CacheableMetadata());
    return $cached ? $cached->data : FALSE;
  }

  /**
@@ -122,52 +145,36 @@ public function onTerminate(TerminateEvent $event) {
   *   The resource object for which to generate a cache item.
   * @param array $normalization_parts
   *   The normalization parts to cache.
   *
   * @see \Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber::responseToRenderArray()
   * @todo Refactor/remove once https://www.drupal.org/node/2551419 lands.
   */
  protected function set(ResourceObject $object, array $normalization_parts) {
    $base = static::generateLookupRenderArray($object);
    $data_as_render_array = $base + [
      // The data we actually care about.
      '#data' => $normalization_parts,
      // Tell RenderCache to cache the #data property: the data we actually care
      // about.
      '#cache_properties' => ['#data'],
      // These exist only to fulfill the requirements of the RenderCache, which
      // is designed to work with render arrays only. We don't care about these.
      '#markup' => '',
      '#attached' => '',
    ];
    // @todo Investigate whether to cache POST and PATCH requests.
    // @todo Follow up on https://www.drupal.org/project/drupal/issues/3381898.
    if (!$this->requestStack->getCurrentRequest()->isMethodCacheable()) {
      return;
    }

    // Merge the entity's cacheability metadata with that of the normalization
    // parts, so that RenderCache can take care of cache redirects for us.
    CacheableMetadata::createFromObject($object)
    // parts, so that VariationCache can take care of cache redirects for us.
    $cacheability = CacheableMetadata::createFromObject($object)
      ->merge(static::mergeCacheableDependencies($normalization_parts[static::RESOURCE_CACHE_SUBSET_BASE]))
      ->merge(static::mergeCacheableDependencies($normalization_parts[static::RESOURCE_CACHE_SUBSET_FIELDS]))
      ->applyTo($data_as_render_array);
      ->merge(static::mergeCacheableDependencies($normalization_parts[static::RESOURCE_CACHE_SUBSET_FIELDS]));

    $this->renderCache->set($data_as_render_array, $base);
    $this->variationCache->set($this->generateCacheKeys($object), $normalization_parts, $cacheability, new CacheableMetadata());
  }

  /**
   * Generates a lookup render array for a normalization.
   * Generates the cache keys for a normalization.
   *
   * @param \Drupal\jsonapi\JsonApiResource\ResourceObject $object
   *   The resource object for which to generate a cache item.
   *   The resource object for which to generate the cache keys.
   *
   * @return array
   *   A render array for use with the RenderCache service.
   * @return string[]
   *   The cache keys to pass to the variation cache.
   *
   * @see \Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber::$dynamicPageCacheRedirectRenderArray
   */
  protected static function generateLookupRenderArray(ResourceObject $object) {
    return [
      '#cache' => [
        'keys' => [$object->getResourceType()->getTypeName(), $object->getId(), $object->getLanguage()->getId()],
        'bin' => 'jsonapi_normalizations',
      ],
    ];
  protected static function generateCacheKeys(ResourceObject $object) {
    return [$object->getResourceType()->getTypeName(), $object->getId(), $object->getLanguage()->getId()];
  }

  /**
+4 −13
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Url;
use Drupal\jsonapi\Normalizer\HttpExceptionNormalizer;
use Drupal\jsonapi\Normalizer\Value\CacheableNormalization;
@@ -386,12 +387,7 @@ protected function assertCacheableNormalizations(): void {
    $this->entity->save();
    $uuid = $this->entity->uuid();
    $language = $this->entity->language()->getId();
    $cache = \Drupal::service('render_cache')->get([
      '#cache' => [
        'keys' => ['node--camelids', $uuid, $language],
        'bin' => 'jsonapi_normalizations',
      ],
    ]);
    $cache = \Drupal::service('variation_cache.jsonapi_normalizations')->get(['node--camelids', $uuid, $language], new CacheableMetadata());
    // After saving the entity the normalization should not be cached.
    $this->assertFalse($cache);
    // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463.
@@ -422,13 +418,8 @@ protected function assertCacheableNormalizations(): void {
   * @internal
   */
  protected function assertNormalizedFieldsAreCached(array $field_names): void {
    $cache = \Drupal::service('render_cache')->get([
      '#cache' => [
        'keys' => ['node--camelids', $this->entity->uuid(), $this->entity->language()->getId()],
        'bin' => 'jsonapi_normalizations',
      ],
    ]);
    $cached_fields = $cache['#data']['fields'];
    $cache = \Drupal::service('variation_cache.jsonapi_normalizations')->get(['node--camelids', $this->entity->uuid(), $this->entity->language()->getId()], new CacheableMetadata());
    $cached_fields = $cache->data['fields'];
    $this->assertSameSize($field_names, $cached_fields);
    array_walk($field_names, function ($field_name) use ($cached_fields) {
      $this->assertInstanceOf(