Jelajahi Sumber

Fixed setup issues (improved modularity)

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@1982 a333f486-631f-4898-b8df-5754b55c2be0
romainq 13 tahun lalu
induk
melakukan
05706f7f76

+ 9 - 1
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;
 	}

+ 1 - 0
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
 {

+ 26 - 0
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);
+	}
+
 }
 ?>

+ 9 - 6
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')

+ 9 - 1
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))

+ 12 - 6
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 = '<span class="hilite">*</span>';
 	$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("<form id=\"theForm\" method=\"get\" action=\"../index.php\">\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)

+ 10 - 3
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();
 	}
 	/**

+ 380 - 0
setup/runtimeenv.class.inc.php

@@ -0,0 +1,380 @@
+<?php
+// Copyright (C) 2010 Combodo SARL
+//
+//   This program is free software; you can redistribute it and/or modify
+//   it under the terms of the GNU General Public License as published by
+//   the Free Software Foundation; version 3 of the License.
+//
+//   This program is distributed in the hope that it will be useful,
+//   but WITHOUT ANY WARRANTY; without even the implied warranty of
+//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//   GNU General Public License for more details.
+//
+//   You should have received a copy of the GNU General Public License
+//   along with this program; if not, write to the Free Software
+//   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+/**
+ * Web page used for displaying the login form
+ *
+ * @author      Erwan Taloc <erwan.taloc@combodo.com>
+ * @author      Romain Quetiez <romain.quetiez@combodo.com>
+ * @author      Denis Flaven <denis.flaven@combodo.com>
+ * @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 => ...
+	 *     )
+	 *     <module_name> => 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(<module1>, <module2>, ...)  
+	 *         '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 <module> => array ('installed' => timestamp, 'version' => <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
+
+
+?>

+ 1 - 323
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 => ...
- *     )
- *     <module_name> => 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(<module1>, <module2>, ...)  
- *         '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 <module> => array ('installed' => timestamp, 'version' => <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;	
-}
-
 ?>