소스 검색

Optimizations:
- Setup: grouped CREATE TABLE / ALTER TABLE statements in one single CREATE table
- Every page: cache the prepared queries and data model into APC
Cleanup: removed unused verb RegisterPlugin
Fix: GetObject could fail (could not find the reference from within the forum)

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@1154 a333f486-631f-4898-b8df-5754b55c2be0

romainq 14 년 전
부모
커밋
6f4cc7cc44

+ 0 - 1
addons/userrights/userrightsprofile.class.inc.php

@@ -509,7 +509,6 @@ class UserRightsProfile extends UserRightsAddOnAPI
 
 	public function Init()
 	{
-		MetaModel::RegisterPlugin('userrights', 'ACbyProfile');
 	}
 
 

+ 2 - 1
addons/userrights/userrightsprojection.class.inc.php

@@ -660,7 +660,8 @@ class UserRightsProjection extends UserRightsAddOnAPI
 
 	public function Init()
 	{
-		MetaModel::RegisterPlugin('userrights', 'ACbyProfile', array($this, 'CacheData'));
+		// CacheData to be invoked in a module extension
+		//MetaModel::RegisterPlugin('userrights', 'ACbyProfile', array($this, 'CacheData'));
 	}
 
 	protected $m_aDimensions = array(); // id -> object

+ 15 - 6
core/dict.class.inc.php

@@ -232,21 +232,21 @@ class Dict
 		MyHelpers::var_dump_html(self::$m_aData);
 	}
 	
-	public static function InCache()
+	public static function InCache($sApplicationPrefix)
 	{
 		if (function_exists('apc_fetch'))
 		{
 			$bResult = false;
 			// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
 			//
-			self::$m_aData = apc_fetch('dict');
+			self::$m_aData = apc_fetch($sApplicationPrefix.'-dict');
 			if (is_bool(self::$m_aData) && (self::$m_aData === false))
 			{
 				self::$m_aData = array();
 			}
 			else
 			{
-				self::$m_aLanguages = apc_fetch('languages');
+				self::$m_aLanguages = apc_fetch($sApplicationPrefix.'-languages');
 				if (is_bool(self::$m_aLanguages) && (self::$m_aLanguages === false))
 				{
 					self::$m_aLanguages = array();
@@ -261,12 +261,21 @@ class Dict
 		return false;
 	}
 	
-	public static function InitCache()
+	public static function InitCache($sApplicationPrefix)
 	{
 		if (function_exists('apc_store'))
 		{
-			apc_store('languages', self::$m_aLanguages);
-			apc_store('dict', self::$m_aData);
+			apc_store($sApplicationPrefix.'-languages', self::$m_aLanguages);
+			apc_store($sApplicationPrefix.'-dict', self::$m_aData);
+		}
+	}
+
+	public static function ResetCache($sApplicationPrefix)
+	{
+		if (function_exists('apc_delete'))
+		{
+			apc_delete($sApplicationPrefix.'-languages');
+			apc_delete($sApplicationPrefix.'-dict');
 		}
 	}
 }

+ 232 - 96
core/metamodel.class.php

@@ -538,7 +538,7 @@ abstract class MetaModel
 
 	final static protected function DBEnumTables()
 	{
-		// This API do not rely on our capability to query the DB and retrieve
+		// This API does not rely on our capability to query the DB and retrieve
 		// the list of existing tables
 		// Rather, it uses the list of expected tables, corresponding to the data model
 		$aTables = array();
@@ -1277,6 +1277,31 @@ abstract class MetaModel
 			//	}
 			//}
 		}
+
+		// Build the list of available extensions
+		//
+		$aInterfaces = array('iApplicationUIExtension', 'iApplicationObjectExtension');
+		foreach($aInterfaces as $sInterface)
+		{
+			self::$m_aExtensionClasses[$sInterface] = array();
+		}
+
+		foreach(get_declared_classes() as $sPHPClass)
+		{
+			$oRefClass = new ReflectionClass($sPHPClass);
+			$oExtensionInstance = null;
+			foreach($aInterfaces as $sInterface)
+			{
+				if ($oRefClass->implementsInterface($sInterface))
+				{
+					if (is_null($oExtensionInstance))
+					{
+						$oExtensionInstance = new $sPHPClass;
+					}
+					self::$m_aExtensionClasses[$sInterface][] = $oExtensionInstance;
+				}
+			}
+		}
 	}
 
 	// To be overriden, must be called for any object class (optimization)
@@ -1782,6 +1807,22 @@ abstract class MetaModel
 				// hit!
 				$oSelect = clone self::$m_aQueryStructCache[$sOqlId];
 			}
