diff --git a/src/DependencyBuilder.php b/src/DependencyBuilder.php index 495968b..f5670b0 100644 --- a/src/DependencyBuilder.php +++ b/src/DependencyBuilder.php @@ -2,11 +2,18 @@ namespace Prestashop\ModuleLibMboInstaller; +use Prestashop\ModuleLibGuzzleAdapter\Interfaces\ClientExceptionInterface; use Symfony\Component\Routing\Router; class DependencyBuilder { const DEPENDENCY_FILENAME = 'ps_dependencies.json'; + const GET_PARAMETER = 'mbo_action_needed'; + const INSTALL_ACTION = 'install'; + const ENABLE_ACTION = 'enable'; + const APP_STATE_LAUNCHABLE = 'launchable'; + const APP_STATE_MBO_IN_PROGRESS = 'mbo_in_progress'; + const APP_STATE_AUTOSTART = 'autostart'; /** * @var \ModuleCore @@ -29,9 +36,69 @@ public function __construct($module) $this->buildRouter(); } + /** + * Handle dependencies behavior and return dependencies data array to be given to the CDC + * + * @return array{ + * "module_display_name": string, + * "module_name": string, + * "module_version": string, + * "ps_version": string, + * "php_version": string, + * "locale": string, + * "dependencies": array + * } + * + * @throws \Exception|ClientExceptionInterface + */ + public function handleDependencies() + { + $appState = $this->handleMboInstallation(); + + return $this->buildDependenciesContext($appState); + } + + /** + * Install or enable the MBO depending on the action requested + * + * @return string + * + * @throws \Exception|ClientExceptionInterface + */ + protected function handleMboInstallation() + { + if (!isset($_GET[self::GET_PARAMETER])) { + return self::APP_STATE_LAUNCHABLE; + } + + $mboStatus = (new Presenter())->present(); + $installer = new Installer(_PS_VERSION_); + + if ($mboStatus['isInstalled'] && $mboStatus['isEnabled']) { + return self::APP_STATE_AUTOSTART; + } + + if (!$mboStatus['isInstalled']) { + $installer->installModule(); + } elseif (!$mboStatus['isEnabled']) { + $installer->enableModule(); + } + + // Force another refresh of the page to correctly clear the cache and load MBO configurations + header('Refresh:0'); + // To avoid wasting time rerendering the entire page, die immediately + return self::APP_STATE_MBO_IN_PROGRESS; + } + /** * Build the dependencies data array to be given to the CDC * + * @param string $appState + * * @return array{ * "module_display_name": string, * "module_name": string, @@ -39,8 +106,8 @@ public function __construct($module) * "ps_version": string, * "php_version": string, * "locale": string, + * "app_state": string, * "dependencies": array (string) $this->module->displayName, @@ -57,6 +124,7 @@ public function buildDependencies() 'module_version' => (string) $this->module->version, 'ps_version' => (string) _PS_VERSION_, 'php_version' => (string) PHP_VERSION, + 'app_state' => $appState, 'dependencies' => [], ]; @@ -84,13 +152,23 @@ public function buildDependencies() } if (!is_array($dependenciesContent) || empty($dependenciesContent['dependencies']) || !is_array($dependenciesContent['dependencies'])) { + $mboDependencyData = $this->addMboInDependencies(); + + if ($mboDependencyData) { + $data['dependencies'][Installer::MODULE_NAME] = $mboDependencyData; + } + return $data; } - foreach ($dependenciesContent['dependencies'] as $dependencyName => $dependencyMinVersion) { + if (!isset($dependenciesContent['dependencies'][Installer::MODULE_NAME])) { + $dependenciesContent['dependencies'][] = Installer::MODULE_NAME; + } + + foreach ($dependenciesContent['dependencies'] as $dependencyName) { $dependencyData = \DbCore::getInstance()->getRow('SELECT `id_module`, `active`, `version` FROM `' . _DB_PREFIX_ . 'module` WHERE `name` = "' . pSQL((string) $dependencyName) . '"'); - $data['dependencies'][$dependencyName] = array_merge(['min_version' => (string) $dependencyMinVersion], $this->buildRoutesForModule($dependencyName)); + $data['dependencies'][$dependencyName] = $this->buildRoutesForModule($dependencyName); if (!$dependencyData) { $data['dependencies'][$dependencyName]['installed'] = false; continue; @@ -137,13 +215,33 @@ protected function buildRouter() $container = $kernel->getContainer(); if (!$container instanceof \Symfony\Component\DependencyInjection\ContainerInterface) { - throw new \Exception('Unable to retrieve Symfony ContainerInterface.'); + throw new \Exception('Unable to retrieve Symfony container.'); } $router = $container->get('router'); if (!$router instanceof Router) { - throw new \Exception('Unable to retrieve Symfony Router.'); + throw new \Exception('Unable to retrieve Symfony router.'); } $this->router = $router; } + + /** + * @return array|null + */ + protected function addMboInDependencies() + { + $mboStatus = (new Presenter())->present(); + + if ((bool) $mboStatus['isEnabled']) { + return null; + } + + $mboRoutes = $this->buildRoutesForModule(Installer::MODULE_NAME); + + return array_merge([ + 'current_version' => (string) $mboStatus['version'], + 'installed' => (bool) $mboStatus['isInstalled'], + 'enabled' => false, + ], $mboRoutes); + } } diff --git a/src/Installer.php b/src/Installer.php index 70da181..4ea461c 100644 --- a/src/Installer.php +++ b/src/Installer.php @@ -4,6 +4,7 @@ use GuzzleHttp\Psr7\Request; use Prestashop\ModuleLibGuzzleAdapter\ClientFactory; +use Prestashop\ModuleLibGuzzleAdapter\Interfaces\ClientExceptionInterface; use Prestashop\ModuleLibGuzzleAdapter\Interfaces\HttpClientInterface; use PrestaShop\PrestaShop\Core\Addon\Module\ModuleManagerBuilder; @@ -30,6 +31,8 @@ class Installer /** * @param string $prestashopVersion + * + * @throws \Exception */ public function __construct($prestashopVersion) { @@ -47,6 +50,8 @@ public function __construct($prestashopVersion) * Installs ps_mbo module * * @return bool + * + * @throws ClientExceptionInterface */ public function installModule() { @@ -59,10 +64,24 @@ public function installModule() return $this->moduleManagerBuilder->build()->install(self::MODULE_NAME); } + /** + * Enable ps_mbo module + * + * @return bool + * + * @throws \Exception + */ + public function enableModule() + { + return $this->moduleManagerBuilder->build()->enable(self::MODULE_NAME); + } + /** * Downloads ps_mbo module source from addons, store it and returns the file name * * @return string + * + * @throws \Exception|ClientExceptionInterface */ private function downloadModule() {