diff --git a/application/loginwebpage.class.inc.php b/application/loginwebpage.class.inc.php index 35c6daee2..e5a454f15 100644 --- a/application/loginwebpage.class.inc.php +++ b/application/loginwebpage.class.inc.php @@ -433,7 +433,7 @@ EOF if ($bMustBeAdmin && !UserRights::IsAdministrator()) { require_once(APPROOT.'/setup/setuppage.class.inc.php'); - $oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError')); + $oP = new SetupPage(Dict::S('UI:PageTitle:FatalError')); $oP->add("

".Dict::S('UI:Login:Error:AccessAdmin')."

\n"); $oP->p("".Dict::S('UI:LogOffMenu').""); $oP->output(); diff --git a/core/config.class.inc.php b/core/config.class.inc.php index c1abed60f..ad326c45e 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -551,8 +551,8 @@ class Config protected $m_bLogNotification; protected $m_bLogIssue; protected $m_bLogWebService; - protected $m_bLogKpiDuration; // private setting - protected $m_bLogKpiMemory; // private setting + protected $m_bLogKPIDuration; // private setting + protected $m_bLogKPIMemory; // private setting protected $m_bDebugQueries; // private setting protected $m_bQueryCacheEnabled; // private setting diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 8f38847f5..ad670092b 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -825,7 +825,11 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) final static public function GetClassFilterDef($sClass, $sFilterCode) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); + if (!array_key_exists($sFilterCode, self::$m_aFilterDefs[$sClass])) + { + throw new CoreException("Unknown filter code '$sFilterCode' for class '$sClass'"); + } return self::$m_aFilterDefs[$sClass][$sFilterCode]; } @@ -4028,11 +4032,19 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) } } - public static function Startup($sConfigFile, $bModelOnly = false, $bAllowCache = true, $bTraceSourceFiles = false) + public static function Startup($config, $bModelOnly = false, $bAllowCache = true, $bTraceSourceFiles = false) { self::$m_bTraceSourceFiles = $bTraceSourceFiles; - self::LoadConfig($sConfigFile, $bAllowCache); + // $config can be either a filename, or a Configuration object (volatile!) + if ($config instanceof Config) + { + self::LoadConfig($config, $bAllowCache); + } + else + { + self::LoadConfig(new Config($config), $bAllowCache); + } if ($bModelOnly) return; @@ -4054,9 +4066,9 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) } } - public static function LoadConfig($sConfigFile, $bAllowCache = false) + public static function LoadConfig($oConfiguration, $bAllowCache = false) { - self::$m_oConfig = new Config($sConfigFile); + self::$m_oConfig = $oConfiguration; // Set log ASAP if (self::$m_oConfig->GetLogGlobal()) @@ -4119,7 +4131,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) { foreach (self::$m_oConfig->GetDictionaries() as $sModule => $sToInclude) { - self::IncludeModule($sConfigFile, 'dictionaries', $sToInclude); + self::IncludeModule('dictionaries', $sToInclude); } if (self::$m_bUseAPCCache) { @@ -4135,19 +4147,19 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) foreach (self::$m_oConfig->GetAppModules() as $sModule => $sToInclude) { - self::IncludeModule($sConfigFile, 'application', $sToInclude); + self::IncludeModule('application', $sToInclude); } foreach (self::$m_oConfig->GetDataModels() as $sModule => $sToInclude) { - self::IncludeModule($sConfigFile, 'business', $sToInclude); + self::IncludeModule('business', $sToInclude); } foreach (self::$m_oConfig->GetWebServiceCategories() as $sModule => $sToInclude) { - self::IncludeModule($sConfigFile, 'webservice', $sToInclude); + self::IncludeModule('webservice', $sToInclude); } foreach (self::$m_oConfig->GetAddons() as $sModule => $sToInclude) { - self::IncludeModule($sConfigFile, 'addons', $sToInclude); + self::IncludeModule('addons', $sToInclude); } $sServer = self::$m_oConfig->GetDBHost(); @@ -4249,7 +4261,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) protected static $m_aExtensionClasses = array(); - protected static function IncludeModule($sConfigFile, $sModuleType, $sToInclude) + protected static function IncludeModule($sModuleType, $sToInclude) { $sFirstChar = substr($sToInclude, 0, 1); $sSecondChar = substr($sToInclude, 1, 1); @@ -4274,6 +4286,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) } if (!file_exists($sFile)) { + $sConfigFile = self::$m_oConfig->GetLoadedFile(); throw new CoreException('Wrong filename in configuration file', array('file' => $sConfigFile, 'module' => $sModuleType, 'filename' => $sFile)); } require_once($sFile); diff --git a/modules/itop-attachments/module.attachments.php b/modules/itop-attachments/module.attachments.php index 2ae724e98..613ca107a 100644 --- a/modules/itop-attachments/module.attachments.php +++ b/modules/itop-attachments/module.attachments.php @@ -98,12 +98,12 @@ class AttachmentInstaller extends ModuleInstallerAPI // get the org_id from the container object // // Prerequisite: change null into 0 (workaround to the fact that we cannot use IS NULL in OQL) - SetupWebPage::log_info("Initializing attachment/item_org_id - null to zero"); + SetupPage::log_info("Initializing attachment/item_org_id - null to zero"); $sTableName = MetaModel::DBGetTable('Attachment'); $sRepair = "UPDATE `$sTableName` SET `item_org_id` = 0 WHERE `item_org_id` IS NULL"; CMDBSource::Query($sRepair); - SetupWebPage::log_info("Initializing attachment/item_org_id - zero to the container"); + SetupPage::log_info("Initializing attachment/item_org_id - zero to the container"); $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE item_org_id = 0"); $oSet = new DBObjectSet($oSearch); $iUpdated = 0; @@ -117,7 +117,7 @@ class AttachmentInstaller extends ModuleInstallerAPI } } - SetupWebPage::log_info("Initializing attachment/item_org_id - $iUpdated records have been adjusted"); + SetupPage::log_info("Initializing attachment/item_org_id - $iUpdated records have been adjusted"); } } diff --git a/modules/itop-change-mgmt-1.0.0/module.itop-change-mgmt.php b/modules/itop-change-mgmt-1.0.0/module.itop-change-mgmt.php index e45e671ae..f5a1e79bb 100644 --- a/modules/itop-change-mgmt-1.0.0/module.itop-change-mgmt.php +++ b/modules/itop-change-mgmt-1.0.0/module.itop-change-mgmt.php @@ -85,7 +85,7 @@ class ChangeManagementInstaller extends ModuleInstallerAPI if (CMDBSource::IsField($sSourceTable, $sField) && CMDBSource::IsField($sTargetTable, $sField) && CMDBSource::IsField($sSourceTable, $sSourceKeyField) && CMDBSource::IsField($sTargetTable, $sTargetKeyField)) { - SetupWebPage::log_info("Issue #464 - Copying change/start_date into ticket/start_date"); + SetupPage::log_info("Issue #464 - Copying change/start_date into ticket/start_date"); $sRepair = "UPDATE `$sTargetTable`, `$sSourceTable` SET `$sTargetTable`.`$sField` = `$sSourceTable`.`$sField` WHERE `$sTargetTable`.`$sField` IS NULL AND`$sTargetTable`.`$sTargetKeyField` = `$sSourceTable`.`$sSourceKeyField`"; CMDBSource::Query($sRepair); } diff --git a/modules/itop-config-mgmt-1.0.0/model.itop-config-mgmt.php b/modules/itop-config-mgmt-1.0.0/model.itop-config-mgmt.php index 376bf6e92..a48a187ff 100644 --- a/modules/itop-config-mgmt-1.0.0/model.itop-config-mgmt.php +++ b/modules/itop-config-mgmt-1.0.0/model.itop-config-mgmt.php @@ -1599,14 +1599,6 @@ class lnkProcessToSolution extends cmdbAbstractObject // Create the top-level group. fRank = 1, means it will be inserted after the group '0', which is usually 'Welcome' -// Note (RQ) : -// After 1.0.1, the welcome page and menus have been removed from the application -// and put into a separate module "itop-welcome-itil" -// Until we develop a migration utility, and as would like to preserve the -// capability to upgrade iTop without any manual operation, we have decided to -// implement this dirty workaround that makes it... -require_once(APPROOT.'modules/itop-welcome-itil/model.itop-welcome-itil.php'); - // Starting with iTop 1.2 you can restrict the list of organizations displayed in the drop-down list // by specifying a query as shown below. Note that this is NOT a security settings, since the // choice 'All Organizations' will always be available in the menu diff --git a/pages/UI.php b/pages/UI.php index 5d2d5447c..5b01b6f6d 100644 --- a/pages/UI.php +++ b/pages/UI.php @@ -2188,7 +2188,7 @@ EOF catch(CoreException $e) { require_once(APPROOT.'/setup/setuppage.class.inc.php'); - $oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError')); + $oP = new SetupPage(Dict::S('UI:PageTitle:FatalError')); if ($e instanceof SecurityException) { $oP->add("

