From 748eb89197e92e80935461bcf19d443d325bc6dd Mon Sep 17 00:00:00 2001 From: "lenaick.moreira" Date: Wed, 12 Aug 2026 09:54:02 +0200 Subject: [PATCH] =?UTF-8?q?N=C2=B09904=20-=20Add=20explanation=20message?= =?UTF-8?q?=20when=20"Check=20compatibility"=20button=20is=20not=20availab?= =?UTF-8?q?le?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup/wizardsteps/WizStepModulesChoice.php | 96 ++++++++++++++----- .../setup/WizStepModulesChoiceTest.php | 2 +- 2 files changed, 71 insertions(+), 27 deletions(-) diff --git a/setup/wizardsteps/WizStepModulesChoice.php b/setup/wizardsteps/WizStepModulesChoice.php index 91b3873a7..768c99a64 100644 --- a/setup/wizardsteps/WizStepModulesChoice.php +++ b/setup/wizardsteps/WizStepModulesChoice.php @@ -51,6 +51,8 @@ class WizStepModulesChoice extends AbstractWizStepInstall private array $aAnalyzeInstallationModules = []; private ?MissingDependencyException $oMissingDependencyException = null; + private array $aFlagsByChoiceId = []; + public function __construct(WizardController $oWizard, $sCurrentState, bool $bOverWriteConfig = true) { parent::__construct($oWizard, $sCurrentState); @@ -290,6 +292,34 @@ class WizStepModulesChoice extends AbstractWizStepInstall $oPage->warning($sManualInstallError); } + // Build the default choices + $aDefaults = $this->GetDefaults($aStepInfo, $this->aAnalyzeInstallationModules); + $index = $this->GetStepIndex(); + + // retrieve the saved selection + // use json_encode:decode to store a hash array: step_id => array(input_name => selected_input_id) + $aParameters = json_decode($this->oWizard->GetParameter('selected_components', '{}'), true); + if (!isset($aParameters[$index])) { + $aParameters[$index] = $aDefaults; + } + $aSelectedComponents = $aParameters[$index]; + + $bDisableUninstallCheck = (bool)$this->oWizard->GetParameter('force-uninstall', false); + + $aOptions = $aStepInfo['options'] ?? []; + foreach ($aOptions as $index => $aChoice) { + $sChoiceId = self::$SEP.$index; + $this->ComputeChoiceFlags($aChoice, $sChoiceId, $aSelectedComponents, false, $bDisableUninstallCheck); + } + + if (!$this->bCanMoveForward) { + if (SetupUtils::IsConnectableToITopHub($this->aAnalyzeInstallationModules)) { + $oPage->error('Due to some inconsistencies the upgrade can\'t continue. You must deactivate "consistency protections" in the previous steps and restore a consistent environment.'); + } else { + $oPage->error('Due to some inconsistencies the upgrade can\'t continue, please contact Combodo support.'); + } + } + $oPage->add('
'); $sBannerPath = isset($aStepInfo['banner']) ? $aStepInfo['banner'] : ''; if (!empty($sBannerPath)) { @@ -308,18 +338,6 @@ class WizStepModulesChoice extends AbstractWizStepInstall $oPage->add(''.$sDescription.''); $oPage->add('
'); - // Build the default choices - $aDefaults = $this->GetDefaults($aStepInfo, $this->aAnalyzeInstallationModules); - $index = $this->GetStepIndex(); - - // retrieve the saved selection - // use json_encode:decode to store a hash array: step_id => array(input_name => selected_input_id) - $aParameters = json_decode($this->oWizard->GetParameter('selected_components', '{}'), true); - if (!isset($aParameters[$index])) { - $aParameters[$index] = $aDefaults; - } - $aSelectedComponents = $aParameters[$index]; - $oPage->add('
'); $this->DisplayOptions($oPage, $aStepInfo, $aSelectedComponents, $aDefaults); $oPage->add('
'); @@ -742,8 +760,12 @@ EOF return $this->aSteps[$index] ?? null; } - public function ComputeChoiceFlags(array $aChoice, string $sChoiceId, array $aSelectedComponents, bool $bAllDisabled, bool $bDisableUninstallCheck, bool $bUpgradeMode) + public function ComputeChoiceFlags(array $aChoice, string $sChoiceId, array $aSelectedComponents, bool $bAllDisabled, bool $bDisableUninstallCheck) { + if (array_key_exists($sChoiceId, $this->aFlagsByChoiceId)) { + return $this->aFlagsByChoiceId[$sChoiceId]; + } + $oITopExtension = $this->oExtensionsMap->GetFromExtensionCode($aChoice['extension_code']); //If the extension is missing from disk, it won't exist in the ExtensionsMap, thus returning null $bCanBeUninstalled = isset($aChoice['uninstallable']) ? $aChoice['uninstallable'] === true || $aChoice['uninstallable'] === 'yes' : $oITopExtension->CanBeUninstalled(); @@ -784,7 +806,7 @@ EOF $aOptions = $aChoice['sub_options']['options'] ?? []; foreach ($aOptions as $index => $aSubChoice) { $sSubChoiceId = $sChoiceId.self::$SEP.$index; - $aSubFlags = $this->ComputeChoiceFlags($aSubChoice, $sSubChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck, $bUpgradeMode); + $aSubFlags = $this->ComputeChoiceFlags($aSubChoice, $sSubChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck); if ($aSubFlags['checked']) { $bChecked = true; if ($aSubFlags['disabled']) { @@ -796,7 +818,7 @@ EOF } } - return [ + $aFlags = [ 'uninstallable' => $bCanBeUninstalled, 'dependency_issue' => $bDependencyIssue, 'mandatory' => $bMandatory, @@ -805,6 +827,11 @@ EOF 'disabled' => $bDisabled, 'checked' => $bChecked, ]; + + $this->bCanMoveForward = $this->bCanMoveForward && $this->CanMoveForwardFromChoiceFlags($aFlags, $bDisableUninstallCheck); + $this->aFlagsByChoiceId[$sChoiceId] = $aFlags; + + return $aFlags; } public function DisplayOptions($oPage, $aStepInfo, $aSelectedComponents, $aDefaults, $sParentId = '', $bAllDisabled = false) @@ -816,16 +843,7 @@ EOF foreach ($aOptions as $index => $aChoice) { $sChoiceId = $sParentId.self::$SEP.$index; - $aFlags = $this->ComputeChoiceFlags($aChoice, $sChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck, $this->bUpgrade); - - if (!$aFlags['checked'] && $aFlags['installed'] && !$bDisableUninstallCheck && (!$aFlags['uninstallable'] || $aFlags['mandatory'])) { - // If the user cannot uninstall a mandatory extension, he cannot move forward unless he uses the "force-uninstall" option - // The same applies if the extension is not uninstallable (i.e. a product extension) - $this->bCanMoveForward = false; - } elseif ($aFlags['checked'] && $aFlags['disabled'] && $aFlags['dependency_issue'] && !$bDisableUninstallCheck) { - // If there is a dependency issue on a selected and disabled extension, the user cannot move forward unless he uses the "force-uninstall" option - $this->bCanMoveForward = false; - } + $aFlags = $this->ComputeChoiceFlags($aChoice, $sChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck); $this->DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId, $sChoiceId, $aFlags); } @@ -864,7 +882,7 @@ EOF $bSelected = ($sChoiceId === $sChoiceIdNone); } - $aFlags = $this->ComputeChoiceFlags($aChoice, $sChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck, $this->bUpgrade); + $aFlags = $this->ComputeChoiceFlags($aChoice, $sChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck); //ComputeChoiceFlags does not completely compute alternative flags $aFlags['disabled'] = $bDisabled; $aFlags['checked'] = $bSelected; @@ -872,6 +890,32 @@ EOF } } + protected function CanMoveForwardFromChoiceFlags(array $aFlags, bool $bDisableUninstallCheck): bool + { + // The user can force to move forward with the "force-uninstall" option + if ($bDisableUninstallCheck) { + return true; + } + + if ($aFlags['checked']) { + // An extension cannot be installed if it has a dependency issue + if ($aFlags['disabled'] && $aFlags['dependency_issue']) { + return false; + } + } elseif ($aFlags['installed']) { + // An extension cannot be uninstalled if it is not uninstallable + if (!$aFlags['uninstallable']) { + return false; + } + // An extension cannot be uninstalled if it is mandatory + if ($aFlags['mandatory']) { + return false; + } + } + + return true; + } + protected function DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceName, $sChoiceId, $aFlags, $sInputType = 'checkbox') { $sMoreInfo = (isset($aChoice['more_info']) && ($aChoice['more_info'] != '')) ? ' diff --git a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php index d9ae25d2e..62473cdd5 100644 --- a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php @@ -592,7 +592,7 @@ class WizStepModulesChoiceTest extends ItopTestCase public function testComputeChoiceFlags($aExtensionsOnDiskOrDb, $aWizardStepDefinition, $bIsCurrentSelected, $bDisableUninstallChecks, $aExpectedFlags) { $this->oWizStepModulesChoiceFake->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensionsOnDiskOrDb)); - $aFlags = $this->oWizStepModulesChoiceFake->ComputeChoiceFlags($aWizardStepDefinition, '_0', $bIsCurrentSelected ? ['_0' => '_0'] : [], false, $bDisableUninstallChecks, true); + $aFlags = $this->oWizStepModulesChoiceFake->ComputeChoiceFlags($aWizardStepDefinition, '_0', $bIsCurrentSelected ? ['_0' => '_0'] : [], false, $bDisableUninstallChecks); $this->assertEquals($aExpectedFlags, $aFlags); }