diff --git a/setup/feature_removal/DryRemovalRuntimeEnvironment.php b/setup/feature_removal/DryRemovalRuntimeEnvironment.php index 2aae85620..22a7286e1 100644 --- a/setup/feature_removal/DryRemovalRuntimeEnvironment.php +++ b/setup/feature_removal/DryRemovalRuntimeEnvironment.php @@ -4,7 +4,7 @@ namespace Combodo\iTop\Setup\FeatureRemoval; use Combodo\iTop\Setup\ModuleDependency\Module; use Config; -use InstallationChoicesService; +use InstallationChoicesToModuleConverter; use iTopExtensionsMap; use MetaModel; use ModuleDiscovery; @@ -57,7 +57,7 @@ class DryRemovalRuntimeEnvironment extends RunTimeEnvironment $aModulesToLoad = $this->GetModulesToLoad($sSourceEnv, $aSearchDirs); - ModuleDiscovery::GetAvailableModules($aSearchDirs, true, $aModulesToLoad); + ModuleDiscovery::GetModulesOrderedByDependencies($aSearchDirs, true, $aModulesToLoad); } private function DeclareExtensionAsRemoved(array $aExtensionCodes): void @@ -77,7 +77,7 @@ class DryRemovalRuntimeEnvironment extends RunTimeEnvironment $sInstallFilePath = null; } - $aModuleIdsToLoad = InstallationChoicesService::GetInstance()->GetInstalledModules($aChoices, $aSearchDirs, $sInstallFilePath); + $aModuleIdsToLoad = InstallationChoicesToModuleConverter::GetInstance()->GetModules($aChoices, $aSearchDirs, $sInstallFilePath); $aModulesToLoad = []; foreach ($aModuleIdsToLoad as $sModuleId) { $oModule = new Module($sModuleId); diff --git a/setup/moduleinstallation/InstallationChoicesToModuleConverter.php b/setup/moduleinstallation/InstallationChoicesToModuleConverter.php new file mode 100644 index 000000000..d2416a992 --- /dev/null +++ b/setup/moduleinstallation/InstallationChoicesToModuleConverter.php @@ -0,0 +1,190 @@ +Get('steps', []); + if (!is_array($aSteps)) { + return []; + } + } else { + $aSteps = $aInstallationChoices; + } + + $aInstalledModuleNames = $this->FindInstalledPackageModules($aPackageModules, $aInstallationChoices, $aSteps, $bInstallationFileProvided); + + $aInstalledModules = []; + foreach (array_keys($aPackageModules) as $sModuleId) { + list($sModuleName) = ModuleDiscovery::GetModuleName($sModuleId); + if (in_array($sModuleName, $aInstalledModuleNames)) { + $aInstalledModules[] = $sModuleId; + } + } + + return $aInstalledModules; + } + + private function FindInstalledPackageModules(array $aPackageModules, array $aInstallationChoices, array $aInstallationDescription, bool $bInstallationFileProvided): array + { + $aInstalledModules = []; + + $this->ProcessDefaultModules($aPackageModules, $aInstalledModules); + + if ($bInstallationFileProvided) { + $this->ProcessInstallationChoices(array_keys($aInstallationChoices), $aInstallationDescription, $aInstalledModules); + } else { + $aInstalledModules = array_merge($aInstalledModules, $aInstallationChoices); + } + + $this->ProcessAutoSelectModules($aPackageModules, $aInstalledModules); + + return array_keys($aInstalledModules); + } + + private function ProcessDefaultModules(array $aPackageModules, array &$aInstalledModules): void + { + foreach ($aPackageModules as $sModuleId => $aModule) { + if (($sModuleId != ROOT_MODULE)) { + if (isset($aModule['auto_select'])) { + continue; + } + + if (($aModule['category'] == 'authentication') || (!$aModule['visible'])) { + list($sModuleName) = ModuleDiscovery::GetModuleName($sModuleId); + $aInstalledModules[$sModuleName] = true; + } + } + } + } + + private function ProcessAutoSelectModules(array $aPackageModules, array &$aInstalledModules): void + { + foreach ($aPackageModules as $sModuleId => $aModule) { + if (($sModuleId !== ROOT_MODULE) && isset($aModule['auto_select'])) { + try { + SetupInfo::SetSelectedModules($aInstalledModules); + $bSelected = DependencyExpression::GetPhpExpressionEvaluator()->ParseAndEvaluateBooleanExpression($aModule['auto_select']); + if ($bSelected) { + list($sModuleName) = ModuleDiscovery::GetModuleName($sModuleId); + $aInstalledModules[$sModuleName] = true; + } + } catch (Exception $e) { + IssueLog::Error('Error evaluating module auto-select', null, [ + 'module' => $sModuleId, + 'error' => $e->getMessage(), + 'evaluated code' => $aModule['auto_select'], + 'stacktrace' => $e->getTraceAsString(), + ]); + } + } + } + } + + private function ProcessInstallationChoices(array $aInstallationChoices, array $aInstallationDescription, array &$aInstalledModules): void + { + foreach ($aInstallationDescription as $aStepInfo) { + $aOptions = $aStepInfo['options'] ?? null; + if (is_array($aOptions)) { + foreach ($aOptions as $aChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aChoiceInfo, $aInstalledModules); + } + } + $aOptions = $aStepInfo['alternatives'] ?? null; + if (is_array($aOptions)) { + foreach ($aOptions as $aChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aChoiceInfo, $aInstalledModules); + } + } + } + } + + private function ProcessSelectedChoice(array $aInstallationChoices, array $aChoiceInfo, array &$aInstalledModules) + { + if (!is_array($aChoiceInfo)) { + return; + } + + $sMandatory = $aChoiceInfo['mandatory'] ?? 'false'; + + $aCurrentModules = $aChoiceInfo['modules'] ?? []; + $sExtensionCode = $aChoiceInfo['extension_code']; + + $bSelected = ($sMandatory === 'true') || in_array($sExtensionCode, $aInstallationChoices); + + if (!$bSelected) { + return; + } + + foreach ($aCurrentModules as $sModuleId) { + $aInstalledModules[$sModuleId] = true; + } + + $aAlternatives = $aChoiceInfo['alternatives'] ?? null; + if (is_array($aAlternatives)) { + foreach ($aAlternatives as $aSubChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aSubChoiceInfo, $aInstalledModules); + } + } + + $aSubOptionsChoiceInfo = $aChoiceInfo['sub_options'] ?? null; + if (is_array($aSubOptionsChoiceInfo)) { + $aSubOptions = $aSubOptionsChoiceInfo['options'] ?? null; + if (is_array($aSubOptions)) { + foreach ($aSubOptions as $aSubChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aSubChoiceInfo, $aInstalledModules); + } + } + $aSubAlternatives = $aSubOptionsChoiceInfo['alternatives'] ?? null; + if (is_array($aSubAlternatives)) { + foreach ($aSubAlternatives as $aSubChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aSubChoiceInfo, $aInstalledModules); + } + } + } + } + +} diff --git a/setup/runtimeenv.class.inc.php b/setup/runtimeenv.class.inc.php index 22373574f..bcae5f90f 100644 --- a/setup/runtimeenv.class.inc.php +++ b/setup/runtimeenv.class.inc.php @@ -33,7 +33,7 @@ require_once APPROOT.'setup/modelfactory.class.inc.php'; require_once APPROOT.'setup/compiler.class.inc.php'; require_once APPROOT.'setup/extensionsmap.class.inc.php'; require_once APPROOT.'setup/moduleinstallation/AnalyzeInstallation.php'; -require_once APPROOT . '/setup/moduleinstallation/InstallationChoicesService.php'; +require_once APPROOT . '/setup/moduleinstallation/InstallationChoicesToModuleConverter.php'; define('MODULE_ACTION_OPTIONAL', 1); define('MODULE_ACTION_MANDATORY', 2); diff --git a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/InstallationChoicesServiceTest.php b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/InstallationChoicesToModuleConverterTest.php similarity index 95% rename from tests/php-unit-tests/unitary-tests/setup/moduleinstallation/InstallationChoicesServiceTest.php rename to tests/php-unit-tests/unitary-tests/setup/moduleinstallation/InstallationChoicesToModuleConverterTest.php index 14a8d703a..b91af9bdf 100644 --- a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/InstallationChoicesServiceTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/InstallationChoicesToModuleConverterTest.php @@ -7,13 +7,13 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase; -class InstallationChoicesServiceTest extends ItopDataTestCase +class InstallationChoicesToModuleConverterTest extends ItopDataTestCase { protected function setUp(): void { parent::setUp(); - $this->RequireOnceItopFile('/setup/moduleinstallation/InstallationChoicesService.php'); + $this->RequireOnceItopFile('/setup/moduleinstallation/InstallationChoicesToModuleConverter.php'); } protected function tearDown(): void @@ -92,7 +92,7 @@ class InstallationChoicesServiceTest extends ItopDataTestCase $aExpectedModulesIds = $this->GetExpectedNonItilInstalledModules($bKnownMgtSelected, $bCoreMgtSelected); - $aInstalledModules = InstallationChoicesService::GetInstance()->GetInstalledModules( + $aInstalledModules = InstallationChoicesToModuleConverter::GetInstance()->GetModules( $aInstallationChoices, $aSearchDirs, __DIR__.'/ressources/installation.xml' @@ -135,7 +135,7 @@ class InstallationChoicesServiceTest extends ItopDataTestCase 'itop-welcome-itil/3.3.0', ]; - $aInstalledModules = InstallationChoicesService::GetInstance()->GetInstalledModules( + $aInstalledModules = InstallationChoicesToModuleConverter::GetInstance()->GetModules( $aInstallationChoices, $aSearchDirs, null