IndexerSetDimensionsModeCommand.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. declare(strict_types=1);
  7. namespace Magento\Indexer\Console\Command;
  8. use Symfony\Component\Console\Input\InputInterface;
  9. use Symfony\Component\Console\Output\OutputInterface;
  10. use Symfony\Component\Console\Input\InputArgument;
  11. use Magento\Framework\App\ObjectManagerFactory;
  12. use Magento\Framework\App\Config\ScopeConfigInterface;
  13. use Magento\Framework\Console\Cli;
  14. use Magento\Indexer\Model\ModeSwitcherInterface;
  15. /**
  16. * Command to set indexer dimensions mode
  17. */
  18. class IndexerSetDimensionsModeCommand extends AbstractIndexerCommand
  19. {
  20. const INPUT_KEY_MODE = 'mode';
  21. const INPUT_KEY_INDEXER = 'indexer';
  22. const DIMENSION_MODE_NONE = 'none';
  23. const XML_PATH_DIMENSIONS_MODE_MASK = 'indexer/%s/dimensions_mode';
  24. /**
  25. * @var string
  26. */
  27. private $commandName = 'indexer:set-dimensions-mode';
  28. /**
  29. * ScopeConfigInterface
  30. *
  31. * @var ScopeConfigInterface
  32. */
  33. private $configReader;
  34. /**
  35. * @var ModeSwitcherInterface[]
  36. */
  37. private $dimensionProviders;
  38. /**
  39. * @param ObjectManagerFactory $objectManagerFactory
  40. * @param ScopeConfigInterface $configReader
  41. * @param ModeSwitcherInterface[] $dimensionSwitchers
  42. */
  43. public function __construct(
  44. ObjectManagerFactory $objectManagerFactory,
  45. ScopeConfigInterface $configReader,
  46. array $dimensionSwitchers
  47. ) {
  48. $this->configReader = $configReader;
  49. $this->dimensionProviders = $dimensionSwitchers;
  50. parent::__construct($objectManagerFactory);
  51. }
  52. /**
  53. * {@inheritdoc}
  54. */
  55. protected function configure()
  56. {
  57. $this->setName($this->commandName)
  58. ->setDescription('Set Indexer Dimensions Mode')
  59. ->setDefinition($this->getInputList());
  60. parent::configure();
  61. }
  62. /**
  63. * {@inheritdoc}
  64. * @param InputInterface $input
  65. * @param OutputInterface $output
  66. * @return int
  67. */
  68. protected function execute(InputInterface $input, OutputInterface $output)
  69. {
  70. $errors = $this->validate($input);
  71. if ($errors) {
  72. throw new \InvalidArgumentException(implode(PHP_EOL, $errors));
  73. }
  74. $returnValue = Cli::RETURN_SUCCESS;
  75. /** @var \Magento\Indexer\Model\Indexer $indexer */
  76. $indexer = $this->getObjectManager()->get(\Magento\Indexer\Model\Indexer::class);
  77. try {
  78. $selectedIndexer = (string)$input->getArgument(self::INPUT_KEY_INDEXER);
  79. if (!$selectedIndexer) {
  80. $this->showAvailableModes($output);
  81. } else {
  82. $indexer->load($selectedIndexer);
  83. $currentMode = $input->getArgument(self::INPUT_KEY_MODE);
  84. $configPath = sprintf(self::XML_PATH_DIMENSIONS_MODE_MASK, $selectedIndexer);
  85. $previousMode = $this->configReader->getValue($configPath) ?: self::DIMENSION_MODE_NONE;
  86. if ($previousMode !== $currentMode) {
  87. /** @var ModeSwitcherInterface $modeSwitcher */
  88. $modeSwitcher = $this->dimensionProviders[$selectedIndexer];
  89. // Switch dimensions mode
  90. $modeSwitcher->switchMode($currentMode, $previousMode);
  91. $output->writeln(
  92. 'Dimensions mode for indexer "' . $indexer->getTitle() . '" was changed from \''
  93. . $previousMode . '\' to \'' . $currentMode . '\''
  94. );
  95. } else {
  96. $output->writeln('Dimensions mode for indexer "' . $indexer->getTitle() . '" has not been changed');
  97. }
  98. }
  99. } catch (\Exception $e) {
  100. $output->writeln('"' . $indexer->getTitle() . '" indexer process unknown error:' . PHP_EOL);
  101. $output->writeln($e->getMessage() . PHP_EOL);
  102. // we must have an exit code higher than zero to indicate something was wrong
  103. $returnValue = Cli::RETURN_FAILURE;
  104. }
  105. return $returnValue;
  106. }
  107. /**
  108. * Display all available indexers and modes
  109. *
  110. * @param OutputInterface $output
  111. * @return void
  112. */
  113. private function showAvailableModes(OutputInterface $output)
  114. {
  115. $output->writeln(sprintf('%-50s', 'Indexer') . 'Available modes');
  116. foreach ($this->dimensionProviders as $indexer => $provider) {
  117. $availableModes = implode(',', array_keys($provider->getDimensionModes()->getDimensions()));
  118. $output->writeln(sprintf('%-50s', $indexer) . $availableModes);
  119. }
  120. }
  121. /**
  122. * Get list of arguments for the command
  123. *
  124. * @return InputArgument[]
  125. */
  126. private function getInputList(): array
  127. {
  128. $dimensionProvidersList = array_keys($this->dimensionProviders);
  129. $indexerOptionDescription = 'Indexer name [' . implode('|', $dimensionProvidersList) . ']';
  130. $arguments[] = new InputArgument(
  131. self::INPUT_KEY_INDEXER,
  132. InputArgument::OPTIONAL,
  133. $indexerOptionDescription
  134. );
  135. $modeOptionDescription = 'Indexer dimension modes' . PHP_EOL;
  136. foreach ($this->dimensionProviders as $indexer => $provider) {
  137. $availableModes = implode(',', array_keys($provider->getDimensionModes()->getDimensions()));
  138. $modeOptionDescription .= sprintf('%-30s ', $indexer) . $availableModes . PHP_EOL;
  139. }
  140. $arguments[] = new InputArgument(
  141. self::INPUT_KEY_MODE,
  142. InputArgument::OPTIONAL,
  143. $modeOptionDescription
  144. );
  145. return $arguments;
  146. }
  147. /**
  148. * Check if all arguments are provided
  149. *
  150. * @param InputInterface $input
  151. * @return string[]
  152. */
  153. private function validate(InputInterface $input): array
  154. {
  155. $errors = [];
  156. $inputIndexer = (string)$input->getArgument(self::INPUT_KEY_INDEXER);
  157. if ($inputIndexer) {
  158. $acceptedValues = array_keys($this->dimensionProviders);
  159. $errors = $this->validateArgument(self::INPUT_KEY_INDEXER, $inputIndexer, $acceptedValues);
  160. if (!$errors) {
  161. $inputIndexerDimensionMode = (string)$input->getArgument(self::INPUT_KEY_MODE);
  162. /** @var ModeSwitcherInterface $modeSwitcher */
  163. $modeSwitcher = $this->dimensionProviders[$inputIndexer];
  164. $acceptedValues = array_keys($modeSwitcher->getDimensionModes()->getDimensions());
  165. $errors = $this->validateArgument(self::INPUT_KEY_MODE, $inputIndexerDimensionMode, $acceptedValues);
  166. }
  167. }
  168. return $errors;
  169. }
  170. /**
  171. * Validate command argument and return errors in case if argument is invalid
  172. *
  173. * @param string $inputKey
  174. * @param string $inputIndexer
  175. * @param array $acceptedValues
  176. * @return string[]
  177. */
  178. private function validateArgument(string $inputKey, string $inputIndexer, array $acceptedValues): array
  179. {
  180. $errors = [];
  181. $acceptedIndexerValues = ' Accepted values for "<' . $inputKey . '>" are \'' .
  182. implode(',', $acceptedValues) . '\'';
  183. if (!$inputIndexer) {
  184. $errors[] = 'Missing argument "<' . $inputKey . '>".' . $acceptedIndexerValues;
  185. } elseif (!\in_array($inputIndexer, $acceptedValues)) {
  186. $errors[] = 'Invalid value for "<' . $inputKey . '>" argument.' . $acceptedIndexerValues;
  187. }
  188. return $errors;
  189. }
  190. }