Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
ThemeUninstallCommand.php
Go to the documentation of this file.
1 <?php
8 
20 use Symfony\Component\Console\Command\Command;
21 use Symfony\Component\Console\Input\InputInterface;
22 use Symfony\Component\Console\Output\OutputInterface;
23 use Symfony\Component\Console\Input\InputOption;
24 use Symfony\Component\Console\Input\InputArgument;
27 
34 class ThemeUninstallCommand extends Command
35 {
39  const INPUT_KEY_BACKUP_CODE = 'backup-code';
40  const INPUT_KEY_THEMES = 'theme';
41  const INPUT_KEY_CLEAR_STATIC_CONTENT = 'clear-static-content';
42 
48  private $dependencyChecker;
49 
55  private $composer;
56 
62  private $themeCollection;
63 
69  private $cache;
70 
76  private $cleanupFiles;
77 
83  private $backupRollbackFactory;
84 
90  private $themeValidator;
91 
97  private $themePackageInfo;
98 
104  private $themeUninstaller;
105 
111  private $themeDependencyChecker;
112 
116  private $maintenanceModeEnabler;
117 
136  public function __construct(
137  Cache $cache,
138  CleanupFiles $cleanupFiles,
139  ComposerInformation $composer,
140  MaintenanceMode $maintenanceMode,
141  DependencyChecker $dependencyChecker,
142  Collection $themeCollection,
143  BackupRollbackFactory $backupRollbackFactory,
144  ThemeValidator $themeValidator,
145  ThemePackageInfo $themePackageInfo,
146  ThemeUninstaller $themeUninstaller,
147  ThemeDependencyChecker $themeDependencyChecker,
148  MaintenanceModeEnabler $maintenanceModeEnabler = null
149  ) {
150  $this->cache = $cache;
151  $this->cleanupFiles = $cleanupFiles;
152  $this->composer = $composer;
153  $this->dependencyChecker = $dependencyChecker;
154  $this->themeCollection = $themeCollection;
155  $this->backupRollbackFactory = $backupRollbackFactory;
156  $this->themeValidator = $themeValidator;
157  $this->themePackageInfo = $themePackageInfo;
158  $this->themeUninstaller = $themeUninstaller;
159  $this->themeDependencyChecker = $themeDependencyChecker;
160  $this->maintenanceModeEnabler =
161  $maintenanceModeEnabler ?: ObjectManager::getInstance()->get(MaintenanceModeEnabler::class);
162  parent::__construct();
163  }
164 
168  protected function configure()
169  {
170  $this->setName('theme:uninstall');
171  $this->setDescription('Uninstalls theme');
172  $this->addOption(
173  self::INPUT_KEY_BACKUP_CODE,
174  null,
175  InputOption::VALUE_NONE,
176  'Take code backup (excluding temporary files)'
177  );
178  $this->addArgument(
179  self::INPUT_KEY_THEMES,
180  InputArgument::IS_ARRAY | InputArgument::REQUIRED,
181  'Path of the theme. Theme path should be specified as full path which is area/vendor/name.'
182  . ' For example, frontend/Magento/blank'
183  );
184  $this->addOption(
185  self::INPUT_KEY_CLEAR_STATIC_CONTENT,
186  'c',
187  InputOption::VALUE_NONE,
188  'Clear generated static view files.'
189  );
190  parent::configure();
191  }
192 
196  protected function execute(InputInterface $input, OutputInterface $output)
197  {
198  $messages = [];
199  $themePaths = $input->getArgument(self::INPUT_KEY_THEMES);
200  $messages = array_merge($messages, $this->validate($themePaths));
201  if (!empty($messages)) {
202  $output->writeln($messages);
203  // we must have an exit code higher than zero to indicate something was wrong
204  return \Magento\Framework\Console\Cli::RETURN_FAILURE;
205  }
206  $messages = array_merge(
207  $messages,
208  $this->themeValidator->validateIsThemeInUse($themePaths),
209  $this->themeDependencyChecker->checkChildTheme($themePaths),
210  $this->checkDependencies($themePaths)
211  );
212  if (!empty($messages)) {
213  $output->writeln(
214  '<error>Unable to uninstall. Please resolve the following issues:</error>'
215  . PHP_EOL . implode(PHP_EOL, $messages)
216  );
217  // we must have an exit code higher than zero to indicate something was wrong
218  return \Magento\Framework\Console\Cli::RETURN_FAILURE;
219  }
220 
221  $result = $this->maintenanceModeEnabler->executeInMaintenanceMode(
222  function () use ($input, $output, $themePaths) {
223  try {
224  if ($input->getOption(self::INPUT_KEY_BACKUP_CODE)) {
225  $time = time();
226  $codeBackup = $this->backupRollbackFactory->create($output);
227  $codeBackup->codeBackup($time);
228  }
229 
230  $this->themeUninstaller->uninstallRegistry($output, $themePaths);
231  $this->themeUninstaller->uninstallCode($output, $themePaths);
232 
233  $this->cleanup($input, $output);
234  return \Magento\Framework\Console\Cli::RETURN_SUCCESS;
235  } catch (\Exception $e) {
236  $output->writeln('<error>' . $e->getMessage() . '</error>');
237  $output->writeln('<error>Please disable maintenance mode after you resolved above issues</error>');
238  // we must have an exit code higher than zero to indicate something was wrong
239  return \Magento\Framework\Console\Cli::RETURN_FAILURE;
240  }
241  },
242  $output,
243  true
244  );
245 
246  return $result;
247  }
248 
255  private function validate($themePaths)
256  {
257  $messages = [];
258 
259  $incorrectThemes = $this->getIncorrectThemes($themePaths);
260  if (!empty($incorrectThemes)) {
261  $text = 'Theme path should be specified as full path which is area/vendor/name.';
262  $messages[] = '<error>Incorrect theme(s) format: ' . implode(', ', $incorrectThemes)
263  . '. ' . $text . '</error>';
264  return $messages;
265  }
266 
267  $unknownPackages = $this->getUnknownPackages($themePaths);
268  $unknownThemes = $this->getUnknownThemes($themePaths);
269 
270  $unknownPackages = array_diff($unknownPackages, $unknownThemes);
271  if (!empty($unknownPackages)) {
272  $text = count($unknownPackages) > 1 ?
273  ' are not installed Composer packages' : ' is not an installed Composer package';
274  $messages[] = '<error>' . implode(', ', $unknownPackages) . $text . '</error>';
275  }
276 
277  if (!empty($unknownThemes)) {
278  $messages[] = '<error>Unknown theme(s): ' . implode(', ', $unknownThemes) . '</error>';
279  }
280 
281  return $messages;
282  }
283 
290  protected function getIncorrectThemes($themePaths)
291  {
292  $result = [];
293  foreach ($themePaths as $themePath) {
294  if (!preg_match('/^[^\/]+\/[^\/]+\/[^\/]+$/', $themePath)) {
295  $result[] = $themePath;
296  continue;
297  }
298  }
299  return $result;
300  }
301 
308  protected function getUnknownPackages($themePaths)
309  {
310  $installedPackages = $this->composer->getRootRequiredPackages();
311 
312  $result = [];
313  foreach ($themePaths as $themePath) {
314  if (array_search($this->themePackageInfo->getPackageName($themePath), $installedPackages) === false) {
315  $result[] = $themePath;
316  }
317  }
318  return $result;
319  }
320 
327  protected function getUnknownThemes($themePaths)
328  {
329  $result = [];
330  foreach ($themePaths as $themePath) {
331  if (!$this->themeCollection->hasTheme($this->themeCollection->getThemeByFullPath($themePath))) {
332  $result[] = $themePath;
333  }
334  }
335  return $result;
336  }
337 
344  private function checkDependencies($themePaths)
345  {
346  $messages = [];
347  $packageToPath = [];
348  foreach ($themePaths as $themePath) {
349  $packageToPath[$this->themePackageInfo->getPackageName($themePath)] = $themePath;
350  }
351  $dependencies = $this->dependencyChecker->checkDependencies(array_keys($packageToPath), true);
352  foreach ($dependencies as $package => $dependingPackages) {
353  if (!empty($dependingPackages)) {
354  $messages[] =
355  '<error>' . $packageToPath[$package] .
356  " has the following dependent package(s):</error>" .
357  PHP_EOL . "\t<error>" . implode('</error>' . PHP_EOL . "\t<error>", $dependingPackages)
358  . "</error>";
359  }
360  }
361  return $messages;
362  }
363 
371  private function cleanup(InputInterface $input, OutputInterface $output)
372  {
373  $this->cache->clean();
374  $output->writeln('<info>Cache cleared successfully.</info>');
375 
376  if ($input->getOption(self::INPUT_KEY_CLEAR_STATIC_CONTENT)) {
377  $this->cleanupFiles->clearMaterializedViewFiles();
378  $output->writeln('<info>Generated static view files cleared successfully.</info>');
379  } else {
380  $output->writeln(
381  '<error>Alert: Generated static view files were not cleared.'
382  . ' You can clear them using the --' . self::INPUT_KEY_CLEAR_STATIC_CONTENT . ' option.'
383  . ' Failure to clear static view files might cause display issues in the Admin and storefront.</error>'
384  );
385  }
386  }
387 }
__construct(Cache $cache, CleanupFiles $cleanupFiles, ComposerInformation $composer, MaintenanceMode $maintenanceMode, DependencyChecker $dependencyChecker, Collection $themeCollection, BackupRollbackFactory $backupRollbackFactory, ThemeValidator $themeValidator, ThemePackageInfo $themePackageInfo, ThemeUninstaller $themeUninstaller, ThemeDependencyChecker $themeDependencyChecker, MaintenanceModeEnabler $maintenanceModeEnabler=null)
endifif( $block->getLastPageNum()>1)( 'Page') ?></strong >< ul class $text
Definition: pager.phtml:43
execute(InputInterface $input, OutputInterface $output)