CopyService.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. /**
  7. * Service of copying customizations from one theme to another
  8. */
  9. namespace Magento\Theme\Model;
  10. use Magento\Framework\App\Filesystem\DirectoryList;
  11. use Magento\Framework\View\Design\ThemeInterface;
  12. class CopyService
  13. {
  14. /**
  15. * @var \Magento\Framework\Filesystem\Directory\Write
  16. */
  17. protected $_directory;
  18. /**
  19. * @var \Magento\Framework\View\Design\Theme\FileFactory
  20. */
  21. protected $_fileFactory;
  22. /**
  23. * @var \Magento\Widget\Model\Layout\Link
  24. */
  25. protected $_link;
  26. /**
  27. * @var \Magento\Widget\Model\Layout\UpdateFactory
  28. */
  29. protected $_updateFactory;
  30. /**
  31. * @var \Magento\Framework\Event\ManagerInterface
  32. */
  33. protected $_eventManager;
  34. /**
  35. * @var \Magento\Framework\View\Design\Theme\Customization\Path
  36. */
  37. protected $_customizationPath;
  38. /**
  39. * @param \Magento\Framework\Filesystem $filesystem
  40. * @param \Magento\Framework\View\Design\Theme\FileFactory $fileFactory
  41. * @param \Magento\Widget\Model\Layout\Link $link
  42. * @param \Magento\Widget\Model\Layout\UpdateFactory $updateFactory
  43. * @param \Magento\Framework\Event\ManagerInterface $eventManager
  44. * @param \Magento\Framework\View\Design\Theme\Customization\Path $customization
  45. */
  46. public function __construct(
  47. \Magento\Framework\Filesystem $filesystem,
  48. \Magento\Framework\View\Design\Theme\FileFactory $fileFactory,
  49. \Magento\Widget\Model\Layout\Link $link,
  50. \Magento\Widget\Model\Layout\UpdateFactory $updateFactory,
  51. \Magento\Framework\Event\ManagerInterface $eventManager,
  52. \Magento\Framework\View\Design\Theme\Customization\Path $customization
  53. ) {
  54. $this->_directory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
  55. $this->_fileFactory = $fileFactory;
  56. $this->_link = $link;
  57. $this->_updateFactory = $updateFactory;
  58. $this->_eventManager = $eventManager;
  59. $this->_customizationPath = $customization;
  60. }
  61. /**
  62. * Copy customizations from one theme to another
  63. *
  64. * @param ThemeInterface $source
  65. * @param ThemeInterface $target
  66. * @return void
  67. */
  68. public function copy(ThemeInterface $source, ThemeInterface $target)
  69. {
  70. $this->_copyDatabaseCustomization($source, $target);
  71. $this->_copyLayoutCustomization($source, $target);
  72. $this->_copyFilesystemCustomization($source, $target);
  73. }
  74. /**
  75. * Copy customizations stored in a database from one theme to another, overriding existing data
  76. *
  77. * @param ThemeInterface $source
  78. * @param ThemeInterface $target
  79. * @return void
  80. */
  81. protected function _copyDatabaseCustomization(ThemeInterface $source, ThemeInterface $target)
  82. {
  83. /** @var $themeFile \Magento\Theme\Model\Theme\File */
  84. foreach ($target->getCustomization()->getFiles() as $themeFile) {
  85. $themeFile->delete();
  86. }
  87. /** @var $newFile \Magento\Theme\Model\Theme\File */
  88. foreach ($source->getCustomization()->getFiles() as $themeFile) {
  89. /** @var $newThemeFile \Magento\Theme\Model\Theme\File */
  90. $newThemeFile = $this->_fileFactory->create();
  91. $newThemeFile->setData(
  92. [
  93. 'theme_id' => $target->getId(),
  94. 'file_path' => $themeFile->getFilePath(),
  95. 'file_type' => $themeFile->getFileType(),
  96. 'content' => $themeFile->getContent(),
  97. 'sort_order' => $themeFile->getData('sort_order'),
  98. ]
  99. );
  100. $newThemeFile->save();
  101. }
  102. }
  103. /**
  104. * Add layout links to general layout updates for themes
  105. *
  106. * @param ThemeInterface $source
  107. * @param ThemeInterface $target
  108. * @return void
  109. */
  110. protected function _copyLayoutCustomization(ThemeInterface $source, ThemeInterface $target)
  111. {
  112. $update = $this->_updateFactory->create();
  113. /** @var $targetUpdates \Magento\Widget\Model\ResourceModel\Layout\Update\Collection */
  114. $targetUpdates = $update->getCollection();
  115. $targetUpdates->addThemeFilter($target->getId());
  116. $targetUpdates->delete();
  117. /** @var $sourceCollection \Magento\Widget\Model\ResourceModel\Layout\Link\Collection */
  118. $sourceCollection = $this->_link->getCollection();
  119. $sourceCollection->addThemeFilter($source->getId());
  120. /** @var $layoutLink \Magento\Widget\Model\Layout\Link */
  121. foreach ($sourceCollection as $layoutLink) {
  122. /** @var $update \Magento\Widget\Model\Layout\Update */
  123. $update = $this->_updateFactory->create();
  124. $update->load($layoutLink->getLayoutUpdateId());
  125. if ($update->getId()) {
  126. $update->setId(null);
  127. $update->save();
  128. $layoutLink->setThemeId($target->getId());
  129. $layoutLink->setLayoutUpdateId($update->getId());
  130. $layoutLink->setId(null);
  131. $layoutLink->save();
  132. }
  133. }
  134. }
  135. /**
  136. * Copy customizations stored in a file system from one theme to another, overriding existing data
  137. *
  138. * @param ThemeInterface $source
  139. * @param ThemeInterface $target
  140. * @return void
  141. */
  142. protected function _copyFilesystemCustomization(ThemeInterface $source, ThemeInterface $target)
  143. {
  144. $sourcePath = $this->_customizationPath->getCustomizationPath($source);
  145. $targetPath = $this->_customizationPath->getCustomizationPath($target);
  146. if (!$sourcePath || !$targetPath) {
  147. return;
  148. }
  149. $this->_deleteFilesRecursively($targetPath);
  150. if ($this->_directory->isDirectory($sourcePath)) {
  151. $this->_copyFilesRecursively($sourcePath, $sourcePath, $targetPath);
  152. }
  153. }
  154. /**
  155. * Copies all files in a directory recursively
  156. *
  157. * @param string $baseDir
  158. * @param string $sourceDir
  159. * @param string $targetDir
  160. * @return void
  161. */
  162. protected function _copyFilesRecursively($baseDir, $sourceDir, $targetDir)
  163. {
  164. foreach ($this->_directory->read($sourceDir) as $path) {
  165. if ($this->_directory->isDirectory($path)) {
  166. $this->_copyFilesRecursively($baseDir, $path, $targetDir);
  167. } else {
  168. $filePath = substr($path, strlen($baseDir) + 1);
  169. $this->_directory->copyFile($path, $targetDir . '/' . $filePath);
  170. }
  171. }
  172. }
  173. /**
  174. * Delete all files in a directory recursively
  175. *
  176. * @param string $targetDir
  177. * @return void
  178. */
  179. protected function _deleteFilesRecursively($targetDir)
  180. {
  181. if ($this->_directory->isExist($targetDir)) {
  182. foreach ($this->_directory->read($targetDir) as $path) {
  183. $this->_directory->delete($path);
  184. }
  185. }
  186. }
  187. }