".Dict::S('UI:SystemIntrusion')."

\n"); @@ -2231,7 +2231,7 @@ catch(CoreException $e) catch(Exception $e) { require_once(APPROOT.'/setup/setuppage.class.inc.php'); - $oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError')); + $oP = new SetupPage(Dict::S('UI:PageTitle:FatalError')); $oP->add("

".Dict::S('UI:FatalErrorMessage')."

\n"); $oP->error(Dict::Format('UI:Error_Details', $e->getMessage())); $oP->output(); diff --git a/pages/audit.php b/pages/audit.php index b31ac4491..68c1a3dcd 100644 --- a/pages/audit.php +++ b/pages/audit.php @@ -269,7 +269,7 @@ try catch(CoreException $e) { require_once(APPROOT.'/setup/setuppage.class.inc.php'); - $oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError')); + $oP = new SetupPage(Dict::S('UI:PageTitle:FatalError')); $oP->add("

".Dict::S('UI:FatalErrorMessage')."

\n"); $oP->error(Dict::Format('UI:Error_Details', $e->getHtmlDesc())); $oP->output(); @@ -298,7 +298,7 @@ catch(CoreException $e) catch(Exception $e) { require_once(APPROOT.'/setup/setuppage.class.inc.php'); - $oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError')); + $oP = new SetupPage(Dict::S('UI:PageTitle:FatalError')); $oP->add("

".Dict::S('UI:FatalErrorMessage')."

\n"); $oP->error(Dict::Format('UI:Error_Details', $e->getMessage())); $oP->output(); diff --git a/pages/csvimport.php b/pages/csvimport.php index 200e80b0d..bd64ee5b2 100644 --- a/pages/csvimport.php +++ b/pages/csvimport.php @@ -1438,10 +1438,10 @@ EOF $oPage->output(); } -catch(xxxxxxxCoreException $e) +catch(CoreException $e) { require_once(APPROOT.'/setup/setuppage.class.inc.php'); - $oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError')); + $oP = new SetupPage(Dict::S('UI:PageTitle:FatalError')); $oP->add("

".Dict::S('UI:FatalErrorMessage')."

\n"); $oP->error(Dict::Format('UI:Error_Details', $e->getHtmlDesc())); $oP->output(); @@ -1467,10 +1467,10 @@ catch(xxxxxxxCoreException $e) // For debugging only //throw $e; } -catch(xxxxxException $e) +catch(Exception $e) { require_once(APPROOT.'/setup/setuppage.class.inc.php'); - $oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError')); + $oP = new SetupPage(Dict::S('UI:PageTitle:FatalError')); $oP->add("

".Dict::S('UI:FatalErrorMessage')."

\n"); $oP->error(Dict::Format('UI:Error_Details', $e->getMessage())); $oP->output(); diff --git a/pages/preferences.php b/pages/preferences.php index e7bbea26d..9380b981c 100644 --- a/pages/preferences.php +++ b/pages/preferences.php @@ -157,7 +157,7 @@ try catch(CoreException $e) { require_once(APPROOT.'/setup/setuppage.class.inc.php'); - $oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError')); + $oP = new SetupPage(Dict::S('UI:PageTitle:FatalError')); $oP->add("

".Dict::S('UI:FatalErrorMessage')."

\n"); $oP->error(Dict::Format('UI:Error_Details', $e->getHtmlDesc())); $oP->output(); @@ -186,7 +186,7 @@ catch(CoreException $e) catch(Exception $e) { require_once(APPROOT.'/setup/setuppage.class.inc.php'); - $oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError')); + $oP = new SetupPage(Dict::S('UI:PageTitle:FatalError')); $oP->add("

".Dict::S('UI:FatalErrorMessage')."

\n"); $oP->error(Dict::Format('UI:Error_Details', $e->getMessage())); $oP->output(); diff --git a/portal/index.php b/portal/index.php index 61ae12a58..f5c50f0c4 100644 --- a/portal/index.php +++ b/portal/index.php @@ -816,7 +816,7 @@ try catch(CoreException $e) { require_once(APPROOT.'/setup/setuppage.class.inc.php'); - $oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError')); + $oP = new SetupPage(Dict::S('UI:PageTitle:FatalError')); $oP->add("

".Dict::S('UI:FatalErrorMessage')."

\n"); $oP->error(Dict::Format('UI:Error_Details', $e->getHtmlDesc())); $oP->output(); @@ -852,7 +852,7 @@ catch(CoreException $e) catch(Exception $e) { require_once(APPROOT.'/setup/setuppage.class.inc.php'); - $oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError')); + $oP = new SetupPage(Dict::S('UI:PageTitle:FatalError')); $oP->add("

".Dict::S('UI:FatalErrorMessage')."