+			elseif (function_exists('apc_fetch'))
+			{
+				// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
+				//
+				$sAppIdentity = self::GetConfig()->Get('session_name');
+				$sOqlAPCCacheId = $sAppIdentity.'-query-cache-'.$sOqlId;
+				$oKPI = new ExecutionKPI();
+				$result = apc_fetch($sOqlAPCCacheId);
+				$oKPI->ComputeStats('Query APC (fetch)', $sOqlQuery);
+
+				if (is_object($result))
+				{
+					$oSelect = $result;
+					self::$m_aQueryStructCache[$sOqlId] = $oSelect;
+				}
+			}
 		}
 
 		if (!isset($oSelect))
@@ -1792,9 +1833,20 @@ abstract class MetaModel
 
 			$oKPI = new ExecutionKPI();
 			$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, array(), true /* main query */);
+			$oSelect->SetSourceOQL($sOqlQuery);
 			$oKPI->ComputeStats('MakeQuery (select)', $sOqlQuery);
 
-			self::$m_aQueryStructCache[$sOqlId] = clone $oSelect;
+			if (self::$m_bQueryCacheEnabled)
+			{
+				if (function_exists('apc_store'))
+				{
+					$oKPI = new ExecutionKPI();
+					apc_store($sOqlAPCCacheId, $oSelect);
+					$oKPI->ComputeStats('Query APC (store)', $sOqlQuery);
+				}
+
+				self::$m_aQueryStructCache[$sOqlId] = clone $oSelect;
+			}
 		}
 
 		// Check the order by specification, and prefix with the class alias
@@ -2697,26 +2749,13 @@ abstract class MetaModel
 
 	protected static function DBCreateTables()
 	{
-		list($aErrors, $aSugFix) = self::DBCheckFormat();
+		list($aErrors, $aSugFix, $aCondensedQueries) = self::DBCheckFormat();
 
-		$aSQL = array();
-		foreach ($aSugFix as $sClass => $aTarget)
+		//$sSQL = implode('; ', $aCondensedQueries); Does not work - multiple queries not allowed
+		foreach($aCondensedQueries as $sQuery)
 		{
-			foreach ($aTarget as $aQueries)
-			{
-				foreach ($aQueries as $sQuery)
-				{
-					if (!empty($sQuery))
-					{
-						//$aSQL[] = $sQuery;
-						// forces a refresh of cached information
-						CMDBSource::CreateTable($sQuery);
-					}
-				}
-			}
+			CMDBSource::CreateTable($sQuery);
 		}
-		// does not work -how to have multiple statements in a single query?
-		// $sDoCreateAll = implode(" ; ", $aSQL);
 	}
 
 	protected static function DBCreateViews()
