Registration.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Theme\Model\Theme;
  7. use Magento\Framework\Filesystem;
  8. use Magento\Framework\Exception\LocalizedException;
  9. use Magento\Framework\View\Design\ThemeInterface;
  10. /**
  11. * Theme registration model class
  12. */
  13. class Registration
  14. {
  15. /**
  16. * @var \Magento\Theme\Model\ResourceModel\Theme\Data\CollectionFactory
  17. */
  18. protected $_collectionFactory;
  19. /**
  20. * Collection of themes in file-system
  21. *
  22. * @var Collection
  23. */
  24. protected $_themeCollection;
  25. /**
  26. * Allowed sequence relation by type, array(parent theme, child theme)
  27. *
  28. * @var array
  29. */
  30. protected $_allowedRelations = [
  31. [ThemeInterface::TYPE_PHYSICAL, ThemeInterface::TYPE_VIRTUAL],
  32. [ThemeInterface::TYPE_VIRTUAL, ThemeInterface::TYPE_STAGING],
  33. ];
  34. /**
  35. * Forbidden sequence relation by type
  36. *
  37. * @var array
  38. */
  39. protected $_forbiddenRelations = [
  40. [ThemeInterface::TYPE_VIRTUAL, ThemeInterface::TYPE_VIRTUAL],
  41. [ThemeInterface::TYPE_PHYSICAL, ThemeInterface::TYPE_STAGING],
  42. ];
  43. /**
  44. * Initialize dependencies
  45. *
  46. * @param \Magento\Theme\Model\ResourceModel\Theme\Data\CollectionFactory $collectionFactory
  47. * @param \Magento\Theme\Model\Theme\Data\Collection $filesystemCollection
  48. */
  49. public function __construct(
  50. \Magento\Theme\Model\ResourceModel\Theme\Data\CollectionFactory $collectionFactory,
  51. \Magento\Theme\Model\Theme\Data\Collection $filesystemCollection
  52. ) {
  53. $this->_collectionFactory = $collectionFactory;
  54. $this->_themeCollection = $filesystemCollection;
  55. }
  56. /**
  57. * Theme registration
  58. *
  59. * @return $this
  60. */
  61. public function register()
  62. {
  63. $this->_themeCollection->clear();
  64. foreach ($this->_themeCollection as $theme) {
  65. $this->_registerThemeRecursively($theme);
  66. }
  67. $this->checkPhysicalThemes()->checkAllowedThemeRelations();
  68. return $this;
  69. }
  70. /**
  71. * Register theme and recursively all its ascendants
  72. * Second param is optional and is used to prevent circular references in inheritance chain
  73. *
  74. * @param ThemeInterface &$theme
  75. * @param array $inheritanceChain
  76. * @return $this
  77. * @throws LocalizedException
  78. */
  79. protected function _registerThemeRecursively(&$theme, $inheritanceChain = [])
  80. {
  81. if ($theme->getId()) {
  82. return $this;
  83. }
  84. $themeModel = $this->getThemeFromDb($theme->getFullPath());
  85. if ($themeModel->getId()) {
  86. $theme = $themeModel;
  87. return $this;
  88. }
  89. $tempId = $theme->getFullPath();
  90. if (in_array($tempId, $inheritanceChain)) {
  91. throw new LocalizedException(__('Circular-reference in theme inheritance detected for "%1"', $tempId));
  92. }
  93. $inheritanceChain[] = $tempId;
  94. $parentTheme = $theme->getParentTheme();
  95. if ($parentTheme) {
  96. $this->_registerThemeRecursively($parentTheme, $inheritanceChain);
  97. $theme->setParentId($parentTheme->getId());
  98. }
  99. $this->_savePreviewImage($theme);
  100. $theme->setType(ThemeInterface::TYPE_PHYSICAL);
  101. $theme->save();
  102. return $this;
  103. }
  104. /**
  105. * Save preview image for theme
  106. *
  107. * @param ThemeInterface $theme
  108. * @return $this
  109. */
  110. protected function _savePreviewImage(ThemeInterface $theme)
  111. {
  112. $themeDirectory = $theme->getCustomization()->getThemeFilesPath();
  113. if (!$theme->getPreviewImage() || !$themeDirectory) {
  114. return $this;
  115. }
  116. $imagePath = $themeDirectory . '/' . $theme->getPreviewImage();
  117. if (0 === strpos($imagePath, $themeDirectory)) {
  118. $theme->getThemeImage()->createPreviewImage($imagePath);
  119. }
  120. return $this;
  121. }
  122. /**
  123. * Get theme from DB by full path
  124. *
  125. * @param string $fullPath
  126. * @return ThemeInterface
  127. */
  128. public function getThemeFromDb($fullPath)
  129. {
  130. return $this->_collectionFactory->create()->getThemeByFullPath($fullPath);
  131. }
  132. /**
  133. * Checks all physical themes that they were not deleted
  134. *
  135. * @return $this
  136. */
  137. public function checkPhysicalThemes()
  138. {
  139. $themes = $this->_collectionFactory->create()->addTypeFilter(ThemeInterface::TYPE_PHYSICAL);
  140. /** @var $theme ThemeInterface */
  141. foreach ($themes as $theme) {
  142. if (!$this->_themeCollection->hasTheme($theme)) {
  143. $theme->setType(ThemeInterface::TYPE_VIRTUAL)->save();
  144. }
  145. }
  146. return $this;
  147. }
  148. /**
  149. * Check whether all themes have correct parent theme by type
  150. *
  151. * @return $this
  152. */
  153. public function checkAllowedThemeRelations()
  154. {
  155. foreach ($this->_forbiddenRelations as $typesSequence) {
  156. list($parentType, $childType) = $typesSequence;
  157. $collection = $this->_collectionFactory->create();
  158. $collection->addTypeRelationFilter($parentType, $childType);
  159. /** @var $theme ThemeInterface */
  160. foreach ($collection as $theme) {
  161. $parentId = $this->_getResetParentId($theme);
  162. if ($theme->getParentId() != $parentId) {
  163. $theme->setParentId($parentId)->save();
  164. }
  165. }
  166. }
  167. return $this;
  168. }
  169. /**
  170. * Reset parent themes by type
  171. *
  172. * @param ThemeInterface $theme
  173. * @return int|null
  174. */
  175. protected function _getResetParentId(ThemeInterface $theme)
  176. {
  177. $parentTheme = $theme->getParentTheme();
  178. while ($parentTheme) {
  179. foreach ($this->_allowedRelations as $typesSequence) {
  180. list($parentType, $childType) = $typesSequence;
  181. if ($theme->getType() == $childType && $parentTheme->getType() == $parentType) {
  182. return $parentTheme->getId();
  183. }
  184. }
  185. $parentTheme = $parentTheme->getParentTheme();
  186. }
  187. return null;
  188. }
  189. }