\n"); $oP->error(Dict::Format('UI:Error_Details', $e->getMessage())); $oP->output(); diff --git a/setup/ajax.dataloader.php b/setup/ajax.dataloader.php index f8168f08c..0d13659d9 100644 --- a/setup/ajax.dataloader.php +++ b/setup/ajax.dataloader.php @@ -26,7 +26,7 @@ /** * This page is called to perform "asynchronously" the setup actions * parameters - * 'operation': one of 'update_db_schema', 'after_db_creation', 'file' + * 'operation': one of 'compile_data_model', 'update_db_schema', 'after_db_creation', 'file' * * if 'operation' == 'update_db_schema': * 'mode': install | upgrade @@ -51,7 +51,7 @@ if (empty($sMemoryLimit)) // On some PHP installations, memory_limit does not exist as a PHP setting! // (encountered on a 5.2.0 under Windows) // In that case, ini_set will not work, let's keep track of this and proceed with the data load - SetupWebPage::log_info("No memory limit has been defined in this instance of PHP"); + SetupPage::log_info("No memory limit has been defined in this instance of PHP"); } else { @@ -62,11 +62,11 @@ else { if (ini_set('memory_limit', SAFE_MINIMUM_MEMORY) === FALSE) { - SetupWebPage::log_error("memory_limit is too small: $iMemoryLimit and can not be increased by the script itself."); + SetupPage::log_error("memory_limit is too small: $iMemoryLimit and can not be increased by the script itself."); } else { - SetupWebPage::log_info("memory_limit increased from $iMemoryLimit to ".SAFE_MINIMUM_MEMORY."."); + SetupPage::log_info("memory_limit increased from $iMemoryLimit to ".SAFE_MINIMUM_MEMORY."."); } } @@ -84,7 +84,7 @@ function FatalErrorCatcher($sOutput) } $sOutput = "$errors\n"; // Logging to a file does not work if the whole memory is exhausted... - //SetupWebPage::log_error("Fatal error - in $__FILE__ , $errors"); + //SetupPage::log_error("Fatal error - in $__FILE__ , $errors"); } return $sOutput; } @@ -95,7 +95,7 @@ function FatalErrorCatcher($sOutput) */ function CreateAdminAccount(Config $oConfig, $sAdminUser, $sAdminPwd, $sLanguage) { - SetupWebPage::log_info('CreateAdminAccount'); + SetupPage::log_info('CreateAdminAccount'); if (UserRights::CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage)) { @@ -136,49 +136,137 @@ try { switch($sOperation) { - - case 'update_db_schema': - SetupWebPage::log_info("Update Database Schema."); - InitDataModel(TMP_CONFIG_FILE, true); // load data model and connect to the database - $sMode = Utils::ReadParam('mode', 'install'); + ////////////////////////////// + // + case 'compile_data_model': + // + SetupPage::log_info("Compiling data model."); + + require_once(APPROOT.'designer/modulediscovery.class.inc.php'); + require_once(APPROOT.'designer/modelfactory.inc.class.php'); + require_once(APPROOT.'designer/compiler.inc.class.php'); + $sSelectedModules = Utils::ReadParam('selected_modules', '', false, 'raw_data'); $aSelectedModules = explode(',', $sSelectedModules); - if(!CreateDatabaseStructure(MetaModel::GetConfig(), $aSelectedModules, $sMode)) + + $sWorkspace = Utils::ReadParam('workspace_dir', '', false, 'raw_data'); + $sSourceDir = Utils::ReadParam('source_dir', '', false, 'raw_data'); + $sTargetDir = Utils::ReadParam('target_dir', '', false, 'raw_data'); + if (empty($sSourceDir) || empty($sTargetDir)) + { + throw new Exception("missing parameter source_dir and/or target_dir"); + } + + $sSourcePath = APPROOT.$sSourceDir; + $sTargetPath = APPROOT.$sTargetDir; + if (!is_dir($sSourcePath)) + { + throw new Exception("Failed to find the source directory '$sSourcePath', please check the rights of the web server"); + } + if (!is_dir($sTargetPath) && !mkdir($sTargetPath)) + { + throw new Exception("Failed to create directory '$sTargetPath', please check the rights of the web server"); + } + // owner:rwx user/group:rx + chmod($sTargetPath, 0755); + + $oFactory = new ModelFactory($sSourcePath); + $aModules = $oFactory->FindModules(); + + foreach($aModules as $foo => $oModule) + { + $sModule = $oModule->GetName(); + if (in_array($sModule, $aSelectedModules)) + { + $oFactory->LoadModule($oModule); + } + } + if (strlen($sWorkspace) > 0) + { + $oWorkspace = new MFWorkspace(APPROOT.$sWorkspace); + if (file_exists($oWorkspace->GetWorkspacePath())) + { + $oFactory->LoadModule($oWorkspace); + } + } + //$oFactory->Dump(); + + $oMFCompiler = new MFCompiler($oFactory, $sSourcePath); + $oMFCompiler->Compile($sTargetPath); + SetupPage::log_info("Data model successfully compiled to '$sTargetPath'."); + break; + + ////////////////////////////// + // + case 'update_db_schema': + // + SetupPage::log_info("Update Database Schema."); + + $oConfig = new Config(TMP_CONFIG_FILE, false /* Don't try to load it */); + + $aParamValues = array( + 'db_server' => utils::ReadParam('db_server', '', false, 'raw_data'), + 'db_user' => utils::ReadParam('db_user', '', false, 'raw_data'), + 'db_pwd' => utils::ReadParam('db_pwd', '', false, 'raw_data'), + 'db_name' => utils::ReadParam('db_name', '', false, 'raw_data'), + 'new_db_name' => utils::ReadParam('new_db_name', '', false, 'raw_data'), + 'db_prefix' => utils::ReadParam('db_prefix', '', false, 'raw_data') + ); + $sModuleDir = Utils::ReadParam('modules_dir', ''); + UpdateConfigSettings($oConfig, $aParamValues, $sModuleDir); + + InitDataModel($oConfig, true); // load data model only + + $sMode = Utils::ReadParam('mode', 'install'); + if(!CreateDatabaseStructure(MetaModel::GetConfig(), $sMode)) { throw(new Exception("Failed to create/upgrade the database structure")); } - SetupWebPage::log_info("Database Schema Successfully Updated."); + SetupPage::log_info("Database Schema Successfully Updated."); break; + ////////////////////////////// + // case 'after_db_create': - SetupWebPage::log_info('After Database Creation'); + // + SetupPage::log_info('After Database Creation'); + + $oConfig = new Config(TMP_CONFIG_FILE, false /* Don't try to load it */); + + $aParamValues = array( + 'db_server' => utils::ReadParam('db_server', '', false, 'raw_data'), + 'db_user' => utils::ReadParam('db_user', '', false, 'raw_data'), + 'db_pwd' => utils::ReadParam('db_pwd', '', false, 'raw_data'), + 'db_name' => utils::ReadParam('db_name', '', false, 'raw_data'), + 'new_db_name' => utils::ReadParam('new_db_name', '', false, 'raw_data'), + 'db_prefix' => utils::ReadParam('db_prefix', '', false, 'raw_data') + ); + $sModuleDir = Utils::ReadParam('modules_dir', ''); + UpdateConfigSettings($oConfig, $aParamValues, $sModuleDir); + + InitDataModel($oConfig, false); // load data model and connect to the database + $sMode = Utils::ReadParam('mode', 'install'); $sSelectedModules = Utils::ReadParam('selected_modules', '', false, 'raw_data'); $aSelectedModules = explode(',', $sSelectedModules); - InitDataModel(TMP_CONFIG_FILE, true); // load data model and connect to the database // Perform here additional DB setup... profiles, etc... - - $aAvailableModules = AnalyzeInstallation(MetaModel::GetConfig()); - - $aStructureDataFiles = array(); - $aSampleDataFiles = array(); - + // + $aAvailableModules = AnalyzeInstallation(MetaModel::GetConfig(), $sModuleDir); foreach($aAvailableModules as $sModuleId => $aModule) { if (($sModuleId != ROOT_MODULE) && in_array($sModuleId, $aSelectedModules) && isset($aAvailableModules[$sModuleId]['installer']) ) { $sModuleInstallerClass = $aAvailableModules[$sModuleId]['installer']; - SetupWebPage::log_info("Calling Module Handler: $sModuleInstallerClass::AfterDatabaseCreation(oConfig, {$aModule['version_db']}, {$aModule['version_code']})"); + SetupPage::log_info("Calling Module Handler: $sModuleInstallerClass::AfterDatabaseCreation(oConfig, {$aModule['version_db']}, {$aModule['version_code']})"); // The validity of the sModuleInstallerClass has been established in BuildConfig() $aCallSpec = array($sModuleInstallerClass, 'AfterDatabaseCreation'); call_user_func_array($aCallSpec, array(MetaModel::GetConfig(), $aModule['version_db'], $aModule['version_code'])); } } - - if (!RecordInstallation(MetaModel::GetConfig(), $aSelectedModules)) + if (!RecordInstallation($oConfig, $aSelectedModules, $sModuleDir)) { throw(new Exception("Failed to record the installation information")); } @@ -195,22 +283,39 @@ try } else { - SetupWebPage::log_info("Administrator account '$sAdminUser' created."); + SetupPage::log_info("Administrator account '$sAdminUser' created."); } } break; + ////////////////////////////// + // case 'load_data': // Load data files + // $sFileName = Utils::ReadParam('file', '', false, 'raw_data'); $sSessionStatus = Utils::ReadParam('session_status', ''); $iPercent = (integer)Utils::ReadParam('percent', 0); - SetupWebPage::log_info("Loading file: $sFileName"); + SetupPage::log_info("Loading file: $sFileName"); if (empty($sFileName) || !file_exists($sFileName)) { throw(new Exception("File $sFileName does not exist")); } - - InitDataModel(TMP_CONFIG_FILE, false); // When called by the wizard, the final config is not yet there + + $oConfig = new Config(TMP_CONFIG_FILE, false /* Don't try to load it */); + + $aParamValues = array( + 'db_server' => utils::ReadParam('db_server', '', false, 'raw_data'), + 'db_user' => utils::ReadParam('db_user', '', false, 'raw_data'), + 'db_pwd' => utils::ReadParam('db_pwd', '', false, 'raw_data'), + 'db_name' => utils::ReadParam('db_name', '', false, 'raw_data'), + 'new_db_name' => utils::ReadParam('new_db_name', '', false, 'raw_data'), + 'db_prefix' => utils::ReadParam('db_prefix', '', false, 'raw_data') + ); + $sModuleDir = Utils::ReadParam('modules_dir', ''); + UpdateConfigSettings($oConfig, $aParamValues, $sModuleDir); + + InitDataModel($oConfig, false); // load data model and connect to the database + $oDataLoader = new XMLDataLoader(); if ($sSessionStatus == 'start') { @@ -218,18 +323,18 @@ try $oChange->Set("date", time()); $oChange->Set("userinfo", "Initialization"); $iChangeId = $oChange->DBInsert(); - SetupWebPage::log_info("starting data load session"); + SetupPage::log_info("starting data load session"); $oDataLoader->StartSession($oChange); } $oDataLoader->LoadFile($sFileName); $sResult = sprintf("loading of %s done. (Overall %d %% completed).", basename($sFileName), $iPercent); - SetupWebPage::log_info($sResult); + SetupPage::log_info($sResult); if ($sSessionStatus == 'end') { $oDataLoader->EndSession(); - SetupWebPage::log_info("ending data load session"); + SetupPage::log_info("ending data load session"); } break; @@ -242,18 +347,18 @@ catch(Exception $e) header("HTTP/1.0 500 Internal server error."); echo "

An error happened while processing the installation:

\n"; echo '

'.$e."

\n"; - SetupWebPage::log_error("An error happened while processing the installation: ".$e); + SetupPage::log_error("An error happened while processing the installation: ".$e); } if (function_exists('memory_get_peak_usage')) { if ($sOperation == 'file') { - SetupWebPage::log_info("loading file '$sFileName', peak memory usage. ".memory_get_peak_usage()); + SetupPage::log_info("loading file '$sFileName', peak memory usage. ".memory_get_peak_usage()); } else { - SetupWebPage::log_info("operation '$sOperation', peak memory usage. ".memory_get_peak_usage()); + SetupPage::log_info("operation '$sOperation', peak memory usage. ".memory_get_peak_usage()); } } ?> diff --git a/setup/email.test.php b/setup/email.test.php index 32dc45081..0ea574b54 100644 --- a/setup/email.test.php +++ b/setup/email.test.php @@ -32,7 +32,7 @@ require_once(APPROOT.'/core/email.class.inc.php'); require_once('./setuppage.class.inc.php'); $sOperation = Utils::ReadParam('operation', 'step1'); -$oP = new SetupWebPage('iTop email test utility'); +$oP = new SetupPage('iTop email test utility'); /** @@ -110,7 +110,7 @@ function CheckEmailSetting($oP) * Display the form for the first step of the test wizard * which consists in a basic check of the configuration and display of a form for testing */ -function DisplayStep1(SetupWebPage $oP) +function DisplayStep1(SetupPage $oP) { $sNextOperation = 'step2'; $oP->add("

