Package.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Deploy\Package;
  7. use Magento\Deploy\Package\Processor\ProcessorInterface;
  8. use Magento\Framework\View\Design\ThemeInterface;
  9. use Magento\Framework\View\Asset\PreProcessor\FileNameResolver;
  10. /**
  11. * Deployment Package
  12. */
  13. class Package
  14. {
  15. /**
  16. * @var PackagePool
  17. */
  18. private $packagePool;
  19. /**
  20. * @var FileNameResolver
  21. */
  22. private $fileNameResolver;
  23. /**
  24. * @var string
  25. */
  26. private $area;
  27. /**
  28. * @var string
  29. */
  30. private $theme;
  31. /**
  32. * @var string
  33. */
  34. private $locale;
  35. /**
  36. * @var string
  37. */
  38. private $isVirtual;
  39. /**
  40. * @var ProcessorInterface[]
  41. */
  42. private $preProcessors;
  43. /**
  44. * @var ProcessorInterface[]
  45. */
  46. private $postProcessors;
  47. /**
  48. * @var PackageFile[]
  49. */
  50. private $files = [];
  51. /**
  52. * @var array
  53. */
  54. private $map = [];
  55. /**
  56. * @var Package
  57. */
  58. private $parent;
  59. /**
  60. * @var Package[]
  61. */
  62. private $parentPackages;
  63. /**
  64. * @var int
  65. */
  66. private $state;
  67. /**
  68. * @var array
  69. */
  70. private $params = [];
  71. /**
  72. * Deployment state identifier for "in progress" state
  73. */
  74. const STATE_PROGRESS = 0;
  75. /**
  76. * Deployment state identifier for "completed" state
  77. */
  78. const STATE_COMPLETED = 1;
  79. /**
  80. * Base area code
  81. */
  82. const BASE_AREA = 'base';
  83. /**
  84. * Base theme code
  85. */
  86. const BASE_THEME = 'Magento/base';
  87. /**
  88. * Base locale code
  89. */
  90. const BASE_LOCALE = 'default';
  91. /**
  92. * @var array
  93. */
  94. private $packageDefaultValues = [
  95. 'area' => self::BASE_AREA,
  96. 'theme' => self::BASE_THEME,
  97. 'locale' => self::BASE_LOCALE
  98. ];
  99. /**
  100. * @param PackagePool $packagePool
  101. * @param FileNameResolver $fileNameResolver
  102. * @param string $area
  103. * @param string $theme
  104. * @param string $locale
  105. * @param bool $isVirtual
  106. * @param ProcessorInterface[] $preProcessors
  107. * @param ProcessorInterface[] $postProcessors
  108. * @internal param string $type
  109. */
  110. public function __construct(
  111. PackagePool $packagePool,
  112. FileNameResolver $fileNameResolver,
  113. $area,
  114. $theme,
  115. $locale,
  116. $isVirtual = false,
  117. array $preProcessors = [],
  118. array $postProcessors = []
  119. ) {
  120. $this->packagePool = $packagePool;
  121. $this->fileNameResolver = $fileNameResolver;
  122. $this->area = $area;
  123. $this->theme = $theme;
  124. $this->locale = $locale;
  125. $this->isVirtual = $isVirtual;
  126. $this->preProcessors = $preProcessors;
  127. $this->postProcessors = $postProcessors;
  128. }
  129. /**
  130. * @return string
  131. */
  132. public function getArea()
  133. {
  134. return $this->area;
  135. }
  136. /**
  137. * @return Package
  138. */
  139. public function getParent()
  140. {
  141. return $this->parent;
  142. }
  143. /**
  144. * @return string
  145. */
  146. public function getTheme()
  147. {
  148. return $this->theme;
  149. }
  150. /**
  151. * @return string
  152. */
  153. public function getLocale()
  154. {
  155. return $this->locale;
  156. }
  157. /**
  158. * Retrieve package path
  159. *
  160. * @return string
  161. */
  162. public function getPath()
  163. {
  164. return $this->getArea() . '/' . $this->getTheme() . '/' . $this->getLocale();
  165. }
  166. /**
  167. * Is package virtual and can not be referenced directly
  168. *
  169. * Package considered as "virtual" when not all of the scope identifiers defined (area, theme, locale)
  170. *
  171. * @return string
  172. */
  173. public function isVirtual()
  174. {
  175. return $this->isVirtual;
  176. }
  177. /**
  178. * @param string $name
  179. * @return mixed|null
  180. */
  181. public function getParam($name)
  182. {
  183. return isset($this->params[$name]) ? $this->params[$name] : null;
  184. }
  185. /**
  186. * @param string $name
  187. * @param mixed $value
  188. * @return bool
  189. */
  190. public function setParam($name, $value)
  191. {
  192. $this->params[$name] = $value;
  193. return true;
  194. }
  195. /**
  196. * Retrieve theme model
  197. *
  198. * @return ThemeInterface|null
  199. */
  200. public function getThemeModel()
  201. {
  202. return $this->packagePool->getThemeModel($this->getArea(), $this->getTheme());
  203. }
  204. /**
  205. * Retrieve file by file id
  206. *
  207. * @param string $fileId
  208. * @return bool|PackageFile
  209. */
  210. public function getFile($fileId)
  211. {
  212. return isset($this->files[$fileId]) ? $this->files[$fileId] : false;
  213. }
  214. /**
  215. * Add file to package
  216. *
  217. * @param PackageFile $file
  218. * @return string
  219. */
  220. public function addFile(PackageFile $file)
  221. {
  222. if (!$file->getLocale()) {
  223. $file->setLocale($this->getLocale());
  224. }
  225. $this->files[$file->getFileId()] = $file;
  226. $deployedFilePath = $this->getPath() . '/'
  227. . ($file->getModule() ? ($file->getModule() . '/') : '')
  228. . $file->getDeployedFileName();
  229. $file->setDeployedFilePath($deployedFilePath);
  230. return $file->getFileId();
  231. }
  232. /**
  233. * Add file to the package map
  234. *
  235. * @param PackageFile $file
  236. * @return void
  237. */
  238. public function addFileToMap(PackageFile $file)
  239. {
  240. $fileId = $file->getDeployedFileId();
  241. $this->map[$fileId] = [
  242. 'area' => $this->getArea(),
  243. 'theme' => $this->getTheme(),
  244. 'locale' => $this->getLocale()
  245. ];
  246. }
  247. /**
  248. * Retrieve all files
  249. *
  250. * @return PackageFile[]
  251. */
  252. public function getFiles()
  253. {
  254. return $this->files;
  255. }
  256. /**
  257. * Retrieve files by type
  258. *
  259. * @param string $type
  260. * @return array
  261. */
  262. public function getFilesByType($type)
  263. {
  264. $files = [];
  265. /** @var PackageFile $file */
  266. foreach ($this->getFiles() as $fileId => $file) {
  267. if (!$file->getFileName()) {
  268. continue;
  269. }
  270. if ($file->getExtension() == $type) {
  271. $files[$fileId] = $file;
  272. }
  273. }
  274. return $files;
  275. }
  276. /**
  277. * Delete file from package by file id
  278. *
  279. * @param string $fileId
  280. * @return void
  281. */
  282. public function deleteFile($fileId)
  283. {
  284. unset($this->files[$fileId]);
  285. }
  286. /**
  287. * Aggregate files from all parent packages
  288. *
  289. * Optionally, parent package could be passed
  290. *
  291. * @param Package $parentPackage
  292. * @return bool true on success
  293. */
  294. public function aggregate(Package $parentPackage = null)
  295. {
  296. $inheritedFiles = $this->getParentFiles();
  297. foreach ($inheritedFiles as $fileId => $file) {
  298. /** @var PackageFile $file */
  299. if (!$this->getFile($fileId)) {
  300. $file = clone $file;
  301. $file->setPackage($this);
  302. }
  303. }
  304. if ($parentPackage) {
  305. $this->setParent($parentPackage);
  306. }
  307. return true;
  308. }
  309. /**
  310. * @param Package $parent
  311. * @return bool
  312. */
  313. public function setParent($parent)
  314. {
  315. $this->parent = $parent;
  316. return true;
  317. }
  318. /**
  319. * Retrieve map
  320. *
  321. * @return array
  322. */
  323. public function getMap()
  324. {
  325. return $this->map;
  326. }
  327. /**
  328. * @return int
  329. */
  330. public function getState()
  331. {
  332. return $this->state;
  333. }
  334. /**
  335. * @param int $state
  336. * @return bool
  337. */
  338. public function setState($state)
  339. {
  340. $this->state = $state;
  341. return true;
  342. }
  343. /**
  344. * @return int
  345. */
  346. public function getInheritanceLevel()
  347. {
  348. $level = 0;
  349. $theme = $this->getThemeModel();
  350. if ($theme) {
  351. ++$level;
  352. while ($theme = $theme->getParentTheme()) {
  353. ++$level;
  354. }
  355. }
  356. return $level;
  357. }
  358. /**
  359. * Retrieve inherited package map
  360. *
  361. * @return array
  362. */
  363. public function getResultMap()
  364. {
  365. $map = $this->getMap();
  366. $parentMap = $this->getParentMap();
  367. return array_merge($parentMap, $map);
  368. }
  369. /**
  370. * Retrieve parent map
  371. *
  372. * @return array
  373. */
  374. public function getParentMap()
  375. {
  376. $map = [];
  377. foreach ($this->getParentPackages() as $parentPackage) {
  378. $map = array_merge($map, $parentPackage->getMap());
  379. }
  380. return $map;
  381. }
  382. /**
  383. * Retrieve parent files
  384. *
  385. * @param string|null $type
  386. * @return PackageFile[]
  387. */
  388. public function getParentFiles($type = null)
  389. {
  390. $files = [];
  391. foreach ($this->getParentPackages() as $parentPackage) {
  392. if ($type === null) {
  393. $files = array_merge($files, $parentPackage->getFiles());
  394. } else {
  395. $files = array_merge($files, $parentPackage->getFilesByType($type));
  396. }
  397. }
  398. return $files;
  399. }
  400. /**
  401. * Retrieve parent packages list
  402. *
  403. * @return Package[]
  404. */
  405. public function getParentPackages()
  406. {
  407. if ($this->parentPackages === null) {
  408. $this->parentPackages = [];
  409. $parentPaths = [];
  410. $this->collectParentPaths(
  411. $this,
  412. $this->getArea(),
  413. $this->getTheme(),
  414. $this->getLocale(),
  415. $parentPaths,
  416. $this->getThemeModel()
  417. );
  418. // collect packages in reverse order to have closer ancestor goes later
  419. foreach (array_reverse($parentPaths) as $path) {
  420. if ($package = $this->packagePool->getPackage($path)) {
  421. $this->parentPackages[$path] = $package;
  422. }
  423. }
  424. }
  425. return $this->parentPackages;
  426. }
  427. /**
  428. * @return Processor\ProcessorInterface[]
  429. */
  430. public function getPreProcessors()
  431. {
  432. return $this->preProcessors;
  433. }
  434. /**
  435. * @return Processor\ProcessorInterface[]
  436. */
  437. public function getPostProcessors()
  438. {
  439. return $this->postProcessors;
  440. }
  441. /**
  442. * Collect the list of parent packages deployment paths
  443. *
  444. * @param Package $package
  445. * @param string $area
  446. * @param string $theme
  447. * @param string $locale
  448. * @param array $result
  449. * @param ThemeInterface|null $themeModel
  450. * @return void
  451. */
  452. private function collectParentPaths(
  453. Package $package,
  454. $area,
  455. $theme,
  456. $locale,
  457. array & $result = [],
  458. ThemeInterface $themeModel = null
  459. ) {
  460. if (($package->getArea() != $area) || ($package->getTheme() != $theme) || ($package->getLocale() != $locale)) {
  461. $result[] = $area . '/' . $theme . '/' . $locale;
  462. }
  463. if ($locale != $this->packageDefaultValues['locale']) {
  464. $result[] = $area . '/' . $theme . '/' . $this->packageDefaultValues['locale'];
  465. }
  466. if ($themeModel) {
  467. if ($themeModel->getParentTheme()) {
  468. $this->collectParentPaths(
  469. $package,
  470. $area,
  471. $themeModel->getParentTheme()->getThemePath(),
  472. $package->getLocale(),
  473. $result,
  474. $themeModel->getParentTheme()
  475. );
  476. } else {
  477. $this->collectParentPaths(
  478. $package,
  479. $area,
  480. $this->packageDefaultValues['theme'],
  481. $package->getLocale(),
  482. $result
  483. );
  484. }
  485. } else {
  486. if ($area != $this->packageDefaultValues['area']) {
  487. $this->collectParentPaths(
  488. $package,
  489. $this->packageDefaultValues['area'],
  490. $theme,
  491. $package->getLocale(),
  492. $result
  493. );
  494. }
  495. }
  496. }
  497. }