Make Json response cacheable

Created on 17 July 2019, almost 5 years ago
Updated 28 July 2023, 11 months ago

Currently, the autocompletion response is returning a Symfony\Component\HttpFoundation\JsonResponse object. This is not cached.

Proposed solution:
Add caching to the json response return by changing \Symfony\Component\HttpFoundation\JsonResponse to \Drupal\Core\Cache\CacheableJsonResponse in AutocompleteController::autocomplete. Patch can be found in the comments in issue #3066540 β†’ .

Also, convert rendered objects to string to prevent "leaked metadata" errors:

  $label = $this->renderer->render($build);

to

  $label = NULL;
  \Drupal::service('renderer')->executeInRenderContext(new RenderContext(), function () use (&$build, &$label) {
    $label = render($build);
  });

AND

  $url = $suggestion->getUrl()->toString();

to

  $url = $suggestion->getUrl()->toString(TRUE);
  $trimmed_label = trim(strip_tags((string) $label)) ?: $url;
  $match = [
    'value' => $trimmed_label,
    'url' => $url->getGeneratedUrl(),
    'label' => $label,
  ];

Notes:
The attached patch file also includes the patch from issue #3066540 β†’ .

✨ Feature request
Status

Needs work

Version

1.0

Component

Framework

Created by

πŸ‡΅πŸ‡­Philippines rmacapagal

Live updates comments and jobs are added and updated live.
  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡¦πŸ‡ΉAustria drunken monkey Vienna, Austria

    The IS lacks a bit of context/description. Taken from #3066540: Is it possible to use a cacheable response? β†’ , the idea seems to not make this cacheable for Drupal itself, but allow a custom module to alter the cache metadata in order to have the response cached by the client – is that correct? Caching search results within Drupal is mostly pointless, as there are only few scenarios where you can expect to reach a reasonable cache hit rate.

    Anyways, on the patch itself, I’m unfortunately no expert in the Drupal cache system, but most of the code does seem sensible. A few comments, though:

    1. +++ b/src/Controller/AutocompleteController.php
      @@ -167,7 +172,9 @@ class AutocompleteController extends ControllerBase implements ContainerInjectio
      -            $label = $this->renderer->render($build);
      +            $label = $this->renderer->executeInRenderContext(new RenderContext(), function () use ($build) {
      +              return $this->renderer->render($build);
      +            });
      

      Wouldn’t this discard any caching information coming from that build array? As said above, I’m no expert (or even intermediate, I guess), but it does seem like we should extract the metadata from the render context afterwards?

    2. +++ b/src/Controller/AutocompleteController.php
      @@ -177,15 +184,19 @@ class AutocompleteController extends ControllerBase implements ContainerInjectio
      +            $url = $suggestion->getUrl();
      +            if ($entity = $url->getOption('entity')) {
      +              $cacheable_metadata->addCacheableDependency($entity);
      +            }
                   // Generate an HTML-free version of the label to use as the value.
                   // Setting the label as the value here is necessary for proper
                   // accessibility via screen readers (which will otherwise read the
                   // URL).
      -            $url = $suggestion->getUrl()->toString();
      +            $url = $suggestion->getUrl()->toString(TRUE);
      

      $suggestion->getUrl()->toString(TRUE) already returns a cacheable object, no need to look for an entity manually (I think).

    3. +++ b/src/Controller/AutocompleteController.php
      @@ -206,7 +217,12 @@ class AutocompleteController extends ControllerBase implements ContainerInjectio
      +    $this->moduleHandler()->alter('search_api_autocomplete_response', $response);
      

      This hook still needs to be documented in search_api_autocomplete.api.php.

    Most of this is addressed in the attached patch revision. However, this still needs a hook documentation and, more importantly, tests. Also, it seems like it even breaks current tests? (Still setting to NR for the test bot, but will switch to NW right afterwards.)

  • πŸ‡¦πŸ‡ΉAustria drunken monkey Vienna, Austria
  • πŸ‡¬πŸ‡§United Kingdom lstirk

    I am getting the leaked metadata errors with the current patch. I think its due to the view been rendered within a block. Autocomplete builds the view, and theres a check in core to see if the view has a URL in `core/modules/views/src/Form/ViewsExposedForm.php`. If theres no URL its rendering one which is triggering the leaked metadata error.

    Moving `$search->createQuery` inside `executeInRenderContext` resolves this.

  • πŸ‡¦πŸ‡ΉAustria drunken monkey Vienna, Austria

    @lstirk: Seems like what you describe might have already been fixed in πŸ› LogicException: Bubbling failed Fixed ? Please try with the latest dev version of the module.

Production build 0.69.0 2024