ReadFromDB($oConfig); } catch (MySQLException $e) { // No database or erroneous information } return $this->ComputeInstalledModules($aSelectInstall); } /** * @param \Config|null $oConfig * @return array * @throws \MySQLException * @throws \MySQLQueryHasNoResultException */ public function ReadFromDB(?Config $oConfig): array { 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 = <<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) { $sModuleVersion = $aInstall['version']; if ($sModuleVersion == '') { // Though the version cannot be empty in iTop 2.0, it used to be possible // therefore we have to put something here or the module will not be considered // as being installed $sModuleVersion = '0.0.0'; } if ($aInstall['parent_id'] == 0) { 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 (!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 { $aInstallByModule = []; // array of => array ('installed' => timestamp, 'version' => ) //module installation datetime is mostly the same for all modules //unless there was issue recording things in DB $sFirstDatetime = null; $iFirstTime = -1; foreach ($aSelectInstall as $aInstall) { //$aInstall['comment']; // unsused $sDatetime = $aInstall['installed']; if (is_null($sFirstDatetime)) { $sFirstDatetime = $sDatetime; $iFirstTime = strtotime($sDatetime); $iInstalled = $iFirstTime; } elseif ($sDatetime === $sFirstDatetime) { $iInstalled = $iFirstTime; } else { $sDatetime = $aInstall['installed']; $iInstalled = strtotime($sDatetime); } $sModuleName = $aInstall['name']; $sModuleVersion = $aInstall['version']; if ($sModuleVersion == '') { // Though the version cannot be empty in iTop 2.0, it used to be possible // therefore we have to put something here or the module will not be considered // as being installed $sModuleVersion = '0.0.0'; } if ($aInstall['parent_id'] == 0) { $aInstallByModule[ROOT_MODULE] = [ 'installed_version' => $sModuleVersion, 'installed' => $iInstalled, 'version' => $sModuleVersion, ]; } else { $aInstallByModule[$sModuleName] = [ 'installed' => $iInstalled, 'version' => $sModuleVersion, ]; } } return $aInstallByModule; } /** * Return previous module installation. offset is applied on parent_id. * @param $iOffset: by default (offset=0) returns current installation * @return array */ public static function GetPreviousModuleInstallationsByOffset(int $iOffset = 0): array { $oFilter = DBObjectSearch::FromOQL('SELECT ModuleInstallation AS mi WHERE mi.parent_id=0 AND mi.name!="datamodel"'); $oSet = new DBObjectSet($oFilter, ['installed' => false]); // Most recent first $oSet->SetLimit($iOffset + 1); $iParentId = 0; /** @var \DBObject $oModuleInstallation */ while ($oModuleInstallation = $oSet->Fetch()) { if ($iOffset == 0) { $iParentId = $oModuleInstallation->Get('id'); break; } $iOffset--; } if ($iParentId === 0) { IssueLog::Error("no ITOP_APPLICATION ModuleInstallation found", null, ['offset' => $iOffset]); throw new \Exception("no ITOP_APPLICATION ModuleInstallation found"); } $oFilter = DBObjectSearch::FromOQL("SELECT ModuleInstallation AS mi WHERE mi.id=$iParentId OR mi.parent_id=$iParentId"); $oSet = new DBObjectSet($oFilter); // Most recent first $aRawValues = $oSet->ToArrayOfValues(); $aValues = []; foreach ($aRawValues as $aRawValue) { $aValue = []; foreach ($aRawValue as $sAliasAttCode => $sValue) { // remove 'mi.' from AttCode $sAttCode = substr($sAliasAttCode, 3); $aValue[$sAttCode] = $sValue; } $aValues[] = $aValue; } return $aValues; } }