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.

7
  • 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, 2018 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, 2018 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, 2018 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, 2018 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, 2018 at 11:16

1 Answer 1

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

3
  • 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, 2018 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']
    – 4uk4
    Mar 26, 2018 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, 2018 at 18:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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