2

I have a custom page displaying a query result from the database. Before I attempt to cache it myself, I am trying to see if Drupal 8 render arrays support caching in anyway for authenticated users. My use case is a route and a controller on the node entity. Users go to node/id/something that displays a list of entries in a table. I would like to cache this in the controller.

I am using the following code.

public function displayContent(NodeInterface $node) {
  // query the DB to generate content. 
   $content['#markup'] = $result_of_db_query; 

    $content['#cache'] = [
      'keys' => ['entity_view', 'node', $node->id()],
      'tags' => ['node:' . $node->id()],
      'max-age' => Cache::PERMANENT,
    ];
    return $content; 
}

It doesn't work: The database query is executed on every page request. I am not sure if this is due to the fact this page is an administrative page and users must be authenticated.

  • 2
    That code snippet doesn't make any sense, you set content to a string and then change it to an array. Also, not working is not a useful problem description, describe what you expect and what you are actually seeing. Render caching definitely also works for authenticated users. You should read through drupal.org/docs/8/api/render-api/cacheability-of-render-arrays first – Berdir Mar 24 '18 at 1:05
  • @Berdir, you are right. I updated my question. I expect the content to be cached and the query that generate the result to not run on every page request. – awm Mar 24 '18 at 18:07
  • 1
    I don't feel the question is unclear in its current state, and should be reopened (I have nominated it as such). It's a good question - is caching enabled for authenticated users, or is it only for unauthenticated users? – Jaypan Mar 25 '18 at 0:41
  • 2
    There are two different questions though. the one from the title is easy to answer: Yes. The actual question in the content is very different about a specific problem. The #cache property is copied 1:1 from api.drupal.org/api/drupal/…, you shouldn't re-use some existing keys, they must be unique for you. Also, you shouldn't need the keys at all when using dynamic page cache on a page that can be cached and if you do, then it can only cache the process of converting that array into a string – Berdir Mar 25 '18 at 11:13
  • 2
    but in your example you already did that because you just set a #markup. Drupal can't know to not call your controller again then (again, unless dynamic page cache is used), it can only cache the actual rendering. For that to make sense, all the logic needs to happen in pre_render callbacks, preprocess and templates. Look how how entities are cached in api.drupal.org/api/drupal/…, nothing is done there, it just sets a pre_render callback that will then do the real work – Berdir Mar 25 '18 at 11:16
3

Now that the topic is open again I will try to answer the questions:

Does the #cache property for render arrays cache content from a query when used in a controller?

Yes, it does. The cache metadata will be used to cache the render array if you set cache keys and the metadata bubbles up to page level.

The database query is executed on every page request. I am not sure if this is due to the fact this page is an administrative page and users must be authenticated.

On page level this is true, as for now it is presumed that admin pages are not cacheable, see Change Dynamic Page Cache's response policy from "deny admin routes" to "deny html admin routes"

I expect the content to be cached and the query that generate the result to not run on every page request.

See the comments from @Berdir and this blog post how to do this by moving the query to a #pre_render callback:

https://dev.acquia.com/blog/drupal-8-performance-render-caching

  • Thanks for your answer, I thought this would solve the issue, but I used a pre_render hook in which I generated the list of entries and tried the #cache key, but still, when I debug, my query is triggered on every page load. Updated the code in the question above. – awm Mar 26 '18 at 17:53
  • 1
    you've updated a lot of code not connected to the problem, but now it seems you have no $content['#cache']['keys'] – 4k4 Mar 26 '18 at 18:13
  • 1
    Thank you, I reverted back to the original question for integrity. So all I needed to get this to work (cache the render array) is as @berdir suggested, 1. Unique Keys, 2. pre_render callback. These were a must for the cache to work. And it's working even if the route is admin_route. I am sorry the question was not very clear and dragged on but I am really tying to understand this. thx all – awm Mar 26 '18 at 18:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.