diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 4661bf3f12..5cc512fd31 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -43,37 +43,37 @@ define('ENUM_PARENT_CLASSES_EXCLUDELEAF', 1); define('ENUM_PARENT_CLASSES_ALL', 2); /** - * Specifies that this attribute is visible/editable.... normal (default config) + * Specifies that this attribute is visible/editable.... normal (default config) * * @package iTopORM */ define('OPT_ATT_NORMAL', 0); /** - * Specifies that this attribute is hidden in that state + * Specifies that this attribute is hidden in that state * * @package iTopORM */ define('OPT_ATT_HIDDEN', 1); /** - * Specifies that this attribute is not editable in that state + * Specifies that this attribute is not editable in that state * * @package iTopORM */ define('OPT_ATT_READONLY', 2); /** - * Specifieds that the attribute must be set (different than default value?) when arriving into that state + * Specifieds that the attribute must be set (different than default value?) when arriving into that state * * @package iTopORM */ define('OPT_ATT_MANDATORY', 4); /** - * Specifies that the attribute must change when arriving into that state + * Specifies that the attribute must change when arriving into that state * * @package iTopORM */ define('OPT_ATT_MUSTCHANGE', 8); /** - * Specifies that the attribute must be proposed when arriving into that state + * Specifies that the attribute must be proposed when arriving into that state * * @package iTopORM */ @@ -87,7 +87,7 @@ define('OPT_ATT_MUSTPROMPT', 16); define('OPT_ATT_SLAVE', 32); /** - * DB Engine -should be moved into CMDBSource + * DB Engine -should be moved into CMDBSource * * @package iTopORM */ @@ -95,9 +95,8 @@ define('MYSQL_ENGINE', 'innodb'); //define('MYSQL_ENGINE', 'myisam'); - /** - * (API) The objects definitions as well as their mapping to the database + * (API) The objects definitions as well as their mapping to the database * * @package iTopORM */ @@ -169,7 +168,7 @@ abstract class MetaModel private static $m_bSkipCheckExtKeys = false; private static $m_bUseAPCCache = false; - + private static $m_bLogIssue = false; private static $m_bLogNotification = false; private static $m_bLogWebService = false; @@ -188,10 +187,12 @@ abstract class MetaModel { return self::$m_bLogIssue; } + public static function IsLogEnabledNotification() { return self::$m_bLogNotification; } + public static function IsLogEnabledWebService() { return self::$m_bLogWebService; @@ -210,9 +211,15 @@ abstract class MetaModel static public function GetParentPersistentClass($sRefClass) { $sClass = get_parent_class($sRefClass); - if (!$sClass) return ''; + if (!$sClass) + { + return ''; + } - if ($sClass == 'DBObject') return ''; // Warning: __CLASS__ is lower case in my version of PHP + if ($sClass == 'DBObject') + { + return ''; + } // Warning: __CLASS__ is lower case in my version of PHP // Note: the UI/business model may implement pure PHP classes (intermediate layers) if (array_key_exists($sClass, self::$m_aClassParams)) @@ -228,6 +235,7 @@ abstract class MetaModel $sStringCode = 'Class:'.$sClass; return Dict::S($sStringCode, str_replace('_', ' ', $sClass)); } + final static public function GetName_Obsolete($sClass) { // Written for compatibility with a data model written prior to version 0.9.1 @@ -241,6 +249,7 @@ abstract class MetaModel return self::GetName($sClass); } } + final static public function GetClassFromLabel($sClassLabel, $bCaseSensitive = true) { foreach(self::GetClasses() as $sClass) @@ -257,7 +266,7 @@ abstract class MetaModel if (strcasecmp(self::GetName($sClass), $sClassLabel) == 0) { return $sClass; - } + } } } return null; @@ -265,20 +274,23 @@ abstract class MetaModel final static public function GetCategory($sClass) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); return self::$m_aClassParams[$sClass]["category"]; } + final static public function HasCategory($sClass, $sCategory) { - self::_check_subclass($sClass); - return (strpos(self::$m_aClassParams[$sClass]["category"], $sCategory) !== false); + self::_check_subclass($sClass); + return (strpos(self::$m_aClassParams[$sClass]["category"], $sCategory) !== false); } + final static public function GetClassDescription($sClass) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); $sStringCode = 'Class:'.$sClass.'+'; return Dict::S($sStringCode, ''); } + final static public function GetClassDescription_Obsolete($sClass) { // Written for compatibility with a data model written prior to version 0.9.1 @@ -292,6 +304,7 @@ abstract class MetaModel return self::GetClassDescription($sClass); } } + final static public function GetClassIcon($sClass, $bImgTag = true, $sMoreStyles = '') { self::_check_subclass($sClass); @@ -316,21 +329,25 @@ abstract class MetaModel } return $sIcon; } + final static public function IsAutoIncrementKey($sClass) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); return (self::$m_aClassParams[$sClass]["key_type"] == "autoincrement"); } + final static public function IsArchivable($sClass) { self::_check_subclass($sClass); return self::$m_aClassParams[$sClass]["archive"]; } + final static public function IsObsoletable($sClass) { self::_check_subclass($sClass); return (!is_null(self::$m_aClassParams[$sClass]['obsolescence_expression'])); } + final static public function GetObsolescenceExpression($sClass) { if (self::IsObsoletable($sClass)) @@ -345,6 +362,7 @@ abstract class MetaModel } return $oRet; } + final static public function GetNameSpec($sClass) { self::_check_subclass($sClass); @@ -355,10 +373,10 @@ abstract class MetaModel if (strlen($sFormat) == 0) { // Default to "%1$s %2$s..." - for($i = 1 ; $i <= count($nameRawSpec) ; $i++) + for($i = 1; $i <= count($nameRawSpec); $i++) { if (empty($sFormat)) - { + { $sFormat .= '%'.$i.'$s'; } else @@ -383,12 +401,12 @@ abstract class MetaModel /** * Get the friendly name expression for a given class - */ + */ final static public function GetNameExpression($sClass) { $aNameSpec = self::GetNameSpec($sClass); $sFormat = $aNameSpec[0]; - $aAttributes = $aNameSpec[1]; + $aAttributes = $aNameSpec[1]; $aPieces = preg_split('/%([0-9])\\$s/', $sFormat, -1, PREG_SPLIT_DELIM_CAPTURE); $aExpressions = array(); @@ -412,7 +430,7 @@ abstract class MetaModel // if (strlen($sPiece) > 0) { - $aExpressions[] = new ScalarExpression($sPiece); + $aExpressions[] = new ScalarExpression($sPiece); } } } @@ -422,13 +440,13 @@ abstract class MetaModel } /** - * Returns the friendly name IIF it is equivalent to a single attribute - */ + * Returns the friendly name IIF it is equivalent to a single attribute + */ final static public function GetFriendlyNameAttributeCode($sClass) { $aNameSpec = self::GetNameSpec($sClass); $sFormat = trim($aNameSpec[0]); - $aAttributes = $aNameSpec[1]; + $aAttributes = $aNameSpec[1]; if (($sFormat != '') && ($sFormat != '%1$s')) { return null; @@ -442,9 +460,10 @@ abstract class MetaModel final static public function GetStateAttributeCode($sClass) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); return self::$m_aClassParams[$sClass]["state_attcode"]; } + final static public function GetDefaultState($sClass) { $sDefaultState = ''; @@ -456,21 +475,23 @@ abstract class MetaModel } return $sDefaultState; } + final static public function GetReconcKeys($sClass) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); return self::$m_aClassParams[$sClass]["reconc_keys"]; } + final static public function GetDisplayTemplate($sClass) { - self::_check_subclass($sClass); - return array_key_exists("display_template", self::$m_aClassParams[$sClass]) ? self::$m_aClassParams[$sClass]["display_template"]: ''; + self::_check_subclass($sClass); + return array_key_exists("display_template", self::$m_aClassParams[$sClass]) ? self::$m_aClassParams[$sClass]["display_template"] : ''; } final static public function GetOrderByDefault($sClass, $bOnlyDeclared = false) { - self::_check_subclass($sClass); - $aOrderBy = array_key_exists("order_by_default", self::$m_aClassParams[$sClass]) ? self::$m_aClassParams[$sClass]["order_by_default"]: array(); + self::_check_subclass($sClass); + $aOrderBy = array_key_exists("order_by_default", self::$m_aClassParams[$sClass]) ? self::$m_aClassParams[$sClass]["order_by_default"] : array(); if ($bOnlyDeclared) { // Used to reverse engineer the declaration of the data model @@ -491,6 +512,7 @@ abstract class MetaModel self::_check_subclass($sClass); return self::$m_aAttribOrigins[$sClass][$sAttCode]; } + final static public function GetPrerequisiteAttributes($sClass, $sAttCode) { self::_check_subclass($sClass); @@ -498,10 +520,11 @@ abstract class MetaModel // Temporary implementation: later, we might be able to compute // the dependencies, based on the attributes definition // (allowed values and default values) - + // Even non-writable attributes (like ExternalFields) can now have Prerequisites return $oAtt->GetPrerequisiteAttributes(); } + /** * Find all attributes that depend on the specified one (reverse of GetPrerequisiteAttributes) * @param string $sClass Name of the class @@ -512,7 +535,7 @@ abstract class MetaModel { $aResults = array(); self::_check_subclass($sClass); - foreach (self::ListAttributeDefs($sClass) as $sDependentAttCode=>$void) + foreach(self::ListAttributeDefs($sClass) as $sDependentAttCode => $void) { $aPrerequisites = self::GetPrerequisiteAttributes($sClass, $sDependentAttCode); if (in_array($sAttCode, $aPrerequisites)) @@ -522,6 +545,7 @@ abstract class MetaModel } return $aResults; } + // #@# restore to private ? final static public function DBGetTable($sClass, $sAttCode = null) { @@ -555,9 +579,12 @@ abstract class MetaModel // the list of existing tables // Rather, it uses the list of expected tables, corresponding to the data model $aTables = array(); - foreach (self::GetClasses() as $sClass) + foreach(self::GetClasses() as $sClass) { - if (!self::HasTable($sClass)) continue; + if (!self::HasTable($sClass)) + { + continue; + } $sTable = self::DBGetTable($sClass); // Could be completed later with all the classes that are using a given table @@ -568,7 +595,7 @@ abstract class MetaModel $aTables[$sTable][] = $sClass; } return $aTables; - } + } final static public function DBGetIndexes($sClass) { @@ -586,14 +613,16 @@ abstract class MetaModel final static public function DBGetKey($sClass) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); return self::$m_aClassParams[$sClass]["db_key_field"]; } + final static public function DBGetClassField($sClass) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); return self::$m_aClassParams[$sClass]["db_finalclass_field"]; } + final static public function IsStandaloneClass($sClass) { self::_check_subclass($sClass); @@ -607,27 +636,45 @@ abstract class MetaModel } return false; } + final static public function IsParentClass($sParentClass, $sChildClass) { self::_check_subclass($sChildClass); self::_check_subclass($sParentClass); - if (in_array($sParentClass, self::$m_aParentClasses[$sChildClass])) return true; - if ($sChildClass == $sParentClass) return true; + if (in_array($sParentClass, self::$m_aParentClasses[$sChildClass])) + { + return true; + } + if ($sChildClass == $sParentClass) + { + return true; + } return false; } + final static public function IsSameFamilyBranch($sClassA, $sClassB) { - self::_check_subclass($sClassA); - self::_check_subclass($sClassB); - if (in_array($sClassA, self::$m_aParentClasses[$sClassB])) return true; - if (in_array($sClassB, self::$m_aParentClasses[$sClassA])) return true; - if ($sClassA == $sClassB) return true; + self::_check_subclass($sClassA); + self::_check_subclass($sClassB); + if (in_array($sClassA, self::$m_aParentClasses[$sClassB])) + { + return true; + } + if (in_array($sClassB, self::$m_aParentClasses[$sClassA])) + { + return true; + } + if ($sClassA == $sClassB) + { + return true; + } return false; } + final static public function IsSameFamily($sClassA, $sClassB) { - self::_check_subclass($sClassA); - self::_check_subclass($sClassB); + self::_check_subclass($sClassA); + self::_check_subclass($sClassB); return (self::GetRootClass($sClassA) == self::GetRootClass($sClassB)); } @@ -646,19 +693,19 @@ abstract class MetaModel */ final static public function ListAttributeDefs($sClass) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); return self::$m_aAttribDefs[$sClass]; } final public static function GetAttributesList($sClass) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); return array_keys(self::$m_aAttribDefs[$sClass]); } final public static function GetFiltersList($sClass) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); return array_keys(self::$m_aFilterDefs[$sClass]); } @@ -672,19 +719,29 @@ abstract class MetaModel { $aExtKeys[] = $sAttCode; } - } + } return $aExtKeys; } - + final static public function IsValidKeyAttCode($sClass, $sAttCode) { - if (!array_key_exists($sClass, self::$m_aAttribDefs)) return false; - if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) return false; + if (!array_key_exists($sClass, self::$m_aAttribDefs)) + { + return false; + } + if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) + { + return false; + } return (self::$m_aAttribDefs[$sClass][$sAttCode]->IsExternalKey()); } + final static public function IsValidAttCode($sClass, $sAttCode, $bExtended = false) { - if (!array_key_exists($sClass, self::$m_aAttribDefs)) return false; + if (!array_key_exists($sClass, self::$m_aAttribDefs)) + { + return false; + } if ($bExtended) { @@ -712,9 +769,10 @@ abstract class MetaModel { $bRes = array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]); } - + return $bRes; } + final static public function IsAttributeOrigin($sClass, $sAttCode) { return (self::$m_aAttribOrigins[$sClass][$sAttCode] == $sClass); @@ -722,9 +780,13 @@ abstract class MetaModel final static public function IsValidFilterCode($sClass, $sFilterCode) { - if (!array_key_exists($sClass, self::$m_aFilterDefs)) return false; + if (!array_key_exists($sClass, self::$m_aFilterDefs)) + { + return false; + } return (array_key_exists($sFilterCode, self::$m_aFilterDefs[$sClass])); } + public static function IsValidClass($sClass) { return (array_key_exists($sClass, self::$m_aAttribDefs)); @@ -732,7 +794,10 @@ abstract class MetaModel public static function IsValidObject($oObject) { - if (!is_object($oObject)) return false; + if (!is_object($oObject)) + { + return false; + } return (self::IsValidClass(get_class($oObject))); } @@ -741,14 +806,14 @@ abstract class MetaModel return (in_array($sAttCode, self::GetReconcKeys($sClass))); } - /** - * Returns the AttributeDefinition of the $sAttCode attribute of the $sClass class - * - * @param string $sClass Class name - * @param string $sAttCode Attribute code - * @return AttributeDefinition - * @throws Exception - */ + /** + * Returns the AttributeDefinition of the $sAttCode attribute of the $sClass class + * + * @param string $sClass Class name + * @param string $sAttCode Attribute code + * @return AttributeDefinition + * @throws Exception + */ final static public function GetAttributeDef($sClass, $sAttCode) { self::_check_subclass($sClass); @@ -773,7 +838,7 @@ abstract class MetaModel final static public function GetExternalKeys($sClass) { $aExtKeys = array(); - foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAtt) + foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAtt) { if ($oAtt->IsExternalKey()) { @@ -786,7 +851,7 @@ abstract class MetaModel final static public function GetLinkedSets($sClass) { $aLinkedSets = array(); - foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAtt) + foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAtt) { if (is_subclass_of($oAtt, 'AttributeLinkedSet')) { @@ -802,7 +867,7 @@ abstract class MetaModel if (!isset($aExtFields[$sClass][$sKeyAttCode])) { $aExtFields[$sClass][$sKeyAttCode] = array(); - foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAtt) + foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAtt) { if ($oAtt->IsExternalField() && ($oAtt->GetKeyAttCode() == $sKeyAttCode)) { @@ -827,24 +892,34 @@ abstract class MetaModel } protected static $m_aTrackForwardCache = array(); + /** * List external keys for which there is a LinkSet (direct or indirect) on the other end * For those external keys, a change will have a special meaning on the other end - * in term of change tracking - */ + * in term of change tracking + */ final static public function GetTrackForwardExternalKeys($sClass) { if (!isset(self::$m_aTrackForwardCache[$sClass])) { $aRes = array(); - foreach (MetaModel::GetExternalKeys($sClass) as $sAttCode => $oAttDef) + foreach(MetaModel::GetExternalKeys($sClass) as $sAttCode => $oAttDef) { $sRemoteClass = $oAttDef->GetTargetClass(); - foreach (MetaModel::ListAttributeDefs($sRemoteClass) as $sRemoteAttCode => $oRemoteAttDef) + foreach(MetaModel::ListAttributeDefs($sRemoteClass) as $sRemoteAttCode => $oRemoteAttDef) { - if (!$oRemoteAttDef->IsLinkSet()) continue; - if (!is_subclass_of($sClass, $oRemoteAttDef->GetLinkedClass()) && $oRemoteAttDef->GetLinkedClass() != $sClass) continue; - if ($oRemoteAttDef->GetExtKeyToMe() != $sAttCode) continue; + if (!$oRemoteAttDef->IsLinkSet()) + { + continue; + } + if (!is_subclass_of($sClass, $oRemoteAttDef->GetLinkedClass()) && $oRemoteAttDef->GetLinkedClass() != $sClass) + { + continue; + } + if ($oRemoteAttDef->GetExtKeyToMe() != $sAttCode) + { + continue; + } $aRes[$sAttCode] = $oRemoteAttDef; } } @@ -868,11 +943,11 @@ abstract class MetaModel /** * Get the attribute label - * @param string sClass Persistent class - * @param string sAttCodeEx Extended attribute code: attcode[->attcode] + * @param string sClass Persistent class + * @param string sAttCodeEx Extended attribute code: attcode[->attcode] * @param bool $bShowMandatory If true, add a star character (at the end or before the ->) to show that the field is mandatory * @return string A user friendly format of the string: AttributeName or AttributeName->ExtAttributeName - */ + */ public static function GetLabel($sClass, $sAttCodeEx, $bShowMandatory = false) { $sLabel = ''; @@ -904,7 +979,10 @@ abstract class MetaModel public static function GetDescription($sClass, $sAttCode) { $oAttDef = self::GetAttributeDef($sClass, $sAttCode); - if ($oAttDef) return $oAttDef->GetDescription(); + if ($oAttDef) + { + return $oAttDef->GetDescription(); + } return ""; } @@ -917,7 +995,7 @@ abstract class MetaModel public static function GetClassFilterDefs($sClass) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); return self::$m_aFilterDefs[$sClass]; } @@ -934,14 +1012,20 @@ abstract class MetaModel public static function GetFilterLabel($sClass, $sFilterCode) { $oFilter = self::GetClassFilterDef($sClass, $sFilterCode); - if ($oFilter) return $oFilter->GetLabel(); + if ($oFilter) + { + return $oFilter->GetLabel(); + } return ""; } public static function GetFilterDescription($sClass, $sFilterCode) { $oFilter = self::GetClassFilterDef($sClass, $sFilterCode); - if ($oFilter) return $oFilter->GetDescription(); + if ($oFilter) + { + return $oFilter->GetDescription(); + } return ""; } @@ -949,7 +1033,10 @@ abstract class MetaModel public static function GetFilterOperators($sClass, $sFilterCode) { $oFilter = self::GetClassFilterDef($sClass, $sFilterCode); - if ($oFilter) return $oFilter->GetOperators(); + if ($oFilter) + { + return $oFilter->GetOperators(); + } return array(); } @@ -957,14 +1044,20 @@ abstract class MetaModel public static function GetFilterLooseOperator($sClass, $sFilterCode) { $oFilter = self::GetClassFilterDef($sClass, $sFilterCode); - if ($oFilter) return $oFilter->GetLooseOperator(); + if ($oFilter) + { + return $oFilter->GetLooseOperator(); + } return array(); } public static function GetFilterOpDescription($sClass, $sFilterCode, $sOpCode) { $oFilter = self::GetClassFilterDef($sClass, $sFilterCode); - if ($oFilter) return $oFilter->GetOpDescription($sOpCode); + if ($oFilter) + { + return $oFilter->GetOpDescription($sOpCode); + } return ""; } @@ -1000,7 +1093,10 @@ abstract class MetaModel } } $sParentClass = self::GetParentPersistentClass($sClass); - if (empty($sParentClass)) return array(); // nothing for the mother of all classes + if (empty($sParentClass)) + { + return array(); + } // nothing for the mother of all classes // Dig recursively return self::GetZListItems($sParentClass, $sListCode); } @@ -1034,7 +1130,7 @@ abstract class MetaModel // for the specified class $aClassRelations = array(); foreach($aResult as $sRelCode) - { + { $aQueriesDown = self::EnumRelationQueries($sClass, $sRelCode); if (count($aQueriesDown) > 0) { @@ -1053,7 +1149,7 @@ abstract class MetaModel } } - return $aClassRelations; + return $aClassRelations; } // Temporary patch: until the impact analysis GUI gets rewritten, @@ -1080,17 +1176,17 @@ abstract class MetaModel { $aClassRelations[$sRelCode]['down'] = self::GetRelationLabel($sRelCode, true); } - + $aQueriesUp = self::EnumRelationQueries($sClass, $sRelCode, false /* Up */); if (count($aQueriesUp) > 0) { $aClassRelations[$sRelCode]['up'] = self::GetRelationLabel($sRelCode, false); } } - + return $aClassRelations; } - + final static public function GetRelationDescription($sRelCode) { return Dict::S("Relation:$sRelCode/Description"); @@ -1100,11 +1196,11 @@ abstract class MetaModel { if ($bDown) { - // The legacy convention is confusing with regard to the way we have conceptualized the relations: - // In the former representation, the main stream was named after "up" - // Now, the relation from A to B says that something is transmitted from A to B, thus going DOWNstream as described in a petri net. - $sKey = "Relation:$sRelCode/DownStream"; - $sLegacy = Dict::S("Relation:$sRelCode/VerbUp", $sKey); + // The legacy convention is confusing with regard to the way we have conceptualized the relations: + // In the former representation, the main stream was named after "up" + // Now, the relation from A to B says that something is transmitted from A to B, thus going DOWNstream as described in a petri net. + $sKey = "Relation:$sRelCode/DownStream"; + $sLegacy = Dict::S("Relation:$sRelCode/VerbUp", $sKey); } else { @@ -1119,7 +1215,7 @@ abstract class MetaModel { $bHasLegacy = false; $aQueries = array(); - foreach (self::GetClasses() as $sClass) + foreach(self::GetClasses() as $sClass) { $aQueries[$sClass]['down'] = array(); if (!array_key_exists('up', $aQueries[$sClass])) @@ -1128,7 +1224,7 @@ abstract class MetaModel } $aNeighboursDown = call_user_func_array(array($sClass, 'GetRelationQueriesEx'), array($sRelCode)); - + // Translate attributes into queries (new style of spec only) foreach($aNeighboursDown as $sNeighbourId => $aNeighbourData) { @@ -1154,7 +1250,7 @@ abstract class MetaModel $sExtKeyToRemote = $oAttDef->GetExtKeyToRemote(); $oRemoteAttDef = self::GetAttributeDef($sLinkedClass, $sExtKeyToRemote); $sRemoteClass = $oRemoteAttDef->GetTargetClass(); - + $aNeighbourData['sToClass'] = $sRemoteClass; $aNeighbourData['sQueryDown'] = "SELECT $sRemoteClass AS o JOIN $sLinkedClass AS lnk ON lnk.$sExtKeyToRemote = o.id WHERE lnk.$sExtKeyToMe = :this->id"; $aNeighbourData['sQueryUp'] = "SELECT ".$aNeighbourData['sFromClass']." AS o JOIN $sLinkedClass AS lnk ON lnk.$sExtKeyToMe = o.id WHERE lnk.$sExtKeyToRemote = :this->id"; @@ -1197,7 +1293,7 @@ abstract class MetaModel { $sFromClass = $aNeighbourData['sFromClass']; $sToClass = $aNeighbourData['sToClass']; - foreach (self::EnumChildClasses($sToClass, ENUM_CHILD_CLASSES_ALL) as $sSubClass) + foreach(self::EnumChildClasses($sToClass, ENUM_CHILD_CLASSES_ALL) as $sSubClass) { $aQueries[$sSubClass]['up'][$sArrowId] = $aNeighbourData; } @@ -1221,15 +1317,18 @@ abstract class MetaModel foreach($aLegacy as $sId => $aLegacyEntry) { $bHasLegacy = true; - + $oFilter = DBObjectSearch::FromOQL($aLegacyEntry['sQuery']); $sRemoteClass = $oFilter->GetClass(); // Determine wether the query is inherited from a parent or not $bInherited = false; - foreach (self::EnumParentClasses($sClass) as $sParent) + foreach(self::EnumParentClasses($sClass) as $sParent) { - if (!isset($aQueries[$sParent]['down'][$sRemoteClass])) continue; + if (!isset($aQueries[$sParent]['down'][$sRemoteClass])) + { + continue; + } if ($aLegacyEntry['sQuery'] == $aQueries[$sParent]['down'][$sRemoteClass]['sQueryDown']) { $bInherited = true; @@ -1263,9 +1362,12 @@ abstract class MetaModel // Determine wether the query is inherited from a parent or not $bInherited = false; - foreach (self::EnumParentClasses($sClass) as $sParent) + foreach(self::EnumParentClasses($sClass) as $sParent) { - if (!isset($aQueries[$sParent]['up'][$sRemoteClass])) continue; + if (!isset($aQueries[$sParent]['up'][$sRemoteClass])) + { + continue; + } if ($aLegacyEntry['sQuery'] == $aQueries[$sParent]['up'][$sRemoteClass]['sQueryUp']) { $bInherited = true; @@ -1298,21 +1400,24 @@ abstract class MetaModel // Perform the up/down reconciliation for the legacy definitions if ($bHasLegacy) { - foreach (self::GetClasses() as $sClass) + foreach(self::GetClasses() as $sClass) { // Foreach "up" legacy query, update its "down" counterpart if (isset($aQueries[$sClass]['up'])) { - foreach ($aQueries[$sClass]['up'] as $sNeighbourId => $aNeighbourData) + foreach($aQueries[$sClass]['up'] as $sNeighbourId => $aNeighbourData) { if (!array_key_exists('_legacy_', $aNeighbourData)) { continue; } - if (!$aNeighbourData['_legacy_']) continue; // Skip modern definitions + if (!$aNeighbourData['_legacy_']) + { + continue; + } // Skip modern definitions $sLocalClass = $aNeighbourData['sToClass']; - foreach (self::EnumChildClasses($aNeighbourData['sFromClass'], ENUM_CHILD_CLASSES_ALL) as $sRemoteClass) + foreach(self::EnumChildClasses($aNeighbourData['sFromClass'], ENUM_CHILD_CLASSES_ALL) as $sRemoteClass) { if (isset($aQueries[$sRemoteClass]['down'][$sLocalClass])) { @@ -1328,12 +1433,15 @@ abstract class MetaModel } } // Foreach "down" legacy query, update its "up" counterpart (if any) - foreach ($aQueries[$sClass]['down'] as $sNeighbourId => $aNeighbourData) + foreach($aQueries[$sClass]['down'] as $sNeighbourId => $aNeighbourData) { - if (!$aNeighbourData['_legacy_']) continue; // Skip modern definitions + if (!$aNeighbourData['_legacy_']) + { + continue; + } // Skip modern definitions $sLocalClass = $aNeighbourData['sFromClass']; - foreach (self::EnumChildClasses($aNeighbourData['sToClass'], ENUM_CHILD_CLASSES_ALL) as $sRemoteClass) + foreach(self::EnumChildClasses($aNeighbourData['sToClass'], ENUM_CHILD_CLASSES_ALL) as $sRemoteClass) { if (isset($aQueries[$sRemoteClass]['up'][$sLocalClass])) { @@ -1366,19 +1474,19 @@ abstract class MetaModel /** * Compute the "RelatedObjects" for a whole set of DBObjects - * + * * @param string $sRelCode The code of the relation to use for the computation * @param array $asourceObjects The objects to start with * @param int $iMaxDepth * @param boolean $bEnableReduncancy * @param array $aUnreachable Array of objects to be considered as 'unreachable' - * + * * @return RelationGraph The graph of all the related objects */ static public function GetRelatedObjectsDown($sRelCode, $aSourceObjects, $iMaxDepth = 99, $bEnableRedundancy = true, $aUnreachable = array(), $aContexts = array()) { $oGraph = new RelationGraph(); - foreach ($aSourceObjects as $oObject) + foreach($aSourceObjects as $oObject) { $oGraph->AddSourceObject($oObject); } @@ -1392,18 +1500,18 @@ abstract class MetaModel /** * Compute the "RelatedObjects" in the reverse way - * + * * @param string $sRelCode The code of the relation to use for the computation * @param array $asourceObjects The objects to start with * @param int $iMaxDepth * @param boolean $bEnableReduncancy - * + * * @return RelationGraph The graph of all the related objects */ static public function GetRelatedObjectsUp($sRelCode, $aSourceObjects, $iMaxDepth = 99, $bEnableRedundancy = true, $aContexts = array()) { $oGraph = new RelationGraph(); - foreach ($aSourceObjects as $oObject) + foreach($aSourceObjects as $oObject) { $oGraph->AddSinkObject($oObject); } @@ -1482,6 +1590,7 @@ abstract class MetaModel $oAttDef = self::GetAttributeDef($sClass, $sStateAttrCode); return $oAttDef->GetValueLabel($sStateValue); } + public static function GetStateDescription($sClass, $sStateValue) { $sStateAttrCode = self::GetStateAttributeCode($sClass); @@ -1500,6 +1609,7 @@ abstract class MetaModel } return array(); } + public static function GetAttributeFlags($sClass, $sState, $sAttCode) { $iFlags = 0; // By default (if no life cycle) no flag at all @@ -1512,7 +1622,7 @@ abstract class MetaModel throw new CoreException("Invalid state '$sState' for class '$sClass', expecting a value in {".implode(', ', array_keys($aStates))."}"); } $aCurrentState = $aStates[$sState]; - if ( (array_key_exists('attribute_list', $aCurrentState)) && (array_key_exists($sAttCode, $aCurrentState['attribute_list'])) ) + if ((array_key_exists('attribute_list', $aCurrentState)) && (array_key_exists($sAttCode, $aCurrentState['attribute_list']))) { $iFlags = $aCurrentState['attribute_list'][$sAttCode]; } @@ -1520,90 +1630,99 @@ abstract class MetaModel return $iFlags; } - /** - * Returns the $sAttCode flags when $sStimulus is applied on an object of $sClass in the $sState state. - * Note: This does NOT combine flags from the target state. - * - * @param $sClass string - * @param $sState string - * @param $sStimulus string - * @param $sAttCode string - * @return int - * @throws CoreException - */ + /** + * Returns the $sAttCode flags when $sStimulus is applied on an object of $sClass in the $sState state. + * Note: This does NOT combine flags from the target state. + * + * @param $sClass string + * @param $sState string + * @param $sStimulus string + * @param $sAttCode string + * @return int + * @throws CoreException + */ public static function GetTransitionFlags($sClass, $sState, $sStimulus, $sAttCode) - { - $iFlags = 0; // By default (if no lifecycle) no flag at all - $sStateAttCode = self::GetStateAttributeCode($sClass); - if (!empty($sStateAttCode)) - { - $aTransitions = MetaModel::EnumTransitions($sClass, $sState); - if(!array_key_exists($sStimulus, $aTransitions)) - { - throw new CoreException("Invalid transition '$sStimulus' for class '$sClass', expecting a value in {".implode(', ', array_keys($aTransitions))."}"); - } + { + $iFlags = 0; // By default (if no lifecycle) no flag at all + $sStateAttCode = self::GetStateAttributeCode($sClass); + if (!empty($sStateAttCode)) + { + $aTransitions = MetaModel::EnumTransitions($sClass, $sState); + if (!array_key_exists($sStimulus, $aTransitions)) + { + throw new CoreException("Invalid transition '$sStimulus' for class '$sClass', expecting a value in {".implode(', ', array_keys($aTransitions))."}"); + } - $aCurrentTransition = $aTransitions[$sStimulus]; - if( (array_key_exists('attribute_list', $aCurrentTransition)) && (array_key_exists($sAttCode, $aCurrentTransition['attribute_list'])) ) - { - $iFlags = $aCurrentTransition['attribute_list'][$sAttCode]; - } - } + $aCurrentTransition = $aTransitions[$sStimulus]; + if ((array_key_exists('attribute_list', $aCurrentTransition)) && (array_key_exists($sAttCode, $aCurrentTransition['attribute_list']))) + { + $iFlags = $aCurrentTransition['attribute_list'][$sAttCode]; + } + } - return $iFlags; - } + return $iFlags; + } - /** - * Returns an array of attribute codes (with their flags) when $sStimulus is applied on an object of $sClass in the $sOriginState state. - * Note: Attributes (and flags) from the target state and the transition are combined. - * - * @param $sClass string Object class - * @param $sStimulus string Stimulus code applied - * @param $sOriginState string State the stimulus comes from - * @return array - */ - public static function GetTransitionAttributes($sClass, $sStimulus, $sOriginState) - { - $aAttributes = array(); + /** + * Returns an array of attribute codes (with their flags) when $sStimulus is applied on an object of $sClass in the $sOriginState state. + * Note: Attributes (and flags) from the target state and the transition are combined. + * + * @param $sClass string Object class + * @param $sStimulus string Stimulus code applied + * @param $sOriginState string State the stimulus comes from + * @return array + */ + public static function GetTransitionAttributes($sClass, $sStimulus, $sOriginState) + { + $aAttributes = array(); - // Retrieving target state - $aTransitions = MetaModel::EnumTransitions($sClass, $sOriginState); - $aTransition = $aTransitions[$sStimulus]; - $sTargetState = $aTransition['target_state']; + // Retrieving target state + $aTransitions = MetaModel::EnumTransitions($sClass, $sOriginState); + $aTransition = $aTransitions[$sStimulus]; + $sTargetState = $aTransition['target_state']; - // Retrieving attributes from state - $aStates = MetaModel::EnumStates($sClass); - $aTargetState = $aStates[$sTargetState]; - $aTargetStateAttributes = $aTargetState['attribute_list']; - // - Merging with results (only MUST_XXX and MANDATORY) - foreach($aTargetStateAttributes as $sTargetStateAttCode => $iTargetStateAttFlags) - { - $iTmpAttFlags = OPT_ATT_NORMAL; - if($iTargetStateAttFlags & OPT_ATT_MUSTPROMPT){ $iTmpAttFlags = $iTmpAttFlags | OPT_ATT_MUSTPROMPT; } - if($iTargetStateAttFlags & OPT_ATT_MUSTCHANGE){ $iTmpAttFlags = $iTmpAttFlags | OPT_ATT_MUSTCHANGE; } - if($iTargetStateAttFlags & OPT_ATT_MANDATORY){ $iTmpAttFlags = $iTmpAttFlags | OPT_ATT_MANDATORY; } + // Retrieving attributes from state + $aStates = MetaModel::EnumStates($sClass); + $aTargetState = $aStates[$sTargetState]; + $aTargetStateAttributes = $aTargetState['attribute_list']; + // - Merging with results (only MUST_XXX and MANDATORY) + foreach($aTargetStateAttributes as $sTargetStateAttCode => $iTargetStateAttFlags) + { + $iTmpAttFlags = OPT_ATT_NORMAL; + if ($iTargetStateAttFlags & OPT_ATT_MUSTPROMPT) + { + $iTmpAttFlags = $iTmpAttFlags | OPT_ATT_MUSTPROMPT; + } + if ($iTargetStateAttFlags & OPT_ATT_MUSTCHANGE) + { + $iTmpAttFlags = $iTmpAttFlags | OPT_ATT_MUSTCHANGE; + } + if ($iTargetStateAttFlags & OPT_ATT_MANDATORY) + { + $iTmpAttFlags = $iTmpAttFlags | OPT_ATT_MANDATORY; + } - $aAttributes[$sTargetStateAttCode] = $iTmpAttFlags; - } + $aAttributes[$sTargetStateAttCode] = $iTmpAttFlags; + } - // Retrieving attributes from transition - $aTransitionAttributes = $aTransition['attribute_list']; - // - Merging with results - foreach($aTransitionAttributes as $sAttCode => $iAttributeFlags) - { - if(array_key_exists($sAttCode, $aAttributes)) - { - $aAttributes[$sAttCode] = $aAttributes[$sAttCode] | $iAttributeFlags; - } - else - { - $aAttributes[$sAttCode] = $iAttributeFlags; - } - } + // Retrieving attributes from transition + $aTransitionAttributes = $aTransition['attribute_list']; + // - Merging with results + foreach($aTransitionAttributes as $sAttCode => $iAttributeFlags) + { + if (array_key_exists($sAttCode, $aAttributes)) + { + $aAttributes[$sAttCode] = $aAttributes[$sAttCode] | $iAttributeFlags; + } + else + { + $aAttributes[$sAttCode] = $iAttributeFlags; + } + } + + return $aAttributes; + } - return $aAttributes; - } - /** * Combines the flags from the all states that compose the initial_state_path */ @@ -1678,15 +1797,15 @@ abstract class MetaModel $aMandatParams = array( "description" => "detailed (though one line) description of the list", "type" => "attributes | filters", - ); - foreach($aMandatParams as $sParamName=>$sParamDesc) + ); + foreach($aMandatParams as $sParamName => $sParamDesc) { if (!array_key_exists($sParamName, $aListInfo)) { throw new CoreException("Declaration of list $sListCode - missing parameter $sParamName"); } } - + self::$m_aListInfos[$sListCode] = $aListInfo; } @@ -1714,6 +1833,7 @@ abstract class MetaModel self::$m_aFilterDefs[$sTargetClass][$sCode] = $oFlt; self::$m_aFilterOrigins[$sTargetClass][$sCode] = $sOriginClass; } + // Must be called once and only once... public static function InitClasses($sTablePrefix) { @@ -1805,7 +1925,7 @@ abstract class MetaModel } self::$m_aClassParams[$sPHPClass]['obsolescence_expression'] = $sObsolescence; - foreach (MetaModel::EnumPlugins('iOnClassInitialization') as $sPluginClass => $oClassInit) + foreach(MetaModel::EnumPlugins('iOnClassInitialization') as $sPluginClass => $oClassInit) { $oClassInit->OnAfterClassInitialization($sPHPClass); } @@ -1822,8 +1942,11 @@ abstract class MetaModel // foreach(self::EnumRootClasses() as $sRootClass) { - if (self::IsStandaloneClass($sRootClass)) continue; - + if (self::IsStandaloneClass($sRootClass)) + { + continue; + } + $sDbFinalClassField = self::DBGetClassField($sRootClass); if (strlen($sDbFinalClassField) == 0) { @@ -1831,15 +1954,15 @@ abstract class MetaModel self::$m_aClassParams[$sRootClass]["db_finalclass_field"] = 'finalclass'; } $oClassAtt = new AttributeFinalClass('finalclass', array( - "sql"=>$sDbFinalClassField, - "default_value"=>$sRootClass, - "is_null_allowed"=>false, - "depends_on"=>array() + "sql" => $sDbFinalClassField, + "default_value" => $sRootClass, + "is_null_allowed" => false, + "depends_on" => array() )); self::AddMagicAttribute($oClassAtt, $sRootClass); $bObsoletable = array_key_exists($sRootClass, $aObsoletableRootClasses); - if ($bObsoletable && is_null(self::$m_aClassParams[$sRootClass]['obsolescence_expression'])) + if ($bObsoletable && is_null(self::$m_aClassParams[$sRootClass]['obsolescence_expression'])) { self::$m_aClassParams[$sRootClass]['obsolescence_expression'] = '0'; } @@ -1859,7 +1982,7 @@ abstract class MetaModel $oCloned->SetFixedValue($sChildClass); self::AddMagicAttribute($oCloned, $sChildClass, $sRootClass); - if ($bObsoletable && is_null(self::$m_aClassParams[$sChildClass]['obsolescence_expression'])) + if ($bObsoletable && is_null(self::$m_aClassParams[$sChildClass]['obsolescence_expression'])) { self::$m_aClassParams[$sChildClass]['obsolescence_expression'] = '0'; } @@ -1867,7 +1990,7 @@ abstract class MetaModel } // Add magic attributes to the classes - foreach (self::GetClasses() as $sClass) + foreach(self::GetClasses() as $sClass) { $sRootClass = self::$m_aRootClasses[$sClass]; @@ -1921,13 +2044,13 @@ abstract class MetaModel // Prepare external fields and filters // Add final class to external keys // Add magic attributes to external keys (finalclass, friendlyname, archive_flag, obsolescence_flag) - foreach (self::GetClasses() as $sClass) + foreach(self::GetClasses() as $sClass) { - foreach (self::$m_aAttribDefs[$sClass] as $sAttCode => $oAttDef) + foreach(self::$m_aAttribDefs[$sClass] as $sAttCode => $oAttDef) { // Compute the filter codes // - foreach ($oAttDef->GetFilterDefinitions() as $sFilterCode => $oFilterDef) + foreach($oAttDef->GetFilterDefinitions() as $sFilterCode => $oFilterDef) { self::$m_aFilterDefs[$sClass][$sFilterCode] = $oFilterDef; @@ -1942,7 +2065,7 @@ abstract class MetaModel self::$m_aFilterOrigins[$sClass][$sFilterCode] = self::$m_aAttribOrigins[$sClass][$sAttCode]; } } - + // Compute the fields that will be used to display a pointer to another object // if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) @@ -1960,26 +2083,26 @@ abstract class MetaModel $sKeyAttCode = $oAttDef->GetKeyAttCode(); $sRemoteAttCode = $oAttDef->GetExtAttCode()."_friendlyname"; $sFriendlyNameAttCode = $sAttCode.'_friendlyname'; - $oFriendlyName = new AttributeExternalField($sFriendlyNameAttCode, array("allowed_values"=>null, "extkey_attcode"=>$sKeyAttCode, "target_attcode"=>$sRemoteAttCode, "depends_on"=>array())); + $oFriendlyName = new AttributeExternalField($sFriendlyNameAttCode, array("allowed_values" => null, "extkey_attcode" => $sKeyAttCode, "target_attcode" => $sRemoteAttCode, "depends_on" => array())); self::AddMagicAttribute($oFriendlyName, $sClass, self::$m_aAttribOrigins[$sClass][$sKeyAttCode]); } else { // Create the friendly name attribute $sFriendlyNameAttCode = $sAttCode.'_friendlyname'; - $oFriendlyName = new AttributeExternalField($sFriendlyNameAttCode, array('allowed_values'=>null, 'extkey_attcode'=>$sAttCode, "target_attcode"=>'friendlyname', 'depends_on'=>array())); + $oFriendlyName = new AttributeExternalField($sFriendlyNameAttCode, array('allowed_values' => null, 'extkey_attcode' => $sAttCode, "target_attcode" => 'friendlyname', 'depends_on' => array())); self::AddMagicAttribute($oFriendlyName, $sClass, self::$m_aAttribOrigins[$sClass][$sAttCode]); if (self::HasChildrenClasses($sRemoteClass)) { // First, create an external field attribute, that gets the final class - $sClassRecallAttCode = $sAttCode.'_finalclass_recall'; + $sClassRecallAttCode = $sAttCode.'_finalclass_recall'; $oClassRecall = new AttributeExternalField($sClassRecallAttCode, array( - "allowed_values"=>null, - "extkey_attcode"=>$sAttCode, - "target_attcode"=>"finalclass", - "is_null_allowed"=>true, - "depends_on"=>array() + "allowed_values" => null, + "extkey_attcode" => $sAttCode, + "target_attcode" => "finalclass", + "is_null_allowed" => true, + "depends_on" => array() )); self::AddMagicAttribute($oClassRecall, $sClass, self::$m_aAttribOrigins[$sClass][$sAttCode]); @@ -2025,7 +2148,7 @@ abstract class MetaModel $sKeyAttCode = $sAttCode; $sRemoteAttCode = 'archive_flag'; } - $oMagic = new AttributeExternalField($sCode, array("allowed_values"=>null, "extkey_attcode"=>$sKeyAttCode, "target_attcode"=>$sRemoteAttCode, "depends_on"=>array())); + $oMagic = new AttributeExternalField($sCode, array("allowed_values" => null, "extkey_attcode" => $sKeyAttCode, "target_attcode" => $sRemoteAttCode, "depends_on" => array())); self::AddMagicAttribute($oMagic, $sClass, self::$m_aAttribOrigins[$sClass][$sKeyAttCode]); } @@ -2044,7 +2167,7 @@ abstract class MetaModel $sKeyAttCode = $sAttCode; $sRemoteAttCode = 'obsolescence_flag'; } - $oMagic = new AttributeExternalField($sCode, array("allowed_values"=>null, "extkey_attcode"=>$sKeyAttCode, "target_attcode"=>$sRemoteAttCode, "depends_on"=>array())); + $oMagic = new AttributeExternalField($sCode, array("allowed_values" => null, "extkey_attcode" => $sKeyAttCode, "target_attcode" => $sRemoteAttCode, "depends_on" => array())); self::AddMagicAttribute($oMagic, $sClass, self::$m_aAttribOrigins[$sClass][$sKeyAttCode]); } } @@ -2092,6 +2215,7 @@ abstract class MetaModel { // In fact it is an ABSTRACT function, but this is not compatible with the fact that it is STATIC (error in E_STRICT interpretation) } + // To be overloaded by biz model declarations public static function GetRelationQueries($sRelCode) { @@ -2111,31 +2235,31 @@ abstract class MetaModel "db_table" => "database table", "db_key_field" => "database field which is the key", "db_finalclass_field" => "database field wich is the reference to the actual class of the object, considering that this will be a compound class", - ); + ); $sClass = self::GetCallersPHPClass("Init", self::$m_bTraceSourceFiles); - foreach($aMandatParams as $sParamName=>$sParamDesc) + foreach($aMandatParams as $sParamName => $sParamDesc) { if (!array_key_exists($sParamName, $aParams)) { throw new CoreException("Declaration of class $sClass - missing parameter $sParamName"); } } - + $aCategories = explode(',', $aParams['category']); - foreach ($aCategories as $sCategory) + foreach($aCategories as $sCategory) { self::$m_Category2Class[$sCategory][] = $sClass; } self::$m_Category2Class[''][] = $sClass; // all categories, include this one - + self::$m_aRootClasses[$sClass] = $sClass; // first, let consider that I am the root... updated on inheritance self::$m_aParentClasses[$sClass] = array(); self::$m_aChildClasses[$sClass] = array(); - self::$m_aClassParams[$sClass]= $aParams; + self::$m_aClassParams[$sClass] = $aParams; self::$m_aAttribDefs[$sClass] = array(); self::$m_aAttribOrigins[$sClass] = array(); @@ -2146,11 +2270,11 @@ abstract class MetaModel protected static function object_array_mergeclone($aSource1, $aSource2) { $aRes = array(); - foreach ($aSource1 as $key=>$object) + foreach($aSource1 as $key => $object) { $aRes[$key] = clone $object; } - foreach ($aSource2 as $key=>$object) + foreach($aSource2 as $key => $object) { $aRes[$key] = clone $object; } @@ -2164,7 +2288,10 @@ abstract class MetaModel { // Default: inherit from parent class $sSourceClass = self::GetParentPersistentClass($sTargetClass); - if (empty($sSourceClass)) return; // no attributes for the mother of all classes + if (empty($sSourceClass)) + { + return; + } // no attributes for the mother of all classes } if (isset(self::$m_aAttribDefs[$sSourceClass])) { @@ -2205,8 +2332,14 @@ abstract class MetaModel { // Differs from self::IsValidClass() // because it is being called before all the classes have been initialized - if (!class_exists($sClass)) return false; - if (!is_subclass_of($sClass, 'DBObject')) return false; + if (!class_exists($sClass)) + { + return false; + } + if (!is_subclass_of($sClass, 'DBObject')) + { + return false; + } return true; } @@ -2230,7 +2363,7 @@ abstract class MetaModel { throw new Exception("Declaration of $sTargetClass: attempting to redeclare the inherited attribute '$sAttCode', originaly declared in ".self::$m_aAttribOrigins[$sTargetClass][$sAttCode]); } - + // Set the "host class" as soon as possible, since HierarchicalKeys use it for their 'target class' as well // and this needs to be know early (for Init_IsKnowClass 19 lines below) $oAtt->SetHostClass($sTargetClass); @@ -2248,7 +2381,7 @@ abstract class MetaModel return; } } - elseif($oAtt->IsExternalKey()) + elseif ($oAtt->IsExternalKey()) { $sRemoteClass = $oAtt->GetTargetClass(); if (!self::Init_IsKnownClass($sRemoteClass)) @@ -2257,7 +2390,7 @@ abstract class MetaModel return; } } - elseif($oAtt->IsExternalField()) + elseif ($oAtt->IsExternalField()) { $sExtKeyAttCode = $oAtt->GetKeyAttCode(); if (isset(self::$m_aIgnoredAttributes[$sTargetClass][$sExtKeyAttCode])) @@ -2291,7 +2424,7 @@ abstract class MetaModel self::Init_CheckZListItems($aItems, $sTargetClass); self::$m_aListData[$sTargetClass][$sListCode] = $aItems; } - + protected static function Init_CheckZListItems(&$aItems, $sTargetClass) { foreach($aItems as $iFoo => $attCode) @@ -2306,9 +2439,12 @@ abstract class MetaModel unset($aItems[$iFoo]); } } - else if (isset(self::$m_aIgnoredAttributes[$sTargetClass][$attCode])) + else { - unset($aItems[$iFoo]); + if (isset(self::$m_aIgnoredAttributes[$sTargetClass][$attCode])) + { + unset($aItems[$iFoo]); + } } } } @@ -2329,11 +2465,14 @@ abstract class MetaModel } return $aResult; } - + public static function Init_DefineState($sStateCode, $aStateDef) { $sTargetClass = self::GetCallersPHPClass("Init"); - if (is_null($aStateDef['attribute_list'])) $aStateDef['attribute_list'] = array(); + if (is_null($aStateDef['attribute_list'])) + { + $aStateDef['attribute_list'] = array(); + } $sParentState = $aStateDef['attribute_inherit']; if (!empty($sParentState)) @@ -2344,13 +2483,13 @@ abstract class MetaModel // Reset the constraint when it was mandatory to set the value at the previous state // - foreach ($aToInherit['attribute_list'] as $sState => $iFlags) + foreach($aToInherit['attribute_list'] as $sState => $iFlags) { $iFlags = $iFlags & ~OPT_ATT_MUSTPROMPT; $iFlags = $iFlags & ~OPT_ATT_MUSTCHANGE; $aToInherit['attribute_list'][$sState] = $iFlags; } - + // The inherited configuration could be overriden $aStateDef['attribute_list'] = array_merge($aToInherit['attribute_list'], $aStateDef['attribute_list']); } @@ -2374,7 +2513,7 @@ abstract class MetaModel $sTargetClass = self::GetCallersPHPClass("Init"); self::$m_aHighlightScales[$sTargetClass] = $aHighlightScale; } - + public static function GetHighlightScale($sTargetClass) { $aScale = array(); @@ -2391,13 +2530,13 @@ abstract class MetaModel } return array_merge($aParentScale, $aScale); // Merge both arrays, the values from the last one have precedence } - + public static function GetHighlightCode($sTargetClass, $sStateCode) { $sCode = ''; - if ( array_key_exists($sTargetClass, self::$m_aStates) - && array_key_exists($sStateCode, self::$m_aStates[$sTargetClass]) - && array_key_exists('highlight', self::$m_aStates[$sTargetClass][$sStateCode]) ) + if (array_key_exists($sTargetClass, self::$m_aStates) + && array_key_exists($sStateCode, self::$m_aStates[$sTargetClass]) + && array_key_exists('highlight', self::$m_aStates[$sTargetClass][$sStateCode])) { $sCode = self::$m_aStates[$sTargetClass][$sStateCode]['highlight']['code']; } @@ -2412,7 +2551,7 @@ abstract class MetaModel } return $sCode; } - + public static function Init_OverloadStateAttribute($sStateCode, $sAttCode, $iFlags) { // Warning: this is not sufficient: the flags have to be copied to the states that are inheriting from this state @@ -2433,7 +2572,10 @@ abstract class MetaModel public static function Init_DefineTransition($sStateCode, $sStimulusCode, $aTransitionDef) { $sTargetClass = self::GetCallersPHPClass("Init"); - if (is_null($aTransitionDef['actions'])) $aTransitionDef['actions'] = array(); + if (is_null($aTransitionDef['actions'])) + { + $aTransitionDef['actions'] = array(); + } self::$m_aTransitions[$sTargetClass][$sStateCode][$sStimulusCode] = $aTransitionDef; } @@ -2444,7 +2586,10 @@ abstract class MetaModel { // Default: inherit from parent class $sSourceClass = self::GetParentPersistentClass($sTargetClass); - if (empty($sSourceClass)) return; // no attributes for the mother of all classes + if (empty($sSourceClass)) + { + return; + } // no attributes for the mother of all classes } self::$m_aClassParams[$sTargetClass]["state_attcode"] = self::$m_aClassParams[$sSourceClass]["state_attcode"]; @@ -2463,11 +2608,13 @@ abstract class MetaModel self::_check_subclass($sClass); return self::$m_aRootClasses[$sClass]; } + public static function IsRootClass($sClass) { self::_check_subclass($sClass); return (self::GetRootClass($sClass) == $sClass); } + public static function GetParentClass($sClass) { if (count(self::$m_aParentClasses[$sClass]) == 0) @@ -2479,6 +2626,7 @@ abstract class MetaModel return end(self::$m_aParentClasses[$sClass]); } } + public static function GetLowestCommonAncestor($aClasses) { $sAncestor = null; @@ -2505,9 +2653,10 @@ abstract class MetaModel } return $sAncestor; } + /** - * Note: assumes that class A and B have a common ancestor - */ + * Note: assumes that class A and B have a common ancestor + */ protected static function LowestCommonAncestor($sClassA, $sClassB) { if ($sClassA == $sClassB) @@ -2537,7 +2686,7 @@ abstract class MetaModel public static function IsHierarchicalClass($sClass) { $sHierarchicalKeyCode = false; - foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAtt) + foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAtt) { if ($oAtt->IsHierarchicalKey()) { @@ -2547,13 +2696,15 @@ abstract class MetaModel } return $sHierarchicalKeyCode; } + public static function EnumRootClasses() { return array_unique(self::$m_aRootClasses); } + public static function EnumParentClasses($sClass, $iOption = ENUM_PARENT_CLASSES_EXCLUDELEAF, $bRootFirst = true) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); if ($bRootFirst) { $aRes = self::$m_aParentClasses[$sClass]; @@ -2577,6 +2728,7 @@ abstract class MetaModel } return $aRes; } + public static function EnumChildClasses($sClass, $iOption = ENUM_CHILD_CLASSES_EXCLUDETOP) { self::_check_subclass($sClass); @@ -2589,10 +2741,11 @@ abstract class MetaModel } return $aRes; } + public static function EnumArchivableClasses() { $aRes = array(); - foreach (self::GetClasses() as $sClass) + foreach(self::GetClasses() as $sClass) { if (self::IsArchivable($sClass)) { @@ -2601,14 +2754,18 @@ abstract class MetaModel } return $aRes; } + public static function EnumObsoletableClasses($bRootClassesOnly = true) { $aRes = array(); - foreach (self::GetClasses() as $sClass) + foreach(self::GetClasses() as $sClass) { if (self::IsObsoletable($sClass)) { - if ($bRootClassesOnly && !static::IsRootClass($sClass)) continue; + if ($bRootClassesOnly && !static::IsRootClass($sClass)) + { + continue; + } $aRes[] = $sClass; } } @@ -2628,7 +2785,7 @@ abstract class MetaModel // Note: use EnumChildClasses to take the compound objects into account public static function GetSubclasses($sClass) { - self::_check_subclass($sClass); + self::_check_subclass($sClass); $aSubClasses = array(); foreach(self::$m_aClassParams as $sSubClass => $foo) { @@ -2639,6 +2796,7 @@ abstract class MetaModel } return $aSubClasses; } + public static function GetClasses($sCategories = '', $bStrict = false) { $aCategories = explode(',', $sCategories); @@ -2660,13 +2818,16 @@ abstract class MetaModel throw new CoreException("unkown class category '$sCategory', expecting a value in {".implode(', ', array_keys(self::$m_Category2Class))."}"); } } - + return array_unique($aClasses); } public static function HasTable($sClass) { - if (strlen(self::DBGetTable($sClass)) == 0) return false; + if (strlen(self::DBGetTable($sClass)) == 0) + { + return false; + } return true; } @@ -2708,7 +2869,7 @@ abstract class MetaModel { if (is_scalar($value)) { - $aScalarArgs[$sArgName] = (string) $value; + $aScalarArgs[$sArgName] = (string)$value; } elseif (is_null($value)) { @@ -2753,7 +2914,7 @@ abstract class MetaModel // Compute query modifiers properties (can be set in the search itself, by the context, etc.) // $aModifierProperties = array(); - foreach (MetaModel::EnumPlugins('iQueryModifier') as $sPluginClass => $oQueryModifier) + foreach(MetaModel::EnumPlugins('iQueryModifier') as $sPluginClass => $oQueryModifier) { // Lowest precedence: the application context $aPluginProps = ApplicationContext::GetPluginProperties($sPluginClass); @@ -2775,7 +2936,7 @@ abstract class MetaModel * Special processing for the hierarchical keys stored as nested sets * @param $iId integer The identifier of the parent * @param $oAttDef AttributeDefinition The attribute corresponding to the hierarchical key - * @param $stable string The name of the database table containing the hierarchical key + * @param $stable string The name of the database table containing the hierarchical key */ public static function HKInsertChildUnder($iId, $oAttDef, $sTable) { @@ -2791,7 +2952,7 @@ abstract class MetaModel } else { - $iMyRight = $aRes[0]['max']+1; + $iMyRight = $aRes[0]['max'] + 1; } } else @@ -2803,14 +2964,14 @@ abstract class MetaModel $sSQLUpdateLeft = "UPDATE `$sTable` SET `".$oAttDef->GetSQLLeft()."` = `".$oAttDef->GetSQLLeft()."` + 2 WHERE `".$oAttDef->GetSQLLeft()."` > $iMyRight"; CMDBSource::Query($sSQLUpdateLeft); } - return array($oAttDef->GetSQLRight() => $iMyRight+1, $oAttDef->GetSQLLeft() => $iMyRight); + return array($oAttDef->GetSQLRight() => $iMyRight + 1, $oAttDef->GetSQLLeft() => $iMyRight); } /** * Special processing for the hierarchical keys stored as nested sets: temporary remove the branch * @param $iId integer The identifier of the parent * @param $oAttDef AttributeDefinition The attribute corresponding to the hierarchical key - * @param $sTable string The name of the database table containing the hierarchical key + * @param $sTable string The name of the database table containing the hierarchical key */ public static function HKTemporaryCutBranch($iMyLeft, $iMyRight, $oAttDef, $sTable) { @@ -2828,7 +2989,7 @@ abstract class MetaModel * Special processing for the hierarchical keys stored as nested sets: replug the temporary removed branch * @param $iId integer The identifier of the parent * @param $oAttDef AttributeDefinition The attribute corresponding to the hierarchical key - * @param $sTable string The name of the database table containing the hierarchical key + * @param $sTable string The name of the database table containing the hierarchical key */ public static function HKReplugBranch($iNewLeft, $iNewRight, $oAttDef, $sTable) { @@ -2844,30 +3005,33 @@ abstract class MetaModel /** * Check (and updates if needed) the hierarchical keys * @param $bDiagnosticsOnly boolean If true only a diagnostic pass will be run, returning true or false - * @param $bVerbose boolean Displays some information about what is done/what needs to be done - * @param $bForceComputation boolean If true, the _left and _right parameters will be recomputed even if some values already exist in the DB - */ + * @param $bVerbose boolean Displays some information about what is done/what needs to be done + * @param $bForceComputation boolean If true, the _left and _right parameters will be recomputed even if some values already exist in the DB + */ public static function CheckHKeys($bDiagnosticsOnly = false, $bVerbose = false, $bForceComputation = false) { $bChangeNeeded = false; - foreach (self::GetClasses() as $sClass) + foreach(self::GetClasses() as $sClass) { - if (!self::HasTable($sClass)) continue; + if (!self::HasTable($sClass)) + { + continue; + } - foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef) + foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { // Check (once) all the attributes that are hierarchical keys - if((self::GetAttributeOrigin($sClass, $sAttCode) == $sClass) && $oAttDef->IsHierarchicalKey()) + if ((self::GetAttributeOrigin($sClass, $sAttCode) == $sClass) && $oAttDef->IsHierarchicalKey()) { if ($bVerbose) { - echo "The attribute $sAttCode from $sClass is a hierarchical key.\n"; + echo "The attribute $sAttCode from $sClass is a hierarchical key.\n"; } $bResult = self::HKInit($sClass, $sAttCode, $bDiagnosticsOnly, $bVerbose, $bForceComputation); $bChangeNeeded |= $bResult; if ($bVerbose && !$bResult) { - echo "Ok, the attribute $sAttCode from class $sClass seems up to date.\n"; + echo "Ok, the attribute $sAttCode from class $sClass seems up to date.\n"; } } } @@ -2882,9 +3046,9 @@ abstract class MetaModel * @param $sClass string Name of the class to process * @param $sAttCode string Code of the attribute to process * @param $bDiagnosticsOnly boolean If true only a diagnostic pass will be run, returning true or false - * @param $bVerbose boolean Displays some information about what is done/what needs to be done + * @param $bVerbose boolean Displays some information about what is done/what needs to be done * @param $bForceComputation boolean If true, the _left and _right parameters will be recomputed even if some values already exist in the DB - * @return true if an update is needed (diagnostics only) / was performed + * @return true if an update is needed (diagnostics only) / was performed */ public static function HKInit($sClass, $sAttCode, $bDiagnosticsOnly = false, $bVerbose = false, $bForceComputation = false) { @@ -2924,7 +3088,7 @@ abstract class MetaModel echo "Ok, table '$sTable' successfully updated.\n"; } } - catch(Exception $e) + catch (Exception $e) { CMDBSource::Query('ROLLBACK'); throw new Exception("An error occured (".$e->getMessage().") while initializing the hierarchy for ($sClass, $sAttCode). The database was not modified."); @@ -2933,7 +3097,7 @@ abstract class MetaModel } return $bUpdateNeeded; } - + /** * Recursive helper function called by HKInit */ @@ -2963,21 +3127,24 @@ abstract class MetaModel */ public static function RebuildMetaEnums($bVerbose = false) { - foreach (self::GetClasses() as $sClass) + foreach(self::GetClasses() as $sClass) { - if (!self::HasTable($sClass)) continue; + if (!self::HasTable($sClass)) + { + continue; + } - foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef) + foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { // Check (once) all the attributes that are hierarchical keys - if((self::GetAttributeOrigin($sClass, $sAttCode) == $sClass) && $oAttDef instanceof AttributeEnum) + if ((self::GetAttributeOrigin($sClass, $sAttCode) == $sClass) && $oAttDef instanceof AttributeEnum) { if (isset(self::$m_aEnumToMeta[$sClass][$sAttCode])) { - foreach (self::$m_aEnumToMeta[$sClass][$sAttCode] as $sMetaAttCode => $oMetaAttDef) + foreach(self::$m_aEnumToMeta[$sClass][$sAttCode] as $sMetaAttCode => $oMetaAttDef) { $aMetaValues = array(); // array of (metavalue => array of values) - foreach ($oAttDef->GetAllowedValues() as $sCode => $sLabel) + foreach($oAttDef->GetAllowedValues() as $sCode => $sLabel) { $aMappingData = $oMetaAttDef->GetMapRule($sClass); if ($aMappingData == null) @@ -3001,7 +3168,7 @@ abstract class MetaModel } $aMetaValues[$sMetaValue][] = $sCode; } - foreach ($aMetaValues as $sMetaValue => $aEnumValues) + foreach($aMetaValues as $sMetaValue => $aEnumValues) { $sMetaTable = self::DBGetTable($sClass, $sMetaAttCode); $sEnumTable = self::DBGetTable($sClass); @@ -3034,7 +3201,7 @@ abstract class MetaModel { echo "There are no Data Sources in the database.\n"; } - while($oSource = $oSet->Fetch()) + while ($oSource = $oSet->Fetch()) { if ($bVerbose) { @@ -3046,9 +3213,9 @@ abstract class MetaModel { echo "Ok.\n"; } - return $bFixNeeded; + return $bFixNeeded; } - + public static function GenerateUniqueAlias(&$aAliases, $sNewName, $sRealName) { if (!array_key_exists($sNewName, $aAliases)) @@ -3057,7 +3224,7 @@ abstract class MetaModel return $sNewName; } - for ($i = 1 ; $i < 100 ; $i++) + for($i = 1; $i < 100; $i++) { $sAnAlias = $sNewName.$i; if (!array_key_exists($sAnAlias, $aAliases)) @@ -3067,7 +3234,7 @@ abstract class MetaModel return $sAnAlias; } } - throw new CoreException('Failed to create an alias', array('aliases' => $aAliases, 'new'=>$sNewName)); + throw new CoreException('Failed to create an alias', array('aliases' => $aAliases, 'new' => $sNewName)); } public static function CheckDefinitions($bExitOnError = true) @@ -3079,7 +3246,7 @@ abstract class MetaModel $aErrors = array(); $aSugFix = array(); - foreach (self::GetClasses() as $sClass) + foreach(self::GetClasses() as $sClass) { $sTable = self::DBGetTable($sClass); $sTableLowercase = strtolower($sTable); @@ -3092,12 +3259,12 @@ abstract class MetaModel $aNameSpec = self::GetNameSpec($sClass); foreach($aNameSpec[1] as $i => $sAttCode) { - if(!self::IsValidAttCode($sClass, $sAttCode)) + if (!self::IsValidAttCode($sClass, $sAttCode)) { $aErrors[$sClass][] = "Unknown attribute code '".$sAttCode."' for the name definition"; $aSugFix[$sClass][] = "Expecting a value in ".implode(", ", self::GetAttributesList($sClass)); } - } + } foreach(self::GetReconcKeys($sClass) as $sReconcKeyAttCode) { @@ -3109,10 +3276,13 @@ abstract class MetaModel } $bHasWritableAttribute = false; - foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef) + foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { // It makes no sense to check the attributes again and again in the subclasses - if (self::$m_aAttribOrigins[$sClass][$sAttCode] != $sClass) continue; + if (self::$m_aAttribOrigins[$sClass][$sAttCode] != $sClass) + { + continue; + } if ($oAttDef->IsExternalKey()) { @@ -3142,57 +3312,63 @@ abstract class MetaModel } } } - else if ($oAttDef->IsLinkSet()) + else { - // Do nothing... - } - else if ($oAttDef instanceof AttributeStopWatch) - { - $aThresholds = $oAttDef->ListThresholds(); - if (is_array($aThresholds)) + if ($oAttDef->IsLinkSet()) { - foreach($aThresholds as $iPercent => $aDef) - { - if (array_key_exists('highlight', $aDef)) - { - if(!array_key_exists('code', $aDef['highlight'])) - { - $aErrors[$sClass][] = "The 'code' element is missing for the 'highlight' property of the $iPercent% threshold in the attribute: '$sAttCode'."; - $aSugFix[$sClass][] = "Add a 'code' entry specifying the value of the highlight code for this threshold."; - } - else - { - $aScale = self::GetHighlightScale($sClass); - if (!array_key_exists($aDef['highlight']['code'], $aScale)) - { - $aErrors[$sClass][] = "'{$aDef['highlight']['code']}' is not a valid value for the 'code' element of the $iPercent% threshold in the attribute: '$sAttCode'."; - $aSugFix[$sClass][] = "The possible highlight codes for this class are: ".implode(', ', array_keys($aScale))."."; - } - } - } - } - } - } - else // standard attributes - { - // Check that the default values definition is a valid object! - $oValSetDef = $oAttDef->GetValuesDef(); - if (!is_null($oValSetDef) && !$oValSetDef instanceof ValueSetDefinition) - { - $aErrors[$sClass][] = "Allowed values for attribute $sAttCode is not of the relevant type"; - $aSugFix[$sClass][] = "Please set it as an instance of a ValueSetDefinition object."; + // Do nothing... } else { - // Default value must be listed in the allowed values (if defined) - $aAllowedValues = self::GetAllowedValues_att($sClass, $sAttCode); - if (!is_null($aAllowedValues)) + if ($oAttDef instanceof AttributeStopWatch) { - $sDefaultValue = $oAttDef->GetDefaultValue(); - if (is_string($sDefaultValue) && !array_key_exists($sDefaultValue, $aAllowedValues)) + $aThresholds = $oAttDef->ListThresholds(); + if (is_array($aThresholds)) { - $aErrors[$sClass][] = "Default value '".$sDefaultValue."' for attribute $sAttCode is not an allowed value"; - $aSugFix[$sClass][] = "Please pickup the default value out of {'".implode(", ", array_keys($aAllowedValues))."'}"; + foreach($aThresholds as $iPercent => $aDef) + { + if (array_key_exists('highlight', $aDef)) + { + if (!array_key_exists('code', $aDef['highlight'])) + { + $aErrors[$sClass][] = "The 'code' element is missing for the 'highlight' property of the $iPercent% threshold in the attribute: '$sAttCode'."; + $aSugFix[$sClass][] = "Add a 'code' entry specifying the value of the highlight code for this threshold."; + } + else + { + $aScale = self::GetHighlightScale($sClass); + if (!array_key_exists($aDef['highlight']['code'], $aScale)) + { + $aErrors[$sClass][] = "'{$aDef['highlight']['code']}' is not a valid value for the 'code' element of the $iPercent% threshold in the attribute: '$sAttCode'."; + $aSugFix[$sClass][] = "The possible highlight codes for this class are: ".implode(', ', array_keys($aScale))."."; + } + } + } + } + } + } + else // standard attributes + { + // Check that the default values definition is a valid object! + $oValSetDef = $oAttDef->GetValuesDef(); + if (!is_null($oValSetDef) && !$oValSetDef instanceof ValueSetDefinition) + { + $aErrors[$sClass][] = "Allowed values for attribute $sAttCode is not of the relevant type"; + $aSugFix[$sClass][] = "Please set it as an instance of a ValueSetDefinition object."; + } + else + { + // Default value must be listed in the allowed values (if defined) + $aAllowedValues = self::GetAllowedValues_att($sClass, $sAttCode); + if (!is_null($aAllowedValues)) + { + $sDefaultValue = $oAttDef->GetDefaultValue(); + if (is_string($sDefaultValue) && !array_key_exists($sDefaultValue, $aAllowedValues)) + { + $aErrors[$sClass][] = "Default value '".$sDefaultValue."' for attribute $sAttCode is not an allowed value"; + $aSugFix[$sClass][] = "Please pickup the default value out of {'".implode(", ", array_keys($aAllowedValues))."'}"; + } + } } } } @@ -3201,7 +3377,7 @@ abstract class MetaModel if ($oAttDef->IsWritable()) { $bHasWritableAttribute = true; - foreach ($oAttDef->GetPrerequisiteAttributes() as $sDependOnAttCode) + foreach($oAttDef->GetPrerequisiteAttributes() as $sDependOnAttCode) { if (!self::IsValidAttCode($sClass, $sDependOnAttCode)) { @@ -3211,10 +3387,10 @@ abstract class MetaModel } } } - foreach(self::GetClassFilterDefs($sClass) as $sFltCode=>$oFilterDef) + foreach(self::GetClassFilterDefs($sClass) as $sFltCode => $oFilterDef) { if (method_exists($oFilterDef, '__GetRefAttribute')) - { + { $oAttDef = $oFilterDef->__GetRefAttribute(); if (!self::IsValidAttCode($sClass, $oAttDef->GetCode())) { @@ -3248,7 +3424,7 @@ abstract class MetaModel else { $aAllowedValues = array_keys($aAllowedValuesRaw); - + // Lifecycle - check the the state attribute allowed values are defined states foreach($aAllowedValues as $sValue) { @@ -3258,7 +3434,7 @@ abstract class MetaModel $aSugFix[$sClass][] = "You may define its allowed_values property as [new ValueSetEnum('".implode(", ", $aStates)."')], or reconsider the list of states"; } } - + // Lifecycle - check that defined states are allowed values foreach($aStates as $sStateValue) { @@ -3269,13 +3445,13 @@ abstract class MetaModel } } } - + // Lifecycle - check that the action handlers are defined - foreach (self::EnumStates($sClass) as $sStateCode => $aStateDef) + foreach(self::EnumStates($sClass) as $sStateCode => $aStateDef) { foreach(self::EnumTransitions($sClass, $sStateCode) as $sStimulusCode => $aTransitionDef) { - foreach ($aTransitionDef['actions'] as $actionHandler) + foreach($aTransitionDef['actions'] as $actionHandler) { if (is_string($actionHandler)) { @@ -3298,7 +3474,7 @@ abstract class MetaModel } if (array_key_exists('highlight', $aStateDef)) { - if(!array_key_exists('code', $aStateDef['highlight'])) + if (!array_key_exists('code', $aStateDef['highlight'])) { $aErrors[$sClass][] = "The 'code' element is missing for the 'highlight' property of state: '$sStateCode'."; $aSugFix[$sClass][] = "Add a 'code' entry specifying the value of the highlight code for this state."; @@ -3331,7 +3507,7 @@ abstract class MetaModel // foreach(self::EnumZLists() as $sListCode) { - foreach (self::FlattenZList(self::GetZListItems($sClass, $sListCode)) as $sMyAttCode) + foreach(self::FlattenZList(self::GetZListItems($sClass, $sListCode)) as $sMyAttCode) { if (!self::IsValidAttCode($sClass, $sMyAttCode)) { @@ -3347,14 +3523,17 @@ abstract class MetaModel { $aTableColumns = array(); // array of column => attcode (the column is used by this attribute) $aTableColumns[self::DBGetKey($sClass)] = 'id'; - + // Check that SQL columns are declared only once // - foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef) + foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { // Skip this attribute if not originaly defined in this class - if (self::$m_aAttribOrigins[$sClass][$sAttCode] != $sClass) continue; - + if (self::$m_aAttribOrigins[$sClass][$sAttCode] != $sClass) + { + continue; + } + foreach($oAttDef->GetSQLColumns() as $sField => $sDBFieldType) { if (array_key_exists($sField, $aTableColumns)) @@ -3370,33 +3549,42 @@ abstract class MetaModel } } } // foreach class - + if (count($aErrors) > 0) { echo "
"; echo "

