protected function EarlyRenderingControllerWrapperSubscriber::wrapControllerExecutionInRenderContext

protected EarlyRenderingControllerWrapperSubscriber::wrapControllerExecutionInRenderContext($controller, array $arguments)

Wraps a controller execution in a render context.

Parameters

callable $controller: The controller to execute.

array $arguments: The arguments to pass to the controller.

Return value

mixed The return value of the controller.

Throws

\LogicException When early rendering has occurred in a controller that returned a Response or domain object that cares about attachments or cacheability.

See also

\Symfony\Component\HttpKernel\HttpKernel::handleRaw()

File

core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php, line 118

Class

EarlyRenderingControllerWrapperSubscriber
Subscriber that wraps controllers, to handle early rendering.

Namespace

Drupal\Core\EventSubscriber

Code

protected function wrapControllerExecutionInRenderContext($controller, array $arguments) {
  $context = new RenderContext();

  $response = $this->renderer->executeInRenderContext($context, function() use ($controller, $arguments) {
    // Now call the actual controller, just like HttpKernel does.
    return call_user_func_array($controller, $arguments);
  });

  // If early rendering happened, i.e. if code in the controller called
  // drupal_render() outside of a render context, then the bubbleable metadata
  // for that is stored in the current render context.
  if (!$context->isEmpty()) {
    /** @var \Drupal\Core\Render\BubbleableMetadata $early_rendering_bubbleable_metadata */
    $early_rendering_bubbleable_metadata = $context->pop();

    // If a render array or AjaxResponse is returned by the controller, merge
    // the "lost" bubbleable metadata.
    if (is_array($response)) {
      BubbleableMetadata::createFromRenderArray($response)
        ->merge($early_rendering_bubbleable_metadata)
        ->applyTo($response);
    }
    elseif ($response instanceof AjaxResponse) {
      $response->addAttachments($early_rendering_bubbleable_metadata->getAttachments());
      // @todo Make AjaxResponse cacheable in
      //   https://www.drupal.org/node/956186. Meanwhile, allow contrib
      //   subclasses to be.
      if ($response instanceof CacheableResponseInterface) {
        $response->addCacheableDependency($early_rendering_bubbleable_metadata);
      }
    }
    // If a non-Ajax Response or domain object is returned and it cares about
    // attachments or cacheability, then throw an exception: early rendering
    // is not permitted in that case. It is the developer's responsibility
    // to not use early rendering.
    elseif ($response instanceof AttachmentsInterface || $response instanceof CacheableResponseInterface || $response instanceof CacheableDependencyInterface) {
      throw new \LogicException(sprintf('The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: %s.', get_class($response)));
    }
    else {
      // A Response or domain object is returned that does not care about
      // attachments nor cacheability; for instance, a RedirectResponse. It is
      // safe to discard any early rendering metadata.
    }
  }

  return $response;
}

© 2001–2016 by the original authors
Licensed under the GNU General Public License, version 2 and later.
Drupal is a registered trademark of Dries Buytaert.
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!EventSubscriber!EarlyRenderingControllerWrapperSubscriber.php/function/EarlyRenderingControllerWrapperSubscriber::wrapControllerExecutionInRenderContext/8.1.x