diff --git a/setup/wizardsteps.class.inc.php b/setup/wizardsteps.class.inc.php
index d80f2d146f..148da3011e 100644
--- a/setup/wizardsteps.class.inc.php
+++ b/setup/wizardsteps.class.inc.php
@@ -1562,7 +1562,7 @@ EOF
}
}
- $aAlternatives = isset($aInfo['alternatives']) ? $aInfo['alternatives'] : [];
+ $aAlternatives = $aInfo['alternatives'] ?? [];
$sChoiceName = null;
foreach ($aAlternatives as $index => $aChoice) {
$sChoiceId = $sParentId.self::$SEP.$index;
@@ -1953,10 +1953,47 @@ EOF
return '';
}
+ public function ComputeChoiceFlags(array $aChoice, string $sChoiceId, array $aSelectedComponents, bool $bAllDisabled, bool $bDisableUninstallCheck, bool $bUpgradeMode)
+ {
+ $oITopExtension = $this->oExtensionsMap->GetFromExtensionCode($aChoice['extension_code']);
+ $bCanBeUninstalled = isset($aChoice['uninstallable']) ? $aChoice['uninstallable'] === true || $aChoice['uninstallable'] === 'yes' : $oITopExtension->CanBeUninstalled();
+ $bSelected = isset($aSelectedComponents[$sChoiceId]) && ($aSelectedComponents[$sChoiceId] == $sChoiceId);
+ $bMandatory = (isset($aChoice['mandatory']) && $aChoice['mandatory']) || $bUpgradeMode && $oITopExtension->bInstalled && !$bCanBeUninstalled && !$bDisableUninstallCheck;
+
+ $bMissingFromDisk = isset($aChoice['missing']) && $aChoice['missing'] === true;
+ $bInstalled = $bMissingFromDisk || $oITopExtension->bInstalled;
+ $bDisabled = $bMandatory || $bAllDisabled || $bMissingFromDisk;
+ $bChecked = $bMandatory || $bSelected;
+
+ if (isset($aChoice['sub_options'])) {
+ $aOptions = $aChoice['sub_options']['options'] ?? [];
+ foreach ($aOptions as $index => $aSubChoice) {
+ $sSubChoiceId = $sChoiceId.self::$SEP.$index;
+ $aSubFlags = $this->ComputeChoiceFlags($aSubChoice, $sSubChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck, $bUpgradeMode);
+ if ($aSubFlags['checked']) {
+ $bChecked = true;
+ if ($aSubFlags['disabled']) {
+ //If some sub options are enabled and cannot be disabled, this choice should also cannot be disabled since it would disable all its sub options
+ $bDisabled = true;
+ }
+ }
+
+ }
+ }
+
+ return [
+ 'uninstallable' => $bCanBeUninstalled,
+ 'missing' => $bMissingFromDisk,
+ 'installed' => $bInstalled,
+ 'disabled' => $bDisabled,
+ 'checked' => $bChecked,
+ ];
+ }
+
protected function DisplayOptions($oPage, $aStepInfo, $aSelectedComponents, $aDefaults, $sParentId = '', $bAllDisabled = false)
{
- $aOptions = isset($aStepInfo['options']) ? $aStepInfo['options'] : [];
- $aAlternatives = isset($aStepInfo['alternatives']) ? $aStepInfo['alternatives'] : [];
+ $aOptions = $aStepInfo['options'] ?? [];
+ $aAlternatives = $aStepInfo['alternatives'] ?? [];
$bDisableUninstallCheck = (bool)$this->oWizard->GetParameter('force-uninstall', false);
@@ -1964,43 +2001,33 @@ EOF
$sChoiceId = $sParentId.self::$SEP.$index;
$sDataId = 'data-id="'.utils::EscapeHtml($aChoice['extension_code']).'"';
$sId = utils::EscapeHtml($aChoice['extension_code']);
- $bIsDefault = array_key_exists($sChoiceId, $aDefaults);
-
- $oITopExtension = $this->oExtensionsMap->GetFromExtensionCode($aChoice['extension_code']);
- $bCanBeUninstalled = isset($aChoice['uninstallable']) ? $aChoice['uninstallable'] : $oITopExtension->CanBeUninstalled();
- $bSelected = isset($aSelectedComponents[$sChoiceId]) && ($aSelectedComponents[$sChoiceId] == $sChoiceId);
- $bMandatory = (isset($aChoice['mandatory']) && $aChoice['mandatory']) || $this->bUpgrade && $bIsDefault && !$bCanBeUninstalled && !$bDisableUninstallCheck;
- ;
- $bMissingFromDisk = isset($aChoice['missing']) && $aChoice['missing'] === true;
- $bInstalled = $bMissingFromDisk || $oITopExtension->bInstalled;
- $bDisabled = $bMandatory || $bAllDisabled || $bMissingFromDisk;
- $bChecked = $bMandatory || $bSelected;
+ $aFlags = static::ComputeChoiceFlags($aChoice, $sChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck, $this->bUpgrade);
$sTooltip = '';
$sUnremovable = '';
- if ($bMissingFromDisk) {
+ if ($aFlags['missing']) {
$sTooltip .= 'source removed';
}
- if ($bInstalled) {
+ if ($aFlags['installed']) {
$sTooltip .= 'installed';
$sTooltip .= 'to be uninstalled';
} else {
$sTooltip .= 'to be installed';
$sTooltip .= 'not installed';
}
- if (!$bCanBeUninstalled) {
+ if (!$aFlags['uninstallable']) {
$sTooltip .= 'cannot be uninstalled';
}
- if ($bDisabled && !$bChecked && !$bCanBeUninstalled && !$bDisableUninstallCheck) {
+ if ($aFlags['disabled'] && !$aFlags['checked'] && !$aFlags['uninstallable'] && !$bDisableUninstallCheck) {
$this->bCanMoveForward = false;//Disable "Next"
}
- $sChecked = $bChecked ? ' checked ' : '';
- $sDisabled = $bDisabled ? ' disabled data-disabled="disabled" ' : '';
- $sMissingModule = $bMissingFromDisk ? 'setup-extension--missing' : '';
+ $sChecked = $aFlags['checked'] ? ' checked ' : '';
+ $sDisabled = $aFlags['disabled'] ? ' disabled data-disabled="disabled" ' : '';
+ $sMissingModule = $aFlags['missing'] ? 'setup-extension--missing' : '';
- $sHiddenInput = $bDisabled && $bChecked ? '' : '';
+ $sHiddenInput = $aFlags['disabled'] && $aFlags['checked'] ? '' : '';
$oPage->add('
'.$sHiddenInput.' ');
- $this->DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId, $bDisabled, $sTooltip);
+ $this->DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId, $aFlags['disabled'], $sTooltip);
$oPage->add('
');
}
$sChoiceName = null;
@@ -2035,7 +2062,6 @@ EOF
$sChoiceId = $sParentId.self::$SEP.$index;
$sDataId = 'data-id="'.utils::EscapeHtml($aChoice['extension_code']).'"';
$sId = utils::EscapeHtml($aChoice['extension_code']);
-
if ($sChoiceName == null) {
$sChoiceName = $sChoiceId; // All radios share the same name
}
diff --git a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceFake.php b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceFake.php
new file mode 100644
index 0000000000..69a99b3dd1
--- /dev/null
+++ b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceFake.php
@@ -0,0 +1,14 @@
+oExtensionsMap = $oMap;
+ }
+}
diff --git a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php
new file mode 100644
index 0000000000..11a11fd46c
--- /dev/null
+++ b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php
@@ -0,0 +1,260 @@
+RequireOnceItopFile('/setup/unattended-install/InstallationFileService.php');
+ require_once __DIR__.'/iTopExtensionsMapFake.php';
+ require_once __DIR__.'/WizStepModulesChoiceFake.php';
+
+ $this->oStep = new \WizStepModulesChoiceFake(new WizardController('', ''), '');
+ ModuleDiscovery::ResetCache();
+ }
+
+ public function ProviderComputeChoiceFlags()
+ {
+ return [
+ 'selected but not installed extension' => [
+ 'aExtensions' => [
+ 'itop-ext1' => [
+ 'installed' => false,
+ ],
+ ],
+ 'bUpgrade' => false,
+ 'bDisableUninstallCheck' => false,
+ 'sChoiceId' => '_0',
+ 'aStepInfo' => [
+ 'extension_code' => 'itop-ext1',
+ 'mandatory' => false,
+ 'uninstallable' => true,
+ ],
+ 'aSelected' => ['_0' => '_0'],
+ 'aExpectedFlags' => [
+ 'uninstallable' => true,
+ 'missing' => false,
+ 'installed' => false,
+ 'disabled' => false,
+ 'checked' => true,
+ ],
+ ],
+ 'not selected, not installed extension' => [
+ 'aExtensions' => [
+ 'itop-ext1' => [
+ 'installed' => false,
+ ],
+ ],
+ 'bUpgrade' => true,
+ 'bDisableUninstallCheck' => false,
+ 'sChoiceId' => '_0',
+ 'aStepInfo' => [
+ 'extension_code' => 'itop-ext1',
+ 'mandatory' => false,
+ 'uninstallable' => true,
+ ],
+ 'aSelected' => [],
+ 'aExpectedFlags' => [
+ 'uninstallable' => true,
+ 'missing' => false,
+ 'installed' => false,
+ 'disabled' => false,
+ 'checked' => false,
+ ],
+ ],
+ 'installed extension' => [
+ 'aExtensions' => [
+ 'itop-ext1' => [
+ 'installed' => true,
+ ],
+ ],
+ 'bUpgrade' => true,
+ 'bDisableUninstallCheck' => false,
+ 'sChoiceId' => '_0',
+ 'aStepInfo' => [
+ 'extension_code' => 'itop-ext1',
+ 'mandatory' => false,
+ 'uninstallable' => true,
+ ],
+ 'aSelected' => [],
+ 'aExpectedFlags' => [
+ 'uninstallable' => true,
+ 'missing' => false,
+ 'installed' => true,
+ 'disabled' => false,
+ 'checked' => false,
+ ],
+ ],
+ 'installed non uninstallable extension' => [
+ 'aExtensions' => [
+ 'itop-ext1' => [
+ 'installed' => true,
+ ],
+ ],
+ 'bUpgrade' => true,
+ 'bDisableUninstallCheck' => false,
+ 'sChoiceId' => '_0',
+ 'aStepInfo' => [
+ 'extension_code' => 'itop-ext1',
+ 'mandatory' => false,
+ 'uninstallable' => false,
+ ],
+ 'aSelected' => [],
+ 'aExpectedFlags' => [
+ 'uninstallable' => false,
+ 'missing' => false,
+ 'installed' => true,
+ 'disabled' => true,
+ 'checked' => true,
+ ],
+ ],
+ 'mandatory extension' => [
+ 'aExtensions' => [
+ 'itop-ext1' => [
+ 'installed' => false,
+ ],
+ ],
+ 'bUpgrade' => true,
+ 'bDisableUninstallCheck' => false,
+ 'sChoiceId' => '_0',
+ 'aStepInfo' => [
+ 'extension_code' => 'itop-ext1',
+ 'mandatory' => true,
+ 'uninstallable' => true,
+ ],
+ 'aSelected' => [],
+ 'aExpectedFlags' => [
+ 'uninstallable' => true,
+ 'missing' => false,
+ 'installed' => false,
+ 'disabled' => true,
+ 'checked' => true,
+ ],
+ ],
+ 'optional sub extension' => [
+ 'aExtensions' => [
+ 'itop-ext1' => [
+ 'installed' => false,
+ ],
+ 'itop-ext1-1' => [
+ 'installed' => false,
+ ],
+ ],
+ 'bUpgrade' => true,
+ 'bDisableUninstallCheck' => false,
+ 'sChoiceId' => '_0',
+ 'aStepInfo' => [
+ 'extension_code' => 'itop-ext1',
+ 'mandatory' => false,
+ 'uninstallable' => true,
+ 'sub_options' => [
+ 'options' => [
+ [
+ 'extension_code' => 'itop-ext1-1',
+ 'mandatory' => false,
+ 'uninstallable' => true,
+ ],
+ ],
+ ],
+ ],
+ 'aSelected' => [],
+ 'aExpectedFlags' => [
+ 'uninstallable' => true,
+ 'missing' => false,
+ 'installed' => false,
+ 'disabled' => false,
+ 'checked' => false,
+ ],
+ ],
+ 'mandatory sub extension' => [
+ 'aExtensions' => [
+ 'itop-ext1' => [
+ 'installed' => false,
+ ],
+ 'itop-ext1-1' => [
+ 'installed' => false,
+ ],
+ ],
+ 'bUpgrade' => true,
+ 'bDisableUninstallCheck' => false,
+ 'sChoiceId' => '_0',
+ 'aStepInfo' => [
+ 'extension_code' => 'itop-ext1',
+ 'mandatory' => false,
+ 'uninstallable' => true,
+ 'sub_options' => [
+ 'options' => [
+ [
+ 'extension_code' => 'itop-ext1-1',
+ 'mandatory' => true,
+ 'uninstallable' => true,
+ ],
+ ],
+ ],
+ ],
+ 'aSelected' => [],
+ 'aExpectedFlags' => [
+ 'uninstallable' => true,
+ 'missing' => false,
+ 'installed' => false,
+ 'disabled' => true,
+ 'checked' => true,
+ ],
+ ],
+ 'non uninstallable sub extension' => [
+ 'aExtensions' => [
+ 'itop-ext1' => [
+ 'installed' => true,
+ ],
+ 'itop-ext1-1' => [
+ 'installed' => true,
+ ],
+ ],
+ 'bUpgrade' => true,
+ 'bDisableUninstallCheck' => false,
+ 'sChoiceId' => '_0',
+ 'aStepInfo' => [
+ 'extension_code' => 'itop-ext1',
+ 'mandatory' => false,
+ 'uninstallable' => true,
+ 'sub_options' => [
+ 'options' => [
+ [
+ 'extension_code' => 'itop-ext1-1',
+ 'mandatory' => false,
+ 'uninstallable' => false,
+ ],
+ ],
+ ],
+ ],
+ 'aSelected' => [],
+ 'aExpectedFlags' => [
+ 'uninstallable' => true,
+ 'missing' => false,
+ 'installed' => true,
+ 'disabled' => true,
+ 'checked' => true,
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider ProviderComputeChoiceFlags
+ */
+ public function testComputeChoiceFlags($aExtensions, $bUpgrade, $bDisableUninstallCheck, $sChoiceId, $aStepInfo, $aSelected, $aExpectedFlags)
+ {
+ $this->oStep->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensions));
+ $aFlags = $this->oStep->ComputeChoiceFlags($aStepInfo, $sChoiceId, $aSelected, false, $bDisableUninstallCheck, $bUpgrade);
+ $this->assertEquals($aExpectedFlags, $aFlags);
+ }
+
+}
diff --git a/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php b/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php
new file mode 100644
index 0000000000..e80b88eb6e
--- /dev/null
+++ b/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php
@@ -0,0 +1,27 @@
+aExtensions = [];
+ $this->aExtensionsByCode = [];
+ $this->aScannedDirs = [];
+ }
+
+ public static function createFromArray($aExtensions)
+ {
+ $oMap = new static();
+ foreach ($aExtensions as $sCode => $aExtension) {
+ $oExtension = new iTopExtension();
+ $oExtension->sCode = $sCode;
+ $oExtension->bInstalled = $aExtension['installed'];
+ $oExtension->aModules = $aExtension['modules'] ?? [];
+ $oExtension->bCanBeUninstalled = $aExtension['uninstallable'] ?? null;
+ $oExtension->sVersion = $aExtension['version'] ?? '1.0.0';
+ $oExtension->aModuleInfo = [];
+ $oMap->AddExtension($oExtension);
+ }
+ return $oMap;
+ }
+}