* @copyright Since 2007 PrestaShop SA and Contributors * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 */ declare(strict_types=1); namespace PrestaShop\Module\Mbo\Module\CommandHandler; use Exception; use PrestaShop\Module\Mbo\Addons\Exception\DownloadModuleException; use PrestaShop\Module\Mbo\Helpers\ModuleErrorHelper; use PrestaShop\Module\Mbo\Module\ActionsManager; use PrestaShop\Module\Mbo\Module\Command\ModuleStatusTransitionCommand; use PrestaShop\Module\Mbo\Module\Exception\ModuleNewVersionNotFoundException; use PrestaShop\Module\Mbo\Module\Exception\TransitionCommandToModuleStatusException; use PrestaShop\Module\Mbo\Module\Exception\UnauthorizedModuleTransitionException; use PrestaShop\Module\Mbo\Module\Exception\UnexpectedModuleSourceContentException; use PrestaShop\Module\Mbo\Module\Module; use PrestaShop\Module\Mbo\Module\ModuleBuilder; use PrestaShop\Module\Mbo\Module\Repository; use PrestaShop\Module\Mbo\Module\TransitionModule; use PrestaShop\Module\Mbo\Module\ValueObject\ModuleTransitionCommand; use PrestaShop\Module\Mbo\Module\Workflow\TransitionApplier; use PrestaShop\Module\Mbo\Module\Workflow\TransitionBuilder; use PrestaShop\Module\Mbo\Module\Workflow\TransitionInterface; use PrestaShop\PrestaShop\Core\Module\SourceHandler\SourceHandlerNotFoundException; final class ModuleStatusTransitionCommandHandler { /** * @var Repository */ private $moduleRepository; /** * @var ActionsManager */ private $actionsManager; /** * @var ModuleBuilder */ private $moduleBuilder; /** * @var TransitionBuilder */ private $transitionBuilder; /** * @var TransitionApplier */ private $transitionApplier; public function __construct( Repository $moduleRepository, ActionsManager $actionsManager, ModuleBuilder $moduleBuilder, TransitionBuilder $transitionBuilder, TransitionApplier $transitionApplier ) { $this->moduleRepository = $moduleRepository; $this->actionsManager = $actionsManager; $this->moduleBuilder = $moduleBuilder; $this->transitionBuilder = $transitionBuilder; $this->transitionApplier = $transitionApplier; } /** * @throws Exception */ public function handle(ModuleStatusTransitionCommand $command): Module { $moduleName = $command->getModuleName(); $moduleId = $command->getModuleId(); $moduleVersion = $command->getModuleVersion(); $source = $command->getSource(); // First get the module from DB // If not exist, get it from the Module Distribution API $dbModule = $this->moduleRepository->findInDatabaseByName($moduleName); $module = new TransitionModule( $moduleName, $dbModule ? $dbModule['version'] : $moduleVersion, $dbModule ? $dbModule['installed'] : false, $dbModule ? $dbModule['active_on_mobile'] : false, $dbModule ? $dbModule['active'] : false ); // Check if transition asked can be mapped to an existing target status $transitionCommand = $command->getCommand()->getValue(); // Download a module before upgrade is not an actual module transition, we do not use the StateMachine if (ModuleTransitionCommand::MODULE_COMMAND_DOWNLOAD === $transitionCommand) { if (null === $source) { $source = $this->actionsManager->downloadModule($moduleId); } $this->actionsManager->downloadAndReplaceModuleFiles($moduleName, $source); } else { if ( !array_key_exists( $transitionCommand, ModuleTransitionCommand::MAPPING_TRANSITION_COMMAND_TARGET_STATUS ) ) { throw ModuleErrorHelper::reportAndConvertError( new TransitionCommandToModuleStatusException($command) ); } // Compute the state machine transition name $transitionName = $this->transitionBuilder->getTransition( $module, $transitionCommand ); // Do nothing, just return the module if ($transitionName === TransitionInterface::NO_CHANGE_TRANSITION) { return $this->buildModuleAndReturn($moduleName); } // Execute the transition $this->transitionApplier->apply($module, $transitionName, [ 'source' => $source, ]); } return $this->buildModuleAndReturn($moduleName); } protected function buildModuleAndReturn(string $moduleName): Module { $this->moduleRepository->clearCache(); $stdModule = new \stdClass(); $stdModule->name = $moduleName; return $this->moduleBuilder->build( $stdModule, $this->moduleRepository->findInDatabaseByName($moduleName) ); } }