function MakeDictionaryTemplate($sModules = '', $sLanguage = 'EN US') { $sRes = ''; Dict::SetDefaultLanguage($sLanguage); $aAvailableLanguages = Dict::GetLanguages(); $sDesc = $aAvailableLanguages[$sLanguage]['description']; $sLocalizedDesc = $aAvailableLanguages[$sLanguage]['localized_description']; $sRes .= "// Dictionary conventions\n"; $sRes .= htmlentities("// Class:<class_name>\n", ENT_QUOTES, 'UTF-8'); $sRes .= htmlentities("// Class:<class_name>+\n", ENT_QUOTES, 'UTF-8'); $sRes .= htmlentities("// Class:<class_name>/Attribute:<attribute_code>\n", ENT_QUOTES, 'UTF-8'); $sRes .= htmlentities("// Class:<class_name>/Attribute:<attribute_code>+\n", ENT_QUOTES, 'UTF-8'); $sRes .= htmlentities("// Class:<class_name>/Attribute:<attribute_code>/Value:<value>\n", ENT_QUOTES, 'UTF-8'); $sRes .= htmlentities("// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+\n", ENT_QUOTES, 'UTF-8'); $sRes .= htmlentities("// Class:<class_name>/Stimulus:<stimulus_code>\n", ENT_QUOTES, 'UTF-8'); $sRes .= htmlentities("// Class:<class_name>/Stimulus:<stimulus_code>+\n", ENT_QUOTES, 'UTF-8'); $sRes .= "\n"; // Note: I did not use EnumCategories(), because a given class maybe found in several categories // 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', 'monitoring'); } else { $aModules = explode(', ', $sModules); } $sRes .= "//////////////////////////////////////////////////////////////////////\n"; $sRes .= "// Note: The classes have been grouped by categories: " . implode(', ', $aModules) . "\n"; $sRes .= "//////////////////////////////////////////////////////////////////////\n"; foreach ($aModules as $sCategory) { $sRes .= "//////////////////////////////////////////////////////////////////////\n"; $sRes .= "// Classes in '{$sCategory}'\n"; $sRes .= "//////////////////////////////////////////////////////////////////////\n"; $sRes .= "//\n"; $sRes .= "\n"; foreach (MetaModel::GetClasses($sCategory) as $sClass) { if (!MetaModel::HasTable($sClass)) { continue; } $bNotInDico = false; $bNotImportant = true; $sClassRes = "//\n"; $sClassRes .= "// Class: {$sClass}\n"; $sClassRes .= "//\n"; $sClassRes .= "\n"; $sClassRes .= "Dict::Add('{$sLanguage}', '{$sDesc}', '{$sLocalizedDesc}', array(\n"; $sClassRes .= MakeDictEntry("Class:{$sClass}", MetaModel::GetName_Obsolete($sClass), $sClass, $bNotInDico); $sClassRes .= MakeDictEntry("Class:{$sClass}+", MetaModel::GetClassDescription_Obsolete($sClass), '', $bNotImportant); foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($sAttCode == 'friendlyname') { continue; } // Skip this attribute if not originaly defined in this class if (MetaModel::GetAttributeOrigin($sClass, $sAttCode) != $sClass) { continue; } $sClassRes .= MakeDictEntry("Class:{$sClass}/Attribute:{$sAttCode}", $oAttDef->GetLabel_Obsolete(), $sAttCode, $bNotInDico); $sClassRes .= MakeDictEntry("Class:{$sClass}/Attribute:{$sAttCode}+", $oAttDef->GetDescription_Obsolete(), '', $bNotImportant); if ($oAttDef instanceof AttributeEnum) { if (MetaModel::GetStateAttributeCode($sClass) == $sAttCode) { foreach (MetaModel::EnumStates($sClass) as $sStateCode => $aStateData) { if (array_key_exists('label', $aStateData)) { $sValue = $aStateData['label']; } else { $sValue = MetaModel::GetStateLabel($sClass, $sStateCode); } if (array_key_exists('description', $aStateData)) { $sValuePlus = $aStateData['description']; } else { $sValuePlus = MetaModel::GetStateDescription($sClass, $sStateCode); } $sClassRes .= MakeDictEntry("Class:{$sClass}/Attribute:{$sAttCode}/Value:{$sStateCode}", $sValue, '', $bNotInDico); $sClassRes .= MakeDictEntry("Class:{$sClass}/Attribute:{$sAttCode}/Value:{$sStateCode}+", $sValuePlus, '', $bNotImportant); } } else { foreach ($oAttDef->GetAllowedValues() as $sKey => $value) { $sClassRes .= MakeDictEntry("Class:{$sClass}/Attribute:{$sAttCode}/Value:{$sKey}", $value, '', $bNotInDico); $sClassRes .= MakeDictEntry("Class:{$sClass}/Attribute:{$sAttCode}/Value:{$sKey}+", $value, '', $bNotImportant); } } } } foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus) { $sClassRes .= MakeDictEntry("Class:{$sClass}/Stimulus:{$sStimulusCode}", $oStimulus->GetLabel_Obsolete(), '', $bNotInDico); $sClassRes .= MakeDictEntry("Class:{$sClass}/Stimulus:{$sStimulusCode}+", $oStimulus->GetDescription_Obsolete(), '', $bNotImportant); } $sClassRes .= "));\n"; $sClassRes .= "\n"; $sRes .= $sClassRes; } } return $sRes; }
protected function MakeSQLObjectQuery(&$oBuild, $aAttToLoad = null, $aValues = array()) { // Note: query class might be different than the class of the filter // -> this occurs when we are linking our class to an external class (referenced by, or pointing to) $sClass = $this->GetFirstJoinedClass(); $sClassAlias = $this->GetFirstJoinedClassAlias(); $bIsOnQueriedClass = array_key_exists($sClassAlias, $oBuild->GetRootFilter()->GetSelectedClasses()); self::DbgTrace("Entering: " . $this->ToOQL() . ", " . ($bIsOnQueriedClass ? "MAIN" : "SECONDARY")); $sRootClass = MetaModel::GetRootClass($sClass); $sKeyField = MetaModel::DBGetKey($sClass); if ($bIsOnQueriedClass) { // default to the whole list of attributes + the very std id/finalclass $oBuild->m_oQBExpressions->AddSelect($sClassAlias . 'id', new FieldExpression('id', $sClassAlias)); if (is_null($aAttToLoad) || !array_key_exists($sClassAlias, $aAttToLoad)) { $sSelectedClass = $oBuild->GetSelectedClass($sClassAlias); $aAttList = MetaModel::ListAttributeDefs($sSelectedClass); } else { $aAttList = $aAttToLoad[$sClassAlias]; } foreach ($aAttList as $sAttCode => $oAttDef) { if (!$oAttDef->IsScalar()) { continue; } // keep because it can be used for sorting - if (!$oAttDef->LoadInObject()) continue; foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr) { $oBuild->m_oQBExpressions->AddSelect($sClassAlias . $sAttCode . $sColId, new FieldExpression($sAttCode . $sColId, $sClassAlias)); } } // Transform the full text condition into additional condition expression $aFullText = $this->GetCriteria_FullText(); if (count($aFullText) > 0) { $aFullTextFields = array(); foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if (!$oAttDef->IsScalar()) { continue; } if ($oAttDef->IsExternalKey()) { continue; } $aFullTextFields[] = new FieldExpression($sAttCode, $sClassAlias); } $oTextFields = new CharConcatWSExpression(' ', $aFullTextFields); foreach ($aFullText as $sFTNeedle) { $oNewCond = new BinaryExpression($oTextFields, 'LIKE', new ScalarExpression("%{$sFTNeedle}%")); $oBuild->m_oQBExpressions->AddCondition($oNewCond); } } } //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n"; $aExpectedAtts = array(); // array of (attcode => fieldexpression) //echo "<p>".__LINE__.": GetUnresolvedFields($sClassAlias, ...)</p>\n"; $oBuild->m_oQBExpressions->GetUnresolvedFields($sClassAlias, $aExpectedAtts); // Compute a clear view of required joins (from the current class) // Build the list of external keys: // -> ext keys required by an explicit join // -> ext keys mentionned in a 'pointing to' condition // -> ext keys required for an external field // -> ext keys required for a friendly name // $aExtKeys = array(); // array of sTableClass => array of (sAttCode (keys) => array of (sAttCode (fields)=> oAttDef)) // // Optimization: could be partially computed once for all (cached) ? // if ($bIsOnQueriedClass) { // Get all Ext keys for the queried class (??) foreach (MetaModel::GetKeysList($sClass) as $sKeyAttCode) { $sKeyTableClass = MetaModel::GetAttributeOrigin($sClass, $sKeyAttCode); $aExtKeys[$sKeyTableClass][$sKeyAttCode] = array(); } } // Get all Ext keys used by the filter foreach ($this->GetCriteria_PointingTo() as $sKeyAttCode => $aPointingTo) { if (array_key_exists(TREE_OPERATOR_EQUALS, $aPointingTo)) { $sKeyTableClass = MetaModel::GetAttributeOrigin($sClass, $sKeyAttCode); $aExtKeys[$sKeyTableClass][$sKeyAttCode] = array(); } } $aFNJoinAlias = array(); // array of (subclass => alias) if (array_key_exists('friendlyname', $aExpectedAtts)) { // To optimize: detect a restriction on child classes in the condition expression // e.g. SELECT FunctionalCI WHERE finalclass IN ('Server', 'VirtualMachine') $oNameExpression = self::GetExtendedNameExpression($sClass); $aNameFields = array(); $oNameExpression->GetUnresolvedFields('', $aNameFields); $aTranslateNameFields = array(); foreach ($aNameFields as $sSubClass => $aFields) { foreach ($aFields as $sAttCode => $oField) { $oAttDef = MetaModel::GetAttributeDef($sSubClass, $sAttCode); if ($oAttDef->IsExternalKey()) { $sClassOfAttribute = MetaModel::GetAttributeOrigin($sSubClass, $sAttCode); $aExtKeys[$sClassOfAttribute][$sAttCode] = array(); } elseif ($oAttDef->IsExternalField() || $oAttDef instanceof AttributeFriendlyName) { $sKeyAttCode = $oAttDef->GetKeyAttCode(); $sClassOfAttribute = MetaModel::GetAttributeOrigin($sSubClass, $sKeyAttCode); $aExtKeys[$sClassOfAttribute][$sKeyAttCode][$sAttCode] = $oAttDef; } else { $sClassOfAttribute = MetaModel::GetAttributeOrigin($sSubClass, $sAttCode); } if (MetaModel::IsParentClass($sClassOfAttribute, $sClass)) { // The attribute is part of the standard query // $sAliasForAttribute = $sClassAlias; } else { // The attribute will be available from an additional outer join // For each subclass (table) one single join is enough // if (!array_key_exists($sClassOfAttribute, $aFNJoinAlias)) { $sAliasForAttribute = $oBuild->GenerateClassAlias($sClassAlias . '_fn_' . $sClassOfAttribute, $sClassOfAttribute); $aFNJoinAlias[$sClassOfAttribute] = $sAliasForAttribute; } else { $sAliasForAttribute = $aFNJoinAlias[$sClassOfAttribute]; } } $aTranslateNameFields[$sSubClass][$sAttCode] = new FieldExpression($sAttCode, $sAliasForAttribute); } } $oNameExpression = $oNameExpression->Translate($aTranslateNameFields, false); $aTranslateNow = array(); $aTranslateNow[$sClassAlias]['friendlyname'] = $oNameExpression; $oBuild->m_oQBExpressions->Translate($aTranslateNow, false); } // Add the ext fields used in the select (eventually adds an external key) foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($oAttDef->IsExternalField() || $oAttDef instanceof AttributeFriendlyName) { if (array_key_exists($sAttCode, $aExpectedAtts)) { $sKeyAttCode = $oAttDef->GetKeyAttCode(); if ($sKeyAttCode != 'id') { // Add the external attribute $sKeyTableClass = MetaModel::GetAttributeOrigin($sClass, $sKeyAttCode); $aExtKeys[$sKeyTableClass][$sKeyAttCode][$sAttCode] = $oAttDef; } } } } // First query built upon on the leaf (ie current) class // self::DbgTrace("Main (=leaf) class, call MakeSQLObjectQuerySingleTable()"); if (MetaModel::HasTable($sClass)) { $oSelectBase = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sClass, $aExtKeys, $aValues); } else { $oSelectBase = null; // As the join will not filter on the expected classes, we have to specify it explicitely $sExpectedClasses = implode("', '", MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL)); $oFinalClassRestriction = Expression::FromOQL("`{$sClassAlias}`.finalclass IN ('{$sExpectedClasses}')"); $oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction); } // Then we join the queries of the eventual parent classes (compound model) foreach (MetaModel::EnumParentClasses($sClass) as $sParentClass) { if (!MetaModel::HasTable($sParentClass)) { continue; } self::DbgTrace("Parent class: {$sParentClass}... let's call MakeSQLObjectQuerySingleTable()"); $oSelectParentTable = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sParentClass, $aExtKeys, $aValues); if (is_null($oSelectBase)) { $oSelectBase = $oSelectParentTable; } else { $oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, MetaModel::DBGetKey($sParentClass)); } } // Filter on objects referencing me foreach ($this->GetCriteria_ReferencedBy() as $sForeignClass => $aKeysAndFilters) { foreach ($aKeysAndFilters as $sForeignKeyAttCode => $oForeignFilter) { $oForeignKeyAttDef = MetaModel::GetAttributeDef($sForeignClass, $sForeignKeyAttCode); self::DbgTrace("Referenced by foreign key: {$sForeignKeyAttCode}... let's call MakeSQLObjectQuery()"); //self::DbgTrace($oForeignFilter); //self::DbgTrace($oForeignFilter->ToOQL()); //self::DbgTrace($oSelectForeign); //self::DbgTrace($oSelectForeign->RenderSelect(array())); $sForeignClassAlias = $oForeignFilter->GetFirstJoinedClassAlias(); $oBuild->m_oQBExpressions->PushJoinField(new FieldExpression($sForeignKeyAttCode, $sForeignClassAlias)); if ($oForeignKeyAttDef instanceof AttributeObjectKey) { $sClassAttCode = $oForeignKeyAttDef->Get('class_attcode'); // Add the condition: `$sForeignClassAlias`.$sClassAttCode IN (subclasses of $sClass') $oClassListExpr = ListExpression::FromScalars(MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL)); $oClassExpr = new FieldExpression($sClassAttCode, $sForeignClassAlias); $oClassRestriction = new BinaryExpression($oClassExpr, 'IN', $oClassListExpr); $oBuild->m_oQBExpressions->AddCondition($oClassRestriction); } $oSelectForeign = $oForeignFilter->MakeSQLObjectQuery($oBuild, $aAttToLoad); $oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField(); $sForeignKeyTable = $oJoinExpr->GetParent(); $sForeignKeyColumn = $oJoinExpr->GetName(); $oSelectBase->AddInnerJoin($oSelectForeign, $sKeyField, $sForeignKeyColumn, $sForeignKeyTable); } } // Additional JOINS for Friendly names // foreach ($aFNJoinAlias as $sSubClass => $sSubClassAlias) { $oSubClassFilter = new DBObjectSearch($sSubClass, $sSubClassAlias); $oSelectFN = $oSubClassFilter->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sSubClass, $aExtKeys, array()); $oSelectBase->AddLeftJoin($oSelectFN, $sKeyField, MetaModel::DBGetKey($sSubClass)); } // That's all... cross fingers and we'll get some working query //MyHelpers::var_dump_html($oSelectBase, true); //MyHelpers::var_dump_html($oSelectBase->RenderSelect(), true); if (self::$m_bDebugQuery) { $oSelectBase->DisplayHtml(); } return $oSelectBase; }
protected function DoExecute() { foreach (MetaModel::GetClasses() as $sClassName) { if (MetaModel::HasTable($sClassName)) { continue; } $oNobody = MetaModel::GetObject($sClassName, 123); $oBaby = new $sClassName(); $oFilter = new DBObjectSearch($sClassName); // Challenge reversibility of OQL / filter object // $sExpr1 = $oFilter->ToOQL(); $oNewFilter = DBObjectSearch::FromOQL($sExpr1); $sExpr2 = $oNewFilter->ToOQL(); if ($sExpr1 != $sExpr2) { $this->ReportError("Found two different OQL expression out of the (same?) filter: <em>{$sExpr1}</em> != <em>{$sExpr2}</em>"); } // Use the filter (perform the query) // $oSet = new CMDBObjectSet($oFilter); $this->ReportSuccess('Found ' . $oSet->Count() . " objects of class {$sClassName}"); } return true; }