iTop email test

\n"); @@ -145,7 +145,7 @@ function DisplayStep1(SetupWebPage $oP) * Display the form for the second step of the configuration wizard * which consists in sending an email, which maybe a problem under Windows */ -function DisplayStep2(SetupWebPage $oP, $sFrom, $sTo) +function DisplayStep2(SetupPage $oP, $sFrom, $sTo) { //$sNextOperation = 'step3'; $oP->add("

iTop configuration wizard

\n"); diff --git a/setup/index.php b/setup/index.php index 7b2ca2866..0d9bf84af 100644 --- a/setup/index.php +++ b/setup/index.php @@ -40,7 +40,7 @@ define('MIN_MEMORY_LIMIT', 32*1024*1024); define('SUHOSIN_GET_MAX_VALUE_LENGTH', 2048); $sOperation = Utils::ReadParam('operation', 'step0'); -$oP = new SetupWebPage('iTop configuration wizard'); +$oP = new SetupPage('iTop configuration wizard'); /////////////////////////////////////////////////////////////////////////////////////////////////// // Various helper function @@ -120,7 +120,7 @@ function GetUploadTmpDir() * is compatible with the application * @return boolean true if this is Ok, false otherwise */ -function CheckPHPVersion(SetupWebPage $oP) +function CheckPHPVersion(SetupPage $oP) { $bResult = true; $aErrors = array(); @@ -380,7 +380,7 @@ function CheckPHPVersion(SetupWebPage $oP) * the existing databases * @return Array The list of databases found in the server */ -function CheckServerConnection(SetupWebPage $oP, $sDBServer, $sDBUser, $sDBPwd) +function CheckServerConnection(SetupPage $oP, $sDBServer, $sDBUser, $sDBPwd) { $aResult = array(); $oP->log('Info - CheckServerConnection'); @@ -442,14 +442,14 @@ function CheckServerConnection(SetupWebPage $oP, $sDBServer, $sDBUser, $sDBPwd) /** * Scans the ./data directory for XML files and output them as a Javascript array */ -function PopulateDataFilesList(SetupWebPage $oP, $aParamValues, $oConfig) +function PopulateDataFilesList(SetupPage $oP, $aParamValues, $oConfig) { $sScript = "function PopulateDataFilesList()\n"; $sScript .= "{\n"; $sScript .= "if (aFilesToLoad.length > 0) return;"; // Populate the list only once... - $aAvailableModules = AnalyzeInstallation($oConfig); + $aAvailableModules = AnalyzeInstallation($oConfig, $aParamValues['source_dir']); $sMode = $aParamValues['mode']; $aStructureDataFiles = array(); @@ -501,11 +501,11 @@ function PopulateDataFilesList(SetupWebPage $oP, $aParamValues, $oConfig) /** * Add some parameters as hidden inputs into a form - * @param SetupWebpage $oP The page to insert the form elements into + * @param SetupPage $oP The page to insert the form elements into * @param Hash $aParamValues The pairs name/value to be stored in the form * @param Array $aExcludeParams A list of parameters to exclude from the previous hash */ -function AddParamsToForm(SetupWebpage $oP, $aParamValues, $aExcludeParams = array()) +function AddParamsToForm(SetupPage $oP, $aParamValues, $aExcludeParams = array()) { foreach($aParamValues as $sName => $value) { @@ -537,64 +537,37 @@ function AddHiddenParam($oP, $sName, $value) } /** - * Build the config file from the parameters (especially the selected modules) - */ -function BuildConfig(SetupWebpage $oP, Config &$oConfig, $aParamValues, $aAvailableModules) + * Helper function to get the available languages from the given directory + * @param $sDir Path to the dictionary + * @return an array of language code => description + */ +function GetAvailableLanguages($sDir) { - // Initialize the arrays below with default values for the application... - $oEmptyConfig = new Config('dummy_file', false); // Do NOT load any config file, just set the default values - $aAddOns = $oEmptyConfig->GetAddOns(); - $aAppModules = $oEmptyConfig->GetAppModules(); - $aDataModels = $oEmptyConfig->GetDataModels(); - $aWebServiceCategories = $oEmptyConfig->GetWebServiceCategories(); - $aDictionaries = $oEmptyConfig->GetDictionaries(); - // Merge the values with the ones provided by the modules - // Make sure when don't load the same file twice... - foreach($aParamValues['module'] as $sModuleId) + require_once(APPROOT.'/core/coreexception.class.inc.php'); + require_once(APPROOT.'/core/dict.class.inc.php'); + + $aFiles = scandir($sDir); + foreach($aFiles as $sFile) { - $oP->log('Installed iTop module: '. $sModuleId); - if (isset($aAvailableModules[$sModuleId]['datamodel'])) + if ($sFile == '.' || $sFile == '..' || $sFile == '.svn') { - $aDataModels = array_unique(array_merge($aDataModels, $aAvailableModules[$sModuleId]['datamodel'])); + // Skip + continue; } - if (isset($aAvailableModules[$sModuleId]['webservice'])) + + $sFilePath = $sDir.'/'.$sFile; + if (is_file($sFilePath) && preg_match('/^.+\.dict.*\.php$/i', $sFilePath, $aMatches)) { - $aWebServiceCategories = array_unique(array_merge($aWebServiceCategories, $aAvailableModules[$sModuleId]['webservice'])); - } - if (isset($aAvailableModules[$sModuleId]['dictionary'])) - { - $aDictionaries = array_unique(array_merge($aDictionaries, $aAvailableModules[$sModuleId]['dictionary'])); - } - if (isset($aAvailableModules[$sModuleId]['settings'])) - { - foreach($aAvailableModules[$sModuleId]['settings'] as $sProperty => $value) - { - list($sName, $sVersion) = GetModuleName($sModuleId); - $oConfig->SetModuleSetting($sName, $sProperty, $value); - } - } - if (isset($aAvailableModules[$sModuleId]['installer'])) - { - $sModuleInstallerClass = $aAvailableModules[$sModuleId]['installer']; - if (!class_exists($sModuleInstallerClass)) - { - throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not a PHP class - Module: ".$aAvailableModules[$sModuleId]['label']); - } - if (!is_subclass_of($sModuleInstallerClass, 'ModuleInstallerAPI')) - { - throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not derived from 'ModuleInstallerAPI' - Module: ".$aAvailableModules[$sModuleId]['label']); - } - $aCallSpec = array($sModuleInstallerClass, 'BeforeWritingConfig'); - $oConfig = call_user_func_array($aCallSpec, array($oConfig)); + require_once($sFilePath); } } - $oConfig->SetAddOns($aAddOns); - $oConfig->SetAppModules($aAppModules); - $oConfig->SetDataModels($aDataModels); - $oConfig->SetWebServiceCategories($aWebServiceCategories); - $oConfig->SetDictionaries($aDictionaries); + + return Dict::GetLanguages(); } + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // Handling of the different steps of the setup wizard ///////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -602,7 +575,7 @@ function BuildConfig(SetupWebpage $oP, Config &$oConfig, $aParamValues, $aAvaila /** * Displays the welcome screen and check some basic prerequisites */ -function WelcomeAndCheckPrerequisites(SetupWebPage $oP, $aParamValues, $iCurrentStep) +function WelcomeAndCheckPrerequisites(SetupPage $oP, $aParamValues, $iCurrentStep) { $sNextOperation = 'step'.($iCurrentStep+1); $aParamValues['previous_step'] = 0; @@ -620,9 +593,8 @@ function WelcomeAndCheckPrerequisites(SetupWebPage $oP, $aParamValues, $iCurrent if (file_exists(FINAL_CONFIG_FILE)) { $oConfig = new Config(FINAL_CONFIG_FILE); - $oConfig->WriteToFile(TMP_CONFIG_FILE); - $aVersion = AnalyzeInstallation($oConfig); + $aVersion = AnalyzeInstallation($oConfig, $aParamValues['source_dir']); if (!empty($aVersion[ROOT_MODULE]['version_db'])) { $aPreviousParams = array('mode', 'db_server', 'db_user', 'db_pwd','db_name', 'new_db_name', 'db_prefix'); @@ -641,6 +613,8 @@ function WelcomeAndCheckPrerequisites(SetupWebPage $oP, $aParamValues, $iCurrent AddHiddenParam($oP, 'db_name', $oConfig->GetDBName()); AddHiddenParam($oP, 'db_prefix', $oConfig->GetDBSubname()); AddHiddenParam($oP, 'mode', $sMode); + AddHiddenParam($oP, 'source_dir', 'whichsourcedir'); + AddHiddenParam($oP, 'target_dir', 'whichtargetdir'); if (CheckPHPVersion($oP)) { $oP->add("

Next: Licence agreement

\n"); @@ -664,7 +638,12 @@ function WelcomeAndCheckPrerequisites(SetupWebPage $oP, $aParamValues, $iCurrent $oP->p(""); $oP->add("

Next: Licence agreement

\n"); $oP->add("\n"); - $aPreviousParams = array('mode'); + + //AddHiddenParam($oP, 'source_dir', 'datamodel'); + AddHiddenParam($oP, 'source_dir', 'modules'); // not ready for the big bang ? + AddHiddenParam($oP, 'target_dir', 'env-production'); + + $aPreviousParams = array('mode', 'source_dir', 'target_dir'); AddParamsToForm($oP, $aParamValues, $aPreviousParams); $oP->add("\n"); $oP->add("\n"); @@ -709,7 +688,7 @@ function LicenceAcknowledgement($oP, $aParamValues, $iCurrentStep) * Display the form for the first step of the configuration wizard * which consists in the database server selection */ -function DatabaseServerSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep) +function DatabaseServerSelection(SetupPage $oP, $aParamValues, $iCurrentStep) { $sNextOperation = 'step'.($iCurrentStep+1); $iPrevStep = 1; @@ -752,7 +731,7 @@ function DatabaseServerSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep) * 1) Validating the parameters by connecting to the database server * 2) Prompting to select an existing database or to create a new one */ -function DatabaseInstanceSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep, $oConfig) +function DatabaseInstanceSelection(SetupPage $oP, $aParamValues, $iCurrentStep, $oConfig) { $sNextOperation = 'step'.($iCurrentStep+1); $iPrevStep = 2; @@ -773,12 +752,6 @@ function DatabaseInstanceSelection(SetupWebPage $oP, $aParamValues, $iCurrentSte } else { - // Connection is Ok, save it and continue the setup wizard - $oConfig->SetDBHost($sDBServer); - $oConfig->SetDBUser($sDBUser); - $oConfig->SetDBPwd($sDBPwd); - $oConfig->WriteToFile(); - $oP->add("
Select the database instance to use for iTop*\n"); $aForm = array(); $bExistingChecked = false; @@ -841,28 +814,17 @@ function DatabaseInstanceSelection(SetupWebPage $oP, $aParamValues, $iCurrentSte /** * Display the form to select the iTop modules to be installed */ -function ModulesSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep, $oConfig) +function ModulesSelection(SetupPage $oP, $aParamValues, $iCurrentStep, $oConfig) { $sNextOperation = 'step'.($iCurrentStep+1); $aParamValues['previous_step'] = $iCurrentStep; // Come back here - $sDBName = $aParamValues['db_name']; - if ($sDBName == '') - { - $sDBName = $aParamValues['new_db_name']; - } - - $sDBPrefix = $aParamValues['db_prefix']; - $oConfig->SetDBName($sDBName); - $oConfig->SetDBSubname($sDBPrefix); - $oConfig->WriteToFile(TMP_CONFIG_FILE); - $oP->add("
\n"); AddParamsToForm($oP, $aParamValues, array('module')); $sRedStar = '*'; $oP->set_title("iTop modules selection"); - $aAvailableModules = AnalyzeInstallation($oConfig); + $aAvailableModules = AnalyzeInstallation($oConfig, $aParamValues['source_dir']); // Form goes here if ($aParamValues['mode'] == 'upgrade') @@ -1040,7 +1002,7 @@ function ModulesSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep, $oConf * 2) Creating the database structure * 3) Prompting for the admin account to be created */ -function AdminAccountDefinition(SetupWebPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) +function AdminAccountDefinition(SetupPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) { $sNextOperation = 'step'.($iCurrentStep+1); $aParamValues['previous_step'] = $iCurrentStep; // Come back here @@ -1050,15 +1012,11 @@ function AdminAccountDefinition(SetupWebPage $oP, $aParamValues, $iCurrentStep, $oP->add("\n"); AddParamsToForm($oP, $aParamValues, array('auth_user', 'auth_pwd', 'language')); - $aAvailableModules = AnalyzeInstallation($oConfig); - BuildConfig($oP, $oConfig, $aParamValues, $aAvailableModules); // Load all the includes based on the modules selected - $oConfig->WriteToFile(TMP_CONFIG_FILE); - InitDataModel(TMP_CONFIG_FILE, true); // Needed to know the available languages $sRedStar = "*"; $oP->add("

Default language for the application:

\n"); // Possible languages (depends on the dictionaries loaded in the config) $aForm = array(); - $aAvailableLanguages = Dict::GetLanguages(); + $aAvailableLanguages = GetAvailableLanguages(APPROOT.'dictionaries'); $sLanguages = ''; $sDefaultCode = $oConfig->GetDefaultLanguage(); foreach($aAvailableLanguages as $sLangCode => $aInfo) @@ -1093,7 +1051,7 @@ function AdminAccountDefinition(SetupWebPage $oP, $aParamValues, $iCurrentStep, * Display the form for validating/entering the URL (path) to the application * which consists in */ -function ApplicationPathSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) +function ApplicationPathSelection(SetupPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) { $sNextOperation = 'step7'; if ($aParamValues['mode'] == 'upgrade') @@ -1139,43 +1097,17 @@ function ApplicationPathSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep * 1) Creating the admin user account * 2) Prompting to load some sample data */ -function SampleDataSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) +function SampleDataSelection(SetupPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) { $sNextOperation = 'step8'; $iPrevStep = 6; $oP->set_title("Application initialization"); - $sAdminUser = $aParamValues['auth_user']; - $sAdminPwd = $aParamValues['auth_pwd']; - $sLanguage = $aParamValues['language']; - if (($aParamValues['mode'] == 'install') || $oConfig->GetDefaultLanguage() == '') - { - $oConfig->SetDefaultLanguage($aParamValues['language']); - } - $aAvailableModules = AnalyzeInstallation($oConfig); - BuildConfig($oP, $oConfig, $aParamValues, $aAvailableModules); // Load all the includes based on the modules selected - - $oConfig->Set('app_root_url', $aParamValues['application_path']); - // in case of upgrade, the value is already present in the config file - $oConfig->WriteToFile(TMP_CONFIG_FILE); $oP->add("\n"); $oP->add("\n"); AddParamsToForm($oP, $aParamValues, array('sample_data')); - InitDataModel(TMP_CONFIG_FILE, true); // load data model and connect to the database - $aAvailableModules = GetAvailableModules($oP); - foreach($aParamValues['module'] as $sModuleId) - { - if (isset($aAvailableModules[$sModuleId]['installer'])) - { - $sModuleInstallerClass = $aAvailableModules[$sModuleId]['installer']; - // The validity of the sModuleInstallerClass has been established in BuildConfig() - $aCallSpec = array($sModuleInstallerClass, 'AfterDatabaseCreation'); - call_user_func_array($aCallSpec, array($oConfig)); - } - } - $oP->add("

Loading of sample data

\n"); $oP->p("
Do you want to load sample data into the database ? \n"); $sChecked = ($aParamValues['sample_data'] == 'no') ? '' : 'checked'; @@ -1194,13 +1126,10 @@ function SampleDataSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep, Con /** * Displays the summary of the actions to be taken */ -function DisplaySummary(SetupWebPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) +function DisplaySummary(SetupPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) { $sMode = $aParamValues['mode']; - $aAvailableModules = AnalyzeInstallation($oConfig); - BuildConfig($oP, $oConfig, $aParamValues, $aAvailableModules); // Load all the includes based on the modules selected - $oConfig->WriteToFile(TMP_CONFIG_FILE); - InitDataModel(TMP_CONFIG_FILE, true); // Needed to know the available languages + $aAvailableModules = AnalyzeInstallation($oConfig, $aParamValues['source_dir']); $aInstall = array(); $aUpgrade = array(); @@ -1260,7 +1189,7 @@ function DisplaySummary(SetupWebPage $oP, $aParamValues, $iCurrentStep, Config $ // Admin account $oP->collapsible('admin_account', "Administrator account", array('Login:'.htmlentities($aParamValues['auth_user'], ENT_QUOTES, 'UTF-8'))); // Default language - $aAvailableLanguages = Dict::GetLanguages(); + $aAvailableLanguages = GetAvailableLanguages(APPROOT.'dictionaries'); $oP->collapsible('language', "Default application language", array( $aAvailableLanguages[$aParamValues['language']]['description']." (".$aAvailableLanguages[$aParamValues['language']]['localized_description'].")")); $oP->add(''); @@ -1415,7 +1344,7 @@ EOF * 1) Creating the final configuration file * 2) Prompting the user to make the file read-only */ -function SetupFinished(SetupWebPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) +function SetupFinished(SetupPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) { $sAuthUser = $aParamValues['auth_user']; $sAuthPwd = $aParamValues['auth_pwd']; @@ -1437,12 +1366,14 @@ function SetupFinished(SetupWebPage $oP, $aParamValues, $iCurrentStep, Config $o // NON case sensitive $oConfig->SetDBCollation('utf8_unicode_ci'); - + // Final config update: add the modules + UpdateConfigSettings($oConfig, $aParamValues, $aParamValues['target_dir']); + // Write the final configuration file $oConfig->WriteToFile(FINAL_CONFIG_FILE); // Start the application - InitDataModel(FINAL_CONFIG_FILE, false, true); // Load model, startup DB and load the cache + InitDataModel($oConfig, false, true); // Load model, startup DB and load the cache if ($aParamValues['mode'] == 'install') { if (UserRights::CheckCredentials($sAuthUser, $sAuthPwd)) @@ -1477,7 +1408,7 @@ function SetupFinished(SetupWebPage $oP, $aParamValues, $iCurrentStep, Config $o $oP->add("\n"); // Check if there are some manual steps required: - $aAvailableModules = AnalyzeInstallation($oConfig); + $aAvailableModules = AnalyzeInstallation($oConfig, $aParamValues['target_dir']); $aManualSteps = array(); $sRootUrl = utils::GetAbsoluteUrlAppRoot(); foreach($aParamValues['module'] as $sModuleId) @@ -1535,7 +1466,7 @@ ini_set('max_execution_time', max(240, ini_get('max_execution_time'))); ini_set('display_errors', true); ini_set('display_startup_errors', true); -$aParams = array('mode', 'previous_step', 'licence_ok', 'db_server', 'db_user', 'db_pwd','db_name', 'new_db_name', 'db_prefix', 'module', 'sample_data', 'auth_user', 'auth_pwd', 'language', 'application_path'); +$aParams = array('mode', 'previous_step', 'licence_ok', 'db_server', 'db_user', 'db_pwd','db_name', 'new_db_name', 'db_prefix', 'module', 'sample_data', 'auth_user', 'auth_pwd', 'language', 'application_path', 'source_dir', 'target_dir'); foreach($aParams as $sName) { $aParamValues[$sName] = utils::ReadParam($sName, '', false, 'raw_data'); @@ -1578,15 +1509,10 @@ else } } -try -{ - $oConfig = new Config(TMP_CONFIG_FILE); -} -catch(Exception $e) -{ - // We'll end here when the tmp config file does not exist. It's normal - $oConfig = new Config(TMP_CONFIG_FILE, false /* Don't try to load it */); -} + +$oConfig = new Config(TMP_CONFIG_FILE, false /* Don't try to load it */); +UpdateConfigSettings($oConfig, $aParamValues); + try { switch($sOperation) diff --git a/setup/setup.js b/setup/setup.js index 4cc05b044..e7e30245c 100644 --- a/setup/setup.js +++ b/setup/setup.js @@ -136,8 +136,8 @@ function DoSubmit(sMsg, iStep) case 7: // Sample data selection break; - case 8: // Display Summary: launch DoUpdateDBSchema to start the asynchronous update - bResult = DoUpdateDBSchema(); + case 8: // Display Summary: launch DoCompileDataModel to start the asynchronous update + bResult = DoCompileDataModel(); break; // Email test page @@ -159,19 +159,51 @@ function DoSubmit(sMsg, iStep) return bResult; } +function DoCompileDataModel() +{ + try + { + // Call the asynchronous page that performs the compilation of the data model and the creation of the configuration file + $('#log').html(''); + $('#setup').block({message: '

Preparing data model...

0%

'}); + $('#progress').progression( {Current:5, Maximum: 100, aBackgroundImg: 'orange-progress.gif', aTextColor: '#000000'} ); + $('#log').load( 'ajax.dataloader.php', + { + 'operation': 'compile_data_model', + 'selected_modules': GetSelectedModules(), + 'mode': $(':input[name=mode]').val(), + 'source_dir': $(':input[name=source_dir]').val(), + 'target_dir': $(':input[name=target_dir]').val() + }, + DoUpdateDBSchema, 'html'); + } + catch(err) + { + alert('An exception occured: '+err); + } + return false; // Do NOT submit the form yet +} + function DoUpdateDBSchema() { try { // Call the asynchronous page that performs the creation/update of the DB Schema $('#log').html(''); - $('#setup').block({message: '

Updating DB schema...

0%

'}); - $('#progress').progression( {Current:5, Maximum: 100, aBackgroundImg: 'orange-progress.gif', aTextColor: '#000000'} ); + $('#setup').block({message: '

Updating DB schema...

5%

'}); + $('#progress').progression( {Current:10, Maximum: 100, aBackgroundImg: 'orange-progress.gif', aTextColor: '#000000'} ); $('#log').load( 'ajax.dataloader.php', { 'operation': 'update_db_schema', 'selected_modules': GetSelectedModules(), - 'mode': $(':input[name=mode]').val() + 'mode': $(':input[name=mode]').val(), + 'db_server': $(':input[name=db_server]').val(), + 'db_user': $(':input[name=db_user]').val(), + 'db_pwd': $(':input[name=db_pwd]').val(), + 'db_name': $(':input[name=db_name]').val(), + 'new_db_name': $(':input[name=new_db_name]').val(), + 'db_prefix': $(':input[name=db_prefix]').val(), + 'modules_dir': $(':input[name=target_dir]').val() }, DoUpdateProfiles, 'html'); } @@ -200,6 +232,13 @@ function DoUpdateProfiles(response, status, xhr) 'operation': 'after_db_create', 'selected_modules': GetSelectedModules(), 'mode': $(':input[name=mode]').val(), + 'db_server': $(':input[name=db_server]').val(), + 'db_user': $(':input[name=db_user]').val(), + 'db_pwd': $(':input[name=db_pwd]').val(), + 'db_name': $(':input[name=db_name]').val(), + 'new_db_name': $(':input[name=new_db_name]').val(), + 'db_prefix': $(':input[name=db_prefix]').val(), + 'modules_dir': $(':input[name=target_dir]').val(), 'auth_user': $(':input[name=auth_user]').val(), 'auth_pwd': $(':input[name=auth_pwd]').val(), 'language': $(':input[name=language]').val() @@ -294,7 +333,22 @@ function LoadNextDataFile(response, status, xhr) //alert('Loading file '+sFileName+' ('+iPercent+' %) - '+sSessionStatus); $("#progress").progression({ Current: iPercent, Maximum: 100, aBackgroundImg: 'orange-progress.gif', aTextColor: '#000000' }); iCounter++; - $('#log').load( 'ajax.dataloader.php', { 'operation': 'load_data', 'file': sFileName, 'percent': iPercent, 'session_status': sSessionStatus }, LoadNextDataFile, 'html'); + $('#log').load( 'ajax.dataloader.php', + { + 'selected_modules': GetSelectedModules(), + 'db_server': $(':input[name=db_server]').val(), + 'db_user': $(':input[name=db_user]').val(), + 'db_pwd': $(':input[name=db_pwd]').val(), + 'db_name': $(':input[name=db_name]').val(), + 'new_db_name': $(':input[name=new_db_name]').val(), + 'db_prefix': $(':input[name=db_prefix]').val(), + 'modules_dir': $(':input[name=target_dir]').val(), + 'operation': 'load_data', + 'file': sFileName, + 'percent': iPercent, + 'session_status': sSessionStatus + }, + LoadNextDataFile, 'html'); } else { diff --git a/setup/setuppage.class.inc.php b/setup/setuppage.class.inc.php index 562b46a49..a963dfc2c 100644 --- a/setup/setuppage.class.inc.php +++ b/setup/setuppage.class.inc.php @@ -24,6 +24,8 @@ */ require_once(APPROOT."/application/nicewebpage.class.inc.php"); +require_once(APPROOT."designer/modulediscovery.class.inc.php"); + define('INSTALL_LOG_FILE', APPROOT.'/setup.log'); define ('MODULE_ACTION_OPTIONAL', 1); @@ -32,7 +34,7 @@ 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 SetupWebPage extends NiceWebPage +class SetupPage extends NiceWebPage { public function __construct($sTitle) { @@ -279,146 +281,120 @@ h3.clickable.open { fclose($hLogFile); } } - - - static $m_aModuleArgs = array( - 'label' => 'One line description shown during the interactive setup', - 'dependencies' => 'array of module ids', - 'mandatory' => 'boolean', - 'visible' => 'boolean', - 'datamodel' => 'array of data model files', - //'dictionary' => 'array of dictionary files', // No longer mandatory, now automated - 'data.struct' => 'array of structural data files', - 'data.sample' => 'array of sample data files', - 'doc.manual_setup' => 'url', - 'doc.more_information' => 'url', - ); - - static $m_aModules = array(); - - // All the entries below are list of file paths relative to the module directory - static $m_aFilesList = array('datamodel', 'webservice', 'dictionary', 'data.struct', 'data.sample'); - - static $m_sModulePath = null; - public static function SetModulePath($sModulePath) - { - self::$m_sModulePath = $sModulePath; - } - - public static function AddModule($sFilePath, $sId, $aArgs) - { - if (!array_key_exists('itop_version', $aArgs)) - { - // Assume 1.0.2 - $aArgs['itop_version'] = '1.0.2'; - } - foreach (self::$m_aModuleArgs as $sArgName => $sArgDesc) - { - if (!array_key_exists($sArgName, $aArgs)) - { - throw new Exception("Module '$sId': missing argument '$sArgName'"); - } - } - - self::$m_aModules[$sId] = $aArgs; - - foreach(self::$m_aFilesList as $sAttribute) - { - if (isset(self::$m_aModules[$sId][$sAttribute])) - { - // All the items below are list of files, that are relative to the current file - // being loaded, let's update their path to store path relative to the application directory - foreach(self::$m_aModules[$sId][$sAttribute] as $idx => $sRelativePath) - { - self::$m_aModules[$sId][$sAttribute][$idx] = self::$m_sModulePath.'/'.$sRelativePath; - } - } - } - // Populate automatically the list of dictionary files - if(preg_match('|^([^/]+)|', $sId, $aMatches)) // ModuleName = everything before the first forward slash - { - $sModuleName = $aMatches[1]; - $sDir = dirname($sFilePath); - if ($hDir = opendir($sDir)) - { - while (($sFile = readdir($hDir)) !== false) - { - $aMatches = array(); - if (preg_match("/^[^\\.]+.dict.$sModuleName.php$/i", $sFile, $aMatches)) // Dictionary files named like .dict..php are loaded automatically - { - self::$m_aModules[$sId]['dictionary'][] = self::$m_sModulePath.'/'.$sFile; - } - } - closedir($hDir); - } - } - } - public static function GetModules($oP = null) - { - // Order the modules to take into account their inter-dependencies - $aDependencies = array(); - foreach(self::$m_aModules as $sId => $aModule) - { - $aDependencies[$sId] = $aModule['dependencies']; - } - $aOrderedModules = array(); - $iLoopCount = 1; - while(($iLoopCount < count(self::$m_aModules)) && (count($aDependencies) > 0) ) - { - foreach($aDependencies as $sId => $aRemainingDeps) - { - $bDependenciesSolved = true; - foreach($aRemainingDeps as $sDepId) - { - if (!in_array($sDepId, $aOrderedModules)) - { - $bDependenciesSolved = false; - } - } - if ($bDependenciesSolved) - { - $aOrderedModules[] = $sId; - unset($aDependencies[$sId]); - } - } - $iLoopCount++; - } - if (count($aDependencies) >0) - { - $sHtml = "
    Warning: the following modules have unmet dependencies, and have been ignored:\n"; - foreach($aDependencies as $sId => $aDeps) - { - $aModule = self::$m_aModules[$sId]; - $sHtml.= "
  • {$aModule['label']} (id: $sId), depends on: ".implode(', ', $aDeps)."
  • "; - } - $sHtml .= "
\n"; - if (is_object($oP)) - { - $oP->warning($sHtml); - } - else - { - self::log_warning($sHtml); - } - } - // Return the ordered list, so that the dependencies are met... - $aResult = array(); - foreach($aOrderedModules as $sId) - { - $aResult[$sId] = self::$m_aModules[$sId]; - } - return $aResult; - } } // End of class + +/** + * Helper function to initialize a configuration from the page arguments + */ +function UpdateConfigSettings(&$oConfig, $aParamValues, $sModulesDir = null) +{ + if (isset($aParamValues['application_path'])) + { + $oConfig->Set('app_root_url', $aParamValues['application_path']); + } + if (isset($aParamValues['mode']) && isset($aParamValues['language'])) + { + if (($aParamValues['mode'] == 'install') || $oConfig->GetDefaultLanguage() == '') + { + $oConfig->SetDefaultLanguage($aParamValues['language']); + } + } + if (isset($aParamValues['db_server'])) + { + $oConfig->SetDBHost($aParamValues['db_server']); + $oConfig->SetDBUser($aParamValues['db_user']); + $oConfig->SetDBPwd($aParamValues['db_pwd']); + $sDBName = $aParamValues['db_name']; + if ($sDBName == '') + { + $sDBName = $aParamValues['new_db_name']; + } + $oConfig->SetDBName($sDBName); + $oConfig->SetDBSubname($aParamValues['db_prefix']); + } + + if (!is_null($sModulesDir)) + { + if (isset($aParamValues['selected_modules'])) + { + $aSelectedModules = explode(',', $aParamValues['selected_modules']); + } + else + { + $aSelectedModules = null; + } + + // Initialize the arrays below with default values for the application... + $oEmptyConfig = new Config('dummy_file', false); // Do NOT load any config file, just set the default values + $aAddOns = $oEmptyConfig->GetAddOns(); + $aAppModules = $oEmptyConfig->GetAppModules(); + $aDataModels = $oEmptyConfig->GetDataModels(); + $aWebServiceCategories = $oEmptyConfig->GetWebServiceCategories(); + $aDictionaries = $oEmptyConfig->GetDictionaries(); + // Merge the values with the ones provided by the modules + // Make sure when don't load the same file twice... + + $aModules = ModuleDiscovery::GetAvailableModules(APPROOT, $sModulesDir); + foreach($aModules as $sModuleId => $aModuleInfo) + { + list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId); + if (is_null($aSelectedModules) || in_array($sModuleName, $aSelectedModules)) + { + if (isset($aModuleInfo['datamodel'])) + { + $aDataModels = array_unique(array_merge($aDataModels, $aModuleInfo['datamodel'])); + } + if (isset($aModuleInfo['webservice'])) + { + $aWebServiceCategories = array_unique(array_merge($aWebServiceCategories, $aModuleInfo['webservice'])); + } + if (isset($aModuleInfo['dictionary'])) + { + $aDictionaries = array_unique(array_merge($aDictionaries, $aModuleInfo['dictionary'])); + } + if (isset($aModuleInfo['settings'])) + { + foreach($aModuleInfo['settings'] as $sProperty => $value) + { + list($sName, $sVersion) = ModuleDiscovery::GetModuleName($sModuleId); + $oConfig->SetModuleSetting($sName, $sProperty, $value); + } + } + if (isset($aModuleInfo['installer'])) + { + $sModuleInstallerClass = $aModuleInfo['installer']; + if (!class_exists($sModuleInstallerClass)) + { + throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not a PHP class - Module: ".$aModuleInfo['label']); + } + if (!is_subclass_of($sModuleInstallerClass, 'ModuleInstallerAPI')) + { + throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not derived from 'ModuleInstallerAPI' - Module: ".$aModuleInfo['label']); + } + $aCallSpec = array($sModuleInstallerClass, 'BeforeWritingConfig'); + $oConfig = call_user_func_array($aCallSpec, array($oConfig)); + } + } + } + $oConfig->SetAddOns($aAddOns); + $oConfig->SetAppModules($aAppModules); + $oConfig->SetDataModels($aDataModels); + $oConfig->SetWebServiceCategories($aWebServiceCategories); + $oConfig->SetDictionaries($aDictionaries); + } +} + + + /** * Helper function to initialize the ORM and load the data model * from the given file - * @param $sConfigFileName string The name of the configuration file to load + * @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($sConfigFileName, $bModelOnly = true, $bUseCache = false) +function InitDataModel($oConfig, $bModelOnly = true, $bUseCache = false) { require_once(APPROOT.'/core/log.class.inc.php'); require_once(APPROOT.'/core/kpi.class.inc.php'); @@ -437,40 +413,30 @@ function InitDataModel($sConfigFileName, $bModelOnly = true, $bUseCache = false) require_once(APPROOT.'/application/cmdbabstract.class.inc.php'); require_once(APPROOT.'/core/userrights.class.inc.php'); require_once(APPROOT.'/setup/moduleinstallation.class.inc.php'); - SetupWebPage::log_info("MetaModel::Startup from file '$sConfigFileName' (ModelOnly = $bModelOnly)"); + + $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 ! - $oConfig = new Config($sConfigFileName, true /* Load Config */); MetaModel::ResetCache($oConfig); } - MetaModel::Startup($sConfigFileName, $bModelOnly, $bUseCache); -} - -/** - * Search (on the disk) for all defined iTop modules, load them and returns the list (as an array) - * of the possible iTop modules to install - * @param none - * @return Hash A big array moduleID => ModuleData - */ -function GetAvailableModules($oP = null) -{ - clearstatcache(); - ListModuleFiles('modules'); - return SetupWebPage::GetModules($oP); + MetaModel::Startup($oConfig, $bModelOnly, $bUseCache); } /** * Analyzes the current installation and the possibilities * - * @param $oP SetupWebPage For accessing the list of loaded modules - * @param $sDBServer string Name/IP of the DB server - * @param $sDBUser username for the DB server connection - * @param $sDBPwd password for the DB server connection - * @param $sDBName Name of the database instance - * @param $sDBPrefix Prefix for the iTop tables in the DB instance + * @param $oConfig Config Defines the target environment (DB) * @return hash Array with the following format: * array => * 'iTop' => array( @@ -494,7 +460,7 @@ function GetAvailableModules($oP = null) * ) * ) */ -function AnalyzeInstallation($oConfig) +function AnalyzeInstallation($oConfig, $sModulesRelativePath) { $aRes = array( ROOT_MODULE => array( @@ -505,10 +471,10 @@ function AnalyzeInstallation($oConfig) ) ); - $aModules = GetAvailableModules(); + $aModules = ModuleDiscovery::GetAvailableModules(APPROOT, $sModulesRelativePath); foreach($aModules as $sModuleId => $aModuleInfo) { - list($sModuleName, $sModuleVersion) = GetModuleName($sModuleId); + list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId); $sModuleAppVersion = $aModuleInfo['itop_version']; $aModuleInfo['version_db'] = ''; @@ -615,39 +581,19 @@ function AnalyzeInstallation($oConfig) return $aRes; } - -/** - * Helper function to interpret the name of a module - * @param $sModuleId string Identifier of the module, in the form 'name/version' - * @return array(name, version) - */ -function GetModuleName($sModuleId) -{ - if (preg_match('!^(.*)/(.*)$!', $sModuleId, $aMatches)) - { - $sName = $aMatches[1]; - $sVersion = $aMatches[2]; - } - else - { - $sName = $sModuleId; - $sVersion = ""; - } - return array($sName, $sVersion); -} /** * Helper function to create the database structure * @return boolean true on success, false otherwise */ -function CreateDatabaseStructure(Config $oConfig, $aSelectedModules, $sMode) +function CreateDatabaseStructure(Config $oConfig, $sMode) { if (strlen($oConfig->GetDBSubname()) > 0) { - SetupWebPage::log_info("Creating the structure in '".$oConfig->GetDBName()."' (table names prefixed by '".$oConfig->GetDBSubname()."')."); + SetupPage::log_info("Creating the structure in '".$oConfig->GetDBName()."' (table names prefixed by '".$oConfig->GetDBSubname()."')."); } else { - SetupWebPage::log_info("Creating the structure in '".$oConfig->GetDBSubname()."'."); + SetupPage::log_info("Creating the structure in '".$oConfig->GetDBSubname()."'."); } //MetaModel::CheckDefinitions(); @@ -656,7 +602,7 @@ function CreateDatabaseStructure(Config $oConfig, $aSelectedModules, $sMode) if (!MetaModel::DBExists(/* bMustBeComplete */ false)) { MetaModel::DBCreate(); - SetupWebPage::log_ok("Database structure successfully created."); + SetupPage::log_ok("Database structure successfully created."); } else { @@ -675,19 +621,19 @@ function CreateDatabaseStructure(Config $oConfig, $aSelectedModules, $sMode) if (MetaModel::DBExists(/* bMustBeComplete */ false)) { MetaModel::DBCreate(); - SetupWebPage::log_ok("Database structure successfully updated."); + 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(); - SetupWebPage::log_ok("Hierchical keys rebuilt: $sFeedback"); + 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(); - SetupWebPage::log_ok("Data sources checked: $sFeedback"); + SetupPage::log_ok("Data sources checked: $sFeedback"); } else { @@ -704,7 +650,7 @@ function CreateDatabaseStructure(Config $oConfig, $aSelectedModules, $sMode) return true; } -function RecordInstallation(Config $oConfig, $aSelectedModules) +function RecordInstallation(Config $oConfig, $aSelectedModules, $sModulesRelativePath) { // Record main installation $oInstallRec = new ModuleInstallation(); @@ -716,7 +662,7 @@ function RecordInstallation(Config $oConfig, $aSelectedModules) // Record installed modules // - $aAvailableModules = AnalyzeInstallation($oConfig); + $aAvailableModules = AnalyzeInstallation($oConfig, $sModulesRelativePath); foreach($aSelectedModules as $sModuleId) { $aModuleData = $aAvailableModules[$sModuleId]; @@ -757,43 +703,4 @@ function RecordInstallation(Config $oConfig, $aSelectedModules) return true; } -function ListModuleFiles($sRelDir) -{ - $sDirectory = APPROOT.'/'.$sRelDir; - //echo "

$sDirectory

\n"; - if ($hDir = opendir($sDirectory)) - { - // This is the correct way to loop over the directory. (according to the documentation) - while (($sFile = readdir($hDir)) !== false) - { - $aMatches = array(); - if (is_dir($sDirectory.'/'.$sFile)) - { - if (($sFile != '.') && ($sFile != '..') && ($sFile != '.svn')) - { - ListModuleFiles($sRelDir.'/'.$sFile); - } - } - else if (preg_match('/^module\.(.*).php$/i', $sFile, $aMatches)) - { - SetupWebPage::SetModulePath($sRelDir); - try - { - //echo "

Loading: $sDirectory/$sFile...

\n"; - require_once($sDirectory.'/'.$sFile); - //echo "

Done.

\n"; - } - catch(Exception $e) - { - // Continue... - } - } - } - closedir($hDir); - } - else - { - throw new Exception("Data directory (".$sDirectory.") not found or not readable."); - } -} ?> diff --git a/setup/xmldataloader.class.inc.php b/setup/xmldataloader.class.inc.php index f762befaa..a5d8fce38 100644 --- a/setup/xmldataloader.class.inc.php +++ b/setup/xmldataloader.class.inc.php @@ -186,7 +186,7 @@ class XMLDataLoader { if (!MetaModel::IsValidClass($sClass)) { - SetupWebPage::log_error("Unknown class - $sClass"); + SetupPage::log_error("Unknown class - $sClass"); throw(new Exception("Unknown class - $sClass")); } @@ -207,7 +207,7 @@ class XMLDataLoader if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) { $sMsg = "Unknown attribute code - $sClass/$sAttCode"; - SetupWebPage::log_error($sMsg); + SetupPage::log_error($sMsg); throw(new Exception($sMsg)); } @@ -229,7 +229,7 @@ class XMLDataLoader else { $sMsg = "Ext key not reconcilied - $sClass/$iSrcId - $sAttCode: '".$sQuery."' - found $iMatches matche(s)"; - SetupWebPage::log_error($sMsg); + SetupPage::log_error($sMsg); $this->m_aErrors[] = $sMsg; $iExtKey = 0; } @@ -271,7 +271,7 @@ class XMLDataLoader { // $res contains the error description $sMsg = "Value not allowed - $sClass/$iSrcId - $sAttCode: '".$oSubNode."' ; $res"; - SetupWebPage::log_error($sMsg); + SetupPage::log_error($sMsg); $this->m_aErrors[] = $sMsg; } $oTargetObj->Set($sAttCode, $value); @@ -352,7 +352,7 @@ class XMLDataLoader } catch(Exception $e) { - SetupWebPage::log_error("An object could not be recorded - $sClass/$iSrcId - ".$e->getMessage()); + SetupPage::log_error("An object could not be recorded - $sClass/$iSrcId - ".$e->getMessage()); $this->m_aErrors[] = "An object could not be recorded - $sClass/$iSrcId - ".$e->getMessage(); } $aParentClasses = MetaModel::EnumParentClasses($sClass); @@ -387,7 +387,7 @@ class XMLDataLoader if ($iExtKey == 0) { $sMsg = "unresolved extkey in $sClass::".$oTargetObj->GetKey()."(".$oTargetObj->GetName().")::$sAttCode=$sTargetClass::$iTempKey"; - SetupWebPage::log_warning($sMsg); + SetupPage::log_warning($sMsg); $this->m_aWarnings[] = $sMsg; //echo "
aKeys[".$sTargetClass."]:\n";
 							//print_r($this->m_aKeys[$sTargetClass]);
diff --git a/test/benchmark.php b/test/benchmark.php
index fdcee00e4..6fbc16899 100644
--- a/test/benchmark.php
+++ b/test/benchmark.php
@@ -709,7 +709,7 @@ class BenchmarkDataCreation
 /**
  * Ask the user what are the settings for the data load
  */  
-function DisplayStep1(SetupWebPage $oP)
+function DisplayStep1(SetupPage $oP)
 {
 	$sNextOperation = 'step2';
 	$oP->add("

iTop benchmarking

\n"); @@ -775,7 +775,7 @@ function DisplayStep1(SetupWebPage $oP) LoginWebPage::DoLogin(); // Check user rights and prompt if needed $sOperation = Utils::ReadParam('operation', 'step1'); -$oP = new SetupWebPage('iTop benchmark utility'); +$oP = new SetupPage('iTop benchmark utility'); ExecutionKPI::EnableDuration(); $oKPI = new ExecutionKPI();