/** * Helper to make an output value for a given attribute * * @param DBObject $oObject The object being reported * @param string $sAttCode The attribute code (must be valid) * @param boolean $bExtendedOutput Output all of the link set attributes ? * @return string A scalar representation of the value */ protected function MakeResultValue(DBObject $oObject, $sAttCode, $bExtendedOutput = false) { if ($sAttCode == 'id') { $value = $oObject->GetKey(); } else { $sClass = get_class($oObject); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ($oAttDef instanceof AttributeLinkedSet) { // Iterate on the set and build an array of array of attcode=>value $oSet = $oObject->Get($sAttCode); $value = array(); while ($oLnk = $oSet->Fetch()) { $sLnkRefClass = $bExtendedOutput ? get_class($oLnk) : $oAttDef->GetLinkedClass(); $aLnkValues = array(); foreach (MetaModel::ListAttributeDefs($sLnkRefClass) as $sLnkAttCode => $oLnkAttDef) { // Skip attributes pointing to the current object (redundant data) if ($sLnkAttCode == $oAttDef->GetExtKeyToMe()) { continue; } // Skip any attribute of the link that points to the current object $oLnkAttDef = MetaModel::GetAttributeDef($sLnkRefClass, $sLnkAttCode); if (method_exists($oLnkAttDef, 'GetKeyAttCode')) { if ($oLnkAttDef->GetKeyAttCode() == $oAttDef->GetExtKeyToMe()) { continue; } } $aLnkValues[$sLnkAttCode] = $this->MakeResultValue($oLnk, $sLnkAttCode, $bExtendedOutput); } $value[] = $aLnkValues; } } else { $value = $oAttDef->GetForJSON($oObject->Get($sAttCode)); } } return $value; }
/** * Computes a text-like fingerprint identifying the content of the object * but excluding the specified columns * @param $aExcludedColumns array The list of columns to exclude * @return string */ public function Fingerprint($aExcludedColumns = array()) { $sFingerprint = ''; foreach (MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode => $oAttDef) { if (!in_array($sAttCode, $aExcludedColumns)) { if ($oAttDef->IsPartOfFingerprint()) { $sFingerprint .= chr(0) . $oAttDef->Fingerprint($this->Get($sAttCode)); } } } return $sFingerprint; }
/** * Find redundancy settings that can be viewed and modified in a tab * Settings are distributed to the corresponding link set attribute so as to be shown in the relevant tab */ protected function FindVisibleRedundancySettings() { $aRet = array(); foreach (MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode => $oAttDef) { if ($oAttDef instanceof AttributeRedundancySettings) { if ($oAttDef->IsVisible()) { $aQueryInfo = $oAttDef->GetRelationQueryData(); if (isset($aQueryInfo['sAttribute'])) { $oUpperAttDef = MetaModel::GetAttributeDef($aQueryInfo['sFromClass'], $aQueryInfo['sAttribute']); $oHostAttDef = $oUpperAttDef->GetMirrorLinkAttribute(); if ($oHostAttDef) { $sHostAttCode = $oHostAttDef->GetCode(); $aRet[$sHostAttCode][] = $oAttDef; } } } } } return $aRet; }
public function ListAttributes($sClass, $sScope = null) { $aScope = null; if ($sScope != null) { $aScope = array(); foreach (explode(',', $sScope) as $sScopeClass) { $aScope[] = trim($sScopeClass); } } $aAttributes = array(); foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { $sAttributeClass = get_class($oAttDef); if ($aScope != null) { foreach ($aScope as $sScopeClass) { if ($sAttributeClass == $sScopeClass || is_subclass_of($sAttributeClass, $sScopeClass)) { $aAttributes[$sAttCode] = $sAttributeClass; break; } } } else { $aAttributes[$sAttCode] = $sAttributeClass; } } return $aAttributes; }
/** * @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending */ public function ToDataArray($aColumns = array(), $aOrderBy = array(), $aArgs = array()) { $sSQL = $this->MakeSelectQuery($aOrderBy, $aArgs); $resQuery = CMDBSource::Query($sSQL); if (!$resQuery) { return; } if (count($aColumns) == 0) { $aColumns = array_keys(MetaModel::ListAttributeDefs($this->GetClass())); // Add the standard id (as first column) array_unshift($aColumns, 'id'); } $aQueryCols = CMDBSource::GetColumns($resQuery); $sClassAlias = $this->GetClassAlias(); $aColMap = array(); foreach ($aColumns as $sAttCode) { $sColName = $sClassAlias . $sAttCode; if (in_array($sColName, $aQueryCols)) { $aColMap[$sAttCode] = $sColName; } } $aRes = array(); while ($aRow = CMDBSource::FetchArray($resQuery)) { $aMappedRow = array(); foreach ($aColMap as $sAttCode => $sColName) { $aMappedRow[$sAttCode] = $aRow[$sColName]; } $aRes[] = $aMappedRow; } CMDBSource::FreeResult($resQuery); return $aRes; }
/** * Compute the order of the fields & pages in the wizard * @param $oPage iTopWebPage The current page (used to display error messages) * @param $sClass string Name of the class * @param $sStateCode string Code of the target state of the object * @return hash Two dimensional array: each element represents the list of fields for a given page */ protected function ComputeWizardStructure() { $aWizardSteps = array('mandatory' => array(), 'optional' => array()); $aFieldsDone = array(); // Store all the fields that are already covered by a previous step of the wizard $aStates = MetaModel::EnumStates($this->m_sClass); $sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass); $aMandatoryAttributes = array(); // Some attributes are always mandatory independently of the state machine (if any) foreach (MetaModel::GetAttributesList($this->m_sClass) as $sAttCode) { $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() && $oAttDef->IsWritable() && $sAttCode != $sStateAttCode) { $aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY; } } // Now check the attributes that are mandatory in the specified state if (!empty($this->m_sTargetState) && count($aStates[$this->m_sTargetState]['attribute_list']) > 0) { // Check all the fields that *must* be included in the wizard for this // particular target state $aFields = array(); foreach ($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions) { if (isset($aMandatoryAttributes[$sAttCode]) && $aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) { $aMandatoryAttributes[$sAttCode] |= $iOptions; } else { $aMandatoryAttributes[$sAttCode] = $iOptions; } } } // Check all the fields that *must* be included in the wizard // i.e. all mandatory, must-change or must-prompt fields that are // not also read-only or hidden. // Some fields may be required (null not allowed) from the database // perspective, but hidden or read-only from the user interface perspective $aFields = array(); foreach ($aMandatoryAttributes as $sAttCode => $iOptions) { if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT) && !($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN))) { $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $aPrerequisites = $oAttDef->GetPrerequisiteAttributes(); $aFields[$sAttCode] = array(); foreach ($aPrerequisites as $sCode) { $aFields[$sAttCode][$sCode] = ''; } } } // Now use the dependencies between the fields to order them // Start from the order of the 'details' $aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details')); $index = 0; $aOrder = array(); foreach ($aFields as $sAttCode => $void) { $aOrder[$sAttCode] = 999; // At the end of the list... } foreach ($aList as $sAttCode) { if (array_key_exists($sAttCode, $aFields)) { $aOrder[$sAttCode] = $index; } $index++; } foreach ($aFields as $sAttCode => $aDependencies) { // All fields with no remaining dependencies can be entered at this // step of the wizard if (count($aDependencies) > 0) { $iMaxPos = 0; // Remove this field from the dependencies of the other fields foreach ($aDependencies as $sDependentAttCode => $void) { // position the current field after the ones it depends on $iMaxPos = max($iMaxPos, 1 + $aOrder[$sDependentAttCode]); } } } asort($aOrder); $aCurrentStep = array(); foreach ($aOrder as $sAttCode => $rank) { $aCurrentStep[] = $sAttCode; $aFieldsDone[$sAttCode] = ''; } $aWizardSteps['mandatory'][] = $aCurrentStep; // Now computes the steps to fill the optional fields $aFields = array(); // reset foreach (MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode => $oAttDef) { $iOptions = isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0; if ($sStateAttCode != $sAttCode && !$oAttDef->IsExternalField() && ($iOptions & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) == 0 && !isset($aFieldsDone[$sAttCode])) { // 'State', external fields, read-only and hidden fields // and fields that are already listed in the wizard // are removed from the 'optional' part of the wizard $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $aPrerequisites = $oAttDef->GetPrerequisiteAttributes(); $aFields[$sAttCode] = array(); foreach ($aPrerequisites as $sCode) { if (!isset($aFieldsDone[$sCode])) { // retain only the dependencies that were not covered // in the 'mandatory' part of the wizard $aFields[$sAttCode][$sCode] = ''; } } } } // Now use the dependencies between the fields to order them while (count($aFields) > 0) { $aCurrentStep = array(); foreach ($aFields as $sAttCode => $aDependencies) { // All fields with no remaining dependencies can be entered at this // step of the wizard if (count($aDependencies) == 0) { $aCurrentStep[] = $sAttCode; $aFieldsDone[$sAttCode] = ''; unset($aFields[$sAttCode]); // Remove this field from the dependencies of the other fields foreach ($aFields as $sUpdatedCode => $aDummy) { // remove the dependency unset($aFields[$sUpdatedCode][$sAttCode]); } } } if (count($aCurrentStep) == 0) { // This step of the wizard would contain NO field ! $this->m_oPage->add(Dict::S('UI:Error:WizardCircularReferenceInDependencies')); print_r($aFields); break; } $aWizardSteps['optional'][] = $aCurrentStep; } return $aWizardSteps; }
public function GetReconciliationFormElement($sTargetClass, $sFieldName) { $sHtml = "<select name=\"{$sFieldName}\">\n"; $sSelected = '' == $this->Get('reconciliation_attcode') ? ' selected' : ''; $sHtml .= "<option value=\"\" {$sSelected}>" . Dict::S('Core:SynchroAttExtKey:ReconciliationById') . "</option>\n"; foreach (MetaModel::ListAttributeDefs($sTargetClass) as $sAttCode => $oAttDef) { if ($oAttDef->IsScalar()) { $sSelected = $sAttCode == $this->Get('reconciliation_attcode') ? ' selected' : ''; $sHtml .= "<option value=\"{$sAttCode}\" {$sSelected}>" . MetaModel::GetLabel($sTargetClass, $sAttCode) . "</option>\n"; } } $sHtml .= "</select>\n"; return $sHtml; }
protected function GetObjectActionGrant($oUser, $sClass, $iActionCode, $oObject = null) { if (is_null($oObject)) { $iObjectRef = -999; } else { $iObjectRef = $oObject->GetKey(); } // load and cache permissions for the current user on the given object // $aTest = @$this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iObjectRef][$iActionCode]; if (is_array($aTest)) { return $aTest; } $sAction = self::$m_aActionCodes[$iActionCode]; $iInstancePermission = UR_ALLOWED_NO; $aAttributes = array(); foreach ($this->GetMatchingProfiles($oUser, $sClass, $oObject) as $iProfile) { $oGrantRecord = $this->GetClassActionGrant($iProfile, $sClass, $sAction); if (is_null($oGrantRecord)) { continue; // loop to the next profile } else { $iInstancePermission = UR_ALLOWED_YES; // update the list of attributes with those allowed for this profile // $oSearch = DBObjectSearch::FromOQL_AllData("SELECT URP_AttributeGrant WHERE actiongrantid = :actiongrantid"); $oSet = new DBObjectSet($oSearch, array(), array('actiongrantid' => $oGrantRecord->GetKey())); $aProfileAttributes = $oSet->GetColumnAsArray('attcode', false); if (count($aProfileAttributes) == 0) { $aAllAttributes = array_keys(MetaModel::ListAttributeDefs($sClass)); $aAttributes = array_merge($aAttributes, $aAllAttributes); } else { $aAttributes = array_merge($aAttributes, $aProfileAttributes); } } } $aRes = array('permission' => $iInstancePermission, 'attributes' => $aAttributes); $this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iObjectRef][$iActionCode] = $aRes; return $aRes; }
/** * 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 */ public static final function GetTrackForwardExternalKeys($sClass) { if (!isset(self::$m_aTrackForwardCache[$sClass])) { $aRes = array(); foreach (MetaModel::GetExternalKeys($sClass) as $sAttCode => $oAttDef) { $sRemoteClass = $oAttDef->GetTargetClass(); 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; } $aRes[$sAttCode] = $oRemoteAttDef; } } self::$m_aTrackForwardCache[$sClass] = $aRes; } return self::$m_aTrackForwardCache[$sClass]; }
protected function FindRecipients($sRecipAttCode, $aArgs) { $sOQL = $this->Get($sRecipAttCode); if (strlen($sOQL) == '') { return ''; } try { $oSearch = DBObjectSearch::FromOQL($sOQL); $oSearch->AllowAllData(); } catch (OQLException $e) { $this->m_aMailErrors[] = "query syntax error for recipient '{$sRecipAttCode}'"; return $e->getMessage(); } $sClass = $oSearch->GetClass(); // Determine the email attribute (the first one will be our choice) foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($oAttDef instanceof AttributeEmailAddress) { $sEmailAttCode = $sAttCode; // we've got one, exit the loop break; } } if (!isset($sEmailAttCode)) { $this->m_aMailErrors[] = "wrong target for recipient '{$sRecipAttCode}'"; return "The objects of the class '{$sClass}' do not have any email attribute"; } $oSet = new DBObjectSet($oSearch, array(), $aArgs); $aRecipients = array(); while ($oObj = $oSet->Fetch()) { $sAddress = trim($oObj->Get($sEmailAttCode)); if (strlen($sAddress) > 0) { $aRecipients[] = $sAddress; $this->m_iRecipients++; } } return implode(', ', $aRecipients); }
/** * 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(); }
/** * Maps an external key to its (newly created) value */ protected function ResolveExternalKeys() { foreach ($this->m_aObjectsCache as $sClass => $oObjList) { foreach ($oObjList as $oTargetObj) { $bChanged = false; $sClass = get_class($oTargetObj); foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($oAttDef->IsExternalKey() && $oTargetObj->Get($sAttCode) < 0) { $sTargetClass = $oAttDef->GetTargetClass(); $iTempKey = $oTargetObj->Get($sAttCode); $iExtKey = $this->GetObjectKey($sTargetClass, -$iTempKey); if ($iExtKey == 0) { $sMsg = "unresolved extkey in {$sClass}::" . $oTargetObj->GetKey() . "(" . $oTargetObj->GetName() . ")::{$sAttCode}={$sTargetClass}::{$iTempKey}"; SetupPage::log_warning($sMsg); $this->m_aWarnings[] = $sMsg; //echo "<pre>aKeys[".$sTargetClass."]:\n"; //print_r($this->m_aKeys[$sTargetClass]); //echo "</pre>\n"; } else { $bChanged = true; $oTargetObj->Set($sAttCode, $iExtKey); } } } if ($bChanged) { try { if (is_subclass_of($oTargetObj, 'CMDBObject')) { $oTargetObj->DBUpdateTracked($this->m_oChange); } else { $oTargetObj->DBUpdate(); } } catch (Exception $e) { $this->m_aErrors[] = "The object changes could not be tracked - {$sClass}/{$iExtKey} - " . $e->getMessage(); } } } } return true; }
/** * The email recipient is the person who is allowed to regain control when the password gets lost * Throws an exception if the feature cannot be available */ public function GetResetPasswordEmail() { if (!MetaModel::IsValidAttCode(get_class($this), 'contactid')) { throw new Exception(Dict::S('UI:ResetPwd-Error-NoContact')); } $iContactId = $this->Get('contactid'); if ($iContactId == 0) { throw new Exception(Dict::S('UI:ResetPwd-Error-NoContact')); } $oContact = MetaModel::GetObject('Contact', $iContactId); // Determine the email attribute (the first one will be our choice) foreach (MetaModel::ListAttributeDefs(get_class($oContact)) as $sAttCode => $oAttDef) { if ($oAttDef instanceof AttributeEmailAddress) { $sEmailAttCode = $sAttCode; // we've got one, exit the loop break; } } if (!isset($sEmailAttCode)) { throw new Exception(Dict::S('UI:ResetPwd-Error-NoEmailAtt')); } $sRes = trim($oContact->Get($sEmailAttCode)); return $sRes; }
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; }
/** * Helpr to clone (in memory) an object and to apply to it the values taken from a second object * @param DBObject $oObjToClone * @param DBObject $oObjWithValues * @return DBObject The modified clone */ protected function CopyFrom($oObjToClone, $oObjWithValues) { $oObj = MetaModel::GetObject(get_class($oObjToClone), $oObjToClone->GetKey()); foreach (MetaModel::ListAttributeDefs(get_class($oObj)) as $sAttCode => $oAttDef) { if (!in_array($sAttCode, $this->aExcludedColumns) && $oAttDef->IsWritable()) { $oObj->Set($sAttCode, $oObjWithValues->Get($sAttCode)); } } return $oObj; }
$aValues = array(); $aObjects = array(); foreach ($aSelectObject as $iId) { $aObjects[] = MetaModel::GetObject($sClass, $iId); } $oSet = DBObjectSet::FromArray($sClass, $aObjects); $oObj = $oSet->ComputeCommonObject($aValues); $sStateAttCode = MetaModel::GetStateAttributeCode($sClass); $oObj->Set($sStateAttCode, $sTargetState); $sReadyScript = ''; foreach ($aExpectedAttributes as $sAttCode => $iExpectCode) { // Prompt for an attribute if // - the attribute must be changed or must be displayed to the user for confirmation // - or the field is mandatory and currently empty if ($iExpectCode & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT) || $iExpectCode & OPT_ATT_MANDATORY && $oObj->Get($sAttCode) == '') { $aAttributesDef = MetaModel::ListAttributeDefs($sClass); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $aPrerequisites = MetaModel::GetPrequisiteAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one if (count($aPrerequisites) > 0) { // When 'enabling' a field, all its prerequisites must be enabled too $sFieldList = "['" . implode("','", $aPrerequisites) . "']"; $oP->add_ready_script("\$('#enable_{$sAttCode}').bind('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, {$sFieldList}, true); } );\n"); } $aDependents = MetaModel::GetDependentAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one if (count($aDependents) > 0) { // When 'disabling' a field, all its dependent fields must be disabled too $sFieldList = "['" . implode("','", $aDependents) . "']"; $oP->add_ready_script("\$('#enable_{$sAttCode}').bind('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, {$sFieldList}, false); } );\n"); }
/** * Read a list of attribute codes from a Rest/Json structure. * * @param string $sClass Name of the class * @param StdClass $oData Structured input data. * @param string $sParamName Name of the parameter to fetch from the input data * @return An array of class => list of attributes (see RestResultWithObjects::AddObject that uses it) * @throws Exception * @api */ public static function GetFieldList($sClass, $oData, $sParamName) { $sFields = self::GetOptionalParam($oData, $sParamName, '*'); $aShowFields = array(); if ($sFields == '*') { foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { $aShowFields[$sClass][] = $sAttCode; } } elseif ($sFields == '*+') { foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sRefClass) { foreach (MetaModel::ListAttributeDefs($sRefClass) as $sAttCode => $oAttDef) { $aShowFields[$sRefClass][] = $sAttCode; } } } else { foreach (explode(',', $sFields) as $sAttCode) { $sAttCode = trim($sAttCode); if ($sAttCode != 'id' && !MetaModel::IsValidAttCode($sClass, $sAttCode)) { throw new Exception("{$sParamName}: invalid attribute code '{$sAttCode}'"); } $aShowFields[$sClass][] = $sAttCode; } } return $aShowFields; }
/** * Display a form for modifying several objects at once * The form will be submitted to the current page, with the specified additional values */ public static function DisplayBulkModifyForm($oP, $sClass, $aSelectedObj, $sCustomOperation, $sCancelUrl, $aExcludeAttributes = array(), $aContextData = array()) { if (count($aSelectedObj) > 0) { $iAllowedCount = count($aSelectedObj); $sSelectedObj = implode(',', $aSelectedObj); $sOQL = "SELECT {$sClass} WHERE id IN (" . $sSelectedObj . ")"; $oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL)); // Compute the distribution of the values for each field to determine which of the "scalar" fields are homogenous $aList = MetaModel::ListAttributeDefs($sClass); $aValues = array(); foreach ($aList as $sAttCode => $oAttDef) { if ($oAttDef->IsScalar()) { $aValues[$sAttCode] = array(); } } while ($oObj = $oSet->Fetch()) { foreach ($aList as $sAttCode => $oAttDef) { if ($oAttDef->IsScalar() && $oAttDef->IsWritable()) { $currValue = $oObj->Get($sAttCode); if ($oAttDef instanceof AttributeCaseLog) { $currValue = ' '; // Don't put an empty string, in case the field would be considered as mandatory... } if (is_object($currValue)) { continue; } // Skip non scalar values... if (!array_key_exists($currValue, $aValues[$sAttCode])) { $aValues[$sAttCode][$currValue] = array('count' => 1, 'display' => $oObj->GetAsHTML($sAttCode)); } else { $aValues[$sAttCode][$currValue]['count']++; } } } } // Now create an object that has values for the homogenous values only $oDummyObj = new $sClass(); // @@ What if the class is abstract ? $aComments = array(); function MyComparison($a, $b) { if ($a['count'] == $b['count']) { return 0; } return $a['count'] > $b['count'] ? -1 : 1; } $iFormId = cmdbAbstractObject::GetNextFormId(); // Identifier that prefixes all the form fields $sReadyScript = ''; $aDependsOn = array(); $sFormPrefix = '2_'; foreach ($aList as $sAttCode => $oAttDef) { $aPrerequisites = MetaModel::GetPrequisiteAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one if (count($aPrerequisites) > 0) { // When 'enabling' a field, all its prerequisites must be enabled too $sFieldList = "['{$sFormPrefix}" . implode("','{$sFormPrefix}", $aPrerequisites) . "']"; $oP->add_ready_script("\$('#enable_{$sFormPrefix}{$sAttCode}').bind('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, {$sFieldList}, true); } );\n"); } $aDependents = MetaModel::GetDependentAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one if (count($aDependents) > 0) { // When 'disabling' a field, all its dependent fields must be disabled too $sFieldList = "['{$sFormPrefix}" . implode("','{$sFormPrefix}", $aDependents) . "']"; $oP->add_ready_script("\$('#enable_{$sFormPrefix}{$sAttCode}').bind('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, {$sFieldList}, false); } );\n"); } if ($oAttDef->IsScalar() && $oAttDef->IsWritable()) { if ($oAttDef->GetEditClass() == 'One Way Password') { $sTip = "Unknown values"; $sReadyScript .= "\$('#multi_values_{$sAttCode}').qtip( { content: '{$sTip}', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );"; $oDummyObj->Set($sAttCode, null); $aComments[$sAttCode] = '<input type="checkbox" id="enable_' . $iFormId . '_' . $sAttCode . '" onClick="ToogleField(this.checked, \'' . $iFormId . '_' . $sAttCode . '\')"/>'; $aComments[$sAttCode] .= '<div class="multi_values" id="multi_values_' . $sAttCode . '"> ? </div>'; $sReadyScript .= 'ToogleField(false, \'' . $iFormId . '_' . $sAttCode . '\');' . "\n"; } else { $iCount = count($aValues[$sAttCode]); if ($iCount == 1) { // Homogenous value reset($aValues[$sAttCode]); $aKeys = array_keys($aValues[$sAttCode]); $currValue = $aKeys[0]; // The only value is the first key //echo "<p>current value for $sAttCode : $currValue</p>"; $oDummyObj->Set($sAttCode, $currValue); $aComments[$sAttCode] = '<input type="checkbox" checked id="enable_' . $iFormId . '_' . $sAttCode . '" onClick="ToogleField(this.checked, \'' . $iFormId . '_' . $sAttCode . '\')"/>'; $aComments[$sAttCode] .= '<div class="mono_value">1</div>'; } else { // Non-homogenous value $aMultiValues = $aValues[$sAttCode]; uasort($aMultiValues, 'MyComparison'); $iMaxCount = 5; $sTip = "<p><b>" . Dict::Format('UI:BulkModify_Count_DistinctValues', $iCount) . "</b><ul>"; $index = 0; foreach ($aMultiValues as $sCurrValue => $aVal) { $sDisplayValue = empty($aVal['display']) ? '<i>' . Dict::S('Enum:Undefined') . '</i>' : str_replace(array("\n", "\r"), " ", $aVal['display']); $sTip .= "<li>" . Dict::Format('UI:BulkModify:Value_Exists_N_Times', $sDisplayValue, $aVal['count']) . "</li>"; $index++; if ($iMaxCount == $index) { $sTip .= "<li>" . Dict::Format('UI:BulkModify:N_MoreValues', count($aMultiValues) - $iMaxCount) . "</li>"; break; } } $sTip .= "</ul></p>"; $sTip = addslashes($sTip); $sReadyScript .= "\$('#multi_values_{$sAttCode}').qtip( { content: '{$sTip}', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );"; $oDummyObj->Set($sAttCode, null); $aComments[$sAttCode] = '<input type="checkbox" id="enable_' . $iFormId . '_' . $sAttCode . '" onClick="ToogleField(this.checked, \'' . $iFormId . '_' . $sAttCode . '\')"/>'; $aComments[$sAttCode] .= '<div class="multi_values" id="multi_values_' . $sAttCode . '">' . $iCount . '</div>'; } $sReadyScript .= 'ToogleField(' . ($iCount == 1 ? 'true' : 'false') . ', \'' . $iFormId . '_' . $sAttCode . '\');' . "\n"; } } } $sStateAttCode = MetaModel::GetStateAttributeCode($sClass); if ($sStateAttCode != '' && $oDummyObj->GetState() == '') { // Hmmm, it's not gonna work like this ! Set a default value for the "state" // Maybe we should use the "state" that is the most common among the objects... $aMultiValues = $aValues[$sStateAttCode]; uasort($aMultiValues, 'MyComparison'); foreach ($aMultiValues as $sCurrValue => $aVal) { $oDummyObj->Set($sStateAttCode, $sCurrValue); break; } //$oStateAtt = MetaModel::GetAttributeDef($sClass, $sStateAttCode); //$oDummyObj->Set($sStateAttCode, $oStateAtt->GetDefaultValue()); } $oP->add("<div class=\"page_header\">\n"); $oP->add("<h1>" . $oDummyObj->GetIcon() . " " . Dict::Format('UI:Modify_M_ObjectsOf_Class_OutOf_N', $iAllowedCount, $sClass, $iAllowedCount) . "</h1>\n"); $oP->add("</div>\n"); $oP->add("<div class=\"wizContainer\">\n"); $sDisableFields = json_encode($aExcludeAttributes); $aParams = array('fieldsComments' => $aComments, 'noRelations' => true, 'custom_operation' => $sCustomOperation, 'custom_button' => Dict::S('UI:Button:PreviewModifications'), 'selectObj' => $sSelectedObj, 'preview_mode' => true, 'disabled_fields' => $sDisableFields, 'disable_plugins' => true); $aParams = $aParams + $aContextData; // merge keeping associations $oDummyObj->DisplayModifyForm($oP, $aParams); $oP->add("</div>\n"); $oP->add_ready_script($sReadyScript); $oP->add_ready_script(<<<EOF \$('.wizContainer button.cancel').unbind('click'); \$('.wizContainer button.cancel').click( function() { window.location.href = '{$sCancelUrl}'; } ); EOF ); } else { $oP->p("No object selected !, nothing to do"); } }
/** * Find the corresponding "link" attribute on the target class * * @return string The attribute code on the target class, or null if none has been found */ public function GetMirrorLinkAttribute() { $oRet = null; $sRemoteClass = $this->GetTargetClass(); foreach (MetaModel::ListAttributeDefs($sRemoteClass) as $sRemoteAttCode => $oRemoteAttDef) { if (!$oRemoteAttDef->IsLinkSet()) { continue; } if (!is_subclass_of($this->GetHostClass(), $oRemoteAttDef->GetLinkedClass()) && $oRemoteAttDef->GetLinkedClass() != $this->GetHostClass()) { continue; } if ($oRemoteAttDef->GetExtKeyToMe() != $this->GetCode()) { continue; } $oRet = $oRemoteAttDef; break; } return $oRet; }
public function MakeValueFromString($sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null, $sAttributeQualifier = null) { if (is_null($sSepItem) || empty($sSepItem)) { $sSepItem = MetaModel::GetConfig()->Get('link_set_item_separator'); } if (is_null($sSepAttribute) || empty($sSepAttribute)) { $sSepAttribute = MetaModel::GetConfig()->Get('link_set_attribute_separator'); } if (is_null($sSepValue) || empty($sSepValue)) { $sSepValue = MetaModel::GetConfig()->Get('link_set_value_separator'); } if (is_null($sAttributeQualifier) || empty($sAttributeQualifier)) { $sAttributeQualifier = MetaModel::GetConfig()->Get('link_set_attribute_qualifier'); } $sTargetClass = $this->Get('linked_class'); $sInput = str_replace($sSepItem, "\n", $sProposedValue); $oCSVParser = new CSVParser($sInput, $sSepAttribute, $sAttributeQualifier); $aInput = $oCSVParser->ToArray(0); $aLinks = array(); foreach ($aInput as $aRow) { // 1st - get the values, split the extkey->searchkey specs, and eventually get the finalclass value $aExtKeys = array(); $aValues = array(); foreach ($aRow as $sCell) { $iSepPos = strpos($sCell, $sSepValue); if ($iSepPos === false) { // Houston... throw new CoreException('Wrong format for link attribute specification', array('value' => $sCell)); } $sAttCode = trim(substr($sCell, 0, $iSepPos)); $sValue = substr($sCell, $iSepPos + strlen($sSepValue)); if (preg_match('/^(.+)->(.+)$/', $sAttCode, $aMatches)) { $sKeyAttCode = $aMatches[1]; $sRemoteAttCode = $aMatches[2]; $aExtKeys[$sKeyAttCode][$sRemoteAttCode] = $sValue; if (!MetaModel::IsValidAttCode($sTargetClass, $sKeyAttCode)) { throw new CoreException('Wrong attribute code for link attribute specification', array('class' => $sTargetClass, 'attcode' => $sKeyAttCode)); } $oKeyAttDef = MetaModel::GetAttributeDef($sTargetClass, $sKeyAttCode); $sRemoteClass = $oKeyAttDef->GetTargetClass(); if (!MetaModel::IsValidAttCode($sRemoteClass, $sRemoteAttCode)) { throw new CoreException('Wrong attribute code for link attribute specification', array('class' => $sRemoteClass, 'attcode' => $sRemoteAttCode)); } } else { if (!MetaModel::IsValidAttCode($sTargetClass, $sAttCode)) { throw new CoreException('Wrong attribute code for link attribute specification', array('class' => $sTargetClass, 'attcode' => $sAttCode)); } $aValues[$sAttCode] = $sValue; } } // 2nd - Instanciate the object and set the value if (isset($aValues['finalclass'])) { $sLinkClass = $aValues['finalclass']; if (!is_subclass_of($sLinkClass, $sTargetClass)) { throw new CoreException('Wrong class for link attribute specification', array('requested_class' => $sLinkClass, 'expected_class' => $sTargetClass)); } } elseif (MetaModel::IsAbstract($sTargetClass)) { throw new CoreException('Missing finalclass for link attribute specification'); } else { $sLinkClass = $sTargetClass; } $oLink = MetaModel::NewObject($sLinkClass); foreach ($aValues as $sAttCode => $sValue) { $oLink->Set($sAttCode, $sValue); } // 3rd - Set external keys from search conditions foreach ($aExtKeys as $sKeyAttCode => $aReconciliation) { $oKeyAttDef = MetaModel::GetAttributeDef($sTargetClass, $sKeyAttCode); $sKeyClass = $oKeyAttDef->GetTargetClass(); $oExtKeyFilter = new CMDBSearchFilter($sKeyClass); $aReconciliationDesc = array(); foreach ($aReconciliation as $sRemoteAttCode => $sValue) { $oExtKeyFilter->AddCondition($sRemoteAttCode, $sValue, '='); $aReconciliationDesc[] = "{$sRemoteAttCode}={$sValue}"; } $oExtKeySet = new CMDBObjectSet($oExtKeyFilter); switch ($oExtKeySet->Count()) { case 0: $sReconciliationDesc = implode(', ', $aReconciliationDesc); throw new CoreException("Found no match", array('ext_key' => $sKeyAttCode, 'reconciliation' => $sReconciliationDesc)); break; case 1: $oRemoteObj = $oExtKeySet->Fetch(); $oLink->Set($sKeyAttCode, $oRemoteObj->GetKey()); break; default: $sReconciliationDesc = implode(', ', $aReconciliationDesc); throw new CoreException("Found several matches", array('ext_key' => $sKeyAttCode, 'reconciliation' => $sReconciliationDesc)); // Found several matches, ambiguous } } // Check (roughly) if such a link is valid $aErrors = array(); foreach (MetaModel::ListAttributeDefs($sTargetClass) as $sAttCode => $oAttDef) { if ($oAttDef->IsExternalKey()) { if ($oAttDef->GetTargetClass() == $this->GetHostClass() || is_subclass_of($this->GetHostClass(), $oAttDef->GetTargetClass())) { continue; // Don't check the key to self } } if ($oAttDef->IsWritable() && $oAttDef->IsNull($oLink->Get($sAttCode)) && !$oAttDef->IsNullAllowed()) { $aErrors[] = $sAttCode; } } if (count($aErrors) > 0) { throw new CoreException("Missing value for mandatory attribute(s): " . implode(', ', $aErrors)); } $aLinks[] = $oLink; } $oSet = DBObjectSet::FromArray($sTargetClass, $aLinks); return $oSet; }
/** * Helper to search for the redundancy attribute */ protected function FindRedundancyAttribute($sRelCode, $aQueryInfo, $sClass) { $oRet = null; foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($oAttDef instanceof AttributeRedundancySettings) { if ($oAttDef->Get('relation_code') == $sRelCode) { if ($oAttDef->Get('neighbour_id') == $aQueryInfo['sNeighbour']) { $oRet = $oAttDef; break; } } } } return $oRet; }
/** * Prepare the given object set with the list of fields as read into $this->aStatusInfo['fields'] */ protected function OptimizeColumnLoad(DBObjectSet $oSet) { $aColumnsToLoad = array(); foreach ($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) { $sClass = $aFieldSpec['sClass']; $sAlias = $aFieldSpec['sAlias']; $sAttCode = $aFieldSpec['sAttCode']; if (!array_key_exists($sAlias, $aColumnsToLoad)) { $aColumnsToLoad[$sAlias] = array(); } // id is not a real attribute code and, moreover, is always loaded if ($sAttCode != 'id') { // Extended attributes are not recognized by DBObjectSet::OptimizeColumnLoad if (($iPos = strpos($sAttCode, '->')) === false) { $aColumnsToLoad[$sAlias][] = $sAttCode; $sClass = '???'; } else { $sExtKeyAttCode = substr($sAttCode, 0, $iPos); $sRemoteAttCode = substr($sAttCode, $iPos + 2); // Load the external key to avoid an object reload! $aColumnsToLoad[$sAlias][] = $sExtKeyAttCode; // Load the external field (if any) to avoid getting the remote object (see DBObject::Get that does the same) $oExtFieldAtt = MetaModel::FindExternalField($sClass, $sExtKeyAttCode, $sRemoteAttCode); if (!is_null($oExtFieldAtt)) { $aColumnsToLoad[$sAlias][] = $oExtFieldAtt->GetCode(); } } } } // Add "always loaded attributes" // $aSelectedClasses = $this->oSearch->GetSelectedClasses(); foreach ($aSelectedClasses as $sAlias => $sClass) { foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($oAttDef->AlwaysLoadInTables()) { $aColumnsToLoad[$sAlias][] = $sAttCode; } } } $oSet->OptimizeColumnLoad($aColumnsToLoad); }
/** * Helper function to build the mapping drop-down list for a field * Spec: Possible choices are "writable" fields in this class plus external fields that are listed as reconciliation keys * for any class pointed to by an external key in the current class. * If not in advanced mode, all "id" fields (id and external keys) must be mapped to ":none:" (i.e -- ignore this field --) * External fields that do not correspond to a reconciliation key must be mapped to ":none:" * Otherwise, if a field equals either the 'code' or the 'label' (translated) of a field, then it's mapped automatically * @param string $sClassName Name of the class used for the mapping * @param string $sFieldName Name of the field, as it comes from the data file (header line) * @param integer $iFieldIndex Number of the field in the sequence * @param bool $bAdvancedMode Whether or not advanced mode was chosen * @param string $sDefaultChoice If set, this will be the item selected by default * @return string The HTML code corresponding to the drop-down list for this field */ function GetMappingForField($sClassName, $sFieldName, $iFieldIndex, $bAdvancedMode, $sDefaultChoice) { $aChoices = array('' => Dict::S('UI:CSVImport:MappingSelectOne')); $aChoices[':none:'] = Dict::S('UI:CSVImport:MappingNotApplicable'); $sFieldCode = ''; // Code of the attribute, if there is a match $aMatches = array(); if (preg_match('/^(.+)\\*$/', $sFieldName, $aMatches)) { // Remove any trailing "star" character. // A star character at the end can be used to indicate a mandatory field $sFieldName = $aMatches[1]; } else { if (preg_match('/^(.+)\\*->(.+)$/', $sFieldName, $aMatches)) { // Remove any trailing "star" character before the arrow (->) // A star character at the end can be used to indicate a mandatory field $sFieldName = $aMatches[1] . '->' . $aMatches[2]; } } if ($sFieldName == 'id') { $sFieldCode = 'id'; } if ($bAdvancedMode) { $aChoices['id'] = Dict::S('UI:CSVImport:idField'); } foreach (MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef) { $sStar = ''; if ($oAttDef->IsExternalKey()) { if ($sFieldName == $oAttDef->GetLabel() || $sFieldName == $sAttCode) { $sFieldCode = $sAttCode; } if ($bAdvancedMode) { $aChoices[$sAttCode] = $oAttDef->GetLabel(); } $oExtKeyAttDef = MetaModel::GetAttributeDef($sClassName, $oAttDef->GetKeyAttCode()); if (!$oExtKeyAttDef->IsNullAllowed()) { $sStar = '*'; } // Get fields of the external class that are considered as reconciliation keys $sTargetClass = $oAttDef->GetTargetClass(); foreach (MetaModel::ListAttributeDefs($sTargetClass) as $sTargetAttCode => $oTargetAttDef) { if (MetaModel::IsReconcKey($sTargetClass, $sTargetAttCode)) { $bExtKey = $oTargetAttDef->IsExternalKey(); $sSuffix = ''; if ($bExtKey) { $sSuffix = '->id'; } if ($bAdvancedMode || !$bExtKey) { // When not in advanced mode do not allow to use reconciliation keys (on external keys) if they are themselves external keys ! $aChoices[$sAttCode . '->' . $sTargetAttCode] = MetaModel::GetLabel($sClassName, $sAttCode . '->' . $sTargetAttCode, true); if (strcasecmp($sFieldName, $oAttDef->GetLabel() . '->' . $oTargetAttDef->GetLabel() . $sSuffix) == 0 || strcasecmp($sFieldName, $sAttCode . '->' . $sTargetAttCode . $sSuffix) == 0) { $sFieldCode = $sAttCode . '->' . $sTargetAttCode; } } } } } else { if ($oAttDef->IsWritable() && (!$oAttDef->IsLinkset() || $bAdvancedMode && $oAttDef->IsIndirect())) { $aChoices[$sAttCode] = MetaModel::GetLabel($sClassName, $sAttCode, true); if ($sFieldName == $oAttDef->GetLabel() || $sFieldName == $sAttCode) { $sFieldCode = $sAttCode; } } } } asort($aChoices); $sHtml = "<select id=\"mapping_{$iFieldIndex}\" name=\"field[{$iFieldIndex}]\">\n"; $bIsIdField = IsIdField($sClassName, $sFieldCode); foreach ($aChoices as $sAttCode => $sLabel) { $sSelected = ''; if ($bIsIdField && !$bAdvancedMode) { if ($sAttCode == ':none:') { $sSelected = ' selected'; } } else { if (empty($sFieldCode) && strpos($sFieldName, '->') !== false) { if ($sAttCode == ':none:') { $sSelected = ' selected'; } } else { if (is_null($sDefaultChoice) && $sFieldCode == $sAttCode) { $sSelected = ' selected'; } else { if (!is_null($sDefaultChoice) && $sDefaultChoice == $sAttCode) { $sSelected = ' selected'; } } } } $sHtml .= "<option value=\"{$sAttCode}\"{$sSelected}>{$sLabel}</option>\n"; } $sHtml .= "</select>\n"; return $sHtml; }
protected function GetInteractiveFieldsWidget(WebPage $oP, $sWidgetId) { $oSet = new DBObjectSet($this->oSearch); $aSelectedClasses = $this->oSearch->GetSelectedClasses(); $aAuthorizedClasses = array(); foreach ($aSelectedClasses as $sAlias => $sClassName) { if (UserRights::IsActionAllowed($sClassName, UR_ACTION_BULK_READ, $oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS)) { $aAuthorizedClasses[$sAlias] = $sClassName; } } $aAllFieldsByAlias = array(); foreach ($aAuthorizedClasses as $sAlias => $sClass) { $aAllFields = array(); if (count($aAuthorizedClasses) > 1) { $sShortAlias = $sAlias . '.'; } else { $sShortAlias = ''; } if ($this->IsValidField($sClass, 'id')) { $aAllFields[] = array('code' => $sShortAlias . 'id', 'unique_label' => $sShortAlias . Dict::S('Core:BulkExport:Identifier'), 'label' => $sShortAlias . 'id', 'subattr' => array(array('code' => $sShortAlias . 'id', 'unique_label' => $sShortAlias . Dict::S('Core:BulkExport:Identifier'), 'label' => $sShortAlias . 'id'), array('code' => $sShortAlias . 'friendlyname', 'unique_label' => $sShortAlias . Dict::S('Core:BulkExport:Friendlyname'), 'label' => $sShortAlias . Dict::S('Core:BulkExport:Friendlyname')))); } foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($this->IsSubAttribute($sClass, $sAttCode, $oAttDef)) { continue; } if ($this->IsValidField($sClass, $sAttCode, $oAttDef)) { $sShortLabel = $oAttDef->GetLabel(); $sLabel = $sShortAlias . $oAttDef->GetLabel(); $aSubAttr = $this->GetSubAttributes($sClass, $sAttCode, $oAttDef); $aValidSubAttr = array(); foreach ($aSubAttr as $aSubAttDef) { if ($this->IsValidField($sClass, $aSubAttDef['code'], $aSubAttDef['attdef'])) { $aValidSubAttr[] = array('code' => $sShortAlias . $aSubAttDef['code'], 'label' => $aSubAttDef['label'], 'unique_label' => $aSubAttDef['unique_label']); } } $aAllFields[] = array('code' => $sShortAlias . $sAttCode, 'label' => $sShortLabel, 'unique_label' => $sLabel, 'subattr' => $aValidSubAttr); } } usort($aAllFields, array(get_class($this), 'SortOnLabel')); if (count($aAuthorizedClasses) > 1) { $sKey = MetaModel::GetName($sClass) . ' (' . $sAlias . ')'; } else { $sKey = MetaModel::GetName($sClass); } $aAllFieldsByAlias[$sKey] = $aAllFields; } $oP->add('<div id="' . $sWidgetId . '"></div>'); $JSAllFields = json_encode($aAllFieldsByAlias); $oSet = new DBObjectSet($this->oSearch); $iCount = $oSet->Count(); $iPreviewLimit = 3; $oSet->SetLimit($iPreviewLimit); $aSampleData = array(); while ($aRow = $oSet->FetchAssoc()) { $aSampleRow = array(); foreach ($aAuthorizedClasses as $sAlias => $sClass) { if (count($aAuthorizedClasses) > 1) { $sShortAlias = $sAlias . '.'; } else { $sShortAlias = ''; } if ($this->IsValidField($sClass, 'id')) { $aSampleRow[$sShortAlias . 'id'] = $this->GetSampleKey($aRow[$sAlias]); } foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($this->IsValidField($sClass, $sAttCode, $oAttDef)) { $aSampleRow[$sShortAlias . $sAttCode] = $this->GetSampleData($aRow[$sAlias], $sAttCode); } } } $aSampleData[] = $aSampleRow; } $sJSSampleData = json_encode($aSampleData); $aLabels = array('preview_header' => Dict::S('Core:BulkExport:DragAndDropHelp'), 'empty_preview' => Dict::S('Core:BulkExport:EmptyPreview'), 'columns_order' => Dict::S('Core:BulkExport:ColumnsOrder'), 'columns_selection' => Dict::S('Core:BulkExport:AvailableColumnsFrom_Class'), 'check_all' => Dict::S('Core:BulkExport:CheckAll'), 'uncheck_all' => Dict::S('Core:BulkExport:UncheckAll'), 'no_field_selected' => Dict::S('Core:BulkExport:NoFieldSelected')); $sJSLabels = json_encode($aLabels); $oP->add_ready_script(<<<EOF \$('#{$sWidgetId}').tabularfieldsselector({fields: {$JSAllFields}, value_holder: '#tabular_fields', advanced_holder: '#tabular_advanced', sample_data: {$sJSSampleData}, total_count: {$iCount}, preview_limit: {$iPreviewLimit}, labels: {$sJSLabels} }); EOF ); }
protected function FixVisibleColumns() { foreach ($this->aClassAliases as $sAlias => $sClass) { foreach ($this->aColumns[$sAlias] as $sAttCode => $aData) { // Remove non-existent columns // TODO: check if the existing ones are still valid (in case their type changed) if ($sAttCode != '_key_' && !MetaModel::IsValidAttCode($sClass, $sAttCode)) { unset($this->aColumns[$sAlias][$sAttCode]); } } $aList = MetaModel::ListAttributeDefs($sClass); // Add the other (non visible ones), sorted in alphabetical order $aTempData = array(); foreach ($aList as $sAttCode => $oAttDef) { if (!array_key_exists($sAttCode, $this->aColumns[$sAlias]) && !$oAttDef instanceof AttributeLinkSet) { $aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false, 'none'); if ($aFieldData) { $aTempData[$aFieldData['label']] = $aFieldData; } } } ksort($aTempData); foreach ($aTempData as $sLabel => $aFieldData) { $this->aColumns[$sAlias][$aFieldData['code']] = $aFieldData; } } }
public function DisplayDetails(WebPage $oPage, $bEditMode = false) { $oPage->add('<h1>' . MetaModel::GetName(get_class($this)) . ': ' . $this->GetName() . '</h1>'); $aValues = array(); $aList = MetaModel::FlattenZList(MetaModel::GetZListItems(get_class($this), 'details')); if (empty($aList)) { $aList = array_keys(MetaModel::ListAttributeDefs(get_class($this))); } foreach ($aList as $sAttCode) { $aValues[$sAttCode] = array('label' => MetaModel::GetLabel(get_class($this), $sAttCode), 'value' => $this->GetAsHTML($sAttCode)); } $oPage->details($aValues); }
public function Render(WebPage $oPage, $aParams = array(), $bEditMode = false) { $sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this->m_oObj)); $aTemplateFields = array(); preg_match_all('/\\$this->([a-z0-9_]+)\\$/', $this->m_sTemplate, $aMatches); foreach ($aMatches[1] as $sAttCode) { if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode)) { $aTemplateFields[] = $sAttCode; } else { $aParams['this->' . $sAttCode] = "<!--Unknown attribute: {$sAttCode}-->"; } } preg_match_all('/\\$this->field\\(([a-z0-9_]+)\\)\\$/', $this->m_sTemplate, $aMatches); foreach ($aMatches[1] as $sAttCode) { if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode)) { $aTemplateFields[] = $sAttCode; } else { $aParams['this->field(' . $sAttCode . ')'] = "<!--Unknown attribute: {$sAttCode}-->"; } } $aFieldsComments = isset($aParams['fieldsComments']) ? $aParams['fieldsComments'] : array(); $aFieldsMap = array(); $sClass = get_class($this->m_oObj); // Renders the fields used in the template foreach (MetaModel::ListAttributeDefs(get_class($this->m_oObj)) as $sAttCode => $oAttDef) { $aParams['this->label(' . $sAttCode . ')'] = $oAttDef->GetLabel(); $aParams['this->comments(' . $sAttCode . ')'] = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : ''; $iInputId = '2_' . $sAttCode; // TODO: generate a real/unique prefix... if (in_array($sAttCode, $aTemplateFields)) { if ($this->m_oObj->IsNew()) { $iFlags = $this->m_oObj->GetInitialStateAttributeFlags($sAttCode); } else { $iFlags = $this->m_oObj->GetAttributeFlags($sAttCode); } if ($iFlags & OPT_ATT_MANDATORY && $this->m_oObj->IsNew()) { $iFlags = $iFlags & ~OPT_ATT_READONLY; // Mandatory fields cannot be read-only when creating an object } if (!$oAttDef->IsWritable() || $sStateAttCode == $sAttCode) { $iFlags = $iFlags | OPT_ATT_READONLY; } if ($iFlags & OPT_ATT_HIDDEN) { $aParams['this->label(' . $sAttCode . ')'] = ''; $aParams['this->field(' . $sAttCode . ')'] = ''; $aParams['this->comments(' . $sAttCode . ')'] = ''; $aParams['this->' . $sAttCode] = ''; } else { if ($bEditMode && $iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE)) { // Check if the attribute is not read-only because of a synchro... $aReasons = array(); $sSynchroIcon = ''; if ($iFlags & OPT_ATT_SLAVE) { $iSynchroFlags = $this->m_oObj->GetSynchroReplicaFlags($sAttCode, $aReasons); $sSynchroIcon = " <img id=\"synchro_{$sInputId}\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>"; $sTip = ''; foreach ($aReasons as $aRow) { $sTip .= "<p>Synchronized with {$aRow['name']} - {$aRow['description']}</p>"; } $oPage->add_ready_script("\$('#synchro_{$iInputId}').qtip( { content: '{$sTip}', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );"); } // Attribute is read-only $sHTMLValue = "<span id=\"field_{$iInputId}\">" . $this->m_oObj->GetAsHTML($sAttCode); $sHTMLValue .= '<input type="hidden" id="' . $iInputId . '" name="attr_' . $sAttCode . '" value="' . htmlentities($this->m_oObj->Get($sAttCode), ENT_QUOTES, 'UTF-8') . '"/></span>'; $aFieldsMap[$sAttCode] = $iInputId; $aParams['this->comments(' . $sAttCode . ')'] = $sSynchroIcon; } if ($bEditMode && !($iFlags & OPT_ATT_READONLY)) { $aParams['this->field(' . $sAttCode . ')'] = "<span id=\"field_{$iInputId}\">" . $this->m_oObj->GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $this->m_oObj->Get($sAttCode), $this->m_oObj->GetEditValue($sAttCode), $iInputId, '', $iFlags, array('this' => $this->m_oObj)) . '</span>'; $aFieldsMap[$sAttCode] = $iInputId; } else { $aParams['this->field(' . $sAttCode . ')'] = $this->m_oObj->GetAsHTML($sAttCode); } $aParams['this->' . $sAttCode] = "<table class=\"field\"><tr><td class=\"label\">" . $aParams['this->label(' . $sAttCode . ')'] . ":</td><td>" . $aParams['this->field(' . $sAttCode . ')'] . "</td><td>" . $aParams['this->comments(' . $sAttCode . ')'] . "</td></tr></table>"; } } } // Renders the PlugIns used in the template preg_match_all('/\\$PlugIn:([A-Za-z0-9_]+)->properties\\(\\)\\$/', $this->m_sTemplate, $aMatches); $aPlugInProperties = $aMatches[1]; foreach ($aPlugInProperties as $sPlugInClass) { $oInstance = MetaModel::GetPlugins('iApplicationUIExtension', $sPlugInClass); if ($oInstance != null) { $offset = $oPage->start_capture(); $oInstance->OnDisplayProperties($this->m_oObj, $oPage, $bEditMode); $sContent = $oPage->end_capture($offset); $aParams["PlugIn:{$sPlugInClass}->properties()"] = $sContent; } else { $aParams["PlugIn:{$sPlugInClass}->properties()"] = "Missing PlugIn: {$sPlugInClass}"; } } $offset = $oPage->start_capture(); parent::Render($oPage, $aParams); $sContent = $oPage->end_capture($offset); // Remove empty table rows in case some attributes are hidden... $sContent = preg_replace('/<tr[^>]*>\\s*(<td[^>]*>\\s*<\\/td>)+\\s*<\\/tr>/im', '', $sContent); $oPage->add($sContent); return $aFieldsMap; }
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; }
public function Process($iTimeLimit) { $aList = array(); foreach (MetaModel::GetClasses() as $sClass) { foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($oAttDef instanceof AttributeStopWatch) { foreach ($oAttDef->ListThresholds() as $iThreshold => $aThresholdData) { $iPercent = $aThresholdData['percent']; // could be different than the index ! $sNow = date('Y-m-d H:i:s'); $sExpression = "SELECT {$sClass} WHERE {$sAttCode}_laststart AND {$sAttCode}_{$iThreshold}_triggered = 0 AND {$sAttCode}_{$iThreshold}_deadline < '{$sNow}'"; $oFilter = DBObjectSearch::FromOQL($sExpression); $oSet = new DBObjectSet($oFilter); while (time() < $iTimeLimit && ($oObj = $oSet->Fetch())) { $sClass = get_class($oObj); $aList[] = $sClass . '::' . $oObj->GetKey() . ' ' . $sAttCode . ' ' . $iThreshold; // Execute planned actions // foreach ($aThresholdData['actions'] as $aActionData) { $sVerb = $aActionData['verb']; $aParams = $aActionData['params']; $aValues = array(); foreach ($aParams as $def) { if (is_string($def)) { // Old method (pre-2.1.0) non typed parameters $aValues[] = $def; } else { $sParamType = array_key_exists('type', $def) ? $def['type'] : 'string'; switch ($sParamType) { case 'int': $value = (int) $def['value']; break; case 'float': $value = (double) $def['value']; break; case 'bool': $value = (bool) $def['value']; break; case 'reference': $value = ${$def['value']}; break; case 'string': default: $value = (string) $def['value']; } $aValues[] = $value; } } $aCallSpec = array($oObj, $sVerb); call_user_func_array($aCallSpec, $aValues); } // Mark the threshold as "triggered" // $oSW = $oObj->Get($sAttCode); $oSW->MarkThresholdAsTriggered($iThreshold); $oObj->Set($sAttCode, $oSW); if ($oObj->IsModified()) { CMDBObject::SetTrackInfo("Automatic - threshold triggered"); $oMyChange = CMDBObject::GetCurrentChange(); $oObj->DBUpdateTracked($oMyChange, true); } // Activate any existing trigger // $sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL)); $oTriggerSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnThresholdReached AS t WHERE t.target_class IN ('{$sClassList}') AND stop_watch_code=:stop_watch_code AND threshold_index = :threshold_index"), array(), array('stop_watch_code' => $sAttCode, 'threshold_index' => $iThreshold)); while ($oTrigger = $oTriggerSet->Fetch()) { $oTrigger->DoActivate($oObj->ToArgs('this')); } } } } } } $iProcessed = count($aList); return "Triggered {$iProcessed} threshold(s):" . implode(", ", $aList); }
// Note: it may happen that an external field has the same label as the external key // in that case, we consider that the external key has precedence // $aKnownColumnNames = array(); foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if ($bLocalize) { $sColName = strtolower(MetaModel::GetLabel($sClass, $sAttCode)); } else { $sColName = strtolower($sAttCode); } if (!$oAttDef->IsExternalField() || !array_key_exists($sColName, $aKnownColumnNames)) { $aKnownColumnNames[$sColName][] = $sAttCode; } if ($oAttDef->IsExternalKey(EXTKEY_RELATIVE)) { $sRemoteClass = $oAttDef->GetTargetClass(); foreach (MetaModel::ListAttributeDefs($sRemoteClass) as $sRemoteAttCode => $oRemoteAttDef) { $sAttCodeEx = $sAttCode . '->' . $sRemoteAttCode; if ($bLocalize) { $sColName = strtolower(MetaModel::GetLabel($sClass, $sAttCodeEx)); } else { $sColName = strtolower($sAttCodeEx); } if (!array_key_exists($sColName, $aKnownColumnNames)) { $aKnownColumnNames[$sColName][] = $sAttCodeEx; } } } } //print_r($aKnownColumnNames); //print_r(array_keys($aKnownColumnNames)); //exit;