Bundle.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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\Filesystem;
  8. use Magento\Framework\View\Asset\Bundle\Manager;
  9. use Magento\Framework\App\Filesystem\DirectoryList;
  10. use Magento\Framework\View\Asset\File\FallbackContext;
  11. /**
  12. * Bundle model
  13. * @deprecated 101.0.0
  14. * @see \Magento\Deploy\Package\Bundle
  15. */
  16. class Bundle
  17. {
  18. /**
  19. * @var array
  20. */
  21. protected $assets = [];
  22. /**
  23. * @var array
  24. */
  25. protected $assetsContent = [];
  26. /**
  27. * @var \Magento\Framework\View\Asset\Bundle\ConfigInterface
  28. */
  29. protected $bundleConfig;
  30. /**
  31. * @var array
  32. */
  33. protected $bundleNames = [
  34. Manager::ASSET_TYPE_JS => 'jsbuild',
  35. Manager::ASSET_TYPE_HTML => 'text'
  36. ];
  37. /**
  38. * @var array
  39. */
  40. protected $content = [];
  41. /**
  42. * @var Minification
  43. */
  44. protected $minification;
  45. /**
  46. * @param Filesystem $filesystem
  47. * @param Bundle\ConfigInterface $bundleConfig
  48. * @param Minification $minification
  49. */
  50. public function __construct(
  51. Filesystem $filesystem,
  52. Bundle\ConfigInterface $bundleConfig,
  53. Minification $minification
  54. ) {
  55. $this->filesystem = $filesystem;
  56. $this->bundleConfig = $bundleConfig;
  57. $this->minification = $minification;
  58. }
  59. /**
  60. * @param LocalInterface $asset
  61. * @return void
  62. */
  63. public function addAsset(LocalInterface $asset)
  64. {
  65. $this->init($asset);
  66. $this->add($asset);
  67. }
  68. /**
  69. * Add asset into array
  70. *
  71. * @param LocalInterface $asset
  72. * @return void
  73. */
  74. protected function add(LocalInterface $asset)
  75. {
  76. $partIndex = $this->getPartIndex($asset);
  77. $parts = &$this->assets[$this->getContextCode($asset)][$asset->getContentType()];
  78. if (!isset($parts[$partIndex])) {
  79. $parts[$partIndex]['assets'] = [];
  80. }
  81. $parts[$partIndex]['assets'][$this->getAssetKey($asset)] = $asset;
  82. }
  83. /**
  84. * @param LocalInterface $asset
  85. * @return void
  86. */
  87. protected function init(LocalInterface $asset)
  88. {
  89. $contextCode = $this->getContextCode($asset);
  90. $type = $asset->getContentType();
  91. if (!isset($this->assets[$contextCode][$type])) {
  92. $this->assets[$contextCode][$type] = [];
  93. }
  94. }
  95. /**
  96. * @param LocalInterface $asset
  97. * @return string
  98. */
  99. protected function getContextCode(LocalInterface $asset)
  100. {
  101. /** @var FallbackContext $context */
  102. $context = $asset->getContext();
  103. return $context->getAreaCode() . ':' . $context->getThemePath() . ':' . $context->getLocale();
  104. }
  105. /**
  106. * @param LocalInterface $asset
  107. * @return int
  108. */
  109. protected function getPartIndex(LocalInterface $asset)
  110. {
  111. $parts = $this->assets[$this->getContextCode($asset)][$asset->getContentType()];
  112. $maxPartSize = $this->getMaxPartSize($asset);
  113. $minSpace = $maxPartSize;
  114. $minIndex = -1;
  115. if ($maxPartSize && count($parts)) {
  116. foreach ($parts as $partIndex => $part) {
  117. $space = $maxPartSize - $this->getSizePartWithNewAsset($asset, $part['assets']);
  118. if ($space >= 0 && $space < $minSpace) {
  119. $minSpace = $space;
  120. $minIndex = $partIndex;
  121. }
  122. }
  123. }
  124. return ($maxPartSize != 0) ? ($minIndex >= 0) ? $minIndex : count($parts) : 0;
  125. }
  126. /**
  127. * @param LocalInterface $asset
  128. * @return int
  129. */
  130. protected function getMaxPartSize(LocalInterface $asset)
  131. {
  132. return $this->bundleConfig->getPartSize($asset->getContext());
  133. }
  134. /**
  135. * Get part size after adding new asset
  136. *
  137. * @param LocalInterface $asset
  138. * @param LocalInterface[] $assets
  139. * @return float
  140. */
  141. protected function getSizePartWithNewAsset(LocalInterface $asset, $assets = [])
  142. {
  143. $assets[$this->getAssetKey($asset)] = $asset;
  144. return mb_strlen($this->getPartContent($assets), 'utf-8') / 1024;
  145. }
  146. /**
  147. * Build asset key
  148. *
  149. * @param LocalInterface $asset
  150. * @return string
  151. */
  152. protected function getAssetKey(LocalInterface $asset)
  153. {
  154. $result = (($asset->getModule() == '') ? '' : $asset->getModule() . '/') . $asset->getFilePath();
  155. $result = $this->minification->addMinifiedSign($result);
  156. return $result;
  157. }
  158. /**
  159. * Prepare bundle for executing in js
  160. *
  161. * @param LocalInterface[] $assets
  162. * @return array
  163. */
  164. protected function getPartContent($assets)
  165. {
  166. $contents = [];
  167. foreach ($assets as $key => $asset) {
  168. $contents[$key] = $this->getAssetContent($asset);
  169. }
  170. $partType = reset($assets)->getContentType();
  171. $content = json_encode($contents, JSON_UNESCAPED_SLASHES);
  172. $content = "require.config({\n" .
  173. " config: {\n" .
  174. " '" . $this->bundleNames[$partType] . "':" . $content . "\n" .
  175. " }\n" .
  176. "});\n";
  177. return $content;
  178. }
  179. /**
  180. * Get content of asset
  181. *
  182. * @param LocalInterface $asset
  183. * @return string
  184. */
  185. protected function getAssetContent(LocalInterface $asset)
  186. {
  187. $assetContextCode = $this->getContextCode($asset);
  188. $assetContentType = $asset->getContentType();
  189. $assetKey = $this->getAssetKey($asset);
  190. if (!isset($this->assetsContent[$assetContextCode][$assetContentType][$assetKey])) {
  191. $content = $asset->getContent();
  192. if (mb_detect_encoding($content) !== "UTF-8") {
  193. $content = mb_convert_encoding($content, "UTF-8");
  194. }
  195. $this->assetsContent[$assetContextCode][$assetContentType][$assetKey] = $content;
  196. }
  197. return $this->assetsContent[$assetContextCode][$assetContentType][$assetKey];
  198. }
  199. /**
  200. * @return string
  201. */
  202. protected function getInitJs()
  203. {
  204. return "require.config({\n" .
  205. " bundles: {\n" .
  206. " 'mage/requirejs/static': [\n" .
  207. " 'jsbuild',\n" .
  208. " 'buildTools',\n" .
  209. " 'text',\n" .
  210. " 'statistician'\n" .
  211. " ]\n" .
  212. " },\n" .
  213. " deps: [\n" .
  214. " 'jsbuild'\n" .
  215. " ]\n" .
  216. "});\n";
  217. }
  218. /**
  219. * @return void
  220. */
  221. public function flush()
  222. {
  223. foreach ($this->assets as $types) {
  224. $this->save($types);
  225. }
  226. $this->assets = [];
  227. $this->content = [];
  228. $this->assetsContent = [];
  229. }
  230. /**
  231. * @param array $types
  232. * @return void
  233. */
  234. protected function save($types)
  235. {
  236. $dir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW);
  237. $bundlePath = '';
  238. foreach ($types as $parts) {
  239. /** @var FallbackContext $context */
  240. $assetsParts = reset($parts);
  241. $context = reset($assetsParts['assets'])->getContext();
  242. $bundlePath = empty($bundlePath) ? $context->getPath() . Manager::BUNDLE_PATH : $bundlePath;
  243. $dir->delete($context->getPath() . DIRECTORY_SEPARATOR . Manager::BUNDLE_JS_DIR);
  244. $this->fillContent($parts, $context);
  245. }
  246. $this->content[max(0, count($this->content) - 1)] .= $this->getInitJs();
  247. foreach ($this->content as $partIndex => $content) {
  248. $dir->writeFile($this->minification->addMinifiedSign($bundlePath . $partIndex . '.js'), $content);
  249. }
  250. }
  251. /**
  252. * @param array $parts
  253. * @param FallbackContext $context
  254. * @return void
  255. */
  256. protected function fillContent($parts, $context)
  257. {
  258. $index = count($this->content) > 0 ? count($this->content) - 1 : 0 ;
  259. foreach ($parts as $part) {
  260. if (!isset($this->content[$index])) {
  261. $this->content[$index] = '';
  262. } elseif ($this->bundleConfig->isSplit($context)) {
  263. ++$index;
  264. $this->content[$index] = '';
  265. }
  266. $this->content[$index] .= $this->getPartContent($part['assets']);
  267. }
  268. }
  269. }