@@ -2906,6 +2945,12 @@ abstract class MetaModel
 	{
 		$aErrors = array();
 		$aSugFix = array();
+
+		// A new way of representing things to be done - quicker to execute !
+		$aCreateTable = array(); // array of <table> => <table options>
+		$aCreateTableItems = array(); // array of <table> => array of <create definition>
+		$aAlterTableItems = array(); // array of <table> => <alter specification>
+		
 		foreach (self::GetClasses() as $sClass)
 		{
 			if (!self::HasTable($sClass)) continue;
@@ -2915,17 +2960,24 @@ abstract class MetaModel
 			$sTable = self::DBGetTable($sClass);
 			$sKeyField = self::DBGetKey($sClass);
 			$sAutoIncrement = (self::IsAutoIncrementKey($sClass) ? "AUTO_INCREMENT" : "");
+			$sKeyFieldDefinition = "`$sKeyField` INT(11) NOT NULL $sAutoIncrement PRIMARY KEY";
 			if (!CMDBSource::IsTable($sTable))
 			{
 				$aErrors[$sClass]['*'][] = "table '$sTable' could not be found into the DB";
-				$aSugFix[$sClass]['*'][] = "CREATE TABLE `$sTable` (`$sKeyField` INT(11) NOT NULL $sAutoIncrement PRIMARY KEY) ENGINE = ".MYSQL_ENGINE." CHARACTER SET utf8 COLLATE utf8_unicode_ci";
+				$aSugFix[$sClass]['*'][] = "CREATE TABLE `$sTable` ($sKeyFieldDefinition) ENGINE = ".MYSQL_ENGINE." CHARACTER SET utf8 COLLATE utf8_unicode_ci";
+				$aCreateTable[$sTable] = "ENGINE = ".MYSQL_ENGINE." CHARACTER SET utf8 COLLATE utf8_unicode_ci";
+				$aCreateTableItems[$sTable][$sKeyField] = $sKeyFieldDefinition;
 			}
 			// Check that the key field exists
 			//
 			elseif (!CMDBSource::IsField($sTable, $sKeyField))
 			{
 				$aErrors[$sClass]['id'][] = "key '$sKeyField' (table $sTable) could not be found";
-				$aSugFix[$sClass]['id'][] = "ALTER TABLE `$sTable` ADD `$sKeyField` INT(11) NOT NULL $sAutoIncrement PRIMARY KEY";
+				$aSugFix[$sClass]['id'][] = "ALTER TABLE `$sTable` ADD $sKeyFieldDefinition";
+				if (!array_key_exists($sTable, $aCreateTable))
+				{
+					$aAlterTableItems[$sTable][$sKeyField] = "ADD $sKeyFieldDefinition";
+				}
 			}
 			else
 			{
@@ -2935,11 +2987,19 @@ abstract class MetaModel
 				{
 					$aErrors[$sClass]['id'][] = "key '$sKeyField' is not a key for table '$sTable'";
 					$aSugFix[$sClass]['id'][] = "ALTER TABLE `$sTable`, DROP PRIMARY KEY, ADD PRIMARY key(`$sKeyField`)";
+					if (!array_key_exists($sTable, $aCreateTable))
+					{
+						$aAlterTableItems[$sTable][$sKeyField] = "CHANGE `$sKeyField` $sKeyFieldDefinition";
+					}
 				}
 				if (self::IsAutoIncrementKey($sClass) && !CMDBSource::IsAutoIncrement($sTable, $sKeyField))
 				{
 					$aErrors[$sClass]['id'][] = "key '$sKeyField' (table $sTable) is not automatically incremented";
-					$aSugFix[$sClass]['id'][] = "ALTER TABLE `$sTable` CHANGE `$sKeyField` `$sKeyField` INT(11) NOT NULL AUTO_INCREMENT";
+					$aSugFix[$sClass]['id'][] = "ALTER TABLE `$sTable` CHANGE `$sKeyField` $sKeyFieldDefinition";
+					if (!array_key_exists($sTable, $aCreateTable))
+					{
+						$aAlterTableItems[$sTable][$sKeyField] = "CHANGE `$sKeyField` $sKeyFieldDefinition";
+					}
 				}
 			}
 			
@@ -2955,15 +3015,31 @@ abstract class MetaModel
 				foreach($oAttDef->GetSQLColumns() as $sField => $sDBFieldType)
 				{
 					$bIndexNeeded = $oAttDef->RequiresIndex();
-					$sFieldSpecs = $oAttDef->IsNullAllowed() ? "$sDBFieldType NULL" : "$sDBFieldType NOT NULL";
+					$sFieldDefinition = "`$sField` ".($oAttDef->IsNullAllowed() ? "$sDBFieldType NULL" : "$sDBFieldType NOT NULL");
 					if (!CMDBSource::IsField($sTable, $sField))
 					{
 						$aErrors[$sClass][$sAttCode][] = "field '$sField' could not be found in table '$sTable'";
-						$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` ADD `$sField` $sFieldSpecs";
+						$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` ADD $sFieldDefinition";
 						if ($bIndexNeeded)
 						{
 							$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` ADD INDEX (`$sField`)";
 						}
+						if (array_key_exists($sTable, $aCreateTable))
+						{
+							$aCreateTableItems[$sTable][$sField] = $sFieldDefinition;
+							if ($bIndexNeeded)
+							{
+								$aCreateTableItems[$sTable][$sField.'_ix'] = "INDEX (`$sField`)";
+							}
+						}
+						else
+						{
+							$aAlterTableItems[$sTable][$sField] = "ADD $sFieldDefinition";
+							if ($bIndexNeeded)
+							{
+								$aAlterTableItems[$sTable][$sField.'_ix'] = "ADD INDEX (`$sField`)";
+							}
+						}
 					}
 					else
 					{
@@ -2990,7 +3066,8 @@ abstract class MetaModel
 						} 
 						if ($bToBeChanged)
 						{
-							$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` CHANGE `$sField` `$sField` $sFieldSpecs";
+							$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` CHANGE `$sField` $sFieldDefinition";
+							$aAlterTableItems[$sTable][$sField] = "CHANGE `$sField` $sFieldDefinition";
 						}
 
 						// Create indexes (external keys only... so far)
@@ -2999,12 +3076,26 @@ abstract class MetaModel
 						{
 							$aErrors[$sClass][$sAttCode][] = "Foreign key '$sField' in table '$sTable' should have an index";
 							$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` ADD INDEX (`$sField`)";
+							$aAlterTableItems[$sTable][$sField.'_ix'] = "ADD INDEX (`$sField`)";
 						}
 					}
 				}
 			}
 		}
