Merged.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\View\Asset;
  7. use Magento\Framework\App\ObjectManager;
  8. /**
  9. * \Iterator that aggregates one or more assets and provides a single public file with equivalent behavior
  10. */
  11. class Merged implements \Iterator
  12. {
  13. /**
  14. * Directory for dynamically generated public view files, relative to STATIC_VIEW
  15. */
  16. const CACHE_VIEW_REL = '_cache';
  17. /**
  18. * @var \Psr\Log\LoggerInterface
  19. */
  20. protected $logger;
  21. /**
  22. * @var MergeStrategyInterface
  23. */
  24. protected $mergeStrategy;
  25. /**
  26. * @var \Magento\Framework\View\Asset\Repository
  27. */
  28. private $assetRepo;
  29. /**
  30. * @var MergeableInterface[]
  31. */
  32. protected $assets;
  33. /**
  34. * @var string
  35. */
  36. protected $contentType;
  37. /**
  38. * @var \Magento\Framework\App\View\Deployment\Version\StorageInterface
  39. */
  40. private $versionStorage;
  41. /**
  42. * @var bool
  43. */
  44. protected $isInitialized = false;
  45. /**
  46. * Merged constructor.
  47. *
  48. * @param \Psr\Log\LoggerInterface $logger
  49. * @param MergeStrategyInterface $mergeStrategy
  50. * @param \Magento\Framework\View\Asset\Repository $assetRepo
  51. * @param MergeableInterface[] $assets
  52. * @param \Magento\Framework\App\View\Deployment\Version\StorageInterface $versionStorage
  53. * @throws \InvalidArgumentException
  54. */
  55. public function __construct(
  56. \Psr\Log\LoggerInterface $logger,
  57. MergeStrategyInterface $mergeStrategy,
  58. \Magento\Framework\View\Asset\Repository $assetRepo,
  59. array $assets,
  60. \Magento\Framework\App\View\Deployment\Version\StorageInterface $versionStorage = null
  61. ) {
  62. $this->logger = $logger;
  63. $this->mergeStrategy = $mergeStrategy;
  64. $this->assetRepo = $assetRepo;
  65. $this->versionStorage = $versionStorage ?: ObjectManager::getInstance()->get(
  66. \Magento\Framework\App\View\Deployment\Version\StorageInterface::class
  67. );
  68. if (!$assets) {
  69. throw new \InvalidArgumentException('At least one asset has to be passed for merging.');
  70. }
  71. /** @var $asset MergeableInterface */
  72. foreach ($assets as $asset) {
  73. if (!($asset instanceof MergeableInterface)) {
  74. throw new \InvalidArgumentException(
  75. 'Asset has to implement \Magento\Framework\View\Asset\MergeableInterface.'
  76. );
  77. }
  78. if (!$this->contentType) {
  79. $this->contentType = $asset->getContentType();
  80. } elseif ($asset->getContentType() != $this->contentType) {
  81. throw new \InvalidArgumentException(
  82. "Content type '{$asset->getContentType()}' cannot be merged with '{$this->contentType}'."
  83. );
  84. }
  85. }
  86. $this->assets = $assets;
  87. }
  88. /**
  89. * Attempt to merge assets, falling back to original non-merged ones, if merging fails
  90. *
  91. * @return void
  92. */
  93. protected function initialize()
  94. {
  95. if (!$this->isInitialized) {
  96. $this->isInitialized = true;
  97. try {
  98. $mergedAsset = $this->createMergedAsset($this->assets);
  99. $this->mergeStrategy->merge($this->assets, $mergedAsset);
  100. $this->assets = [$mergedAsset];
  101. } catch (\Exception $e) {
  102. $this->logger->critical($e);
  103. }
  104. }
  105. }
  106. /**
  107. * Create an asset object for merged file
  108. *
  109. * @param array $assets
  110. * @return MergeableInterface
  111. */
  112. private function createMergedAsset(array $assets)
  113. {
  114. $paths = [];
  115. /** @var MergeableInterface $asset */
  116. foreach ($assets as $asset) {
  117. $paths[] = $asset->getPath();
  118. }
  119. $paths = array_unique($paths);
  120. $version = $this->versionStorage->load();
  121. if ($version) {
  122. $paths[] = $version;
  123. }
  124. $filePath = md5(implode('|', $paths)) . '.' . $this->contentType;
  125. return $this->assetRepo->createArbitrary($filePath, self::getRelativeDir());
  126. }
  127. /**
  128. * {@inheritdoc}
  129. *
  130. * @return AssetInterface
  131. */
  132. public function current()
  133. {
  134. $this->initialize();
  135. return current($this->assets);
  136. }
  137. /**
  138. * {@inheritdoc}
  139. */
  140. public function key()
  141. {
  142. $this->initialize();
  143. return key($this->assets);
  144. }
  145. /**
  146. * {@inheritdoc}
  147. */
  148. public function next()
  149. {
  150. $this->initialize();
  151. next($this->assets);
  152. }
  153. /**
  154. * {@inheritdoc}
  155. */
  156. public function rewind()
  157. {
  158. $this->initialize();
  159. reset($this->assets);
  160. }
  161. /**
  162. * {@inheritdoc}
  163. */
  164. public function valid()
  165. {
  166. $this->initialize();
  167. return (bool)current($this->assets);
  168. }
  169. /**
  170. * Returns directory for storing merged files relative to STATIC_VIEW
  171. *
  172. * @return string
  173. */
  174. public static function getRelativeDir()
  175. {
  176. return self::CACHE_VIEW_REL . '/merged';
  177. }
  178. }