From 39be3b449ee424cb167e916db46b8da4994b73c9 Mon Sep 17 00:00:00 2001 From: Romain Quetiez Date: Thu, 10 May 2012 09:30:48 +0000 Subject: [PATCH] Fixed setup issues (improved modularity) SVN:trunk[1982] --- application/utils.inc.php | 10 +- core/cmdbsource.class.inc.php | 1 + core/config.class.inc.php | 26 +++ setup/ajax.dataloader.php | 15 +- setup/compiler.class.inc.php | 10 +- setup/index.php | 18 +- setup/modelfactory.class.inc.php | 13 +- setup/runtimeenv.class.inc.php | 380 +++++++++++++++++++++++++++++++ setup/setuppage.class.inc.php | 324 +------------------------- 9 files changed, 457 insertions(+), 340 deletions(-) create mode 100644 setup/runtimeenv.class.inc.php diff --git a/application/utils.inc.php b/application/utils.inc.php index 07178ebf3..a94fd6fdb 100644 --- a/application/utils.inc.php +++ b/application/utils.inc.php @@ -464,7 +464,15 @@ class utils if (self::$oConfig == null) { $sConfigFile = self::GetConfigFilePath(); - self::$oConfig = new Config($sConfigFile); + if (file_exists($sConfigFile)) + { + self::$oConfig = new Config($sConfigFile); + } + else + { + // When executing the setup, the config file may be still missing + self::$oConfig = new Config(); + } } return self::$oConfig; } diff --git a/core/cmdbsource.class.inc.php b/core/cmdbsource.class.inc.php index e18ea6277..499c8054c 100644 --- a/core/cmdbsource.class.inc.php +++ b/core/cmdbsource.class.inc.php @@ -24,6 +24,7 @@ */ require_once('MyHelpers.class.inc.php'); +require_once(APPROOT.'core/kpi.class.inc.php'); class MySQLException extends CoreException { diff --git a/core/config.class.inc.php b/core/config.class.inc.php index b57f68034..3fe6b430d 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -1462,5 +1462,31 @@ class Config } } + /** + * Helper: for an array of string, change the prefix when found + */ + protected static function ChangePrefix(&$aStrings, $sSearchPrefix, $sNewPrefix) + { + foreach ($aStrings as &$sFile) + { + if (substr($sFile, 0, strlen($sSearchPrefix)) == $sSearchPrefix) + { + $sFile = $sNewPrefix.substr($sFile, strlen($sSearchPrefix)); + } + } + } + + /** + * Quick an dirty way to clone a config file into another environment + */ + public function ChangeModulesPath($sSourceEnv, $sTargetEnv) + { + $sSearchPrefix = 'env-'.$sSourceEnv.'/'; + $sNewPrefix = 'env-'.$sTargetEnv.'/'; + self::ChangePrefix($this->m_aDataModels, $sSearchPrefix, $sNewPrefix); + self::ChangePrefix($this->m_aWebServiceCategories, $sSearchPrefix, $sNewPrefix); + self::ChangePrefix($this->m_aDictionaries, $sSearchPrefix, $sNewPrefix); + } + } ?> diff --git a/setup/ajax.dataloader.php b/setup/ajax.dataloader.php index 895876830..360ab6812 100644 --- a/setup/ajax.dataloader.php +++ b/setup/ajax.dataloader.php @@ -227,10 +227,11 @@ try $sModuleDir = Utils::ReadParam('modules_dir', ''); $oConfig->UpdateFromParams($aParamValues, $sModuleDir); - InitDataModel($oConfig, true); // load data model only + $oProductionEnv = new RunTimeEnvironment(); + $oProductionEnv->InitDataModel($oConfig, true); // load data model only $sMode = Utils::ReadParam('mode', 'install'); - if(!CreateDatabaseStructure(MetaModel::GetConfig(), $sMode)) + if(!$oProductionEnv->CreateDatabaseStructure(MetaModel::GetConfig(), $sMode)) { throw(new Exception("Failed to create/upgrade the database structure")); } @@ -256,7 +257,8 @@ try $sModuleDir = Utils::ReadParam('modules_dir', ''); $oConfig->UpdateFromParams($aParamValues, $sModuleDir); - InitDataModel($oConfig, false); // load data model and connect to the database + $oProductionEnv = new RunTimeEnvironment(); + $oProductionEnv->InitDataModel($oConfig, false); // load data model and connect to the database $sMode = Utils::ReadParam('mode', 'install'); $sSelectedModules = Utils::ReadParam('selected_modules', '', false, 'raw_data'); @@ -264,7 +266,7 @@ try // Perform here additional DB setup... profiles, etc... // - $aAvailableModules = AnalyzeInstallation(MetaModel::GetConfig(), $sModuleDir); + $aAvailableModules = $oProductionEnv->AnalyzeInstallation(MetaModel::GetConfig(), $sModuleDir); foreach($aAvailableModules as $sModuleId => $aModule) { if (($sModuleId != ROOT_MODULE) && in_array($sModuleId, $aSelectedModules) && @@ -278,7 +280,7 @@ try } } - if (!RecordInstallation($oConfig, $aSelectedModules, $sModuleDir)) + if (!$oProductionEnv->RecordInstallation($oConfig, $aSelectedModules, $sModuleDir)) { throw(new Exception("Failed to record the installation information")); } @@ -326,7 +328,8 @@ try $sModuleDir = Utils::ReadParam('modules_dir', ''); $oConfig->UpdateFromParams($aParamValues, $sModuleDir); - InitDataModel($oConfig, false); // load data model and connect to the database + $oProductionEnv = new RunTimeEnvironment(); + $oProductionEnv->InitDataModel($oConfig, false); // load data model and connect to the database $oDataLoader = new XMLDataLoader(); if ($sSessionStatus == 'start') diff --git a/setup/compiler.class.inc.php b/setup/compiler.class.inc.php index f64cb40ab..4ebc11751 100644 --- a/setup/compiler.class.inc.php +++ b/setup/compiler.class.inc.php @@ -398,7 +398,15 @@ EOF; $aClassParams['reconc_keys'] = $sReconcKeys; $aClassParams['db_table'] = "'".$oProperties->GetChildText('db_table')."'"; - $aClassParams['db_key_field'] = "'".$oProperties->GetChildText('db_key_field')."'"; + + $sKeyField = $oProperties->GetChildText('db_key_field'); + if ($sKeyField == '') + { + $sKeyField = 'id'; + } + $aClassParams['db_key_field'] = "'".$sKeyField."'"; + + // TODO: faire automatiquement (pas dans le XML !!!) $aClassParams['db_finalclass_field'] = "'".$oProperties->GetChildText('db_final_class_field')."'"; if (($sDisplayTemplate = $oProperties->GetChildText('display_template')) && (strlen($sDisplayTemplate) > 0)) diff --git a/setup/index.php b/setup/index.php index 6244e5dff..fe01f1749 100644 --- a/setup/index.php +++ b/setup/index.php @@ -447,7 +447,8 @@ function PopulateDataFilesList(SetupPage $oP, $aParamValues, $oConfig) $sScript .= "{\n"; $sScript .= "if (aFilesToLoad.length > 0) return;"; // Populate the list only once... - $aAvailableModules = AnalyzeInstallation($oConfig, $aParamValues['source_dir']); + $oProductionEnv = new RunTimeEnvironment(); + $aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, $aParamValues['source_dir']); $sMode = $aParamValues['mode']; $aStructureDataFiles = array(); @@ -595,7 +596,8 @@ function WelcomeAndCheckPrerequisites(SetupPage $oP, $aParamValues, $iCurrentSte { $oConfig = new Config($sConfigFile); - $aVersion = AnalyzeInstallation($oConfig, 'datamodel'); + $oProductionEnv = new RunTimeEnvironment(); + $aVersion = $oProductionEnv->AnalyzeInstallation($oConfig, 'datamodel'); if (!empty($aVersion[ROOT_MODULE]['version_db'])) { $aPreviousParams = array('mode', 'db_server', 'db_user', 'db_pwd','db_name', 'new_db_name', 'db_prefix', 'source_dir', 'target_dir'); @@ -826,7 +828,8 @@ function ModulesSelection(SetupPage $oP, $aParamValues, $iCurrentStep, $oConfig) $sRedStar = '*'; $oP->set_title("iTop modules selection"); - $aAvailableModules = AnalyzeInstallation($oConfig, $aParamValues['source_dir']); + $oProductionEnv = new RunTimeEnvironment(); + $aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, $aParamValues['source_dir']); $sConfigFile = utils::GetConfigFilePath(); // Form goes here @@ -1132,7 +1135,8 @@ function SampleDataSelection(SetupPage $oP, $aParamValues, $iCurrentStep, Config function DisplaySummary(SetupPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) { $sMode = $aParamValues['mode']; - $aAvailableModules = AnalyzeInstallation($oConfig, $aParamValues['source_dir']); + $oProductionEnv = new RunTimeEnvironment(); + $aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, $aParamValues['source_dir']); $aInstall = array(); $aUpgrade = array(); @@ -1388,7 +1392,8 @@ function SetupFinished(SetupPage $oP, $aParamValues, $iCurrentStep, Config $oCon $oConfig->WriteToFile($sConfigFile); // Start the application - InitDataModel($oConfig, false, true); // Load model, startup DB and load the cache + $oProductionEnv = new RunTimeEnvironment(); + $oProductionEnv->InitDataModel($oConfig, false, true); // Load model, startup DB and load the cache if ($aParamValues['mode'] == 'install') { if (UserRights::CheckCredentials($sAuthUser, $sAuthPwd)) @@ -1421,7 +1426,8 @@ function SetupFinished(SetupPage $oP, $aParamValues, $iCurrentStep, Config $oCon $oP->add("
\n"); // Check if there are some manual steps required: - $aAvailableModules = AnalyzeInstallation($oConfig, $aParamValues['target_dir']); + $oProductionEnv = new RunTimeEnvironment(); + $aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, $aParamValues['target_dir']); $aManualSteps = array(); $sRootUrl = utils::GetAbsoluteUrlAppRoot(); foreach($aParamValues['module'] as $sModuleId) diff --git a/setup/modelfactory.class.inc.php b/setup/modelfactory.class.inc.php index abbf46b4c..ab45734df 100644 --- a/setup/modelfactory.class.inc.php +++ b/setup/modelfactory.class.inc.php @@ -124,6 +124,7 @@ class ModelFactory $this->sRootDir = $sRootDir; $this->oDOMDocument = new MFDocument(); $this->oRoot = $this->oDOMDocument->CreateElement('itop_design'); + $this->oRoot->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); $this->oDOMDocument->AppendChild($this->oRoot); $this->oModules = $this->oDOMDocument->CreateElement('loaded_modules'); $this->oRoot->AppendChild($this->oModules); @@ -299,12 +300,18 @@ class ModelFactory $oNodeList = $oXPath->query('/itop_design/classes//class'); foreach($oNodeList as $oNode) { - $oNode->SetAttribute('_created_in', $sModuleName); + if ($oNode->getAttribute('_created_in') == '') + { + $oNode->SetAttribute('_created_in', $sModuleName); + } } $oNodeList = $oXPath->query('/itop_design/menus/menu'); foreach($oNodeList as $oNode) { - $oNode->SetAttribute('_created_in', $sModuleName); + if ($oNode->getAttribute('_created_in') == '') + { + $oNode->SetAttribute('_created_in', $sModuleName); + } } $oDeltaRoot = $oDocument->childNodes->item(0); @@ -1648,9 +1655,9 @@ class MFDocument extends DOMDocument if (!$oRootNode) { $oRootNode = $this->createElement('itop_design'); // make sure that the document is not empty + $oRootNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); $this->appendChild($oRootNode); } - $oRootNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); return parent::saveXML(); } /** diff --git a/setup/runtimeenv.class.inc.php b/setup/runtimeenv.class.inc.php new file mode 100644 index 000000000..3edfa65d3 --- /dev/null +++ b/setup/runtimeenv.class.inc.php @@ -0,0 +1,380 @@ + + * @author Romain Quetiez + * @author Denis Flaven + * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL + */ + +require_once(APPROOT."setup/modulediscovery.class.inc.php"); + +define ('MODULE_ACTION_OPTIONAL', 1); +define ('MODULE_ACTION_MANDATORY', 2); +define ('MODULE_ACTION_IMPOSSIBLE', 3); +define ('ROOT_MODULE', '_Root_'); // Convention to store IN MEMORY the name/version of the root module i.e. application + +class RunTimeEnvironment +{ + protected $sTargetEnv; + + public function __construct($sEnvironment = 'production') + { + $this->sTargetEnv = $sEnvironment; + } + + /** + * Helper function to initialize the ORM and load the data model + * from the given file + * @param $oConfig object The configuration (volatile, not necessarily already on disk) + * @param $bModelOnly boolean Whether or not to allow loading a data model with no corresponding DB + * @return none + */ + public function InitDataModel($oConfig, $bModelOnly = true, $bUseCache = false) + { + require_once(APPROOT.'/core/log.class.inc.php'); + require_once(APPROOT.'/core/kpi.class.inc.php'); + require_once(APPROOT.'/core/coreexception.class.inc.php'); + require_once(APPROOT.'/core/dict.class.inc.php'); + require_once(APPROOT.'/core/attributedef.class.inc.php'); + require_once(APPROOT.'/core/filterdef.class.inc.php'); + require_once(APPROOT.'/core/stimulus.class.inc.php'); + require_once(APPROOT.'/core/MyHelpers.class.inc.php'); + require_once(APPROOT.'/core/expression.class.inc.php'); + require_once(APPROOT.'/core/cmdbsource.class.inc.php'); + require_once(APPROOT.'/core/sqlquery.class.inc.php'); + require_once(APPROOT.'/core/dbobject.class.php'); + require_once(APPROOT.'/core/dbobjectsearch.class.php'); + require_once(APPROOT.'/core/dbobjectset.class.php'); + require_once(APPROOT.'/application/cmdbabstract.class.inc.php'); + require_once(APPROOT.'/core/userrights.class.inc.php'); + require_once(APPROOT.'/setup/moduleinstallation.class.inc.php'); + + $sConfigFile = $oConfig->GetLoadedFile(); + if (strlen($sConfigFile) > 0) + { + $this->log_info("MetaModel::Startup from $sConfigFile (ModelOnly = $bModelOnly)"); + } + else + { + $this->log_info("MetaModel::Startup (ModelOnly = $bModelOnly)"); + } + + if (!$bUseCache) + { + // Reset the cache for the first use ! + MetaModel::ResetCache($oConfig); + } + + MetaModel::Startup($oConfig, $bModelOnly, $bUseCache); + } + + /** + * Analyzes the current installation and the possibilities + * + * @param $oConfig Config Defines the target environment (DB) + * @return hash Array with the following format: + * array => + * 'iTop' => array( + * 'version_db' => ... (could be empty in case of a fresh install) + * 'version_code => ... + * ) + * => array( + * 'version_db' => ... + * 'version_code' => ... + * 'install' => array( + * 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY + * 'message' => ... + * ) + * 'uninstall' => array( + * 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY + * 'message' => ... + * ) + * 'label' => ... + * 'dependencies' => array(, , ...) + * 'visible' => true | false + * ) + * ) + */ + public function AnalyzeInstallation($oConfig, $sModulesRelativePath) + { + $aRes = array( + ROOT_MODULE => array( + 'version_db' => '', + 'name_db' => '', + 'version_code' => ITOP_VERSION.'.'.ITOP_REVISION, + 'name_code' => ITOP_APPLICATION, + ) + ); + + $aModules = ModuleDiscovery::GetAvailableModules(APPROOT, $sModulesRelativePath); + foreach($aModules as $sModuleId => $aModuleInfo) + { + list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId); + + $sModuleAppVersion = $aModuleInfo['itop_version']; + $aModuleInfo['version_db'] = ''; + $aModuleInfo['version_code'] = $sModuleVersion; + + if (!in_array($sModuleAppVersion, array('1.0.0', '1.0.1', '1.0.2'))) + { + // This module is NOT compatible with the current version + $aModuleInfo['install'] = array( + 'flag' => MODULE_ACTION_IMPOSSIBLE, + 'message' => 'the module is not compatible with the current version of the application' + ); + } + elseif ($aModuleInfo['mandatory']) + { + $aModuleInfo['install'] = array( + 'flag' => MODULE_ACTION_MANDATORY, + 'message' => 'the module is part of the application' + ); + } + else + { + $aModuleInfo['install'] = array( + 'flag' => MODULE_ACTION_OPTIONAL, + 'message' => '' + ); + } + $aRes[$sModuleName] = $aModuleInfo; + } + + try + { + CMDBSource::Init($oConfig->GetDBHost(), $oConfig->GetDBUser(), $oConfig->GetDBPwd(), $oConfig->GetDBName()); + $aSelectInstall = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->GetDBSubname()."priv_module_install"); + } + catch (MySQLException $e) + { + // No database or eroneous information + $aSelectInstall = array(); + } + + // Build the list of installed module (get the latest installation) + // + $aInstallByModule = array(); // array of => array ('installed' => timestamp, 'version' => ) + foreach ($aSelectInstall as $aInstall) + { + //$aInstall['comment']; // unsused + $iInstalled = strtotime($aInstall['installed']); + $sModuleName = $aInstall['name']; + $sModuleVersion = $aInstall['version']; + + if ($aInstall['parent_id'] == 0) + { + $sModuleName = ROOT_MODULE; + } + + if (array_key_exists($sModuleName, $aInstallByModule)) + { + if ($iInstalled < $aInstallByModule[$sModuleName]['installed']) + { + continue; + } + } + + if ($aInstall['parent_id'] == 0) + { + $aRes[$sModuleName]['version_db'] = $sModuleVersion; + $aRes[$sModuleName]['name_db'] = $aInstall['name']; + } + + $aInstallByModule[$sModuleName]['installed'] = $iInstalled; + $aInstallByModule[$sModuleName]['version'] = $sModuleVersion; + } + + // Adjust the list of proposed modules + // + foreach ($aInstallByModule as $sModuleName => $aModuleDB) + { + if ($sModuleName == ROOT_MODULE) continue; // Skip the main module + + if (!array_key_exists($sModuleName, $aRes)) + { + // A module was installed, it is not proposed in the new build... skip + continue; + } + $aRes[$sModuleName]['version_db'] = $aModuleDB['version']; + + if ($aRes[$sModuleName]['install']['flag'] == MODULE_ACTION_MANDATORY) + { + $aRes[$sModuleName]['uninstall'] = array( + 'flag' => MODULE_ACTION_IMPOSSIBLE, + 'message' => 'the module is part of the application' + ); + } + else + { + $aRes[$sModuleName]['uninstall'] = array( + 'flag' => MODULE_ACTION_OPTIONAL, + 'message' => '' + ); + } + } + + return $aRes; + } + + /** + * Helper function to create the database structure + * @return boolean true on success, false otherwise + */ + public function CreateDatabaseStructure(Config $oConfig, $sMode) + { + if (strlen($oConfig->GetDBSubname()) > 0) + { + $this->log_info("Creating the structure in '".$oConfig->GetDBName()."' (table names prefixed by '".$oConfig->GetDBSubname()."')."); + } + else + { + $this->log_info("Creating the structure in '".$oConfig->GetDBSubname()."'."); + } + + //MetaModel::CheckDefinitions(); + if ($sMode == 'install') + { + if (!MetaModel::DBExists(/* bMustBeComplete */ false)) + { + MetaModel::DBCreate(); + $this->log_ok("Database structure successfully created."); + } + else + { + if (strlen($oConfig->GetDBSubname()) > 0) + { + throw new Exception("Error: found iTop tables into the database '".$oConfig->GetDBName()."' (prefix: '".$oConfig->GetDBSubname()."'). Please, try selecting another database instance or specify another prefix to prevent conflicting table names."); + } + else + { + throw new Exception("Error: found iTop tables into the database '".$oConfig->GetDBName()."'. Please, try selecting another database instance or specify a prefix to prevent conflicting table names."); + } + } + } + else + { + if (MetaModel::DBExists(/* bMustBeComplete */ false)) + { + MetaModel::DBCreate(); + $this->log_ok("Database structure successfully updated."); + + // Check (and update only if it seems needed) the hierarchical keys + ob_start(); + MetaModel::CheckHKeys(false /* bDiagnosticsOnly */, true /* bVerbose*/, true /* bForceUpdate */); // Since in 1.2-beta the detection was buggy, let's force the rebuilding of HKeys + $sFeedback = ob_get_clean(); + $this->log_ok("Hierchical keys rebuilt: $sFeedback"); + + // Check (and fix) data sync configuration + ob_start(); + MetaModel::CheckDataSources(false /*$bDiagnostics*/, true/*$bVerbose*/); + $sFeedback = ob_get_clean(); + $this->log_ok("Data sources checked: $sFeedback"); + } + else + { + if (strlen($oConfig->GetDBSubname()) > 0) + { + throw new Exception("Error: No previous instance of iTop found into the database '".$oConfig->GetDBName()."' (prefix: '".$oConfig->GetDBSubname()."'). Please, try selecting another database instance."); + } + else + { + throw new Exception("Error: No previous instance of iTop found into the database '".$oConfig->GetDBName()."'. Please, try selecting another database instance."); + } + } + } + return true; + } + + public function RecordInstallation(Config $oConfig, $aSelectedModules, $sModulesRelativePath) + { + // Record main installation + $oInstallRec = new ModuleInstallation(); + $oInstallRec->Set('name', ITOP_APPLICATION); + $oInstallRec->Set('version', ITOP_VERSION.'.'.ITOP_REVISION); + $oInstallRec->Set('comment', "Done by the setup program\nBuilt on ".ITOP_BUILD_DATE); + $oInstallRec->Set('parent_id', 0); // root module + $iMainItopRecord = $oInstallRec->DBInsertNoReload(); + + // Record installed modules + // + $aAvailableModules = $this->AnalyzeInstallation($oConfig, $sModulesRelativePath); + foreach($aSelectedModules as $sModuleId) + { + $aModuleData = $aAvailableModules[$sModuleId]; + $sName = $sModuleId; + $sVersion = $aModuleData['version_code']; + $aComments = array(); + $aComments[] = 'Done by the setup program'; + if ($aModuleData['mandatory']) + { + $aComments[] = 'Mandatory'; + } + else + { + $aComments[] = 'Optional'; + } + if ($aModuleData['visible']) + { + $aComments[] = 'Visible (during the setup)'; + } + else + { + $aComments[] = 'Hidden (selected automatically)'; + } + foreach ($aModuleData['dependencies'] as $sDependOn) + { + $aComments[] = "Depends on module: $sDependOn"; + } + $sComment = implode("\n", $aComments); + + $oInstallRec = new ModuleInstallation(); + $oInstallRec->Set('name', $sName); + $oInstallRec->Set('version', $sVersion); + $oInstallRec->Set('comment', $sComment); + $oInstallRec->Set('parent_id', $iMainItopRecord); + $oInstallRec->DBInsertNoReload(); + } + // Database is created, installation has been tracked into it + return true; + } + + /** + * Wrappers for logging into the setup log files + */ + protected function log_error($sText) + { + SetupPage::log_error($sText); + } + protected function log_warning($sText) + { + SetupPage::log_warning($sText); + } + protected function log_info($sText) + { + SetupPage::log_info($sText); + } + protected function log_ok($sText) + { + SetupPage::log_ok($sText); + } +} // End of class + + +?> diff --git a/setup/setuppage.class.inc.php b/setup/setuppage.class.inc.php index f29b45509..d7db91462 100644 --- a/setup/setuppage.class.inc.php +++ b/setup/setuppage.class.inc.php @@ -25,14 +25,10 @@ require_once(APPROOT."/application/nicewebpage.class.inc.php"); require_once(APPROOT."setup/modulediscovery.class.inc.php"); +require_once(APPROOT."setup/runtimeenv.class.inc.php"); define('INSTALL_LOG_FILE', APPROOT.'/setup.log'); -define ('MODULE_ACTION_OPTIONAL', 1); -define ('MODULE_ACTION_MANDATORY', 2); -define ('MODULE_ACTION_IMPOSSIBLE', 3); -define ('ROOT_MODULE', '_Root_'); // Convention to store IN MEMORY the name/version of the root module i.e. application - date_default_timezone_set('Europe/Paris'); class SetupPage extends NiceWebPage { @@ -309,322 +305,4 @@ h3.clickable.open { } } // End of class - - -/** - * Helper function to initialize the ORM and load the data model - * from the given file - * @param $oConfig object The configuration (volatile, not necessarily already on disk) - * @param $bModelOnly boolean Whether or not to allow loading a data model with no corresponding DB - * @return none - */ -function InitDataModel($oConfig, $bModelOnly = true, $bUseCache = false) -{ - require_once(APPROOT.'/core/log.class.inc.php'); - require_once(APPROOT.'/core/kpi.class.inc.php'); - require_once(APPROOT.'/core/coreexception.class.inc.php'); - require_once(APPROOT.'/core/dict.class.inc.php'); - require_once(APPROOT.'/core/attributedef.class.inc.php'); - require_once(APPROOT.'/core/filterdef.class.inc.php'); - require_once(APPROOT.'/core/stimulus.class.inc.php'); - require_once(APPROOT.'/core/MyHelpers.class.inc.php'); - require_once(APPROOT.'/core/expression.class.inc.php'); - require_once(APPROOT.'/core/cmdbsource.class.inc.php'); - require_once(APPROOT.'/core/sqlquery.class.inc.php'); - require_once(APPROOT.'/core/dbobject.class.php'); - require_once(APPROOT.'/core/dbobjectsearch.class.php'); - require_once(APPROOT.'/core/dbobjectset.class.php'); - require_once(APPROOT.'/application/cmdbabstract.class.inc.php'); - require_once(APPROOT.'/core/userrights.class.inc.php'); - require_once(APPROOT.'/setup/moduleinstallation.class.inc.php'); - - $sConfigFile = $oConfig->GetLoadedFile(); - if (strlen($sConfigFile) > 0) - { - SetupPage::log_info("MetaModel::Startup from $sConfigFile (ModelOnly = $bModelOnly)"); - } - else - { - SetupPage::log_info("MetaModel::Startup (ModelOnly = $bModelOnly)"); - } - - if (!$bUseCache) - { - // Reset the cache for the first use ! - MetaModel::ResetCache($oConfig); - } - - MetaModel::Startup($oConfig, $bModelOnly, $bUseCache); -} - -/** - * Analyzes the current installation and the possibilities - * - * @param $oConfig Config Defines the target environment (DB) - * @return hash Array with the following format: - * array => - * 'iTop' => array( - * 'version_db' => ... (could be empty in case of a fresh install) - * 'version_code => ... - * ) - * => array( - * 'version_db' => ... - * 'version_code' => ... - * 'install' => array( - * 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY - * 'message' => ... - * ) - * 'uninstall' => array( - * 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY - * 'message' => ... - * ) - * 'label' => ... - * 'dependencies' => array(, , ...) - * 'visible' => true | false - * ) - * ) - */ -function AnalyzeInstallation($oConfig, $sModulesRelativePath) -{ - $aRes = array( - ROOT_MODULE => array( - 'version_db' => '', - 'name_db' => '', - 'version_code' => ITOP_VERSION.'.'.ITOP_REVISION, - 'name_code' => ITOP_APPLICATION, - ) - ); - - $aModules = ModuleDiscovery::GetAvailableModules(APPROOT, $sModulesRelativePath); - foreach($aModules as $sModuleId => $aModuleInfo) - { - list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId); - - $sModuleAppVersion = $aModuleInfo['itop_version']; - $aModuleInfo['version_db'] = ''; - $aModuleInfo['version_code'] = $sModuleVersion; - - if (!in_array($sModuleAppVersion, array('1.0.0', '1.0.1', '1.0.2'))) - { - // This module is NOT compatible with the current version - $aModuleInfo['install'] = array( - 'flag' => MODULE_ACTION_IMPOSSIBLE, - 'message' => 'the module is not compatible with the current version of the application' - ); - } - elseif ($aModuleInfo['mandatory']) - { - $aModuleInfo['install'] = array( - 'flag' => MODULE_ACTION_MANDATORY, - 'message' => 'the module is part of the application' - ); - } - else - { - $aModuleInfo['install'] = array( - 'flag' => MODULE_ACTION_OPTIONAL, - 'message' => '' - ); - } - $aRes[$sModuleName] = $aModuleInfo; - } - - try - { - CMDBSource::Init($oConfig->GetDBHost(), $oConfig->GetDBUser(), $oConfig->GetDBPwd(), $oConfig->GetDBName()); - $aSelectInstall = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->GetDBSubname()."priv_module_install"); - } - catch (MySQLException $e) - { - // No database or eroneous information - $aSelectInstall = array(); - } - - // Build the list of installed module (get the latest installation) - // - $aInstallByModule = array(); // array of => array ('installed' => timestamp, 'version' => ) - foreach ($aSelectInstall as $aInstall) - { - //$aInstall['comment']; // unsused - $iInstalled = strtotime($aInstall['installed']); - $sModuleName = $aInstall['name']; - $sModuleVersion = $aInstall['version']; - - if ($aInstall['parent_id'] == 0) - { - $sModuleName = ROOT_MODULE; - } - - if (array_key_exists($sModuleName, $aInstallByModule)) - { - if ($iInstalled < $aInstallByModule[$sModuleName]['installed']) - { - continue; - } - } - - if ($aInstall['parent_id'] == 0) - { - $aRes[$sModuleName]['version_db'] = $sModuleVersion; - $aRes[$sModuleName]['name_db'] = $aInstall['name']; - } - - $aInstallByModule[$sModuleName]['installed'] = $iInstalled; - $aInstallByModule[$sModuleName]['version'] = $sModuleVersion; - } - - // Adjust the list of proposed modules - // - foreach ($aInstallByModule as $sModuleName => $aModuleDB) - { - if ($sModuleName == ROOT_MODULE) continue; // Skip the main module - - if (!array_key_exists($sModuleName, $aRes)) - { - // A module was installed, it is not proposed in the new build... skip - continue; - } - $aRes[$sModuleName]['version_db'] = $aModuleDB['version']; - - if ($aRes[$sModuleName]['install']['flag'] == MODULE_ACTION_MANDATORY) - { - $aRes[$sModuleName]['uninstall'] = array( - 'flag' => MODULE_ACTION_IMPOSSIBLE, - 'message' => 'the module is part of the application' - ); - } - else - { - $aRes[$sModuleName]['uninstall'] = array( - 'flag' => MODULE_ACTION_OPTIONAL, - 'message' => '' - ); - } - } - - return $aRes; -} - -/** - * Helper function to create the database structure - * @return boolean true on success, false otherwise - */ -function CreateDatabaseStructure(Config $oConfig, $sMode) -{ - if (strlen($oConfig->GetDBSubname()) > 0) - { - SetupPage::log_info("Creating the structure in '".$oConfig->GetDBName()."' (table names prefixed by '".$oConfig->GetDBSubname()."')."); - } - else - { - SetupPage::log_info("Creating the structure in '".$oConfig->GetDBSubname()."'."); - } - - //MetaModel::CheckDefinitions(); - if ($sMode == 'install') - { - if (!MetaModel::DBExists(/* bMustBeComplete */ false)) - { - MetaModel::DBCreate(); - SetupPage::log_ok("Database structure successfully created."); - } - else - { - if (strlen($oConfig->GetDBSubname()) > 0) - { - throw new Exception("Error: found iTop tables into the database '".$oConfig->GetDBName()."' (prefix: '".$oConfig->GetDBSubname()."'). Please, try selecting another database instance or specify another prefix to prevent conflicting table names."); - } - else - { - throw new Exception("Error: found iTop tables into the database '".$oConfig->GetDBName()."'. Please, try selecting another database instance or specify a prefix to prevent conflicting table names."); - } - } - } - else - { - if (MetaModel::DBExists(/* bMustBeComplete */ false)) - { - MetaModel::DBCreate(); - SetupPage::log_ok("Database structure successfully updated."); - - // Check (and update only if it seems needed) the hierarchical keys - ob_start(); - MetaModel::CheckHKeys(false /* bDiagnosticsOnly */, true /* bVerbose*/, true /* bForceUpdate */); // Since in 1.2-beta the detection was buggy, let's force the rebuilding of HKeys - $sFeedback = ob_get_clean(); - SetupPage::log_ok("Hierchical keys rebuilt: $sFeedback"); - - // Check (and fix) data sync configuration - ob_start(); - MetaModel::CheckDataSources(false /*$bDiagnostics*/, true/*$bVerbose*/); - $sFeedback = ob_get_clean(); - SetupPage::log_ok("Data sources checked: $sFeedback"); - } - else - { - if (strlen($oConfig->GetDBSubname()) > 0) - { - throw new Exception("Error: No previous instance of iTop found into the database '".$oConfig->GetDBName()."' (prefix: '".$oConfig->GetDBSubname()."'). Please, try selecting another database instance."); - } - else - { - throw new Exception("Error: No previous instance of iTop found into the database '".$oConfig->GetDBName()."'. Please, try selecting another database instance."); - } - } - } - return true; -} - -function RecordInstallation(Config $oConfig, $aSelectedModules, $sModulesRelativePath) -{ - // Record main installation - $oInstallRec = new ModuleInstallation(); - $oInstallRec->Set('name', ITOP_APPLICATION); - $oInstallRec->Set('version', ITOP_VERSION.'.'.ITOP_REVISION); - $oInstallRec->Set('comment', "Done by the setup program\nBuilt on ".ITOP_BUILD_DATE); - $oInstallRec->Set('parent_id', 0); // root module - $iMainItopRecord = $oInstallRec->DBInsertNoReload(); - - // Record installed modules - // - $aAvailableModules = AnalyzeInstallation($oConfig, $sModulesRelativePath); - foreach($aSelectedModules as $sModuleId) - { - $aModuleData = $aAvailableModules[$sModuleId]; - $sName = $sModuleId; - $sVersion = $aModuleData['version_code']; - $aComments = array(); - $aComments[] = 'Done by the setup program'; - if ($aModuleData['mandatory']) - { - $aComments[] = 'Mandatory'; - } - else - { - $aComments[] = 'Optional'; - } - if ($aModuleData['visible']) - { - $aComments[] = 'Visible (during the setup)'; - } - else - { - $aComments[] = 'Hidden (selected automatically)'; - } - foreach ($aModuleData['dependencies'] as $sDependOn) - { - $aComments[] = "Depends on module: $sDependOn"; - } - $sComment = implode("\n", $aComments); - - $oInstallRec = new ModuleInstallation(); - $oInstallRec->Set('name', $sName); - $oInstallRec->Set('version', $sVersion); - $oInstallRec->Set('comment', $sComment); - $oInstallRec->Set('parent_id', $iMainItopRecord); - $oInstallRec->DBInsertNoReload(); - } - // Database is created, installation has been tracked into it - return true; -} - ?>