mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
N°8760 :fix ModuleInstallation db query + refactor query in ModuleInstallationService
extensionmap cleanup fix setup broken
This commit is contained in:
@@ -186,9 +186,7 @@ function collect_configuration()
|
||||
|
||||
// iTop modules
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
$sLatestInstallationDate = CMDBSource::QueryToScalar("SELECT max(installed) FROM ".$oConfig->Get('db_subname')."priv_module_install");
|
||||
// Get the latest installed modules, without the "root" ones (iTop version and datamodel version)
|
||||
$aInstalledModules = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->Get('db_subname')."priv_module_install WHERE installed = '".$sLatestInstallationDate."' AND parent_id != 0");
|
||||
$aInstalledModules = ModuleInstallationService::GetInstance()->ReadFromDB($oConfig);
|
||||
|
||||
foreach ($aInstalledModules as $aDBInfo) {
|
||||
$aConfiguration['itop_modules'][$aDBInfo['name']] = $aDBInfo['version'];
|
||||
|
||||
@@ -96,7 +96,7 @@ class AnalyzeInstallation
|
||||
$aRes[$sModuleName] = $aModuleInfo;
|
||||
}
|
||||
|
||||
$aCurrentlyInstalledModules = ModuleInstallationService::GetInstance()->ReadFromDB($oConfig);
|
||||
$aCurrentlyInstalledModules = ModuleInstallationService::GetInstance()->ReadComputeInstalledModules($oConfig);
|
||||
|
||||
// Adjust the list of proposed modules
|
||||
foreach ($aCurrentlyInstalledModules as $sModuleName => $aModuleDB) {
|
||||
|
||||
@@ -23,34 +23,16 @@ class ModuleInstallationService
|
||||
}
|
||||
|
||||
private ?array $aSelectInstall = null;
|
||||
public function ReadFromDB(?Config $oConfig): array
|
||||
|
||||
/**
|
||||
* @param \Config|null $oConfig
|
||||
* @return array
|
||||
*/
|
||||
public function ReadComputeInstalledModules(?Config $oConfig): array
|
||||
{
|
||||
$aSelectInstall = [];
|
||||
try {
|
||||
$aSelectInstall = [];
|
||||
if (! is_null($oConfig)) {
|
||||
if (! is_null($this->aSelectInstall)) {
|
||||
//test only
|
||||
$aSelectInstall = $this->aSelectInstall;
|
||||
} else {
|
||||
CMDBSource::InitFromConfig($oConfig);
|
||||
|
||||
//read db module installations
|
||||
$aSelectInstallOld = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->Get('db_subname')."priv_module_install");
|
||||
//file_put_contents(APPROOT."/tests/php-unit-tests/unitary-tests/setup/ressources/priv_modules.json", json_encode($aSelectInstallOld, JSON_PRETTY_PRINT));
|
||||
|
||||
$iRootId = CMDBSource::QueryToScalar("SELECT max(parent_id) FROM ".$oConfig->Get('db_subname')."priv_module_install");
|
||||
$sDbSubName = $oConfig->Get('db_subname');
|
||||
// Get the latest installed modules, without the "root" ones (iTop version and datamodel version)
|
||||
$sSQL = <<<SQL
|
||||
SELECT * FROM $sDbSubName.priv_module_install
|
||||
WHERE
|
||||
parent_id='$iRootId'
|
||||
OR id='$iRootId'
|
||||
SQL;
|
||||
$aSelectInstall = CMDBSource::QueryToArray($sSQL);
|
||||
//file_put_contents(APPROOT."/tests/php-unit-tests/unitary-tests/setup/ressources/priv_modules2.json", json_encode($aSelectInstall, JSON_PRETTY_PRINT));
|
||||
}
|
||||
}
|
||||
$aSelectInstall = $this->ReadFromDB($oConfig);
|
||||
} catch (MySQLException $e) {
|
||||
// No database or erroneous information
|
||||
}
|
||||
@@ -58,24 +40,69 @@ SQL;
|
||||
return $this->ComputeInstalledModules($aSelectInstall);
|
||||
}
|
||||
|
||||
private function ComputeInstalledModulesLegacy(array $aSelectInstall): array
|
||||
/**
|
||||
* @param \Config|null $oConfig
|
||||
* @return array
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLQueryHasNoResultException
|
||||
*/
|
||||
public function ReadFromDB(?Config $oConfig): array
|
||||
{
|
||||
$aInstallByModule = []; // array of <module> => array ('installed' => timestamp, 'version' => <version>)
|
||||
$iRootId = 0;
|
||||
foreach ($aSelectInstall as $aInstall) {
|
||||
if (($aInstall['parent_id'] == 0) && ($aInstall['name'] != 'datamodel')) {
|
||||
// Root module, what is its ID ?
|
||||
$iId = (int) $aInstall['id'];
|
||||
if ($iId > $iRootId) {
|
||||
$iRootId = $iId;
|
||||
}
|
||||
}
|
||||
if (is_null($oConfig)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (! is_null($this->aSelectInstall)) {
|
||||
//test only
|
||||
return $this->aSelectInstall;
|
||||
}
|
||||
|
||||
CMDBSource::InitFromConfig($oConfig);
|
||||
//read db module installations
|
||||
$tableWithPrefix = $this->GetTableWithPrefix($oConfig);
|
||||
$iRootId = CMDBSource::QueryToScalar("SELECT max(parent_id) FROM $tableWithPrefix");
|
||||
// Get the latest installed modules, without the "root" ones (iTop version and datamodel version)
|
||||
$sSQL = <<<SQL
|
||||
SELECT * FROM $tableWithPrefix
|
||||
WHERE
|
||||
parent_id='$iRootId'
|
||||
OR id='$iRootId'
|
||||
SQL;
|
||||
return CMDBSource::QueryToArray($sSQL);
|
||||
}
|
||||
|
||||
private function GetTableWithPrefix(Config $oConfig)
|
||||
{
|
||||
$sPrefix = $oConfig->Get('db_subname');
|
||||
if (utils::IsNullOrEmptyString($sPrefix)) {
|
||||
return "priv_module_install";
|
||||
}
|
||||
|
||||
return "{$sPrefix}priv_module_install";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Config $oConfig
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public function GetApplicationVersion(Config $oConfig)
|
||||
{
|
||||
try {
|
||||
CMDBSource::InitFromConfig($oConfig);
|
||||
$tableWithPrefix = $this->GetTableWithPrefix($oConfig);
|
||||
$sSQLQuery = "SELECT * FROM $tableWithPrefix";
|
||||
$aSelectInstall = CMDBSource::QueryToArray($sSQLQuery);
|
||||
} catch (MySQLException $e) {
|
||||
// No database or erroneous information
|
||||
$this->log_error('Can not connect to the database: host: '.$oConfig->Get('db_host').', user:'.$oConfig->Get('db_user').', pwd:'.$oConfig->Get('db_pwd').', db name:'.$oConfig->Get('db_name'));
|
||||
$this->log_error('Exception '.$e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
$aResult = [];
|
||||
// Scan the list of installed modules to get the version of the 'ROOT' module which holds the main application version
|
||||
foreach ($aSelectInstall as $aInstall) {
|
||||
//$aInstall['comment']; // unsused
|
||||
$iInstalled = strtotime($aInstall['installed']);
|
||||
$sModuleName = $aInstall['name'];
|
||||
$sModuleVersion = $aInstall['version'];
|
||||
if ($sModuleVersion == '') {
|
||||
// Though the version cannot be empty in iTop 2.0, it used to be possible
|
||||
@@ -85,27 +112,25 @@ SQL;
|
||||
}
|
||||
|
||||
if ($aInstall['parent_id'] == 0) {
|
||||
$sModuleName = ROOT_MODULE;
|
||||
} elseif ($aInstall['parent_id'] != $iRootId) {
|
||||
// Skip all modules belonging to previous installations
|
||||
continue;
|
||||
}
|
||||
|
||||
if (array_key_exists($sModuleName, $aInstallByModule)) {
|
||||
if ($iInstalled < $aInstallByModule[$sModuleName]['installed']) {
|
||||
continue;
|
||||
if ($aInstall['name'] == DATAMODEL_MODULE) {
|
||||
$aResult['datamodel_version'] = $sModuleVersion;
|
||||
$aComments = json_decode($aInstall['comment'], true);
|
||||
if (is_array($aComments)) {
|
||||
$aResult = array_merge($aResult, $aComments);
|
||||
}
|
||||
} else {
|
||||
$aResult['product_name'] = $aInstall['name'];
|
||||
$aResult['product_version'] = $sModuleVersion;
|
||||
}
|
||||
}
|
||||
|
||||
if ($aInstall['parent_id'] == 0) {
|
||||
$aInstallByModule[$sModuleName]['installed_version'] = $sModuleVersion;
|
||||
}
|
||||
|
||||
$aInstallByModule[$sModuleName]['installed'] = $iInstalled;
|
||||
$aInstallByModule[$sModuleName]['version'] = $sModuleVersion;
|
||||
}
|
||||
|
||||
return $aInstallByModule;
|
||||
if (!array_key_exists('datamodel_version', $aResult)) {
|
||||
// Versions prior to 2.0 did not record the version of the datamodel
|
||||
// so assume that the datamodel version is equal to the application version
|
||||
$aResult['datamodel_version'] = $aResult['product_version'];
|
||||
}
|
||||
$this->log_info("GetApplicationVersion returns: product_name: ".$aResult['product_name'].', product_version: '.$aResult['product_version']);
|
||||
return empty($aResult) ? false : $aResult;
|
||||
}
|
||||
|
||||
private function ComputeInstalledModules(array $aSelectInstall): array
|
||||
|
||||
@@ -179,7 +179,7 @@ class iTopExtensionsMap
|
||||
foreach ($aExtraDirs as $sDir) {
|
||||
$this->ReadDir($sDir, iTopExtension::SOURCE_REMOTE);
|
||||
}
|
||||
$this->CheckDependencies($sFromEnvironment);
|
||||
$this->CheckDependencies();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,8 +190,10 @@ class iTopExtensionsMap
|
||||
*/
|
||||
protected function ScanDisk($sEnvironment)
|
||||
{
|
||||
if (!$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x') && !$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x')) {
|
||||
if (!$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x')) {
|
||||
//no installation xml found in 2.x: let's read all extensions in 2.x first
|
||||
if (!$this->ReadDir(APPROOT.'/datamodels/2.x', iTopExtension::SOURCE_WIZARD)) {
|
||||
//nothing found in 2.x : fallback read in 1.x (flat structure)
|
||||
$this->ReadDir(APPROOT.'/datamodels/1.x', iTopExtension::SOURCE_WIZARD);
|
||||
}
|
||||
}
|
||||
@@ -387,19 +389,15 @@ class iTopExtensionsMap
|
||||
// to this extension
|
||||
$sModuleId = $aModuleInfo[ModuleFileReader::MODULE_INFO_ID];
|
||||
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
if ($sModuleVersion == '') {
|
||||
// Provide a default module version since version is mandatory when recording ExtensionInstallation
|
||||
$sModuleVersion = '0.0.1';
|
||||
}
|
||||
$aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG]['uninstallable'] ??= 'yes';
|
||||
|
||||
if (($sParentExtensionId !== null) && (array_key_exists($sParentExtensionId, $this->aExtensions)) && ($this->aExtensions[$sParentExtensionId] instanceof iTopExtension)) {
|
||||
// Already inside an extension, let's add this module the list of modules belonging to this extension
|
||||
$this->aExtensions[$sParentExtensionId]->aModules[] = $sModuleName;
|
||||
$this->aExtensions[$sParentExtensionId]->aModuleVersion[$sModuleName] = $sModuleVersion;
|
||||
$this->aExtensions[$sParentExtensionId]->aModuleInfo[$sModuleName] = $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG];
|
||||
} else {
|
||||
// Not already inside a folder containing an 'extension.xml' file
|
||||
$oExtension = null;
|
||||
if ($sParentExtensionId !== null) {
|
||||
$oExtension = $this->aExtensions[$sParentExtensionId] ?? null;
|
||||
}
|
||||
|
||||
if (is_null($oExtension)) {
|
||||
// Not already inside an folder containing an 'extension.xml' file
|
||||
|
||||
// Ignore non-visible modules and auto-select ones, since these are never prompted
|
||||
// as a choice to the end-user
|
||||
@@ -423,6 +421,13 @@ class iTopExtensionsMap
|
||||
$oExtension->sSourceDir = $sSearchDir;
|
||||
$oExtension->bVisible = $bVisible;
|
||||
$this->AddExtension($oExtension);
|
||||
} else {
|
||||
$oExtension->aModules[] = $sModuleName;
|
||||
$oExtension->aModuleVersion[$sModuleName] = $sModuleVersion;
|
||||
$oExtension->aModuleInfo[$sModuleName] = $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG];
|
||||
|
||||
$this->aExtensions[$sParentExtensionId] = $oExtension;
|
||||
$this->aExtensionsByCode[$oExtension->sCode] = $oExtension;
|
||||
}
|
||||
|
||||
closedir($hDir);
|
||||
@@ -444,10 +449,9 @@ class iTopExtensionsMap
|
||||
/**
|
||||
* Check if some extension contains a module with missing dependencies...
|
||||
* If so, populate the aMissingDepenencies array
|
||||
* @param string $sFromEnvironment
|
||||
* @return void
|
||||
*/
|
||||
protected function CheckDependencies($sFromEnvironment)
|
||||
protected function CheckDependencies()
|
||||
{
|
||||
$aSearchDirs = [];
|
||||
|
||||
@@ -459,7 +463,7 @@ class iTopExtensionsMap
|
||||
$aSearchDirs = array_merge($aSearchDirs, $this->aScannedDirs);
|
||||
|
||||
try {
|
||||
$aAllModules = ModuleDiscovery::GetAvailableModules($aSearchDirs, true);
|
||||
ModuleDiscovery::GetAvailableModules($aSearchDirs, true);
|
||||
} catch (MissingDependencyException $e) {
|
||||
// Some modules have missing dependencies
|
||||
// Let's check what is the impact at the "extensions" level
|
||||
@@ -629,8 +633,6 @@ class iTopExtensionsMap
|
||||
*/
|
||||
public function ModuleIsChosenAsPartOfAnExtension($sModuleNameToFind, $sInSourceOnly = iTopExtension::SOURCE_REMOTE)
|
||||
{
|
||||
$bChosen = false;
|
||||
|
||||
foreach ($this->GetAllExtensions() as $oExtension) {
|
||||
if (($oExtension->sSource == $sInSourceOnly) &&
|
||||
($oExtension->bMarkedAsChosen == true) &&
|
||||
|
||||
@@ -248,8 +248,6 @@ class RunTimeEnvironment
|
||||
$aExtraDirs = $this->GetExtraDirsToScan($aDirsToCompile);
|
||||
$aDirsToCompile = array_merge($aDirsToCompile, $aExtraDirs);
|
||||
|
||||
$aRet = [];
|
||||
|
||||
// Determine the installed modules and extensions
|
||||
//
|
||||
$oSourceConfig = new Config(APPCONF.$sSourceEnv.'/'.ITOP_CONFIG_FILE);
|
||||
@@ -290,7 +288,6 @@ class RunTimeEnvironment
|
||||
$aModules = $oFactory->FindModules();
|
||||
foreach ($aModules as $oModule) {
|
||||
$sModule = $oModule->GetName();
|
||||
$sModuleRootDir = $oModule->GetRootDir();
|
||||
$bIsExtra = $this->GetExtensionMap()->ModuleIsChosenAsPartOfAnExtension($sModule, iTopExtension::SOURCE_REMOTE);
|
||||
if (array_key_exists($sModule, $aAvailableModules)) {
|
||||
if (($aAvailableModules[$sModule]['installed_version'] != '') || $bIsExtra && !$oModule->IsAutoSelect()) { //Extra modules are always unless they are 'AutoSelect'
|
||||
@@ -628,9 +625,7 @@ class RunTimeEnvironment
|
||||
public function GetApplicationVersion(Config $oConfig)
|
||||
{
|
||||
try {
|
||||
CMDBSource::InitFromConfig($oConfig);
|
||||
$sSQLQuery = "SELECT * FROM ".$oConfig->Get('db_subname')."priv_module_install";
|
||||
$aSelectInstall = CMDBSource::QueryToArray($sSQLQuery);
|
||||
$aSelectInstall = ModuleInstallationService::GetInstance()->ReadFromDB($oConfig);
|
||||
} catch (MySQLException $e) {
|
||||
// No database or erroneous information
|
||||
$this->log_error('Can not connect to the database: host: '.$oConfig->Get('db_host').', user:'.$oConfig->Get('db_user').', pwd:'.$oConfig->Get('db_pwd').', db name:'.$oConfig->Get('db_name'));
|
||||
|
||||
Reference in New Issue
Block a user