PackagePool.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  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\Collector\Collector;
  8. use Magento\Deploy\Console\DeployStaticOptions as Options;
  9. use Magento\Framework\AppInterface;
  10. use Magento\Framework\View\Design\ThemeInterface;
  11. use Magento\Framework\View\Design\Theme\ListInterface;
  12. /**
  13. * Deployment Packages Pool class
  14. */
  15. class PackagePool
  16. {
  17. /**
  18. * @var Collector
  19. */
  20. private $collector;
  21. /**
  22. * @var ThemeInterface[]
  23. */
  24. private $themes;
  25. /**
  26. * @var PackageFactory
  27. */
  28. private $packageFactory;
  29. /**
  30. * @var Package[]
  31. */
  32. private $packages = [];
  33. /**
  34. * @var bool
  35. */
  36. private $collected = false;
  37. /**
  38. * PackagePool constructor
  39. *
  40. * @param Collector $collector
  41. * @param ListInterface $themeCollection
  42. * @param PackageFactory $packageFactory
  43. */
  44. public function __construct(
  45. Collector $collector,
  46. ListInterface $themeCollection,
  47. PackageFactory $packageFactory
  48. ) {
  49. $this->collector = $collector;
  50. $themeCollection->clear()->resetConstraints();
  51. $this->themes = $themeCollection->getItems();
  52. $this->packageFactory = $packageFactory;
  53. }
  54. /**
  55. * @param string $path
  56. * @return Package|null
  57. */
  58. public function getPackage($path)
  59. {
  60. $this->collect();
  61. return isset($this->packages[$path]) ? $this->packages[$path] : null;
  62. }
  63. /**
  64. * @return Package[]
  65. */
  66. public function getPackages()
  67. {
  68. $this->collect();
  69. return $this->packages;
  70. }
  71. /**
  72. * @param string $areaCode
  73. * @param string $themePath
  74. * @return ThemeInterface|null
  75. */
  76. public function getThemeModel($areaCode, $themePath)
  77. {
  78. $theme = $this->getThemeByFullPath($areaCode . '/' . $themePath);
  79. if ($theme && !$theme->getThemePath()) {
  80. $theme->setThemePath($themePath);
  81. }
  82. return $theme;
  83. }
  84. /**
  85. * @param array $options
  86. * @return Package[]
  87. */
  88. public function getPackagesForDeployment(array $options)
  89. {
  90. $this->collect();
  91. $this->ensurePackagesForRequiredLocales($options);
  92. $toSkip = [];
  93. $toDeploy = [];
  94. foreach ($this->packages as $path => $package) {
  95. if ($this->checkPackageSkip($package, $options)) {
  96. $toSkip[$path] = $package;
  97. continue;
  98. } else {
  99. $toDeploy[$path] = $package;
  100. }
  101. }
  102. foreach ($toSkip as $path => $package) {
  103. if (!$this->isAncestorForDeployedPackages($package, $toDeploy)) {
  104. unset($this->packages[$path]);
  105. }
  106. }
  107. return $this->packages;
  108. }
  109. /**
  110. * Check if package has related child packages which are must be deployed
  111. *
  112. * @param Package $excludedPackage
  113. * @param Package[] $deployedPackages
  114. * @return bool
  115. */
  116. private function isAncestorForDeployedPackages(Package $excludedPackage, array $deployedPackages)
  117. {
  118. foreach ($deployedPackages as $deployedPackage) {
  119. $parents = $deployedPackage->getParentPackages();
  120. if (array_key_exists($excludedPackage->getPath(), $parents)) {
  121. return true;
  122. }
  123. }
  124. return false;
  125. }
  126. /**
  127. * @param string $fullPath
  128. * @return ThemeInterface|null
  129. */
  130. private function getThemeByFullPath($fullPath)
  131. {
  132. foreach ($this->themes as $theme) {
  133. if ($theme->getFullPath() === $fullPath) {
  134. return $theme;
  135. }
  136. }
  137. return null;
  138. }
  139. /**
  140. * @param bool $recollect
  141. * @return void
  142. */
  143. private function collect($recollect = false)
  144. {
  145. if (!$this->collected || $recollect) {
  146. $this->packages = $this->collector->collect();
  147. $this->collected = true;
  148. }
  149. }
  150. /**
  151. * Create required packages according to provided options
  152. *
  153. * @param array $options
  154. * @return void
  155. */
  156. private function ensurePackagesForRequiredLocales(array $options)
  157. {
  158. $this->ensureRequiredLocales($options);
  159. $resultPackages = $this->packages;
  160. /** @var ThemeInterface $theme */
  161. foreach ($this->themes as $theme) {
  162. $inheritedThemes = $theme->getInheritedThemes();
  163. foreach ($resultPackages as $package) {
  164. if ($package->getTheme() === Package::BASE_THEME) {
  165. continue;
  166. }
  167. foreach ($inheritedThemes as $inheritedTheme) {
  168. if ($package->getTheme() === $inheritedTheme->getThemePath()
  169. && $package->getArea() === $inheritedTheme->getArea()
  170. ) {
  171. $this->ensurePackage([
  172. 'area' => $package->getArea(),
  173. 'theme' => $theme->getThemePath(),
  174. 'locale' => $package->getLocale(),
  175. 'isVirtual' => $package->getLocale() == Package::BASE_LOCALE
  176. ]);
  177. }
  178. }
  179. }
  180. }
  181. }
  182. /**
  183. * Make sure that packages for all requested locales are created
  184. *
  185. * @param array $options
  186. * @return void
  187. */
  188. private function ensureRequiredLocales(array $options)
  189. {
  190. if (empty($options[Options::LANGUAGE]) || $options[Options::LANGUAGE][0] === 'all') {
  191. $forcedLocales = [AppInterface::DISTRO_LOCALE_CODE];
  192. } else {
  193. $forcedLocales = $options[Options::LANGUAGE];
  194. }
  195. $resultPackages = $this->packages;
  196. foreach ($resultPackages as $package) {
  197. if ($package->getTheme() === Package::BASE_THEME) {
  198. continue;
  199. }
  200. foreach ($forcedLocales as $locale) {
  201. $this->ensurePackage([
  202. 'area' => $package->getArea(),
  203. 'theme' => $package->getTheme(),
  204. 'locale' => $locale
  205. ]);
  206. }
  207. }
  208. }
  209. /**
  210. * Check if package can be deployed
  211. *
  212. * @param Package $package
  213. * @param array $options
  214. * @return bool
  215. */
  216. private function checkPackageSkip(Package $package, array $options)
  217. {
  218. return !$this->canDeployArea($package, $options)
  219. || !$this->canDeployTheme($package, $options)
  220. || !$this->canDeployLocale($package, $options);
  221. }
  222. /**
  223. * @param Package $package
  224. * @param array $options
  225. * @return bool
  226. */
  227. private function canDeployArea(Package $package, array $options)
  228. {
  229. $area = $package->getArea();
  230. if ($area == 'install') {
  231. return false;
  232. }
  233. if ($area == Package::BASE_AREA) {
  234. return true;
  235. }
  236. $exclude = $this->getOption(Options::EXCLUDE_AREA, $options);
  237. $include = $this->getOption(Options::AREA, $options);
  238. return $this->isIncluded($area, $include, $exclude);
  239. }
  240. /**
  241. * @param Package $package
  242. * @param array $options
  243. * @return bool
  244. */
  245. private function canDeployTheme(Package $package, array $options)
  246. {
  247. $theme = $package->getTheme();
  248. if ($theme == Package::BASE_THEME) {
  249. return true;
  250. }
  251. $exclude = $this->getOption(Options::EXCLUDE_THEME, $options);
  252. $include = $this->getOption(Options::THEME, $options);
  253. return $this->isIncluded($theme, $include, $exclude);
  254. }
  255. /**
  256. * @param Package $package
  257. * @param array $options
  258. * @return bool
  259. */
  260. private function canDeployLocale(Package $package, array $options)
  261. {
  262. $locale = $package->getLocale();
  263. if ($locale == Package::BASE_LOCALE) {
  264. return true;
  265. }
  266. $exclude = $this->getOption(Options::EXCLUDE_LANGUAGE, $options);
  267. $include = $this->getOption(Options::LANGUAGE, $options);
  268. return $this->isIncluded($locale, $include, $exclude);
  269. }
  270. /**
  271. * @param string $entity
  272. * @param array $includedEntities
  273. * @param array $excludedEntities
  274. * @return bool
  275. */
  276. private function isIncluded($entity, array $includedEntities, array $excludedEntities)
  277. {
  278. $result = true;
  279. if ($includedEntities[0] === 'all' && $excludedEntities[0] === 'none') {
  280. $result = true;
  281. } elseif ($excludedEntities[0] !== 'none') {
  282. $result = !in_array($entity, $excludedEntities);
  283. } elseif ($includedEntities[0] !== 'all') {
  284. $result = in_array($entity, $includedEntities);
  285. }
  286. return $result;
  287. }
  288. /**
  289. * @param string $name
  290. * @param array $options
  291. * @return mixed|null
  292. */
  293. private function getOption($name, $options)
  294. {
  295. return isset($options[$name]) ? $options[$name] : null;
  296. }
  297. /**
  298. * @param array $params
  299. * @return void
  300. */
  301. private function ensurePackage(array $params)
  302. {
  303. $packagePath = "{$params['area']}/{$params['theme']}/{$params['locale']}";
  304. if (!isset($this->packages[$packagePath])) {
  305. $this->packages[$packagePath] = $this->packageFactory->create($params);
  306. }
  307. }
  308. }