-		return array($aErrors, $aSugFix);
+
+		$aCondensedQueries = array();
+		foreach($aCreateTable as $sTable => $sTableOptions)
+		{
+			$sTableItems = implode(', ', $aCreateTableItems[$sTable]);
+			$aCondensedQueries[] = "CREATE TABLE `$sTable` ($sTableItems) $sTableOptions";
+		}
+		foreach($aAlterTableItems as $sTable => $aChangeList)
+		{
+			$sChangeList = implode(', ', $aChangeList);
+			$aCondensedQueries[] = "ALTER TABLE `$sTable` $sChangeList";
+		}
+
+		return array($aErrors, $aSugFix, $aCondensedQueries);
 	}
 
 	public static function DBCheckViews()
@@ -3462,37 +3553,10 @@ abstract class MetaModel
 	{
 		self::LoadConfig($sConfigFile);
 
-		$aInterfaces = array('iApplicationUIExtension', 'iApplicationObjectExtension');
-		foreach($aInterfaces as $sInterface)
-		{
-			self::$m_aExtensionClasses[$sInterface] = array();
-		}
-
-		foreach(get_declared_classes() as $sPHPClass)
-		{
-			$oRefClass = new ReflectionClass($sPHPClass);
-			$oExtensionInstance = null;
-			foreach($aInterfaces as $sInterface)
-			{
-				if ($oRefClass->implementsInterface($sInterface))
-				{
-					if (is_null($oExtensionInstance))
-					{
-						$oExtensionInstance = new $sPHPClass;
-					}
-					self::$m_aExtensionClasses[$sInterface][] = $oExtensionInstance;
-				}
-			}
-		}
-
 		if ($bModelOnly) return;
 
 		CMDBSource::SelectDB(self::$m_sDBName);
 
-		// Some of the init could not be done earlier (requiring classes to be declared and DB to be accessible)
-		// To be deprecated
-		self::InitPlugins();
-
 		foreach(get_declared_classes() as $sPHPClass)
 		{
 			if (is_subclass_of($sPHPClass, 'ModuleHandlerAPI'))
@@ -3550,13 +3614,14 @@ abstract class MetaModel
 
 		// Note: load the dictionary as soon as possible, because it might be
 		//       needed when some error occur
-		if (!Dict::InCache())
+		$sAppIdentity = self::GetConfig()->Get('session_name');
+		if (!Dict::InCache($sAppIdentity))
 		{
 			foreach (self::$m_oConfig->GetDictionaries() as $sModule => $sToInclude)
 			{
-				self::Plugin($sConfigFile, 'dictionaries', $sToInclude);
+				self::IncludeModule($sConfigFile, 'dictionaries', $sToInclude);
 			}
-			Dict::InitCache();
+			Dict::InitCache($sAppIdentity);
 		}
 		// Set the language... after the dictionaries have been loaded!
 		Dict::SetDefaultLanguage(self::$m_oConfig->GetDefaultLanguage());
@@ -3567,19 +3632,19 @@ abstract class MetaModel
 
 		foreach (self::$m_oConfig->GetAppModules() as $sModule => $sToInclude)
 		{
-			self::Plugin($sConfigFile, 'application', $sToInclude);
+			self::IncludeModule($sConfigFile, 'application', $sToInclude);
 		}
 		foreach (self::$m_oConfig->GetDataModels() as $sModule => $sToInclude)
 		{
-			self::Plugin($sConfigFile, 'business', $sToInclude);
+			self::IncludeModule($sConfigFile, 'business', $sToInclude);
 		}
 		foreach (self::$m_oConfig->GetWebServiceCategories() as $sModule => $sToInclude)
 		{
-			self::Plugin($sConfigFile, 'webservice', $sToInclude);
+			self::IncludeModule($sConfigFile, 'webservice', $sToInclude);
 		}
 		foreach (self::$m_oConfig->GetAddons() as $sModule => $sToInclude)
 		{
-			self::Plugin($sConfigFile, 'addons', $sToInclude);
+			self::IncludeModule($sConfigFile, 'addons', $sToInclude);
 		}
 
 		$sServer = self::$m_oConfig->GetDBHost();
@@ -3590,13 +3655,76 @@ abstract class MetaModel
 		$sCharacterSet = self::$m_oConfig->GetDBCharacterSet();
 		$sCollation = self::$m_oConfig->GetDBCollation();
 
-		$oKPI = new ExecutionKPI();
+		if (function_exists('apc_fetch'))
+		{
+			$oKPI = new ExecutionKPI();
+			// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
+			//
+			$sAppIdentity = self::GetConfig()->Get('session_name');
+			$sOqlAPCCacheId = $sAppIdentity.'-metamodel';
+			$result = apc_fetch($sOqlAPCCacheId);
 
-		// The include have been included, let's browse the existing classes and
-		// develop some data based on the proposed model
-		self::InitClasses($sTablePrefix);
+			if (is_array($result))
+			{
+				// todo - verifier que toutes les classes mentionnees ici sont chargees dans InitClasses()
+				self::$m_aExtensionClasses = $result['m_aExtensionClasses'];
+				self::$m_Category2Class = $result['m_Category2Class'];
+				self::$m_aRootClasses = $result['m_aRootClasses'];
+				self::$m_aParentClasses = $result['m_aParentClasses']; 
+				self::$m_aChildClasses = $result['m_aChildClasses'];
+				self::$m_aClassParams = $result['m_aClassParams'];
+				self::$m_aAttribDefs = $result['m_aAttribDefs'];
+				self::$m_aAttribOrigins = $result['m_aAttribOrigins'];
+				self::$m_aExtKeyFriends = $result['m_aExtKeyFriends'];
+				self::$m_aIgnoredAttributes = $result['m_aIgnoredAttributes'];
+				self::$m_aFilterDefs = $result['m_aFilterDefs'];
+				self::$m_aFilterOrigins = $result['m_aFilterOrigins'];
+				self::$m_aListInfos = $result['m_aListInfos'];
+				self::$m_aListData = $result['m_aListData'];
+				self::$m_aRelationInfos = $result['m_aRelationInfos'];
+				self::$m_aStates = $result['m_aStates'];
+				self::$m_aStimuli = $result['m_aStimuli'];
+				self::$m_aTransitions = $result['m_aTransitions'];
+			}
+			$oKPI->ComputeAndReport('Metamodel APC (fetch + read)');
+		}
 
-		$oKPI->ComputeAndReport('Initialization of Data model structures');
+      if (count(self::$m_aAttribDefs) == 0)
+      {
+			// The includes have been included, let's browse the existing classes and
+			// develop some data based on the proposed model
+			$oKPI = new ExecutionKPI();
+
+			self::InitClasses($sTablePrefix);
+
+			$oKPI->ComputeAndReport('Initialization of Data model structures');
+			if (function_exists('apc_store'))
+			{
+				$oKPI = new ExecutionKPI();
+
+				$aCache = array();
+				$aCache['m_aExtensionClasses'] = self::$m_aExtensionClasses;
+				$aCache['m_Category2Class'] = self::$m_Category2Class;
+				$aCache['m_aRootClasses'] = self::$m_aRootClasses; // array of "classname" => "rootclass"
+				$aCache['m_aParentClasses'] = self::$m_aParentClasses; // array of ("classname" => array of "parentclass") 
+				$aCache['m_aChildClasses'] = self::$m_aChildClasses; // array of ("classname" => array of "childclass")
+				$aCache['m_aClassParams'] = self::$m_aClassParams; // array of ("classname" => array of class information)
+				$aCache['m_aAttribDefs'] = self::$m_aAttribDefs; // array of ("classname" => array of attributes)
+				$aCache['m_aAttribOrigins'] = self::$m_aAttribOrigins; // array of ("classname" => array of ("attcode"=>"sourceclass"))
+				$aCache['m_aExtKeyFriends'] = self::$m_aExtKeyFriends; // array of ("classname" => array of ("indirect ext key attcode"=> array of ("relative ext field")))
+				$aCache['m_aIgnoredAttributes'] = self::$m_aIgnoredAttributes; //array of ("classname" => array of ("attcode")
+				$aCache['m_aFilterDefs'] = self::$m_aFilterDefs; // array of ("classname" => array filterdef)
+				$aCache['m_aFilterOrigins'] = self::$m_aFilterOrigins; // array of ("classname" => array of ("attcode"=>"sourceclass"))
+				$aCache['m_aListInfos'] = self::$m_aListInfos; // array of ("listcode" => various info on the list, common to every classes)
+				$aCache['m_aListData'] = self::$m_aListData; // array of ("classname" => array of "listcode" => list)
+				$aCache['m_aRelationInfos'] = self::$m_aRelationInfos; // array of ("relcode" => various info on the list, common to every classes)
+				$aCache['m_aStates'] = self::$m_aStates; // array of ("classname" => array of "statecode"=>array('label'=>..., attribute_inherit=> attribute_list=>...))
+				$aCache['m_aStimuli'] = self::$m_aStimuli; // array of ("classname" => array of ("stimuluscode"=>array('label'=>...)))
+				$aCache['m_aTransitions'] = self::$m_aTransitions; // array of ("classname" => array of ("statcode_from"=>array of ("stimuluscode" => array('target_state'=>..., 'actions'=>array of handlers procs, 'user_restriction'=>TBD)))
+				apc_store($sOqlAPCCacheId, $aCache);
+				$oKPI->ComputeAndReport('Metamodel APC (store)');
+			}
+		}
 
 		self::$m_sDBName = $sSource;
 		self::$m_sTablePrefix = $sTablePrefix;
@@ -3617,16 +3745,7 @@ abstract class MetaModel
 
 	protected static $m_aExtensionClasses = array();
 
-	protected static $m_aPlugins = array();
-	public static function RegisterPlugin($sType, $sName, $aInitCallSpec = array())
-	{
-		self::$m_aPlugins[$sName] = array(
-			'type' => $sType,
-			'init' => $aInitCallSpec,
-		);
-	}
-
-	protected static function Plugin($sConfigFile, $sModuleType, $sToInclude)
+	protected static function IncludeModule($sConfigFile, $sModuleType, $sToInclude)
 	{
 		$sFirstChar = substr($sToInclude, 0, 1);
 		$sSecondChar = substr($sToInclude, 1, 1);
@@ -3656,24 +3775,6 @@ abstract class MetaModel
 		require_once($sFile);
 	}
 
-	// #@# to be deprecated!
-	//
-	protected static function InitPlugins()
-	{
-		foreach(self::$m_aPlugins as $sName => $aData)
-		{
-			$aCallSpec = @$aData['init'];
-			if (count($aCallSpec) == 2)
-			{
-				if (!is_callable($aCallSpec))
-				{
-					throw new CoreException('Wrong declaration in plugin', array('plugin' => $aData['name'], 'type' => $aData['type'], 'class' => $aData['class'], 'init' => $aData['init'])); 
-				}
-				call_user_func($aCallSpec);
-			}
-		}
-	}
-
 	// Building an object
 	//
 	//
@@ -3698,8 +3799,8 @@ abstract class MetaModel
 			// NOTE: Quick and VERY dirty caching mechanism which relies on
 			//       the fact that the string '987654321' will never appear in the
 			//       standard query
-			//       This will be replaced for sure with a prepared statement
-			//       or a view... next optimization to come! 
+			//       This could be simplified a little, relying solely on the query cache,
+			//       but this would slow down -by how much time?- the application
 			$oFilter = new DBObjectSearch($sClass);
 			$oFilter->AddCondition('id', 987654321, '=');
 			if ($bAllowAllData)
@@ -3717,7 +3818,7 @@ abstract class MetaModel
 			self::$aQueryCacheGetObjectHits[$sClass] += 1;
 //			echo " -load $sClass/$iKey- ".self::$aQueryCacheGetObjectHits[$sClass]."<br/>\n";
 		}
-		$sSQL = str_replace('987654321', CMDBSource::Quote($iKey), $sSQL);
+		$sSQL = str_replace(CMDBSource::Quote(987654321), CMDBSource::Quote($iKey), $sSQL);
 		$res = CMDBSource::Query($sSQL);
 		
 		$aRow = CMDBSource::FetchArray($res);
@@ -4021,6 +4122,41 @@ abstract class MetaModel
 			return array();
 		}
 	}
