You are here

protected function HtmlRenderer::prepare in Drupal 8

Same name and namespace in other branches
  1. 9 core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php \Drupal\Core\Render\MainContent\HtmlRenderer::prepare()

Prepares the HTML body: wraps the main content in #type 'page'.

Parameters

array $main_content: The render array representing the main content.

\Symfony\Component\HttpFoundation\Request $request: The request object, for context.

\Drupal\Core\Routing\RouteMatchInterface $route_match: The route match, for context.

Return value

array An array with two values: 0. A #type 'page' render array. 1. The page title.

Throws

\LogicException If the selected display variant does not implement PageVariantInterface.

1 call to HtmlRenderer::prepare()
HtmlRenderer::renderResponse in core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php
The entire HTML: takes a #type 'page' and wraps it in a #type 'html'.

File

core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php, line 189

Class

HtmlRenderer
Default main content renderer for HTML requests.

Namespace

Drupal\Core\Render\MainContent

Code

protected function prepare(array $main_content, Request $request, RouteMatchInterface $route_match) {

  // Determine the title: use the title provided by the main content if any,
  // otherwise get it from the routing information.
  $get_title = function (array $main_content) use ($request, $route_match) {
    return isset($main_content['#title']) ? $main_content['#title'] : $this->titleResolver
      ->getTitle($request, $route_match
      ->getRouteObject());
  };

  // If the _controller result already is #type => page,
  // we have no work to do: The "main content" already is an entire "page"
  // (see html.html.twig).
  if (isset($main_content['#type']) && $main_content['#type'] === 'page') {
    $page = $main_content;
    $title = $get_title($page);
  }
  else {

    // Select the page display variant to be used to render this main content,
    // default to the built-in "simple page".
    $event = new PageDisplayVariantSelectionEvent('simple_page', $route_match);
    $this->eventDispatcher
      ->dispatch(RenderEvents::SELECT_PAGE_DISPLAY_VARIANT, $event);
    $variant_id = $event
      ->getPluginId();

    // We must render the main content now already, because it might provide a
    // title. We set its $is_root_call parameter to FALSE, to ensure
    // placeholders are not yet replaced. This is essentially "pre-rendering"
    // the main content, the "full rendering" will happen in
    // ::renderResponse().
    // @todo Remove this once https://www.drupal.org/node/2359901 lands.
    if (!empty($main_content)) {
      $this->renderer
        ->executeInRenderContext(new RenderContext(), function () use (&$main_content) {
        if (isset($main_content['#cache']['keys'])) {

          // Retain #title, otherwise, dynamically generated titles would be
          // missing for controllers whose entire returned render array is
          // render cached.
          $main_content['#cache_properties'][] = '#title';
        }
        return $this->renderer
          ->render($main_content, FALSE);
      });
      $main_content = $this->renderCache
        ->getCacheableRenderArray($main_content) + [
        '#title' => isset($main_content['#title']) ? $main_content['#title'] : NULL,
      ];
    }
    $title = $get_title($main_content);

    // Instantiate the page display, and give it the main content.
    $page_display = $this->displayVariantManager
      ->createInstance($variant_id);
    if (!$page_display instanceof PageVariantInterface) {
      throw new \LogicException('Cannot render the main content for this page because the provided display variant does not implement PageVariantInterface.');
    }
    $page_display
      ->setMainContent($main_content)
      ->setTitle($title)
      ->addCacheableDependency($event)
      ->setConfiguration($event
      ->getPluginConfiguration());

    // Some display variants need to be passed an array of contexts with
    // values because they can't get all their contexts globally. For example,
    // in Page Manager, you can create a Page which has a specific static
    // context (e.g. a context that refers to the Node with nid 6), if any
    // such contexts were added to the $event, pass them to the $page_display.
    if ($page_display instanceof ContextAwareVariantInterface) {
      $page_display
        ->setContexts($event
        ->getContexts());
    }

    // Generate a #type => page render array using the page display variant,
    // the page display will build the content for the various page regions.
    $page = [
      '#type' => 'page',
    ];
    $page += $page_display
      ->build();
  }

  // $page is now fully built. Find all non-empty page regions, and add a
  // theme wrapper function that allows them to be consistently themed.
  $regions = \Drupal::theme()
    ->getActiveTheme()
    ->getRegions();
  foreach ($regions as $region) {
    if (!empty($page[$region])) {
      $page[$region]['#theme_wrappers'][] = 'region';
      $page[$region]['#region'] = $region;
    }
  }

  // Allow hooks to add attachments to $page['#attached'].
  $this
    ->invokePageAttachmentHooks($page);
  return [
    $page,
    $title,
  ];
}