Change record status: 
Project: 
Introduced in branch: 
8.0.x
Introduced in version: 
8.0.0-BETA12
Description: 

Many controllers in core still do early rendering. Therefore the probability is high that in contrib there will be early rendering as well. Rather than forcing them to fix their code, we now collect the bubbleable metadata of early rendering, and merge it with the render array returned by the controller. This eases the transition from D7 to D8.

Note that before this change, early rendering's bubbleable metadata was lost, which could have easily led to security problems (due to missing cache tags/contexts on the response).

What you need to change

Nothing. Your controllers returning render arrays that are still doing early rendering are now gathering all bubbleable metadata as well. You're welcome :)

Only in the — currently still rare — case that you are returning a Response object that either is capable of having attachments (i.e. it implements AttachmentsInterface) or cacheability metadata (i.e. it implements CacheableResponseInterface), an exception is thrown. Since you're returning responses, you want to fully control what is sent, so you should also be a responsible citizen and not do any early rendering.

Setting up a render-context for the rare-case

To be able to do so, you should adjust your code to explicitly setup a rendering context, e.g. like this:

  $renderer = \Drupal::service('renderer');
  $context = new RenderContext();

  $response = $renderer->executeInRenderContext($context, function() use ($renderer) {
     // Build a render array.
     $build = [ ... ];
 
     // This should not early render, but its not always possible to control that.
     $renderer->render($build);

     // Return a response for ourselves.
     return new HtmlResponse($build, 200);
  });

  // If there is metadata left on the context, apply it on the response.
  if (!$context->isEmpty()) {
    $metadata = $context->pop();
    $response->addCacheableDependency($metadata);
    $response->addAttachments($metadata->getAttachments());
  }

Note: In 99% of the cases, the above code is not needed.

API changes

  1. All rendering must happen within a render context. Most code is unaffected. Affected code was insecure. (See beginning of issue summary.)
  2. Added RendererInterface::executeInRenderContext(RenderContext $context, calllable $callable).
Impacts: 
Module developers