Business model inconsistencies have been found

\n"; // #@# later -> this is the responsibility of the caller to format the output - foreach ($aErrors as $sClass => $aMessages) + foreach($aErrors as $sClass => $aMessages) { echo "

Wrong declaration for class $sClass

\n"; echo "\n"; } - if ($bExitOnError) echo "

Aborting...

\n"; + if ($bExitOnError) + { + echo "

Aborting...

\n"; + } echo "
\n"; - if ($bExitOnError) exit; + if ($bExitOnError) + { + exit; + } } } public static function DBShowApplyForm($sRepairUrl, $sSQLStatementArgName, $aSQLFixes) { - if (empty($sRepairUrl)) return; + if (empty($sRepairUrl)) + { + return; + } // By design, some queries might be blank, we have to ignore them $aCleanFixes = array(); @@ -3407,7 +3595,10 @@ abstract class MetaModel $aCleanFixes[] = $sSQLFix; } } - if (count($aCleanFixes) == 0) return; + if (count($aCleanFixes) == 0) + { + return; + } echo "
\n"; echo " \n"; @@ -3428,7 +3619,7 @@ abstract class MetaModel $aFound = array(); $aMissing = array(); - foreach (self::DBEnumTables() as $sTable => $aClasses) + foreach(self::DBEnumTables() as $sTable => $aClasses) { if (CMDBSource::IsTable($sTable)) { @@ -3475,7 +3666,7 @@ abstract class MetaModel { // Do drop only tables corresponding to the sub-database (table prefix) // then possibly drop the DB itself (if no table remain) - foreach (CMDBSource::EnumTables() as $sTable) + foreach(CMDBSource::EnumTables() as $sTable) { // perform a case insensitive test because on Windows the table names become lowercase :-( if (strtolower(substr($sTable, 0, strlen(self::$m_sTablePrefix))) == strtolower(self::$m_sTablePrefix)) @@ -3531,11 +3722,11 @@ abstract class MetaModel list($aErrors, $aSugFix) = self::DBCheckViews(); $aSQL = array(); - foreach ($aSugFix as $sClass => $aTarget) + foreach($aSugFix as $sClass => $aTarget) { - foreach ($aTarget as $aQueries) + foreach($aTarget as $aQueries) { - foreach ($aQueries as $sQuery) + foreach($aQueries as $sQuery) { if (!empty($sQuery)) { @@ -3551,7 +3742,7 @@ abstract class MetaModel public static function DBDump() { $aDataDump = array(); - foreach (self::DBEnumTables() as $sTable => $aClasses) + foreach(self::DBEnumTables() as $sTable => $aClasses) { $aRows = CMDBSource::DumpTable($sTable); $aDataDump[$sTable] = $aRows; @@ -3561,7 +3752,7 @@ abstract class MetaModel /* * Determines wether the target DB is frozen or not - */ + */ public static function DBIsReadOnly() { // Improvement: check the mySQL variable -> Read-only @@ -3583,7 +3774,10 @@ abstract class MetaModel public static function DBHasAccess($iRequested = ACCESS_FULL) { $iMode = self::$m_oConfig->Get('access_mode'); - if (($iMode & $iRequested) == 0) return false; + if (($iMode & $iRequested) == 0) + { + return false; + } return true; } @@ -3621,7 +3815,7 @@ abstract class MetaModel // Need to invent the "module", to characterize the origins of a class if (strlen($sModules) == 0) { - $aModules = array('bizmodel', 'core/cmdb', 'gui' , 'application', 'addon/userrights'); + $aModules = array('bizmodel', 'core/cmdb', 'gui', 'application', 'addon/userrights'); } else { @@ -3632,17 +3826,20 @@ abstract class MetaModel $sRes .= "// Note: The classes have been grouped by categories: ".implode(', ', $aModules)."\n"; $sRes .= "//////////////////////////////////////////////////////////////////////\n"; - foreach ($aModules as $sCategory) + foreach($aModules as $sCategory) { $sRes .= "//////////////////////////////////////////////////////////////////////\n"; $sRes .= "// Classes in '$sCategory'\n"; $sRes .= "//////////////////////////////////////////////////////////////////////\n"; $sRes .= "//\n"; $sRes .= "\n"; - foreach (self::GetClasses($sCategory) as $sClass) + foreach(self::GetClasses($sCategory) as $sClass) { - if (!self::HasTable($sClass)) continue; - + if (!self::HasTable($sClass)) + { + continue; + } + $bNotInDico = false; $sClassRes = "//\n"; @@ -3655,15 +3852,18 @@ abstract class MetaModel foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { // Skip this attribute if not originaly defined in this class - if (self::$m_aAttribOrigins[$sClass][$sAttCode] != $sClass) continue; - + if (self::$m_aAttribOrigins[$sClass][$sAttCode] != $sClass) + { + continue; + } + $sClassRes .= self::MakeDictEntry("Class:$sClass/Attribute:$sAttCode", $oAttDef->GetLabel_Obsolete(), $sAttCode, $bNotInDico); $sClassRes .= self::MakeDictEntry("Class:$sClass/Attribute:$sAttCode+", $oAttDef->GetDescription_Obsolete(), '', $bNotInDico); if ($oAttDef instanceof AttributeEnum) { if (self::GetStateAttributeCode($sClass) == $sAttCode) { - foreach (self::EnumStates($sClass) as $sStateCode => $aStateData) + foreach(self::EnumStates($sClass) as $sStateCode => $aStateData) { if (array_key_exists('label', $aStateData)) { @@ -3687,7 +3887,7 @@ abstract class MetaModel } else { - foreach ($oAttDef->GetAllowedValues() as $sKey => $value) + foreach($oAttDef->GetAllowedValues() as $sKey => $value) { $sClassRes .= self::MakeDictEntry("Class:$sClass/Attribute:$sAttCode/Value:$sKey", $value, '', $bNotInDico); $sClassRes .= self::MakeDictEntry("Class:$sClass/Attribute:$sAttCode/Value:$sKey+", $value, '', $bNotInDico); @@ -3700,11 +3900,11 @@ abstract class MetaModel $sClassRes .= self::MakeDictEntry("Class:$sClass/Stimulus:$sStimulusCode", $oStimulus->GetLabel_Obsolete(), '', $bNotInDico); $sClassRes .= self::MakeDictEntry("Class:$sClass/Stimulus:$sStimulusCode+", $oStimulus->GetDescription_Obsolete(), '', $bNotInDico); } - + $sClassRes .= "));\n"; $sClassRes .= "\n"; - if ($bNotInDico || ($sOutputFilter != 'NotInDictionary')) + if ($bNotInDico || ($sOutputFilter != 'NotInDictionary')) { $sRes .= $sClassRes; } @@ -3722,10 +3922,13 @@ abstract class MetaModel $aCreateTable = array(); // array of =>
$aCreateTableItems = array(); // array of
=> array of $aAlterTableItems = array(); // array of
=> - - foreach (self::GetClasses() as $sClass) - { - if (!self::HasTable($sClass)) continue; + + foreach(self::GetClasses() as $sClass) + { + if (!self::HasTable($sClass)) + { + continue; + } // Check that the table exists @@ -3775,17 +3978,20 @@ abstract class MetaModel } } } - + // Check that any defined field exists // $aTableInfo = CMDBSource::GetTableInfo($sTable); $aTableInfo['Fields'][$sKeyField]['used'] = true; - foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef) + foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if (!$oAttDef->CopyOnAllTables()) { // Skip this attribute if not originaly defined in this class - if (self::$m_aAttribOrigins[$sClass][$sAttCode] != $sClass) continue; + if (self::$m_aAttribOrigins[$sClass][$sAttCode] != $sClass) + { + continue; + } } foreach($oAttDef->GetSQLColumns(true) as $sField => $sDBFieldSpec) { @@ -3828,9 +4034,9 @@ abstract class MetaModel $sActualFieldSpec = CMDBSource::GetFieldSpec($sTable, $sField); if (strcasecmp($sDBFieldSpec, $sActualFieldSpec) != 0) { - $bToBeChanged = true; + $bToBeChanged = true; $aErrors[$sClass][$sAttCode][] = "field '$sField' in table '$sTable' has a wrong type: found '$sActualFieldSpec' while expecting '$sDBFieldSpec'"; - } + } if ($bToBeChanged) { $aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` CHANGE `$sField` $sFieldDefinition"; @@ -3857,13 +4063,13 @@ abstract class MetaModel } } } - + // Check indexes - foreach (self::DBGetIndexes($sClass) as $aColumns) + foreach(self::DBGetIndexes($sClass) as $aColumns) { $sIndexId = implode('_', $aColumns); - if(!CMDBSource::HasIndex($sTable, $sIndexId, $aColumns)) + if (!CMDBSource::HasIndex($sTable, $sIndexId, $aColumns)) { $sColumns = "`".implode("`, `", $aColumns)."`"; if (CMDBSource::HasIndex($sTable, $sIndexId)) @@ -3932,7 +4138,7 @@ abstract class MetaModel // Reporting views (must be created after any other table) // - foreach (self::GetClasses('bizmodel') as $sClass) + foreach(self::GetClasses('bizmodel') as $sClass) { $sView = self::DBGetView($sClass); if (CMDBSource::IsTable($sView)) @@ -3982,26 +4188,35 @@ abstract class MetaModel $sSelWrongRecs .= " AND maintable.`$sKeyField` NOT IN ('".implode("', '", $aPlannedDel[$sTable])."')"; } $aWrongRecords = CMDBSource::QueryToCol($sSelWrongRecs, "id"); - if (count($aWrongRecords) == 0) return; + if (count($aWrongRecords) == 0) + { + return; + } - if (!array_key_exists($sRootClass, $aErrorsAndFixes)) $aErrorsAndFixes[$sRootClass] = array(); - if (!array_key_exists($sTable, $aErrorsAndFixes[$sRootClass])) $aErrorsAndFixes[$sRootClass][$sTable] = array(); + if (!array_key_exists($sRootClass, $aErrorsAndFixes)) + { + $aErrorsAndFixes[$sRootClass] = array(); + } + if (!array_key_exists($sTable, $aErrorsAndFixes[$sRootClass])) + { + $aErrorsAndFixes[$sRootClass][$sTable] = array(); + } - foreach ($aWrongRecords as $iRecordId) + foreach($aWrongRecords as $iRecordId) { if (array_key_exists($iRecordId, $aErrorsAndFixes[$sRootClass][$sTable])) { switch ($aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action']) { - case 'Delete': - // Already planned for a deletion - // Let's concatenate the errors description together - $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Reason'] .= ', '.$sErrorDesc; - break; + case 'Delete': + // Already planned for a deletion + // Let's concatenate the errors description together + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Reason'] .= ', '.$sErrorDesc; + break; - case 'Update': - // Let's plan a deletion - break; + case 'Update': + // Let's plan a deletion + break; } } else @@ -4029,14 +4244,17 @@ abstract class MetaModel if (!$bProcessingFriends) { $sDeleteKeys = "'".implode("', '", $aWrongRecords)."'"; - foreach (self::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_ALL) as $sFriendClass) + foreach(self::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_ALL) as $sFriendClass) { $sFriendTable = self::DBGetTable($sFriendClass); $sFriendKey = self::DBGetKey($sFriendClass); - + // skip the current table - if ($sFriendTable == $sTable) continue; - + if ($sFriendTable == $sTable) + { + continue; + } + $sFindRelatedRec = "SELECT DISTINCT maintable.`$sFriendKey` AS id FROM `$sFriendTable` AS maintable WHERE maintable.`$sFriendKey` IN ($sDeleteKeys)"; self::DBCheckIntegrity_Check2Delete($sFindRelatedRec, "Cascading deletion of record in friend table `$sTable`", $sFriendClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel, true); } @@ -4054,45 +4272,54 @@ abstract class MetaModel $sSelWrongRecs .= " AND maintable.`$sKeyField` NOT IN ('".implode("', '", $aPlannedDel[$sTable])."')"; } $aWrongRecords = CMDBSource::QueryToCol($sSelWrongRecs, "id"); - if (count($aWrongRecords) == 0) return; + if (count($aWrongRecords) == 0) + { + return; + } - if (!array_key_exists($sRootClass, $aErrorsAndFixes)) $aErrorsAndFixes[$sRootClass] = array(); - if (!array_key_exists($sTable, $aErrorsAndFixes[$sRootClass])) $aErrorsAndFixes[$sRootClass][$sTable] = array(); + if (!array_key_exists($sRootClass, $aErrorsAndFixes)) + { + $aErrorsAndFixes[$sRootClass] = array(); + } + if (!array_key_exists($sTable, $aErrorsAndFixes[$sRootClass])) + { + $aErrorsAndFixes[$sRootClass][$sTable] = array(); + } - foreach ($aWrongRecords as $iRecordId) + foreach($aWrongRecords as $iRecordId) { if (array_key_exists($iRecordId, $aErrorsAndFixes[$sRootClass][$sTable])) { switch ($aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action']) { - case 'Delete': - // No need to update, the record will be deleted! - break; + case 'Delete': + // No need to update, the record will be deleted! + break; - case 'Update': - // Already planned for an update - // Add this new update spec to the list - $bFoundSameSpec = false; - foreach ($aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action_Details'] as $aUpdateSpec) - { - if (($sColumn == $aUpdateSpec['column']) && ($sNewValue == $aUpdateSpec['newvalue'])) - { - $bFoundSameSpec = true; - } - } - if (!$bFoundSameSpec) - { - $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action_Details'][] = (array('column' => $sColumn, 'newvalue'=>$sNewValue)); - $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Reason'] .= ', '.$sErrorDesc; - } - break; + case 'Update': + // Already planned for an update + // Add this new update spec to the list + $bFoundSameSpec = false; + foreach($aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action_Details'] as $aUpdateSpec) + { + if (($sColumn == $aUpdateSpec['column']) && ($sNewValue == $aUpdateSpec['newvalue'])) + { + $bFoundSameSpec = true; + } + } + if (!$bFoundSameSpec) + { + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action_Details'][] = (array('column' => $sColumn, 'newvalue' => $sNewValue)); + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Reason'] .= ', '.$sErrorDesc; + } + break; } } else { $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Reason'] = $sErrorDesc; $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action'] = 'Update'; - $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action_Details'] = array(array('column' => $sColumn, 'newvalue'=>$sNewValue)); + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action_Details'] = array(array('column' => $sColumn, 'newvalue' => $sNewValue)); $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Pass'] = 123; } @@ -4102,9 +4329,12 @@ abstract class MetaModel // returns the count of records found for deletion public static function DBCheckIntegrity_SinglePass(&$aErrorsAndFixes, &$iNewDelCount, &$aPlannedDel) { - foreach (self::GetClasses() as $sClass) + foreach(self::GetClasses() as $sClass) { - if (!self::HasTable($sClass)) continue; + if (!self::HasTable($sClass)) + { + continue; + } $sRootClass = self::GetRootClass($sClass); $sTable = self::DBGetTable($sClass); $sKeyField = self::DBGetKey($sClass); @@ -4116,10 +4346,10 @@ abstract class MetaModel // Check that the final class field contains the name of a class which inherited from the current class // $sFinalClassField = self::DBGetClassField($sClass); - + $aAllowedValues = self::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL); $sAllowedValues = implode(",", CMDBSource::Quote($aAllowedValues, true)); - + $sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS id FROM `$sTable` AS maintable WHERE `$sFinalClassField` NOT IN ($sAllowedValues)"; self::DBCheckIntegrity_Check2Delete($sSelWrongRecs, "final class (field `$sFinalClassField`) is wrong (expected a value in {".$sAllowedValues."})", $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); } @@ -4128,16 +4358,16 @@ abstract class MetaModel $sRootTable = self::DBGetTable($sRootClass); $sRootKey = self::DBGetKey($sRootClass); $sFinalClassField = self::DBGetClassField($sRootClass); - + $aExpectedClasses = self::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL); $sExpectedClasses = implode(",", CMDBSource::Quote($aExpectedClasses, true)); - + // Check that any record found here has its counterpart in the root table // and which refers to a child class // $sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS id FROM `$sTable` as maintable LEFT JOIN `$sRootTable` ON maintable.`$sKeyField` = `$sRootTable`.`$sRootKey` AND `$sRootTable`.`$sFinalClassField` IN ($sExpectedClasses) WHERE `$sRootTable`.`$sRootKey` IS NULL"; self::DBCheckIntegrity_Check2Delete($sSelWrongRecs, "Found a record in `$sTable`, but no counterpart in root table `$sRootTable` (inc. records pointing to a class in {".$sExpectedClasses."})", $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); - + // Check that any record found in the root table and referring to a child class // has its counterpart here (detect orphan nodes -root or in the middle of the hierarchy) // @@ -4146,10 +4376,13 @@ abstract class MetaModel } } - foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef) + foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { // Skip this attribute if not defined in this table - if (self::$m_aAttribOrigins[$sClass][$sAttCode] != $sClass) continue; + if (self::$m_aAttribOrigins[$sClass][$sAttCode] != $sClass) + { + continue; + } if ($oAttDef->IsExternalKey()) { @@ -4197,20 +4430,23 @@ abstract class MetaModel } } } - else if ($oAttDef->IsBasedOnDBColumns()) + else { - // Check that the values fit the allowed values - // - $aAllowedValues = self::GetAllowedValues_att($sClass, $sAttCode); - if (!is_null($aAllowedValues) && count($aAllowedValues) > 0) + if ($oAttDef->IsBasedOnDBColumns()) { - $sExpectedValues = implode(",", CMDBSource::Quote(array_keys($aAllowedValues), true)); - - $aCols = $oAttDef->GetSQLExpressions(); // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc()) - $sMyAttributeField = current($aCols); // get the first column for the moment - $sDefaultValue = $oAttDef->GetDefaultValue(); - $sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS id FROM `$sTable` AS maintable WHERE maintable.`$sMyAttributeField` NOT IN ($sExpectedValues)"; - self::DBCheckIntegrity_Check2Update($sSelWrongRecs, "Record having a column ('$sAttCode') with an unexpected value", $sMyAttributeField, CMDBSource::Quote($sDefaultValue), $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); + // Check that the values fit the allowed values + // + $aAllowedValues = self::GetAllowedValues_att($sClass, $sAttCode); + if (!is_null($aAllowedValues) && count($aAllowedValues) > 0) + { + $sExpectedValues = implode(",", CMDBSource::Quote(array_keys($aAllowedValues), true)); + + $aCols = $oAttDef->GetSQLExpressions(); // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc()) + $sMyAttributeField = current($aCols); // get the first column for the moment + $sDefaultValue = $oAttDef->GetDefaultValue(); + $sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS id FROM `$sTable` AS maintable WHERE maintable.`$sMyAttributeField` NOT IN ($sExpectedValues)"; + self::DBCheckIntegrity_Check2Update($sSelWrongRecs, "Record having a column ('$sAttCode') with an unexpected value", $sMyAttributeField, CMDBSource::Quote($sDefaultValue), $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); + } } } } @@ -4226,7 +4462,7 @@ abstract class MetaModel // Records to be ignored in the current/next pass // by Table = array of RecordId $aPlannedDel = array(); - + // Count of errors in the next pass: no error means that we can leave... $iErrorCount = 0; // Limit in case of a bug in the algorythm @@ -4243,7 +4479,7 @@ abstract class MetaModel // $iMaxDel = 1000; $iPlannedDel = 0; - foreach ($aPlannedDel as $sTable => $aPlannedDelOnTable) + foreach($aPlannedDel as $sTable => $aPlannedDelOnTable) { $iPlannedDel += count($aPlannedDelOnTable); } @@ -4269,11 +4505,11 @@ abstract class MetaModel $aFixesDelete = array(); $aFixesUpdate = array(); - foreach ($aErrorsAndFixes as $sRootClass => $aTables) + foreach($aErrorsAndFixes as $sRootClass => $aTables) { - foreach ($aTables as $sTable => $aRecords) + foreach($aTables as $sTable => $aRecords) { - foreach ($aRecords as $iRecord => $aError) + foreach($aRecords as $iRecord => $aError) { $sAction = $aError['Action']; $sReason = $aError['Reason']; @@ -4282,26 +4518,26 @@ abstract class MetaModel switch ($sAction) { case 'Delete': - $sActionDetails = ""; - $aFixesDelete[$sTable][] = $iRecord; - break; + $sActionDetails = ""; + $aFixesDelete[$sTable][] = $iRecord; + break; case 'Update': - $aUpdateDesc = array(); - foreach($aError['Action_Details'] as $aUpdateSpec) - { - $aUpdateDesc[] = $aUpdateSpec['column']." -> ".$aUpdateSpec['newvalue']; - $aFixesUpdate[$sTable][$aUpdateSpec['column']][$aUpdateSpec['newvalue']][] = $iRecord; - } - $sActionDetails = "Set ".implode(", ", $aUpdateDesc); + $aUpdateDesc = array(); + foreach($aError['Action_Details'] as $aUpdateSpec) + { + $aUpdateDesc[] = $aUpdateSpec['column']." -> ".$aUpdateSpec['newvalue']; + $aFixesUpdate[$sTable][$aUpdateSpec['column']][$aUpdateSpec['newvalue']][] = $iRecord; + } + $sActionDetails = "Set ".implode(", ", $aUpdateDesc); - break; + break; default: - $sActionDetails = "bug: unknown action '$sAction'"; + $sActionDetails = "bug: unknown action '$sAction'"; } $aIssues[] = "$sRootClass / $sTable / $iRecord / $sReason / $sAction / $sActionDetails"; - $iIssueCount++; + $iIssueCount++; } } } @@ -4313,25 +4549,28 @@ abstract class MetaModel // First step, be able to get class data out of the table name // Could be optimized, because we've made the job earlier... but few benefits, so... $aTable2ClassProp = array(); - foreach (self::GetClasses() as $sClass) + foreach(self::GetClasses() as $sClass) { - if (!self::HasTable($sClass)) continue; + if (!self::HasTable($sClass)) + { + continue; + } $sRootClass = self::GetRootClass($sClass); $sTable = self::DBGetTable($sClass); $sKeyField = self::DBGetKey($sClass); - + $aErrorsAndFixes[$sRootClass][$sTable] = array(); - $aTable2ClassProp[$sTable] = array('rootclass'=>$sRootClass, 'class'=>$sClass, 'keyfield'=>$sKeyField); + $aTable2ClassProp[$sTable] = array('rootclass' => $sRootClass, 'class' => $sClass, 'keyfield' => $sKeyField); } // Second step, build a flat list of SQL queries $aSQLFixes = array(); $iPlannedUpdate = 0; - foreach ($aFixesUpdate as $sTable => $aColumns) + foreach($aFixesUpdate as $sTable => $aColumns) { - foreach ($aColumns as $sColumn => $aNewValues) + foreach($aColumns as $sColumn => $aNewValues) { - foreach ($aNewValues as $sNewValue => $aRecords) + foreach($aNewValues as $sNewValue => $aRecords) { $iPlannedUpdate += count($aRecords); $sWrongRecords = "'".implode("', '", $aRecords)."'"; @@ -4342,7 +4581,7 @@ abstract class MetaModel } } $iPlannedDel = 0; - foreach ($aFixesDelete as $sTable => $aRecords) + foreach($aFixesDelete as $sTable => $aRecords) { $iPlannedDel += count($aRecords); $sWrongRecords = "'".implode("', '", $aRecords)."'"; @@ -4357,7 +4596,7 @@ abstract class MetaModel echo "

Database corruption error(s): $iErrorCount issues have been encountered. $iPlannedDel records will be deleted, $iPlannedUpdate records will be updated:

\n"; // #@# later -> this is the responsibility of the caller to format the output echo "