+
+	public static function GetCacheEntries()
+	{
+		if (!function_exists('apc_cache_info')) return array();
+
+		$aCacheUserData = apc_cache_info('user');  
+		$sAppIdentity = MetaModel::GetConfig()->Get('session_name');
+		$sPrefix = $sAppIdentity.'-';
+
+		$aEntries = array();
+		foreach($aCacheUserData['cache_list'] as $i => $aEntry)
+		{
+			$sEntryKey = $aEntry['info'];
+			if (strpos($sEntryKey, $sPrefix) === 0)
+			{
+				$sCleanKey = substr($sEntryKey, strlen($sPrefix));
+				$aEntries[$sCleanKey] = $aEntry;
+			}
+		}
+		return $aEntries;
+	}
+
+	public static function ResetCache()
+	{
+		if (!function_exists('apc_delete')) return;
+
+		$sAppIdentity = MetaModel::GetConfig()->Get('session_name');
+		Dict::ResetCache($sAppIdentity);
+
+		foreach(self::GetCacheEntries() as $sKey => $aAPCInfo)
+		{
+			$sAPCKey = $aAPCInfo['info'];
+			apc_delete($sAPCKey);
+		}
+	}
 } // class MetaModel
 
 

+ 11 - 0
core/sqlquery.class.inc.php

@@ -37,6 +37,7 @@ require_once('cmdbsource.class.inc.php');
 
 class SQLQuery
 {
+	private $m_SourceOQL = '';
 	private $m_sTable = '';
 	private $m_sTableAlias = '';
 	private $m_aFields = array();
@@ -69,6 +70,16 @@ class SQLQuery
 		$this->m_oSelectedIdField = $oSelectedIdField;
 	}
 
+	public function SetSourceOQL($sOQL)
+	{
+		$this->m_SourceOQL = $sOQL;
+	}
+
+	public function GetSourceOQL()
+	{
+		return $this->m_SourceOQL;
+	}
+
 	public function DisplayHtml()
 	{
 		if (count($this->m_aFields) == 0) $sFields = "";