ProcessLayoutRenderElement.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <?php
  2. /**
  3. *
  4. * Copyright © Magento, Inc. All rights reserved.
  5. * See COPYING.txt for license details.
  6. */
  7. namespace Magento\PageCache\Observer;
  8. use Magento\Framework\Event\ObserverInterface;
  9. use Magento\Framework\Serialize\Serializer\Base64Json;
  10. use Magento\Framework\Serialize\Serializer\Json;
  11. use Magento\Framework\View\EntitySpecificHandlesList;
  12. class ProcessLayoutRenderElement implements ObserverInterface
  13. {
  14. /**
  15. * Application config object
  16. *
  17. * @var \Magento\PageCache\Model\Config
  18. */
  19. private $_config;
  20. /**
  21. * Is varnish enabled flag
  22. *
  23. * @var bool
  24. */
  25. private $isVarnishEnabled;
  26. /**
  27. * Is full page cache enabled flag
  28. *
  29. * @var bool
  30. */
  31. private $isFullPageCacheEnabled;
  32. /**
  33. * @var EntitySpecificHandlesList
  34. */
  35. private $entitySpecificHandlesList;
  36. /**
  37. * @var Base64Json
  38. */
  39. private $base64jsonSerializer;
  40. /**
  41. * @var Json
  42. */
  43. private $jsonSerializer;
  44. /**
  45. * Class constructor
  46. *
  47. * @param \Magento\PageCache\Model\Config $config
  48. * @param EntitySpecificHandlesList $entitySpecificHandlesList
  49. * @param Json $jsonSerializer
  50. * @param Base64Json $base64jsonSerializer
  51. */
  52. public function __construct(
  53. \Magento\PageCache\Model\Config $config,
  54. EntitySpecificHandlesList $entitySpecificHandlesList = null,
  55. Json $jsonSerializer = null,
  56. Base64Json $base64jsonSerializer = null
  57. ) {
  58. $this->_config = $config;
  59. $this->entitySpecificHandlesList = $entitySpecificHandlesList
  60. ?: \Magento\Framework\App\ObjectManager::getInstance()->get(EntitySpecificHandlesList::class);
  61. $this->jsonSerializer = $jsonSerializer
  62. ?: \Magento\Framework\App\ObjectManager::getInstance()->get(Json::class);
  63. $this->base64jsonSerializer = $base64jsonSerializer
  64. ?: \Magento\Framework\App\ObjectManager::getInstance()->get(Base64Json::class);
  65. }
  66. /**
  67. * Replace the output of the block, containing ttl attribute, with ESI tag
  68. *
  69. * @param \Magento\Framework\View\Element\AbstractBlock $block
  70. * @param \Magento\Framework\View\Layout $layout
  71. * @return string
  72. */
  73. private function _wrapEsi(
  74. \Magento\Framework\View\Element\AbstractBlock $block,
  75. \Magento\Framework\View\Layout $layout
  76. ) {
  77. $handles = $layout->getUpdate()->getHandles();
  78. $pageSpecificHandles = $this->entitySpecificHandlesList->getHandles();
  79. $url = $block->getUrl(
  80. 'page_cache/block/esi',
  81. [
  82. 'blocks' => $this->jsonSerializer->serialize([$block->getNameInLayout()]),
  83. 'handles' => $this->base64jsonSerializer->serialize(
  84. array_values(array_diff($handles, $pageSpecificHandles))
  85. )
  86. ]
  87. );
  88. // Varnish does not support ESI over HTTPS must change to HTTP
  89. $url = substr($url, 0, 5) === 'https' ? 'http' . substr($url, 5) : $url;
  90. return sprintf('<esi:include src="%s" />', $url);
  91. }
  92. /**
  93. * Is full page cache enabled
  94. *
  95. * @return bool
  96. */
  97. private function isFullPageCacheEnabled()
  98. {
  99. if ($this->isFullPageCacheEnabled === null) {
  100. $this->isFullPageCacheEnabled = $this->_config->isEnabled();
  101. }
  102. return $this->isFullPageCacheEnabled;
  103. }
  104. /**
  105. * Is varnish cache engine enabled
  106. *
  107. * @return bool
  108. */
  109. private function isVarnishEnabled()
  110. {
  111. if ($this->isVarnishEnabled === null) {
  112. $this->isVarnishEnabled = ($this->_config->getType() == \Magento\PageCache\Model\Config::VARNISH);
  113. }
  114. return $this->isVarnishEnabled;
  115. }
  116. /**
  117. * Add comment cache containers to private blocks
  118. * Blocks are wrapped only if page is cacheable
  119. *
  120. * @param \Magento\Framework\Event\Observer $observer
  121. * @return void
  122. */
  123. public function execute(\Magento\Framework\Event\Observer $observer)
  124. {
  125. $event = $observer->getEvent();
  126. /** @var \Magento\Framework\View\Layout $layout */
  127. $layout = $event->getLayout();
  128. if ($this->isFullPageCacheEnabled() && $layout->isCacheable()) {
  129. $name = $event->getElementName();
  130. /** @var \Magento\Framework\View\Element\AbstractBlock $block */
  131. $block = $layout->getBlock($name);
  132. $transport = $event->getTransport();
  133. if ($block instanceof \Magento\Framework\View\Element\AbstractBlock) {
  134. $blockTtl = $block->getTtl();
  135. $output = $transport->getData('output');
  136. if (isset($blockTtl) && $this->isVarnishEnabled()) {
  137. $output = $this->_wrapEsi($block, $layout);
  138. } elseif ($block->isScopePrivate()) {
  139. $output = sprintf(
  140. '<!-- BLOCK %1$s -->%2$s<!-- /BLOCK %1$s -->',
  141. $block->getNameInLayout(),
  142. $output
  143. );
  144. }
  145. $transport->setData('output', $output);
  146. }
  147. }
  148. }
  149. }