mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-26 21:54:13 +01:00
N°8760 - Audit uninstall of extensions that declare final classes
N°8760 - be able to list modules based on extension choices refactoring: move some classes in a moduleinstallation folder (coming namespace) N°8760 - module dependency check applied before audit N°8760 - make dependency check work during audit N°8760 - fix ci N°8760 - fix ci N°8760 - add GetCreatedIn to get module name based on DBObject class - everything stored in MetaModel during compilation and autoload N°8760 - be able to describe from which module a datamodel class comes via MetaModel created_in field N°8760 - rename GetCreatedIn <- GetModuleName + compute module name live instead having complex stuff in MetaModel/compilation temp review 1 review: renaming InstallationChoicesToModuleConverter review: renaming InstallationChoicesToModuleConverter review: ModuleDiscovery:GetModulesOrderedByDependencies replacing deprecated GetAvailableModules method ci: fix typo cleanup review: rework InstallationChoicesToModuleConverter N°8760 - review tests
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Setup\ModuleDependency\DependencyExpression;
|
||||
|
||||
require_once __DIR__.'/ModuleInstallationException.php';
|
||||
require_once(APPROOT.'/setup/moduledependency/module.class.inc.php');
|
||||
|
||||
class InstallationChoicesToModuleConverter
|
||||
{
|
||||
private static ?InstallationChoicesToModuleConverter $oInstance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
final public static function GetInstance(): InstallationChoicesToModuleConverter
|
||||
{
|
||||
if (!isset(self::$oInstance)) {
|
||||
self::$oInstance = new InstallationChoicesToModuleConverter();
|
||||
}
|
||||
|
||||
return self::$oInstance;
|
||||
}
|
||||
|
||||
final public static function SetInstance(?InstallationChoicesToModuleConverter $oInstance): void
|
||||
{
|
||||
self::$oInstance = $oInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aInstallationChoices
|
||||
* @param array $aSearchDirs
|
||||
*
|
||||
* @return array
|
||||
* @throws \ModuleInstallationException
|
||||
*/
|
||||
public function GetModules(array $aInstallationChoices, array $aSearchDirs, ?string $sInstallationFilePath = null): array
|
||||
{
|
||||
$aPackageModules = ModuleDiscovery::GetAllModules($aSearchDirs);
|
||||
|
||||
$bInstallationFileProvided = ! is_null($sInstallationFilePath) && is_file($sInstallationFilePath);
|
||||
|
||||
if ($bInstallationFileProvided) {
|
||||
$oXMLParameters = new XMLParameters($sInstallationFilePath);
|
||||
$aSteps = $oXMLParameters->Get('steps', []);
|
||||
if (!is_array($aSteps)) {
|
||||
return [];
|
||||
}
|
||||
$aInstalledModuleNames = $this->FindInstalledPackageModules($aPackageModules, $aInstallationChoices, $aSteps);
|
||||
} else {
|
||||
$aInstalledModuleNames = $this->FindInstalledPackageModules($aPackageModules, $aInstallationChoices);
|
||||
}
|
||||
|
||||
$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 = null): array
|
||||
{
|
||||
$aInstalledModules = [];
|
||||
|
||||
$this->ProcessDefaultModules($aPackageModules, $aInstalledModules);
|
||||
|
||||
if (is_null($aInstallationDescription)) {
|
||||
//in legacy usecase: choices are flat modules list already
|
||||
foreach ($aInstallationChoices as $sModuleName) {
|
||||
$aInstalledModules[$sModuleName] = true;
|
||||
}
|
||||
} else {
|
||||
$this->GetModuleNamesFromInstallationChoices($aInstallationChoices, $aInstallationDescription, $aInstalledModules);
|
||||
}
|
||||
|
||||
$this->ProcessAutoSelectModules($aPackageModules, $aInstalledModules);
|
||||
|
||||
return array_keys($aInstalledModules);
|
||||
}
|
||||
|
||||
private function IsDefaultModule(string $sModuleId, array $aModule): bool
|
||||
{
|
||||
if (($sModuleId === ROOT_MODULE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($aModule['auto_select'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($aModule['category'] === 'authentication') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !$aModule['visible'];
|
||||
}
|
||||
|
||||
private function ProcessDefaultModules(array &$aPackageModules, array &$aInstalledModules): void
|
||||
{
|
||||
foreach ($aPackageModules as $sModuleId => $aModule) {
|
||||
if ($this->IsDefaultModule($sModuleId, $aModule)) {
|
||||
list($sModuleName) = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
$aInstalledModules[$sModuleName] = true;
|
||||
unset($aPackageModules[$sModuleId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function IsAutoSelectedModule(array $aInstalledModules, string $sModuleId, array $aModule): bool
|
||||
{
|
||||
if (($sModuleId === ROOT_MODULE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($aModule['auto_select'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
SetupInfo::SetSelectedModules($aInstalledModules);
|
||||
return DependencyExpression::GetPhpExpressionEvaluator()->ParseAndEvaluateBooleanExpression($aModule['auto_select']);
|
||||
} catch (Exception $e) {
|
||||
IssueLog::Error('Error evaluating module auto-select', null, [
|
||||
'module' => $sModuleId,
|
||||
'error' => $e->getMessage(),
|
||||
'evaluated code' => $aModule['auto_select'],
|
||||
'stacktrace' => $e->getTraceAsString(),
|
||||
]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function ProcessAutoSelectModules(array $aPackageModules, array &$aInstalledModules): void
|
||||
{
|
||||
foreach ($aPackageModules as $sModuleId => $aModule) {
|
||||
if ($this->IsAutoSelectedModule($aInstalledModules, $sModuleId, $aModule)) {
|
||||
list($sModuleName) = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
$aInstalledModules[$sModuleName] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function GetModuleNamesFromInstallationChoices(array $aInstallationChoices, array $aInstallationDescription, array &$aModuleNames): void
|
||||
{
|
||||
foreach ($aInstallationDescription as $aStepInfo) {
|
||||
$aOptions = $aStepInfo['options'] ?? null;
|
||||
if (is_array($aOptions)) {
|
||||
foreach ($aOptions as $aChoiceInfo) {
|
||||
$this->ProcessSelectedChoice($aInstallationChoices, $aChoiceInfo, $aModuleNames);
|
||||
}
|
||||
}
|
||||
$aOptions = $aStepInfo['alternatives'] ?? null;
|
||||
if (is_array($aOptions)) {
|
||||
foreach ($aOptions as $aChoiceInfo) {
|
||||
$this->ProcessSelectedChoice($aInstallationChoices, $aChoiceInfo, $aModuleNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user