DefaultHtmlFragmentRenderer.php 5.21 KB
Newer Older
1 2 3 4 5 6 7 8 9
<?php

/**
 * @file
 * Contains \Drupal\Core\Page\DefaultHtmlFragmentRenderer
 */

namespace Drupal\Core\Page;

10
use Drupal\Core\Cache\Cache;
11
use Drupal\Core\Cache\CacheableInterface;
12
use Drupal\Core\Language\LanguageManagerInterface;
13 14 15 16 17 18 19 20 21

/**
 * Default page rendering engine.
 */
class DefaultHtmlFragmentRenderer implements HtmlFragmentRendererInterface {

  /**
   * The language manager.
   *
22
   * @var \Drupal\Core\Language\LanguageManagerInterface
23 24 25 26 27 28
   */
  protected $languageManager;

  /**
   * Constructs a new DefaultHtmlPageRenderer.
   *
29
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
30 31
   *   The language manager service.
   */
32
  public function __construct(LanguageManagerInterface $language_manager) {
33 34 35 36 37 38
    $this->languageManager = $language_manager;
  }

  /**
   * {@inheritdoc}
   */
39
  public function render(HtmlFragmentInterface $fragment, $status_code = 200) {
40 41 42 43 44 45 46
    // Converts the given HTML fragment which represents the main content region
    // of the page into a render array.
    $page_content['main'] = array(
      '#markup' => $fragment->getContent(),
    );
    $page_content['#title'] = $fragment->getTitle();

47 48 49 50
    if ($fragment instanceof CacheableInterface) {
      $page_content['main']['#cache']['tags'] = $fragment->getCacheTags();
    }

51 52 53 54 55
    // Build the full page array by calling drupal_prepare_page(), which invokes
    // hook_page_build(). This adds the other regions to the page.
    $page_array = drupal_prepare_page($page_content);

    // Build the HtmlPage object.
56
    $page = new HtmlPage('', array(), $fragment->getTitle());
57 58 59 60 61 62
    $page = $this->preparePage($page, $page_array);
    $page->setBodyTop(drupal_render($page_array['page_top']));
    $page->setBodyBottom(drupal_render($page_array['page_bottom']));
    $page->setContent(drupal_render($page_array));
    $page->setStatusCode($status_code);

63 64 65 66 67 68 69 70
    drupal_process_attached($page_array);
    if (isset($page_array['page_top'])) {
      drupal_process_attached($page_array['page_top']);
    }
    if (isset($page_array['page_bottom'])) {
      drupal_process_attached($page_array['page_bottom']);
    }

71
    if ($fragment instanceof CacheableInterface) {
72 73 74
      // Persist cache tags associated with this page. Also associate the
      // "rendered" cache tag. This allows us to invalidate the entire render
      // cache, regardless of the cache bin.
75 76 77 78 79 80
      $cache_tags = Cache::mergeTags(
        isset($page_array['page_top']) ? $page_array['page_top']['#cache']['tags'] : [],
        $page_array['#cache']['tags'],
        isset($page_array['page_bottom']) ? $page_array['page_bottom']['#cache']['tags'] : [],
        ['rendered']
      );
81 82 83 84
      // Only keep unique cache tags. We need to prevent duplicates here already
      // rather than only in the cache layer, because they are also used by
      // reverse proxies (like Varnish), not only by Drupal's page cache.
      $page->setCacheTags(array_unique($cache_tags));
85 86
    }

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
    return $page;
  }

  /**
   * Enhances a page object based on a render array.
   *
   * @param \Drupal\Core\Page\HtmlPage $page
   *   The page object to enhance.
   * @param array $page_array
   *   The page array to extract onto the page object.
   *
   * @return \Drupal\Core\Page\HtmlPage
   *   The modified page object.
   */
  public function preparePage(HtmlPage $page, &$page_array) {
    $page_array['#page'] = $page;

    // HTML element attributes.
    $language_interface = $this->languageManager->getCurrentLanguage();
    $html_attributes = $page->getHtmlAttributes();
107
    $html_attributes['lang'] = $language_interface->getId();
108
    $html_attributes['dir'] = $language_interface->getDirection();
109

110 111
    $this->setDefaultMetaTags($page);

112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
    // Add libraries and CSS used by this theme.
    $active_theme = \Drupal::theme()->getActiveTheme();
    foreach ($active_theme->getLibraries() as $library) {
      $page_array['#attached']['library'][] = $library;
    }
    foreach ($active_theme->getStyleSheets() as $media => $stylesheets) {
      foreach ($stylesheets as $stylesheet) {
        $page_array['#attached']['css'][$stylesheet] = array(
          'group' => CSS_AGGREGATE_THEME,
          'every_page' => TRUE,
          'media' => $media
        );
      }
    }

127 128 129
    return $page;
  }

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
  /**
   * Apply the default meta tags to the page object.
   *
   * @param \Drupal\Core\Page\HtmlPage $page
   *   The html page.
   */
  protected function setDefaultMetaTags(HtmlPage $page) {
    // Add default elements. Make sure the Content-Type comes first because the
    // IE browser may be vulnerable to XSS via encoding attacks from any content
    // that comes before this META tag, such as a TITLE tag.
    $page->addMetaElement(new MetaElement(NULL, array(
      'name' => 'charset',
      'charset' => 'utf-8',
    )));
    // Show Drupal and the major version number in the META GENERATOR tag.
    // Get the major version.
    list($version) = explode('.', \Drupal::VERSION, 2);
    $page->addMetaElement(new MetaElement('Drupal ' . $version . ' (http://drupal.org)', array(
      'name' => 'Generator',
    )));

    // Display the html.html.twig's default mobile metatags for responsive design.
152
    $page->addMetaElement(new MetaElement(NULL, array('name' => 'viewport', 'content' => 'width=device-width, initial-scale=1.0')));
153 154
  }

155
}