/** * Helper to modify an enum value * The change is made in the datamodel definition, but the value has to be changed in the DB as well * Must be called BEFORE DB update, i.e within an implementation of BeforeDatabaseCreation() * This helper does change ONE value at a time * * @param string $sClass A valid class name * @param string $sAttCode The enum attribute code * @param string $sFrom Original value (already INVALID in the current datamodel) * @param string $sTo New value (valid in the current datamodel) * @return void */ public static function RenameEnumValueInDB($sClass, $sAttCode, $sFrom, $sTo) { try { $sOriginClass = MetaModel::GetAttributeOrigin($sClass, $sAttCode); $sTableName = MetaModel::DBGetTable($sOriginClass); $oAttDef = MetaModel::GetAttributeDef($sOriginClass, $sAttCode); if ($oAttDef instanceof AttributeEnum) { $oValDef = $oAttDef->GetValuesDef(); if ($oValDef) { $aNewValues = array_keys($oValDef->GetValues(array(), "")); if (in_array($sTo, $aNewValues)) { $sEnumCol = $oAttDef->Get("sql"); $aFields = CMDBSource::QueryToArray("SHOW COLUMNS FROM `{$sTableName}` WHERE Field = '{$sEnumCol}'"); if (isset($aFields[0]['Type'])) { $sColType = $aFields[0]['Type']; // Note: the parsing should rely on str_getcsv (requires PHP 5.3) to cope with escaped string if (preg_match("/^enum\\(\\'(.*)\\'\\)\$/", $sColType, $aMatches)) { $aCurrentValues = explode("','", $aMatches[1]); } } if (!in_array($sFrom, $aNewValues)) { if (!in_array($sTo, $aCurrentValues)) { $sNullSpec = $oAttDef->IsNullAllowed() ? 'NULL' : 'NOT NULL'; if (strtolower($sTo) == strtolower($sFrom)) { SetupPage::log_info("Changing enum in DB - {$sClass}::{$sAttCode} from '{$sFrom}' to '{$sTo}' (just a change in the case)"); $aTargetValues = array(); foreach ($aCurrentValues as $sValue) { if ($sValue == $sFrom) { $sValue = $sTo; } $aTargetValues[] = $sValue; } $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aTargetValues)) . ") {$sNullSpec}"; $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}"; CMDBSource::Query($sRepair); } else { // 1st - Allow both values in the column definition // SetupPage::log_info("Changing enum in DB - {$sClass}::{$sAttCode} from '{$sFrom}' to '{$sTo}'"); $aAllValues = $aCurrentValues; $aAllValues[] = $sTo; $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aAllValues)) . ") {$sNullSpec}"; $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}"; CMDBSource::Query($sRepair); // 2nd - Change the old value into the new value // $sRepair = "UPDATE `{$sTableName}` SET `{$sEnumCol}` = '{$sTo}' WHERE `{$sEnumCol}` = BINARY '{$sFrom}'"; CMDBSource::Query($sRepair); $iAffectedRows = CMDBSource::AffectedRows(); SetupPage::log_info("Changing enum in DB - {$iAffectedRows} rows updated"); // 3rd - Remove the useless value from the column definition // $aTargetValues = array(); foreach ($aCurrentValues as $sValue) { if ($sValue == $sFrom) { $sValue = $sTo; } $aTargetValues[] = $sValue; } $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aTargetValues)) . ") {$sNullSpec}"; $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}"; CMDBSource::Query($sRepair); SetupPage::log_info("Changing enum in DB - removed useless value '{$sFrom}'"); } } } else { SetupPage::log_warning("Changing enum in DB - {$sClass}::{$sAttCode} - '{$sFrom}' is still a valid value (" . implode(', ', $aNewValues) . ")"); } } else { SetupPage::log_warning("Changing enum in DB - {$sClass}::{$sAttCode} - '{$sTo}' is not a known value (" . implode(', ', $aNewValues) . ")"); } } } } catch (Exception $e) { SetupPage::log_warning("Changing enum in DB - {$sClass}::{$sAttCode} - '{$sTo}' failed. Reason " . $e->getMessage()); } }
protected function MakeSQLObjectQuerySingleTable(&$oBuild, $aAttToLoad, $sTableClass, $aExtKeys, $aValues) { // $aExtKeys is an array of sTableClass => array of (sAttCode (keys) => array of sAttCode (fields)) //echo "MakeSQLObjectQuery($sTableClass)-liste des clefs externes($sTableClass): <pre>".print_r($aExtKeys, true)."</pre><br/>\n"; // Prepare the query for a single table (compound objects) // Ignores the items (attributes/filters) that are not on the target table // Perform an (inner or left) join for every external key (and specify the expected fields) // // Returns an SQLQuery // $sTargetClass = $this->GetFirstJoinedClass(); $sTargetAlias = $this->GetFirstJoinedClassAlias(); $sTable = MetaModel::DBGetTable($sTableClass); $sTableAlias = $oBuild->GenerateTableAlias($sTargetAlias . '_' . $sTable, $sTable); $aTranslation = array(); $aExpectedAtts = array(); $oBuild->m_oQBExpressions->GetUnresolvedFields($sTargetAlias, $aExpectedAtts); $bIsOnQueriedClass = array_key_exists($sTargetAlias, $oBuild->GetRootFilter()->GetSelectedClasses()); self::DbgTrace("Entering: tableclass={$sTableClass}, filter=" . $this->ToOQL() . ", " . ($bIsOnQueriedClass ? "MAIN" : "SECONDARY")); // 1 - SELECT and UPDATE // // Note: no need for any values nor fields for foreign Classes (ie not the queried Class) // $aUpdateValues = array(); // 1/a - Get the key and friendly name // // We need one pkey to be the key, let's take the first one available $oSelectedIdField = null; $oIdField = new FieldExpressionResolved(MetaModel::DBGetKey($sTableClass), $sTableAlias); $aTranslation[$sTargetAlias]['id'] = $oIdField; if ($bIsOnQueriedClass) { // Add this field to the list of queried fields (required for the COUNT to work fine) $oSelectedIdField = $oIdField; } // 1/b - Get the other attributes // foreach (MetaModel::ListAttributeDefs($sTableClass) as $sAttCode => $oAttDef) { // Skip this attribute if not defined in this table if (MetaModel::GetAttributeOrigin($sTargetClass, $sAttCode) != $sTableClass) { continue; } // Skip this attribute if not made of SQL columns if (count($oAttDef->GetSQLExpressions()) == 0) { continue; } // Update... // if ($bIsOnQueriedClass && array_key_exists($sAttCode, $aValues)) { assert($oAttDef->IsDirectField()); foreach ($oAttDef->GetSQLValues($aValues[$sAttCode]) as $sColumn => $sValue) { $aUpdateValues[$sColumn] = $sValue; } } } // 2 - The SQL query, for this table only // $oSelectBase = new SQLObjectQuery($sTable, $sTableAlias, array(), $bIsOnQueriedClass, $aUpdateValues, $oSelectedIdField); // 3 - Resolve expected expressions (translation table: alias.attcode => table.column) // foreach (MetaModel::ListAttributeDefs($sTableClass) as $sAttCode => $oAttDef) { // Skip this attribute if not defined in this table if (MetaModel::GetAttributeOrigin($sTargetClass, $sAttCode) != $sTableClass) { continue; } // Select... // if ($oAttDef->IsExternalField()) { // skip, this will be handled in the joined tables (done hereabove) } else { //echo "<p>MakeSQLObjectQuerySingleTable: Field $sAttCode is part of the table $sTable (named: $sTableAlias)</p>"; // standard field, or external key // add it to the output foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr) { if (array_key_exists($sAttCode . $sColId, $aExpectedAtts)) { $oFieldSQLExp = new FieldExpressionResolved($sSQLExpr, $sTableAlias); foreach (MetaModel::EnumPlugins('iQueryModifier') as $sPluginClass => $oQueryModifier) { $oFieldSQLExp = $oQueryModifier->GetFieldExpression($oBuild, $sTargetClass, $sAttCode, $sColId, $oFieldSQLExp, $oSelectBase); } $aTranslation[$sTargetAlias][$sAttCode . $sColId] = $oFieldSQLExp; } } } } //echo "MakeSQLObjectQuery- Classe $sTableClass<br/>\n"; // 4 - The external keys -> joins... // $aAllPointingTo = $this->GetCriteria_PointingTo(); if (array_key_exists($sTableClass, $aExtKeys)) { foreach ($aExtKeys[$sTableClass] as $sKeyAttCode => $aExtFields) { $oKeyAttDef = MetaModel::GetAttributeDef($sTableClass, $sKeyAttCode); $aPointingTo = $this->GetCriteria_PointingTo($sKeyAttCode); //echo "MakeSQLObjectQuery-Cle '$sKeyAttCode'<br/>\n"; if (!array_key_exists(TREE_OPERATOR_EQUALS, $aPointingTo)) { //echo "MakeSQLObjectQuery-Ajoutons l'operateur TREE_OPERATOR_EQUALS pour $sKeyAttCode<br/>\n"; // The join was not explicitely defined in the filter, // we need to do it now $sKeyClass = $oKeyAttDef->GetTargetClass(); $sKeyClassAlias = $oBuild->GenerateClassAlias($sKeyClass . '_' . $sKeyAttCode, $sKeyClass); $oExtFilter = new DBObjectSearch($sKeyClass, $sKeyClassAlias); $aAllPointingTo[$sKeyAttCode][TREE_OPERATOR_EQUALS][$sKeyClassAlias] = $oExtFilter; } } } //echo "MakeSQLObjectQuery-liste des clefs de jointure: <pre>".print_r(array_keys($aAllPointingTo), true)."</pre><br/>\n"; foreach ($aAllPointingTo as $sKeyAttCode => $aPointingTo) { foreach ($aPointingTo as $iOperatorCode => $aFilter) { foreach ($aFilter as $oExtFilter) { if (!MetaModel::IsValidAttCode($sTableClass, $sKeyAttCode)) { continue; } // Not defined in the class, skip it // The aliases should not conflict because normalization occured while building the filter $oKeyAttDef = MetaModel::GetAttributeDef($sTableClass, $sKeyAttCode); $sKeyClass = $oExtFilter->GetFirstJoinedClass(); $sKeyClassAlias = $oExtFilter->GetFirstJoinedClassAlias(); //echo "MakeSQLObjectQuery-$sTableClass::$sKeyAttCode Foreach PointingTo($iOperatorCode) <span style=\"color:red\">$sKeyClass (alias:$sKeyClassAlias)</span><br/>\n"; // Note: there is no search condition in $oExtFilter, because normalization did merge the condition onto the top of the filter tree //echo "MakeSQLObjectQuery-array_key_exists($sTableClass, \$aExtKeys)<br/>\n"; if ($iOperatorCode == TREE_OPERATOR_EQUALS) { if (array_key_exists($sTableClass, $aExtKeys) && array_key_exists($sKeyAttCode, $aExtKeys[$sTableClass])) { // Specify expected attributes for the target class query // ... and use the current alias ! $aTranslateNow = array(); // Translation for external fields - must be performed before the join is done (recursion...) foreach ($aExtKeys[$sTableClass][$sKeyAttCode] as $sAttCode => $oAtt) { //echo "MakeSQLObjectQuery aExtKeys[$sTableClass][$sKeyAttCode] => $sAttCode-oAtt: <pre>".print_r($oAtt, true)."</pre><br/>\n"; if ($oAtt instanceof AttributeFriendlyName) { // Note: for a given ext key, there is one single attribute "friendly name" $aTranslateNow[$sTargetAlias][$sAttCode] = new FieldExpression('friendlyname', $sKeyClassAlias); //echo "<p><b>aTranslateNow[$sTargetAlias][$sAttCode] = new FieldExpression('friendlyname', $sKeyClassAlias);</b></p>\n"; } else { $sExtAttCode = $oAtt->GetExtAttCode(); // Translate mainclass.extfield => remoteclassalias.remotefieldcode $oRemoteAttDef = MetaModel::GetAttributeDef($sKeyClass, $sExtAttCode); foreach ($oRemoteAttDef->GetSQLExpressions() as $sColId => $sRemoteAttExpr) { $aTranslateNow[$sTargetAlias][$sAttCode . $sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias); //echo "<p><b>aTranslateNow[$sTargetAlias][$sAttCode.$sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias);</b></p>\n"; } //echo "<p><b>ExtAttr2: $sTargetAlias.$sAttCode to $sKeyClassAlias.$sRemoteAttExpr (class: $sKeyClass)</b></p>\n"; } } if ($oKeyAttDef instanceof AttributeObjectKey) { // Add the condition: `$sTargetAlias`.$sClassAttCode IN (subclasses of $sKeyClass') $sClassAttCode = $oKeyAttDef->Get('class_attcode'); $oClassAttDef = MetaModel::GetAttributeDef($sTargetClass, $sClassAttCode); foreach ($oClassAttDef->GetSQLExpressions() as $sColId => $sSQLExpr) { $aTranslateNow[$sTargetAlias][$sClassAttCode . $sColId] = new FieldExpressionResolved($sSQLExpr, $sTableAlias); } $oClassListExpr = ListExpression::FromScalars(MetaModel::EnumChildClasses($sKeyClass, ENUM_CHILD_CLASSES_ALL)); $oClassExpr = new FieldExpression($sClassAttCode, $sTargetAlias); $oClassRestriction = new BinaryExpression($oClassExpr, 'IN', $oClassListExpr); $oBuild->m_oQBExpressions->AddCondition($oClassRestriction); } // Translate prior to recursing // //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."\n".print_r($aTranslateNow, true)."</pre></p>\n"; $oBuild->m_oQBExpressions->Translate($aTranslateNow, false); //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n"; //echo "<p>External key $sKeyAttCode (class: $sKeyClass), call MakeSQLObjectQuery()/p>\n"; self::DbgTrace("External key {$sKeyAttCode} (class: {$sKeyClass}), call MakeSQLObjectQuery()"); $oBuild->m_oQBExpressions->PushJoinField(new FieldExpression('id', $sKeyClassAlias)); //echo "<p>Recursive MakeSQLObjectQuery ".__LINE__.": <pre>\n".print_r($oBuild->GetRootFilter()->GetSelectedClasses(), true)."</pre></p>\n"; $oSelectExtKey = $oExtFilter->MakeSQLObjectQuery($oBuild, $aAttToLoad); $oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField(); $sExternalKeyTable = $oJoinExpr->GetParent(); $sExternalKeyField = $oJoinExpr->GetName(); $aCols = $oKeyAttDef->GetSQLExpressions(); // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc()) $sLocalKeyField = current($aCols); // get the first column for an external key self::DbgTrace("External key {$sKeyAttCode}, Join on {$sLocalKeyField} = {$sExternalKeyField}"); if ($oKeyAttDef->IsNullAllowed()) { $oSelectBase->AddLeftJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable); } else { $oSelectBase->AddInnerJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable); } } } elseif (MetaModel::GetAttributeOrigin($sKeyClass, $sKeyAttCode) == $sTableClass) { $oBuild->m_oQBExpressions->PushJoinField(new FieldExpression($sKeyAttCode, $sKeyClassAlias)); $oSelectExtKey = $oExtFilter->MakeSQLObjectQuery($oBuild, $aAttToLoad); $oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField(); $sExternalKeyTable = $oJoinExpr->GetParent(); $sExternalKeyField = $oJoinExpr->GetName(); $sLeftIndex = $sExternalKeyField . '_left'; // TODO use GetSQLLeft() $sRightIndex = $sExternalKeyField . '_right'; // TODO use GetSQLRight() $LocalKeyLeft = $oKeyAttDef->GetSQLLeft(); $LocalKeyRight = $oKeyAttDef->GetSQLRight(); $oSelectBase->AddInnerJoinTree($oSelectExtKey, $LocalKeyLeft, $LocalKeyRight, $sLeftIndex, $sRightIndex, $sExternalKeyTable, $iOperatorCode); } } } } // Translate the selected columns // //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n"; $oBuild->m_oQBExpressions->Translate($aTranslation, false); //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n"; //MyHelpers::var_dump_html($oSelectBase->RenderSelect()); return $oSelectBase; }
/** * Display the details of a given class of objects */ function DisplayClassDetails($oPage, $sClass, $sContext) { $oPage->add("<h2>" . MetaModel::GetName($sClass) . " ({$sClass}) - " . MetaModel::GetClassDescription($sClass) . "</h2>\n"); if (MetaModel::IsAbstract($sClass)) { $oPage->p(Dict::S('UI:Schema:AbstractClass')); } else { $oPage->p(Dict::S('UI:Schema:NonAbstractClass')); } // $oPage->p("<h3>".Dict::S('UI:Schema:ClassHierarchyTitle')."</h3>"); $aParentClasses = array(); foreach (MetaModel::EnumParentClasses($sClass) as $sParentClass) { $aParentClasses[] = MakeClassHLink($sParentClass, $sContext); } if (count($aParentClasses) > 0) { $sParents = implode(' >> ', $aParentClasses) . " >> <b>{$sClass}</b>"; } else { $sParents = ''; } $oPage->p("[<a href=\"schema.php?operation=list{$sContext}\">" . Dict::S('UI:Schema:AllClasses') . "</a>] {$sParents}"); if (MetaModel::HasChildrenClasses($sClass)) { $oPage->add("<ul id=\"ClassHierarchy\">"); $oPage->add("<li class=\"closed\">" . $sClass . "\n"); DisplaySubclasses($oPage, $sClass, $sContext); $oPage->add("</li>\n"); $oPage->add("</ul>\n"); $oPage->add_ready_script('$("#ClassHierarchy").treeview();'); } $oPage->p(''); $oPage->AddTabContainer('details'); $oPage->SetCurrentTabContainer('details'); // List the attributes of the object $aForwardChangeTracking = MetaModel::GetTrackForwardExternalKeys($sClass); $aDetails = array(); foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($oAttDef->IsExternalKey()) { $sValue = Dict::Format('UI:Schema:ExternalKey_To', MakeClassHLink($oAttDef->GetTargetClass(), $sContext)); if (array_key_exists($sAttCode, $aForwardChangeTracking)) { $oLinkSet = $aForwardChangeTracking[$sAttCode]; $sRemoteClass = $oLinkSet->GetHostClass(); $sValue = $sValue . "<span title=\"Forward changes to {$sRemoteClass}\">*</span>"; } } elseif ($oAttDef->IsLinkSet()) { $sValue = MakeClassHLink($oAttDef->GetLinkedClass(), $sContext); } else { $sValue = $oAttDef->GetDescription(); } $sType = $oAttDef->GetType() . ' (' . $oAttDef->GetTypeDesc() . ')'; $sOrigin = MetaModel::GetAttributeOrigin($sClass, $sAttCode); $sAllowedValues = ""; $sMoreInfo = ""; $aCols = array(); foreach ($oAttDef->GetSQLColumns() as $sCol => $sFieldDesc) { $aCols[] = "{$sCol}: {$sFieldDesc}"; } if (count($aCols) > 0) { $sCols = implode(', ', $aCols); $aMoreInfo = array(); $aMoreInfo[] = Dict::Format('UI:Schema:Columns_Description', $sCols); $aMoreInfo[] = Dict::Format('UI:Schema:Default_Description', $oAttDef->GetDefaultValue()); $aMoreInfo[] = $oAttDef->IsNullAllowed() ? Dict::S('UI:Schema:NullAllowed') : Dict::S('UI:Schema:NullNotAllowed'); $sMoreInfo .= implode(', ', $aMoreInfo); } if ($oAttDef instanceof AttributeEnum) { // Display localized values for the enum (which depend on the localization provided by the class) $aLocalizedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, array()); $aDescription = array(); foreach ($aLocalizedValues as $val => $sDisplay) { $aDescription[] = htmlentities("{$val} => ", ENT_QUOTES, 'UTF-8') . $sDisplay; } $sAllowedValues = implode(', ', $aDescription); } else { $sAllowedValues = ''; } $aDetails[] = array('code' => $oAttDef->GetCode(), 'type' => $sType, 'origin' => $sOrigin, 'label' => $oAttDef->GetLabel(), 'description' => $sValue, 'values' => $sAllowedValues, 'moreinfo' => $sMoreInfo); } $oPage->SetCurrentTab(Dict::S('UI:Schema:Attributes')); $aConfig = array('code' => array('label' => Dict::S('UI:Schema:AttributeCode'), 'description' => Dict::S('UI:Schema:AttributeCode+')), 'label' => array('label' => Dict::S('UI:Schema:Label'), 'description' => Dict::S('UI:Schema:Label+')), 'type' => array('label' => Dict::S('UI:Schema:Type'), 'description' => Dict::S('UI:Schema:Type+')), 'origin' => array('label' => Dict::S('UI:Schema:Origin'), 'description' => Dict::S('UI:Schema:Origin+')), 'description' => array('label' => Dict::S('UI:Schema:Description'), 'description' => Dict::S('UI:Schema:Description+')), 'values' => array('label' => Dict::S('UI:Schema:AllowedValues'), 'description' => Dict::S('UI:Schema:AllowedValues+')), 'moreinfo' => array('label' => Dict::S('UI:Schema:MoreInfo'), 'description' => Dict::S('UI:Schema:MoreInfo+'))); $oPage->table($aConfig, $aDetails); // List the search criteria for this object $aDetails = array(); foreach (MetaModel::GetClassFilterDefs($sClass) as $sFilterCode => $oFilterDef) { $aOpDescs = array(); foreach ($oFilterDef->GetOperators() as $sOpCode => $sOpDescription) { $sIsTheLooser = $sOpCode == $oFilterDef->GetLooseOperator() ? " (loose search)" : ""; $aOpDescs[] = "{$sOpCode} ({$sOpDescription}){$sIsTheLooser}"; } $aDetails[] = array('code' => $sFilterCode, 'description' => $oFilterDef->GetLabel(), 'operators' => implode(" / ", $aOpDescs)); } $oPage->SetCurrentTab(Dict::S('UI:Schema:SearchCriteria')); $aConfig = array('code' => array('label' => Dict::S('UI:Schema:FilterCode'), 'description' => Dict::S('UI:Schema:FilterCode+')), 'description' => array('label' => Dict::S('UI:Schema:FilterDescription'), 'description' => Dict::S('UI:Schema:FilterDescription+')), 'operators' => array('label' => Dict::S('UI:Schema:AvailOperators'), 'description' => Dict::S('UI:Schema:AvailOperators+'))); $oPage->table($aConfig, $aDetails); $oPage->SetCurrentTab(Dict::S('UI:Schema:ChildClasses')); DisplaySubclasses($oPage, $sClass, $sContext); $oPage->SetCurrentTab(Dict::S('UI:Schema:ReferencingClasses')); DisplayReferencingClasses($oPage, $sClass, $sContext); $oPage->SetCurrentTab(Dict::S('UI:Schema:RelatedClasses')); DisplayRelatedClasses($oPage, $sClass, $sContext); $oPage->SetCurrentTab(Dict::S('UI:Schema:LifeCycle')); DisplayLifecycle($oPage, $sClass, $sContext); $oPage->SetCurrentTab(Dict::S('UI:Schema:Triggers')); DisplayTriggers($oPage, $sClass, $sContext); $oPage->SetCurrentTab(); $oPage->SetCurrentTabContainer(); }
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; }
/** * Helper to modify an enum value * The change is made in the datamodel definition, but the value has to be changed in the DB as well * Must be called BEFORE DB update, i.e within an implementation of BeforeDatabaseCreation() * * @param string $sClass A valid class name * @param string $sAttCode The enum attribute code * @param string $sFrom Original value (already INVALID in the current datamodel) * @param string $sTo New value (valid in the current datamodel) * @return void */ public static function RenameEnumValueInDB($sClass, $sAttCode, $sFrom, $sTo) { $sOriginClass = MetaModel::GetAttributeOrigin($sClass, $sAttCode); $sTableName = MetaModel::DBGetTable($sOriginClass); $oAttDef = MetaModel::GetAttributeDef($sOriginClass, $sAttCode); if ($oAttDef instanceof AttributeEnum) { $oValDef = $oAttDef->GetValuesDef(); if ($oValDef) { $aNewValues = array_keys($oValDef->GetValues(array(), "")); if (in_array($sTo, $aNewValues)) { $aAllValues = $aNewValues; $aAllValues[] = $sFrom; if (!in_array($sFrom, $aNewValues)) { $sEnumCol = $oAttDef->Get("sql"); $sNullSpec = $oAttDef->IsNullAllowed() ? 'NULL' : 'NOT NULL'; if (strtolower($sTo) == strtolower($sFrom)) { SetupPage::log_info("Changing enum in DB - {$sClass}::{$sAttCode} from '{$sFrom}' to '{$sTo}' (just a change in the case)"); $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aNewValues)) . ") {$sNullSpec}"; $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}"; CMDBSource::Query($sRepair); } else { // 1st - Allow both values in the column definition // SetupPage::log_info("Changing enum in DB - {$sClass}::{$sAttCode} from '{$sFrom}' to '{$sTo}'"); $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aAllValues)) . ") {$sNullSpec}"; $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}"; CMDBSource::Query($sRepair); // 2nd - Change the old value into the new value // $sRepair = "UPDATE `{$sTableName}` SET `{$sEnumCol}` = '{$sTo}' WHERE `{$sEnumCol}` = BINARY '{$sFrom}'"; CMDBSource::Query($sRepair); $iAffectedRows = CMDBSource::AffectedRows(); SetupPage::log_info("Changing enum in DB - {$iAffectedRows} rows updated"); // 3rd - Remove the useless value from the column definition // $sColumnDefinition = "ENUM(" . implode(",", CMDBSource::Quote($aNewValues)) . ") {$sNullSpec}"; $sRepair = "ALTER TABLE `{$sTableName}` MODIFY `{$sEnumCol}` {$sColumnDefinition}"; CMDBSource::Query($sRepair); SetupPage::log_info("Changing enum in DB - removed useless value '{$sFrom}'"); } } else { SetupPage::log_warning("Changing enum in DB - {$sClass}::{$sAttCode} - '{$sFrom}' is still a valid value (" . implode(', ', $aNewValues) . ")"); } } else { SetupPage::log_warning("Changing enum in DB - {$sClass}::{$sAttCode} - '{$sTo}' is not a known value (" . implode(', ', $aNewValues) . ")"); } } } }
/** * Returns the meta value for the given object. * See also MetaModel::RebuildMetaEnums() that must be maintained when MapValue changes * * @param $oObject * @return mixed * @throws Exception */ public function MapValue($oObject) { $aMappingData = $this->GetMapRule(get_class($oObject)); if ($aMappingData == null) { $sRet = $this->GetDefaultValue(); } else { $sAttCode = $aMappingData['attcode']; $value = $oObject->Get($sAttCode); if (array_key_exists($value, $aMappingData['values'])) { $sRet = $aMappingData['values'][$value]; } elseif ($this->GetDefaultValue() != '') { $sRet = $this->GetDefaultValue(); } else { throw new Exception('AttributeMetaEnum::MapValue(): mapping not found for value "' . $value . '" in ' . get_class($oObject) . ', on attribute ' . MetaModel::GetAttributeOrigin($this->GetHostClass(), $this->GetCode()) . '::' . $this->GetCode()); } } return $sRet; }