/** * Split the string into placholders * @param Hash $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>' * @return void */ protected function Analyze($aParamTypes = array()) { if (!is_null($this->m_aPlaceholders)) { return; } $this->m_aPlaceholders = array(); if (preg_match_all('/\\$([a-z0-9_]+(->[a-z0-9_]+)*)\\$/', $this->m_sRaw, $aMatches)) { foreach ($aMatches[1] as $sPlaceholder) { $oPlaceholder = new TemplateStringPlaceholder($sPlaceholder); $oPlaceholder->bIsValid = false; foreach ($aParamTypes as $sParamName => $sClass) { $sParamPrefix = $sParamName . '->'; if (substr($sPlaceholder, 0, strlen($sParamPrefix)) == $sParamPrefix) { // Todo - detect functions (label...) $oPlaceholder->sFunction = ''; $oPlaceholder->sParamName = $sParamName; $sAttcode = substr($sPlaceholder, strlen($sParamPrefix)); $oPlaceholder->sAttcode = $sAttcode; $oPlaceholder->bIsValid = MetaModel::IsValidAttCode($sClass, $sAttcode, true); } } $this->m_aPlaceholders[] = $oPlaceholder; } } }
/** * Adds the context parameters to the audit query */ function FilterByContext(DBSearch &$oFilter, ApplicationContext $oAppContext) { $sObjClass = $oFilter->GetClass(); $aContextParams = $oAppContext->GetNames(); $aCallSpec = array($sObjClass, 'MapContextParam'); if (is_callable($aCallSpec)) { foreach ($aContextParams as $sParamName) { $sValue = $oAppContext->GetCurrentValue($sParamName, null); if ($sValue != null) { $sAttCode = call_user_func($aCallSpec, $sParamName); // Returns null when there is no mapping for this parameter if ($sAttCode != null && MetaModel::IsValidAttCode($sObjClass, $sAttCode)) { // Check if the condition points to a hierarchical key if ($sAttCode == 'id') { // Filtering on the objects themselves $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sObjClass); if ($sHierarchicalKeyCode !== false) { $oRootFilter = new DBObjectSearch($sObjClass); $oRootFilter->AddCondition($sAttCode, $sValue); $oFilter->AddCondition_PointingTo($oRootFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default $bConditionAdded = true; } } else { $oAttDef = MetaModel::GetAttributeDef($sObjClass, $sAttCode); $bConditionAdded = false; if ($oAttDef->IsExternalKey()) { $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($oAttDef->GetTargetClass()); if ($sHierarchicalKeyCode !== false) { $oRootFilter = new DBObjectSearch($oAttDef->GetTargetClass()); $oRootFilter->AddCondition('id', $sValue); $oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass()); $oHKFilter->AddCondition_PointingTo($oRootFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default $oFilter->AddCondition_PointingTo($oHKFilter, $sAttCode); $bConditionAdded = true; } } } if (!$bConditionAdded) { $oFilter->AddCondition($sAttCode, $sValue); } } } } } }
function DisplayBareRelations(WebPage $oPage, $bEditMode = false) { parent::DisplayBareRelations($oPage, $bEditMode); $sTicketListAttCode = 'tickets_list'; if (MetaModel::IsValidAttCode(get_class($this), $sTicketListAttCode)) { // Display one list per leaf class (the only way to display the status as of now) $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sTicketListAttCode); $sLnkClass = $oAttDef->GetLinkedClass(); $sExtKeyToMe = $oAttDef->GetExtKeyToMe(); $sExtKeyToRemote = $oAttDef->GetExtKeyToRemote(); $iTotal = 0; $aSearches = array(); foreach (MetaModel::EnumChildClasses('Ticket') as $sSubClass) { if (!MetaModel::HasChildrenClasses($sSubClass)) { $sStateAttCode = MetaModel::GetStateAttributeCode($sSubClass); if ($sStateAttCode != '') { $oSearch = DBSearch::FromOQL("SELECT {$sSubClass} AS t JOIN {$sLnkClass} AS lnk ON lnk.{$sExtKeyToRemote} = t.id WHERE {$sExtKeyToMe} = :myself AND {$sStateAttCode} NOT IN ('rejected', 'resolved', 'closed')", array('myself' => $this->GetKey())); $aSearches[$sSubClass] = $oSearch; $oSet = new DBObjectSet($oSearch); $iTotal += $oSet->Count(); } } } $sCount = $iTotal > 0 ? ' (' . $iTotal . ')' : ''; $oPage->SetCurrentTab(Dict::S('Class:FunctionalCI/Tab:OpenedTickets') . $sCount); foreach ($aSearches as $sSubClass => $oSearch) { $sBlockId = __CLASS__ . '_opened_' . $sSubClass; $oPage->add('<fieldset>'); $oPage->add('<legend>' . MetaModel::GetName($sSubClass) . '</legend>'); $oBlock = new DisplayBlock($oSearch, 'list', false); $oBlock->Display($oPage, $sBlockId, array('menu' => false)); $oPage->add('</fieldset>'); } } }
/** * Specify a condition on external keys or link sets * @param sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively * Example: infra_list->ci_id->location_id->country * @param value The value to match (can be an array => IN(val1, val2...) * @return void */ public function AddConditionAdvanced($sAttSpec, $value) { $sClass = $this->GetClass(); $iPos = strpos($sAttSpec, '->'); if ($iPos !== false) { $sAttCode = substr($sAttSpec, 0, $iPos); $sSubSpec = substr($sAttSpec, $iPos + 2); if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) { throw new Exception("Invalid attribute code '{$sClass}/{$sAttCode}' in condition specification '{$sAttSpec}'"); } $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ($oAttDef->IsLinkSet()) { $sTargetClass = $oAttDef->GetLinkedClass(); $sExtKeyToMe = $oAttDef->GetExtKeyToMe(); $oNewFilter = new DBObjectSearch($sTargetClass); $oNewFilter->AddConditionAdvanced($sSubSpec, $value); $this->AddCondition_ReferencedBy($oNewFilter, $sExtKeyToMe); } elseif ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) { $sTargetClass = $oAttDef->GetTargetClass(EXTKEY_ABSOLUTE); $oNewFilter = new DBObjectSearch($sTargetClass); $oNewFilter->AddConditionAdvanced($sSubSpec, $value); $this->AddCondition_PointingTo($oNewFilter, $sAttCode); } else { throw new Exception("Attribute specification '{$sAttSpec}', '{$sAttCode}' should be either a link set or an external key"); } } else { // $sAttSpec is an attribute code // if (is_array($value)) { $oField = new FieldExpression($sAttSpec, $this->GetClass()); $oListExpr = ListExpression::FromScalars($value); $oInValues = new BinaryExpression($oField, 'IN', $oListExpr); $this->AddConditionExpression($oInValues); } else { $this->AddCondition($sAttSpec, $value); } } }
public function GetValueDescription($sValue) { if (is_null($sValue)) { // Unless a specific label is defined for the null value of this enum, use a generic "undefined" label $sDescription = Dict::S('Class:' . $this->GetHostClass() . '/Attribute:' . $this->GetCode() . '/Value:' . $sValue . '+', Dict::S('Enum:Undefined')); } else { $sDescription = Dict::S('Class:' . $this->GetHostClass() . '/Attribute:' . $this->GetCode() . '/Value:' . $sValue . '+', '', true); if (strlen($sDescription) == 0) { $sParentClass = MetaModel::GetParentClass($this->m_sHostClass); if ($sParentClass) { if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode)) { $oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode); $sDescription = $oAttDef->GetValueDescription($sValue); } } } } return $sDescription; }
protected function ForgotPwdGo() { $sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data'); try { UserRights::Login($sAuthUser); // Set the user's language (if possible!) $oUser = UserRights::GetUserObject(); if ($oUser == null) { throw new Exception(Dict::Format('UI:ResetPwd-Error-WrongLogin', $sAuthUser)); } if (!MetaModel::IsValidAttCode(get_class($oUser), 'reset_pwd_token')) { throw new Exception(Dict::S('UI:ResetPwd-Error-NotPossible')); } if (!$oUser->CanChangePassword()) { throw new Exception(Dict::S('UI:ResetPwd-Error-FixedPwd')); } $sTo = $oUser->GetResetPasswordEmail(); // throws Exceptions if not allowed if ($sTo == '') { throw new Exception(Dict::S('UI:ResetPwd-Error-NoEmail')); } // This token allows the user to change the password without knowing the previous one $sToken = substr(md5(APPROOT . uniqid()), 0, 16); $oUser->Set('reset_pwd_token', $sToken); CMDBObject::SetTrackInfo('Reset password'); $oUser->DBUpdate(); $oEmail = new Email(); $oEmail->SetRecipientTO($sTo); $sFrom = MetaModel::GetConfig()->Get('forgot_password_from'); if ($sFrom == '') { $sFrom = $sTo; } $oEmail->SetRecipientFrom($sFrom); $oEmail->SetSubject(Dict::S('UI:ResetPwd-EmailSubject')); $sResetUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?loginop=reset_pwd&auth_user='******'login')) . '&token=' . urlencode($sToken); $oEmail->SetBody(Dict::Format('UI:ResetPwd-EmailBody', $sResetUrl)); $iRes = $oEmail->Send($aIssues, true); switch ($iRes) { //case EMAIL_SEND_PENDING: case EMAIL_SEND_OK: break; case EMAIL_SEND_ERROR: default: IssueLog::Error('Failed to send the email with the NEW password for ' . $oUser->Get('friendlyname') . ': ' . implode(', ', $aIssues)); throw new Exception(Dict::S('UI:ResetPwd-Error-Send')); } $this->DisplayLoginHeader(); $this->add("<div id=\"login\">\n"); $this->add("<h1>" . Dict::S('UI:Login:ForgotPwdForm') . "</h1>\n"); $this->add("<p>" . Dict::S('UI:ResetPwd-EmailSent') . "</p>"); $this->add("<form method=\"post\">\n"); $this->add("<table>\n"); $this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"><input type=\"button\" onClick=\"window.close();\" value=\"" . Dict::S('UI:Button:Done') . "\" /></td></tr>\n"); $this->add("</table>\n"); $this->add("</form>\n"); $this->add("</div\n"); } catch (Exception $e) { $this->DisplayForgotPwdForm(true, $e->getMessage()); } }
/** * Updates the object from a flat array of values * @param string $aValues array of attcode => scalar or array (N-N links) * @return void */ public function UpdateObjectFromArray($aValues) { foreach ($aValues as $sAttCode => $value) { $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode); if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect()) { $aLinks = $value; $sLinkedClass = $oAttDef->GetLinkedClass(); $sExtKeyToRemote = $oAttDef->GetExtKeyToRemote(); $sExtKeyToMe = $oAttDef->GetExtKeyToMe(); $oLinkedSet = DBObjectSet::FromScratch($sLinkedClass); if (is_array($aLinks)) { foreach ($aLinks as $id => $aData) { if (is_numeric($id)) { if ($id < 0) { // New link to be created, the opposite of the id (-$id) is the ID of the remote object $oLink = MetaModel::NewObject($sLinkedClass); $oLink->Set($sExtKeyToRemote, -$id); $oLink->Set($sExtKeyToMe, $this->GetKey()); } else { // Existing link, potentially to be updated... $oLink = MetaModel::GetObject($sLinkedClass, $id); } // Now populate the attributes foreach ($aData as $sName => $value) { if (MetaModel::IsValidAttCode($sLinkedClass, $sName)) { $oLinkAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sName); if ($oLinkAttDef->IsWritable()) { $oLink->Set($sName, $value); } } } $oLinkedSet->AddObject($oLink); } } } $this->Set($sAttCode, $oLinkedSet); } elseif ($oAttDef->GetEditClass() == 'Document') { // There should be an uploaded file with the named attr_<attCode> $oDocument = $value['fcontents']; if (!$oDocument->IsEmpty()) { // A new file has been uploaded $this->Set($sAttCode, $oDocument); } } elseif ($oAttDef->GetEditClass() == 'One Way Password') { // Check if the password was typed/changed $aPwdData = $value; if (!is_null($aPwdData) && $aPwdData['changed']) { // The password has been changed or set $this->Set($sAttCode, $aPwdData['value']); } } elseif ($oAttDef->GetEditClass() == 'Duration') { $aDurationData = $value; if (!is_array($aDurationData)) { continue; } $iValue = ((24 * $aDurationData['d'] + $aDurationData['h']) * 60 + $aDurationData['m']) * 60 + $aDurationData['s']; $this->Set($sAttCode, $iValue); $previousValue = $this->Get($sAttCode); if ($previousValue !== $iValue) { $this->Set($sAttCode, $iValue); } } else { if ($oAttDef->GetEditClass() == 'LinkedSet' && !$oAttDef->IsIndirect() && ($oAttDef->GetEditMode() == LINKSET_EDITMODE_INPLACE || $oAttDef->GetEditMode() == LINKSET_EDITMODE_ADDREMOVE)) { $oLinkset = $this->Get($sAttCode); $sLinkedClass = $oLinkset->GetClass(); $aObjSet = array(); $oLinkset->Rewind(); $bModified = false; while ($oLink = $oLinkset->Fetch()) { if (in_array($oLink->GetKey(), $value['to_be_deleted'])) { // The link is to be deleted, don't copy it in the array $bModified = true; } else { if (!array_key_exists('to_be_removed', $value) || !in_array($oLink->GetKey(), $value['to_be_removed'])) { $aObjSet[] = $oLink; } } } if (array_key_exists('to_be_created', $value) && count($value['to_be_created']) > 0) { // Now handle the links to be created foreach ($value['to_be_created'] as $aData) { $sSubClass = $aData['class']; if ($sLinkedClass == $sSubClass || is_subclass_of($sSubClass, $sLinkedClass)) { $aObjData = $aData['data']; $oLink = new $sSubClass(); $oLink->UpdateObjectFromArray($aObjData); $aObjSet[] = $oLink; $bModified = true; } } } if (array_key_exists('to_be_added', $value) && count($value['to_be_added']) > 0) { // Now handle the links to be added by making the remote object point to self foreach ($value['to_be_added'] as $iObjKey) { $oLink = MetaModel::GetObject($sLinkedClass, $iObjKey, false); if ($oLink) { $aObjSet[] = $oLink; $bModified = true; } } } if (array_key_exists('to_be_removed', $value) && count($value['to_be_removed']) > 0) { // Now handle the links to be removed by making the remote object point to nothing // Keep them in the set (modified), DBWriteLinks will handle them foreach ($value['to_be_removed'] as $iObjKey) { $oLink = MetaModel::GetObject($sLinkedClass, $iObjKey, false); if ($oLink) { $sExtKeyToMe = $oAttDef->GetExtKeyToMe(); $oLink->Set($sExtKeyToMe, null); $aObjSet[] = $oLink; $bModified = true; } } } if ($bModified) { $oNewSet = DBObjectSet::FromArray($oLinkset->GetClass(), $aObjSet); $this->Set($sAttCode, $oNewSet); } } else { if (!is_null($value)) { $aAttributes[$sAttCode] = trim($value); $previousValue = $this->Get($sAttCode); if ($previousValue !== $aAttributes[$sAttCode]) { $this->Set($sAttCode, $aAttributes[$sAttCode]); } } } } } }
/** * Create an ResponseTicket (Incident or UserRequest) from an external system * Some CIs might be specified (by their name/IP) * * @param string sClass The class of the ticket: Incident or UserRequest * @param string sTitle * @param string sDescription * @param array aCallerDesc * @param array aCustomerDesc * @param array aServiceDesc * @param array aServiceSubcategoryDesc * @param string sProduct * @param array aWorkgroupDesc * @param array aImpactedCIs * @param string sImpact * @param string sUrgency * * @return WebServiceResult */ protected function _CreateResponseTicket($sClass, $sTitle, $sDescription, $aCallerDesc, $aCustomerDesc, $aServiceDesc, $aServiceSubcategoryDesc, $sProduct, $aWorkgroupDesc, $aImpactedCIs, $sImpact, $sUrgency) { $oRes = new WebServiceResult(); try { $oMyChange = MetaModel::NewObject("CMDBChange"); $oMyChange->Set("date", time()); $oMyChange->Set("userinfo", "Administrator"); $iChangeId = $oMyChange->DBInsertNoReload(); $oNewTicket = MetaModel::NewObject($sClass); $this->MyObjectSetScalar('title', 'title', $sTitle, $oNewTicket, $oRes); $this->MyObjectSetScalar('description', 'description', $sDescription, $oNewTicket, $oRes); $this->MyObjectSetExternalKey('org_id', 'customer', $aCustomerDesc, $oNewTicket, $oRes); $this->MyObjectSetExternalKey('caller_id', 'caller', $aCallerDesc, $oNewTicket, $oRes); $this->MyObjectSetExternalKey('service_id', 'service', $aServiceDesc, $oNewTicket, $oRes); if (!array_key_exists('service_id', $aServiceSubcategoryDesc)) { $aServiceSubcategoryDesc['service_id'] = $oNewTicket->Get('service_id'); } $this->MyObjectSetExternalKey('servicesubcategory_id', 'servicesubcategory', $aServiceSubcategoryDesc, $oNewTicket, $oRes); if (MetaModel::IsValidAttCode($sClass, 'product')) { // 1.x data models $this->MyObjectSetScalar('product', 'product', $sProduct, $oNewTicket, $oRes); } if (MetaModel::IsValidAttCode($sClass, 'workgroup_id')) { // 1.x data models $this->MyObjectSetExternalKey('workgroup_id', 'workgroup', $aWorkgroupDesc, $oNewTicket, $oRes); } else { if (MetaModel::IsValidAttCode($sClass, 'team_id')) { // 2.x data models $this->MyObjectSetExternalKey('team_id', 'workgroup', $aWorkgroupDesc, $oNewTicket, $oRes); } } if (MetaModel::IsValidAttCode($sClass, 'ci_list')) { // 1.x data models $aDevicesNotFound = $this->AddLinkedObjects('ci_list', 'impacted_cis', 'FunctionalCI', $aImpactedCIs, $oNewTicket, $oRes); } else { if (MetaModel::IsValidAttCode($sClass, 'functionalcis_list')) { // 2.x data models $aDevicesNotFound = $this->AddLinkedObjects('functionalcis_list', 'impacted_cis', 'FunctionalCI', $aImpactedCIs, $oNewTicket, $oRes); } } if (count($aDevicesNotFound) > 0) { $this->MyObjectSetScalar('description', 'n/a', $sDescription . ' - Related CIs: ' . implode(', ', $aDevicesNotFound), $oNewTicket, $oRes); } else { $this->MyObjectSetScalar('description', 'n/a', $sDescription, $oNewTicket, $oRes); } $this->MyObjectSetScalar('impact', 'impact', $sImpact, $oNewTicket, $oRes); $this->MyObjectSetScalar('urgency', 'urgency', $sUrgency, $oNewTicket, $oRes); $this->MyObjectInsert($oNewTicket, 'created', $oMyChange, $oRes); } catch (CoreException $e) { $oRes->LogError($e->getMessage()); } catch (Exception $e) { $oRes->LogError($e->getMessage()); } $this->LogUsage(__FUNCTION__, $oRes); return $oRes; }
public static function GetContactId($sName = '') { if (empty($sName)) { $oUser = self::$m_oUser; } else { $oUser = FindUser($sName); } if (is_null($oUser)) { return ''; } if (!MetaModel::IsValidAttCode(get_class($oUser), 'contactid')) { return ''; } return $oUser->Get('contactid'); }
public function Get($sAttCode) { if (($iPos = strpos($sAttCode, '->')) === false) { return $this->GetStrict($sAttCode); } else { $sExtKeyAttCode = substr($sAttCode, 0, $iPos); $sRemoteAttCode = substr($sAttCode, $iPos + 2); if (!MetaModel::IsValidAttCode(get_class($this), $sExtKeyAttCode)) { throw new CoreException("Unknown external key '{$sExtKeyAttCode}' for the class " . get_class($this)); } $oExtFieldAtt = MetaModel::FindExternalField(get_class($this), $sExtKeyAttCode, $sRemoteAttCode); if (!is_null($oExtFieldAtt)) { return $this->GetStrict($oExtFieldAtt->GetCode()); } else { $oKeyAttDef = MetaModel::GetAttributeDef(get_class($this), $sExtKeyAttCode); $sRemoteClass = $oKeyAttDef->GetTargetClass(); $oRemoteObj = MetaModel::GetObject($sRemoteClass, $this->GetStrict($sExtKeyAttCode), false); if (is_null($oRemoteObj)) { return ''; } else { return $oRemoteObj->Get($sRemoteAttCode); } } } }
/** * Find out which attribute is corresponding the the dimension 'owner org' * returns null if no such attribute has been found (no filtering should occur) */ public static function GetOwnerOrganizationAttCode($sClass) { $sAttCode = null; $aCallSpec = array($sClass, 'MapContextParam'); if ($sClass == 'Organization' || is_subclass_of($sClass, 'Organization')) { $sAttCode = 'id'; } elseif (is_callable($aCallSpec)) { $sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) { // Skip silently. The data model checker will tell you something about this... $sAttCode = null; } } elseif (MetaModel::IsValidAttCode($sClass, 'org_id')) { $sAttCode = 'org_id'; } return $sAttCode; }
public static final function IsValidAttCode($sClass, $sAttCode, $bExtended = false) { if (!array_key_exists($sClass, self::$m_aAttribDefs)) { return false; } if ($bExtended) { if (($iPos = strpos($sAttCode, '->')) === false) { $bRes = array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]); } else { $sExtKeyAttCode = substr($sAttCode, 0, $iPos); $sRemoteAttCode = substr($sAttCode, $iPos + 2); if (MetaModel::IsValidAttCode($sClass, $sExtKeyAttCode)) { $oKeyAttDef = MetaModel::GetAttributeDef($sClass, $sExtKeyAttCode); $sRemoteClass = $oKeyAttDef->GetTargetClass(); $bRes = MetaModel::IsValidAttCode($sRemoteClass, $sRemoteAttCode, true); } else { $bRes = false; } } } else { $bRes = array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]); } return $bRes; }
/** * Give a default value for item_org_id (if relevant...) * @return void */ public function SetDefaultOrgId() { // First check that the organization CAN be fetched from the target class // $sClass = $this->Get('item_class'); $aCallSpec = array($sClass, 'MapContextParam'); if (is_callable($aCallSpec)) { $sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter if (MetaModel::IsValidAttCode($sClass, $sAttCode)) { // Second: check that the organization CAN be fetched from the current user // if (MetaModel::IsValidClass('Person')) { $aCallSpec = array($sClass, 'MapContextParam'); if (is_callable($aCallSpec)) { $sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter if (MetaModel::IsValidAttCode($sClass, $sAttCode)) { // OK - try it // $oCurrentPerson = MetaModel::GetObject('Person', UserRights::GetContactId(), false); if ($oCurrentPerson) { $this->Set('item_org_id', $oCurrentPerson->Get($sAttCode)); } } } } } } }
/** * Initializes the given object with the default values provided by the context */ public function InitObjectFromContext(DBObject &$oObj) { $sClass = get_class($oObj); foreach ($this->GetNames() as $key) { $aCallSpec = array($sClass, 'MapContextParam'); if (is_callable($aCallSpec)) { $sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter if (MetaModel::IsValidAttCode($sClass, $sAttCode)) { $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ($oAttDef->IsWritable()) { $value = $this->GetCurrentValue($key, null); if (!is_null($value)) { $oObj->Set($sAttCode, $value); } } } } } }
/** * Helper function to load the objects from a standard XML file into the database * @param $sFilePath string The full path to the XML file to load * @param $bUpdateKeyCacheOnly bool Set to true to *just* update the keys cache but not reload the objects */ function LoadFile($sFilePath, $bUpdateKeyCacheOnly = false) { global $aKeys; $oXml = simplexml_load_file($sFilePath); $aReplicas = array(); foreach ($oXml as $sClass => $oXmlObj) { if (!MetaModel::IsValidClass($sClass)) { SetupPage::log_error("Unknown class - {$sClass}"); throw new Exception("Unknown class - {$sClass}"); } $iSrcId = (int) $oXmlObj['id']; // Mandatory to cast // Import algorithm // Here enumerate all the attributes of the object // for all attribute that is neither an external field // not an external key, assign it // Store all external keys for further reference // Create the object an store the correspondance between its newly created Id // and its original Id // Once all the objects have been created re-assign all the external keys to // their actual Ids $iExistingId = $this->GetObjectKey($sClass, $iSrcId); if ($iExistingId != 0) { $oTargetObj = MetaModel::GetObject($sClass, $iExistingId); } else { $oTargetObj = MetaModel::NewObject($sClass); } foreach ($oXmlObj as $sAttCode => $oSubNode) { if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) { $sMsg = "Unknown attribute code - {$sClass}/{$sAttCode}"; continue; // ignore silently... //SetupPage::log_error($sMsg); //throw(new Exception($sMsg)); } $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ($oAttDef->IsWritable() && $oAttDef->IsScalar()) { if ($oAttDef->IsExternalKey()) { if (substr(trim($oSubNode), 0, 6) == 'SELECT') { $sQuery = trim($oSubNode); $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sQuery)); $iMatches = $oSet->Count(); if ($iMatches == 1) { $oFoundObject = $oSet->Fetch(); $iExtKey = $oFoundObject->GetKey(); } else { $sMsg = "Ext key not reconcilied - {$sClass}/{$iSrcId} - {$sAttCode}: '" . $sQuery . "' - found {$iMatches} matche(s)"; SetupPage::log_error($sMsg); $this->m_aErrors[] = $sMsg; $iExtKey = 0; } } else { $iDstObj = (int) $oSubNode; // Attempt to find the object in the list of loaded objects $iExtKey = $this->GetObjectKey($oAttDef->GetTargetClass(), $iDstObj); if ($iExtKey == 0) { $iExtKey = -$iDstObj; // Convention: Unresolved keys are stored as negative ! $oTargetObj->RegisterAsDirty(); } // here we allow external keys to be invalid because we will resolve them later on... } //$oTargetObj->CheckValue($sAttCode, $iExtKey); $oTargetObj->Set($sAttCode, $iExtKey); } elseif ($oAttDef instanceof AttributeBlob) { $sMimeType = (string) $oSubNode->mimetype; $sFileName = (string) $oSubNode->filename; $data = base64_decode((string) $oSubNode->data); $oDoc = new ormDocument($data, $sMimeType, $sFileName); $oTargetObj->Set($sAttCode, $oDoc); } else { $value = (string) $oSubNode; if ($value == '') { $value = $oAttDef->GetNullValue(); } $res = $oTargetObj->CheckValue($sAttCode, $value); if ($res !== true) { // $res contains the error description $sMsg = "Value not allowed - {$sClass}/{$iSrcId} - {$sAttCode}: '" . $oSubNode . "' ; {$res}"; SetupPage::log_error($sMsg); $this->m_aErrors[] = $sMsg; } $oTargetObj->Set($sAttCode, $value); } } } $this->StoreObject($sClass, $oTargetObj, $iSrcId, $bUpdateKeyCacheOnly, $bUpdateKeyCacheOnly); } return true; }
/** * Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context * @param DBObject $oSourceObj * @param DBObjectSearch $oSearch */ protected function SetSearchDefaultFromContext($oSourceObj, &$oSearch) { $oAppContext = new ApplicationContext(); $sSrcClass = get_class($oSourceObj); $sDestClass = $oSearch->GetClass(); foreach ($oAppContext->GetNames() as $key) { // Find the value of the object corresponding to each 'context' parameter $aCallSpec = array($sSrcClass, 'MapContextParam'); $sAttCode = ''; if (is_callable($aCallSpec)) { $sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter } if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode)) { $oAttDef = MetaModel::GetAttributeDef($sSrcClass, $sAttCode); $defaultValue = $oSourceObj->Get($sAttCode); // Find the attcode for the same 'context' parameter in the destination class // and sets its value as the default value for the search condition $aCallSpec = array($sDestClass, 'MapContextParam'); $sAttCode = ''; if (is_callable($aCallSpec)) { $sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter } if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue)) { $oSearch->AddCondition($sAttCode, $defaultValue); } } } }
/** * Update the destination object with given values */ public function UpdateDestObject($aValues, $oChange, &$oStatLog) { try { if ($this->Get('dest_class') == '') { $this->SetLastError('No destination object to update'); $oStatLog->Inc('stats_nb_obj_obsoleted_errors'); } else { $oDestObj = MetaModel::GetObject($this->Get('dest_class'), $this->Get('dest_id')); foreach ($aValues as $sAttCode => $value) { if (!MetaModel::IsValidAttCode(get_class($oDestObj), $sAttCode)) { throw new Exception("Unknown attribute code '{$sAttCode}'"); } $oDestObj->Set($sAttCode, $value); } $this->Set('info_last_modified', date('Y-m-d H:i:s')); $oDestObj->DBUpdateTracked($oChange); $oStatLog->AddTrace("Replica marked as obsolete", $this); $oStatLog->Inc('stats_nb_obj_obsoleted'); } } catch (Exception $e) { $this->SetLastError('Unable to update the destination object: ', $e); $oStatLog->Inc('stats_nb_obj_obsoleted_errors'); } }
/** * Add a condition (restriction) to the current DBSearch on which the display block is based * taking into account the hierarchical keys for which the condition is based on the 'below' operator */ protected function AddCondition($sFilterCode, $condition, $sOpCode = null) { // Workaround to an issue revealed whenever a condition on org_id is applied twice (with a hierarchy of organizations) // Moreover, it keeps the query as simple as possible if (isset($this->m_aConditions[$sFilterCode]) && $condition == $this->m_aConditions[$sFilterCode]) { // Skip return; } $this->m_aConditions[$sFilterCode] = $condition; $sClass = $this->m_oFilter->GetClass(); $bConditionAdded = false; // If the condition is an external key with a class having a hierarchy, use a "below" criteria if (MetaModel::IsValidAttCode($sClass, $sFilterCode)) { $oAttDef = MetaModel::GetAttributeDef($sClass, $sFilterCode); if ($oAttDef->IsExternalKey()) { $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($oAttDef->GetTargetClass()); if ($sHierarchicalKeyCode !== false) { $oFilter = new DBObjectSearch($oAttDef->GetTargetClass()); if ($sOpCode == 'IN' && is_array($condition)) { $oFilter->AddConditionExpression(self::GetConditionIN($oFilter, 'id', $condition)); } else { $oFilter->AddCondition('id', $condition); } $oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass()); $oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default $this->m_oFilter->AddCondition_PointingTo($oHKFilter, $sFilterCode); $bConditionAdded = true; } else { if ($sOpCode == 'IN' && is_array($condition)) { $this->m_oFilter->AddConditionExpression(self::GetConditionIN($this->m_oFilter, $sFilterCode, $condition)); $bConditionAdded = true; } } } else { if ($sOpCode == 'IN' && is_array($condition)) { $this->m_oFilter->AddConditionExpression(self::GetConditionIN($this->m_oFilter, $sFilterCode, $condition)); $bConditionAdded = true; } } } // In all other cases, just add the condition directly if (!$bConditionAdded) { $this->m_oFilter->AddCondition($sFilterCode, $condition); // Use the default 'loose' operator } }
$oPage->add('<td> </td>'); $oPage->add('<td><input id="search_' . $index . '" type="checkbox" name="search_field[' . $index . ']" value="1" /></td>'); $oPage->add('<td>' . (isset($aData[$iStartLine][$index - 1]) ? htmlentities($aData[$iStartLine][$index - 1], ENT_QUOTES, 'UTF-8') : ' ') . '</td>'); $oPage->add('<td>' . (isset($aData[$iStartLine + 1][$index - 1]) ? htmlentities($aData[$iStartLine + 1][$index - 1], ENT_QUOTES, 'UTF-8') : ' ') . '</td>'); $oPage->add('</tr>'); $index++; } $oPage->add("</table>\n"); if (empty($sInitSearchField)) { // Propose a reconciliation scheme // $aReconciliationKeys = MetaModel::GetReconcKeys($sClassName); $aMoreReconciliationKeys = array(); // Store: key => void to automatically remove duplicates foreach ($aReconciliationKeys as $sAttCode) { if (!MetaModel::IsValidAttCode($sClassName, $sAttCode)) { continue; } $oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode); if ($oAttDef->IsExternalKey()) { // An external key is specified as a reconciliation key: this means that all the reconciliation // keys of this class are proposed to identify the target object $aMoreReconciliationKeys = array_merge($aMoreReconciliationKeys, GetMappingsForExtKey($sAttCode, $oAttDef, $bAdvanced)); } elseif ($oAttDef->IsExternalField()) { // An external field is specified as a reconciliation key, translate the field into a field on the target class // since external fields are not writable, and thus never appears in the mapping form $sKeyAttCode = $oAttDef->GetKeyAttCode(); $sTargetAttCode = $oAttDef->GetExtAttCode(); $aMoreReconciliationKeys[$sKeyAttCode . '->' . $sTargetAttCode] = ''; } }
public function IsValidAttCode($sClass, $sAttCode) { return MetaModel::IsValidAttCode($sClass, $sAttCode); }
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 GetForTemplate($sPlaceholderAttCode) { $ret = null; if (($iPos = strpos($sPlaceholderAttCode, '->')) !== false) { $sExtKeyAttCode = substr($sPlaceholderAttCode, 0, $iPos); $sRemoteAttCode = substr($sPlaceholderAttCode, $iPos + 2); if (!MetaModel::IsValidAttCode(get_class($this), $sExtKeyAttCode)) { throw new CoreException("Unknown attribute '{$sExtKeyAttCode}' for the class " . get_class($this)); } $oKeyAttDef = MetaModel::GetAttributeDef(get_class($this), $sExtKeyAttCode); if (!$oKeyAttDef instanceof AttributeExternalKey) { throw new CoreException("'{$sExtKeyAttCode}' is not an external key of the class " . get_class($this)); } $sRemoteClass = $oKeyAttDef->GetTargetClass(); $oRemoteObj = MetaModel::GetObject($sRemoteClass, $this->GetStrict($sExtKeyAttCode), false); if (is_null($oRemoteObj)) { $ret = Dict::S('UI:UndefinedObject'); } else { // Recurse $ret = $oRemoteObj->GetForTemplate($sRemoteAttCode); } } else { switch ($sPlaceholderAttCode) { case 'id': $ret = $this->GetKey(); break; case 'hyperlink()': $ret = $this->GetHyperlink('iTopStandardURLMaker', false); break; case 'hyperlink(portal)': $ret = $this->GetHyperlink('PortalURLMaker', false); break; case 'name()': $ret = $this->GetName(); break; default: if (preg_match('/^([^(]+)\\((.+)\\)$/', $sPlaceholderAttCode, $aMatches)) { $sVerb = $aMatches[1]; $sAttCode = $aMatches[2]; } else { $sVerb = ''; $sAttCode = $sPlaceholderAttCode; } $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode); $ret = $oAttDef->GetForTemplate($this->Get($sAttCode), $sVerb, $this); } } return $ret; }
/** * Describe (as a text string) the modifications corresponding to this change */ public function GetDescription() { $sResult = ''; $oTargetObjectClass = $this->Get('objclass'); $oTargetObjectKey = $this->Get('objkey'); $oTargetSearch = new DBObjectSearch($oTargetObjectClass); $oTargetSearch->AddCondition('id', $oTargetObjectKey, '='); $oMonoObjectSet = new DBObjectSet($oTargetSearch); if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES) { if (!MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) { return ''; } // Protects against renamed attributes... $oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode')); $sAttName = $oAttDef->GetLabel(); $sLinkClass = $oAttDef->GetLinkedClass(); $aLinkClasses = MetaModel::EnumChildClasses($sLinkClass, ENUM_CHILD_CLASSES_ALL); // Search for changes on the corresponding link // $oSearch = new DBObjectSearch('CMDBChangeOpSetAttribute'); $oSearch->AddCondition('change', $this->Get('change'), '='); $oSearch->AddCondition('objkey', $this->Get('link_id'), '='); if (count($aLinkClasses) == 1) { // Faster than the whole building of the expression below for just one value ?? $oSearch->AddCondition('objclass', $sLinkClass, '='); } else { $oField = new FieldExpression('objclass', $oSearch->GetClassAlias()); $sListExpr = '(' . implode(', ', CMDBSource::Quote($aLinkClasses)) . ')'; $sOQLCondition = $oField->Render() . " IN {$sListExpr}"; $oNewCondition = Expression::FromOQL($sOQLCondition); $oSearch->AddConditionExpression($oNewCondition); } $oSet = new DBObjectSet($oSearch); $aChanges = array(); while ($oChangeOp = $oSet->Fetch()) { $aChanges[] = $oChangeOp->GetDescription(); } if (count($aChanges) == 0) { return ''; } $sItemDesc = MetaModel::GetHyperLink($this->Get('item_class'), $this->Get('item_id')); $sResult = $sAttName . ' - '; $sResult .= Dict::Format('Change:LinkSet:Modified', $sItemDesc); $sResult .= ' : ' . implode(', ', $aChanges); } return $sResult; }
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; }
/** * Helper to link objects * * @param string sLinkAttCode * @param string sLinkedClass * @param array $aLinkList * @param DBObject oTargetObj * @param WebServiceResult oRes * * @return array List of objects that could not be found */ protected function AddLinkedObjects($sLinkAttCode, $sParamName, $sLinkedClass, $aLinkList, &$oTargetObj, &$oRes) { $oLinkAtt = MetaModel::GetAttributeDef(get_class($oTargetObj), $sLinkAttCode); $sLinkClass = $oLinkAtt->GetLinkedClass(); $sExtKeyToItem = $oLinkAtt->GetExtKeyToRemote(); $aItemsFound = array(); $aItemsNotFound = array(); if (is_null($aLinkList)) { return $aItemsNotFound; } foreach ($aLinkList as $aItemData) { if (!array_key_exists('class', $aItemData)) { $oRes->LogWarning("Parameter {$sParamName}: missing 'class' specification"); continue; // skip } $sTargetClass = $aItemData['class']; if (!MetaModel::IsValidClass($sTargetClass)) { $oRes->LogError("Parameter {$sParamName}: invalid class '{$sTargetClass}'"); continue; // skip } if (!MetaModel::IsParentClass($sLinkedClass, $sTargetClass)) { $oRes->LogError("Parameter {$sParamName}: '{$sTargetClass}' is not a child class of '{$sLinkedClass}'"); continue; // skip } $oReconFilter = new CMDBSearchFilter($sTargetClass); $aCIStringDesc = array(); foreach ($aItemData['search'] as $sAttCode => $value) { if (!MetaModel::IsValidFilterCode($sTargetClass, $sAttCode)) { $aCodes = array_keys(MetaModel::GetClassFilterDefs($sTargetClass)); $oRes->LogError("Parameter {$sParamName}: '{$sAttCode}' is not a valid filter code for class '{$sTargetClass}', expecting a value in {" . implode(', ', $aCodes) . "}"); continue 2; // skip the entire item } $aCIStringDesc[] = "{$sAttCode}: {$value}"; // The attribute is one of our reconciliation key $oReconFilter->AddCondition($sAttCode, $value, '='); } if (count($aCIStringDesc) == 1) { // take the last and unique value to describe the object $sItemDesc = $value; } else { // describe the object by the given keys $sItemDesc = $sTargetClass . '(' . implode('/', $aCIStringDesc) . ')'; } $oExtObjects = new CMDBObjectSet($oReconFilter); switch ($oExtObjects->Count()) { case 0: $oRes->LogWarning("Parameter {$sParamName}: object to link {$sLinkedClass} / {$sItemDesc} could not be found (searched: '" . $oReconFilter->ToOQL(true) . "')"); $aItemsNotFound[] = $sItemDesc; break; case 1: $aItemsFound[] = array('object' => $oExtObjects->Fetch(), 'link_values' => @$aItemData['link_values'], 'desc' => $sItemDesc); break; default: $oRes->LogWarning("Parameter {$sParamName}: Found " . $oExtObjects->Count() . " matches for item '{$sItemDesc}' (searched: '" . $oReconFilter->ToOQL(true) . "')"); $aItemsNotFound[] = $sItemDesc; } } if (count($aItemsFound) > 0) { $aLinks = array(); foreach ($aItemsFound as $aItemData) { $oLink = MetaModel::NewObject($sLinkClass); $oLink->Set($sExtKeyToItem, $aItemData['object']->GetKey()); foreach ($aItemData['link_values'] as $sKey => $value) { if (!MetaModel::IsValidAttCode($sLinkClass, $sKey)) { $oRes->LogWarning("Parameter {$sParamName}: Attaching item '" . $aItemData['desc'] . "', the attribute code '{$sKey}' is not valid ; check the class '{$sLinkClass}'"); } else { $oLink->Set($sKey, $value); } } $aLinks[] = $oLink; } $oImpactedInfraSet = DBObjectSet::FromArray($sLinkClass, $aLinks); $oTargetObj->Set($sLinkAttCode, $oImpactedInfraSet); } return $aItemsNotFound; }
/** * Interpret the Rest/Json value and get a valid attribute value * * @param string $sClass Name of the class * @param string $sAttCode Attribute code * @param mixed $value Depending on the type of attribute (a scalar, or search criteria, or list of related objects...) * @return mixed The value that can be used with DBObject::Set() * @throws Exception If the specification of the value is not valid. * @api */ public static function MakeValue($sClass, $sAttCode, $value) { try { if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) { throw new Exception("Unknown attribute"); } $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ($oAttDef instanceof AttributeExternalKey) { $oExtKeyObject = static::FindObjectFromKey($oAttDef->GetTargetClass(), $value, true); $value = $oExtKeyObject != null ? $oExtKeyObject->GetKey() : 0; } elseif ($oAttDef instanceof AttributeLinkedSet) { if (!is_array($value)) { throw new Exception("A link set must be defined by an array of objects"); } $sLnkClass = $oAttDef->GetLinkedClass(); $aLinks = array(); foreach ($value as $oValues) { $oLnk = static::MakeObjectFromFields($sLnkClass, $oValues); $aLinks[] = $oLnk; } $value = DBObjectSet::FromArray($sLnkClass, $aLinks); } else { $value = $oAttDef->FromJSONToValue($value); } } catch (Exception $e) { throw new Exception("{$sAttCode}: " . $e->getMessage(), $e->getCode()); } return $value; }
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; }
/** * Validate the parameters and create the ticket object (based on the page's POSTed parameters) * @param WebPage $oP The current web page for the output * @param Organization $oUserOrg The organization of the current user * @return void */ function DoCreateRequest($oP, $oUserOrg) { $aParameters = $oP->ReadAllParams(PORTAL_ALL_PARAMS . ',template_id'); $sTransactionId = utils::ReadPostedParam('transaction_id', ''); if (!utils::IsTransactionValid($sTransactionId)) { $oP->add("<h1>" . Dict::S('UI:Error:ObjectAlreadyCreated') . "</h1>\n"); //ShowOngoingTickets($oP); return; } // Validate the parameters // 1) ServiceCategory $oSearch = DBObjectSearch::FromOQL(PORTAL_VALIDATE_SERVICECATEGORY_QUERY); $oSearch->AllowAllData(); // In case the user has the rights on his org only $oSet = new CMDBObjectSet($oSearch, array(), array('id' => $aParameters['service_id'], 'org_id' => $oUserOrg->GetKey())); if ($oSet->Count() != 1) { // Invalid service for the current user ! throw new Exception("Invalid Service Category: id={$aParameters['service_id']} - count: " . $oSet->Count()); } $oServiceCategory = $oSet->Fetch(); // 2) Service Subcategory $oSearch = DBObjectSearch::FromOQL(PORTAL_VALIDATE_SERVICESUBCATEGORY_QUERY); RestrictSubcategories($oSearch); $oSearch->AllowAllData(); // In case the user has the rights on his org only $oSet = new CMDBObjectSet($oSearch, array(), array('service_id' => $aParameters['service_id'], 'id' => $aParameters['servicesubcategory_id'], 'org_id' => $oUserOrg->GetKey())); if ($oSet->Count() != 1) { // Invalid subcategory throw new Exception("Invalid ServiceSubcategory: id={$aParameters['servicesubcategory_id']} for service category " . $oServiceCategory->GetName() . "({$aParameters['service_id']}) - count: " . $oSet->Count()); } $oServiceSubCategory = $oSet->Fetch(); $sClass = ComputeClass($oServiceSubCategory->GetKey()); $oRequest = MetaModel::NewObject($sClass); $aAttList = array_merge(explode(',', GetConstant($sClass, 'FORM_ATTRIBUTES')), array('service_id', 'servicesubcategory_id')); $oRequest->UpdateObjectFromPostedForm('', $aAttList); $oRequest->Set('org_id', $oUserOrg->GetKey()); $oRequest->Set('caller_id', UserRights::GetContactId()); if (isset($aParameters['moreinfo'])) { // There is a template, insert it into the description $sLogAttCode = GetConstant($sClass, 'PUBLIC_LOG'); $oRequest->Set($sLogAttCode, $aParameters['moreinfo']); } $sTypeAttCode = GetConstant($sClass, 'TYPE'); if ($sTypeAttCode != '' && PORTAL_SET_TYPE_FROM != '') { $oRequest->Set($sTypeAttCode, $oServiceSubCategory->Get(PORTAL_SET_TYPE_FROM)); } if (MetaModel::IsValidAttCode($sClass, 'origin')) { $oRequest->Set('origin', 'portal'); } $oAttPlugin = new AttachmentPlugIn(); $oAttPlugin->OnFormSubmit($oRequest); list($bRes, $aIssues) = $oRequest->CheckToWrite(); if ($bRes) { if (isset($aParameters['template_id'])) { $oTemplate = MetaModel::GetObject('Template', $aParameters['template_id']); $sLogAttCode = GetConstant($sClass, 'PUBLIC_LOG'); $oRequest->Set($sLogAttCode, $oTemplate->GetPostedValuesAsText($oRequest) . "\n"); $oRequest->DBInsertNoReload(); $oTemplate->RecordExtraDataFromPostedForm($oRequest); } else { $oRequest->DBInsertNoReload(); } $oP->add("<h1>" . Dict::Format('UI:Title:Object_Of_Class_Created', $oRequest->GetName(), MetaModel::GetName($sClass)) . "</h1>\n"); //DisplayObject($oP, $oRequest, $oUserOrg); ShowOngoingTickets($oP); } else { RequestCreationForm($oP, $oUserOrg); $sIssueDesc = Dict::Format('UI:ObjectCouldNotBeWritten', implode(', ', $aIssues)); $oP->add_ready_script("alert('" . addslashes($sIssueDesc) . "');"); } }
protected function DisplaySearchField($sClass, $sAttSpec, $aExtraParams, $sPrefix, $sFieldName = null, $aFilterParams = array()) { if (is_null($sFieldName)) { $sFieldName = str_replace('->', PARAM_ARROW_SEP, $sAttSpec); } $iPos = strpos($sAttSpec, '->'); if ($iPos !== false) { $sAttCode = substr($sAttSpec, 0, $iPos); $sSubSpec = substr($sAttSpec, $iPos + 2); if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) { throw new Exception("Invalid attribute code '{$sClass}/{$sAttCode}' in search specification '{$sAttSpec}'"); } $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ($oAttDef->IsLinkSet()) { $sTargetClass = $oAttDef->GetLinkedClass(); } elseif ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) { $sTargetClass = $oAttDef->GetTargetClass(EXTKEY_ABSOLUTE); } else { throw new Exception("Attribute specification '{$sAttSpec}', '{$sAttCode}' should be either a link set or an external key"); } $this->DisplaySearchField($sTargetClass, $sSubSpec, $aExtraParams, $sPrefix, $sFieldName, $aFilterParams); } else { // $sAttSpec is an attribute code // $this->add('<span style="white-space: nowrap;padding:5px;display:inline-block;">'); $sFilterValue = ''; $sFilterValue = utils::ReadParam($sPrefix . $sFieldName, '', false, 'raw_data'); $sFilterOpCode = null; // Use the default 'loose' OpCode $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttSpec); if ($oAttDef->IsExternalKey()) { $sTargetClass = $oAttDef->GetTargetClass(); $sFilterDefName = 'PORTAL_TICKETS_SEARCH_FILTER_' . $sAttSpec; if (defined($sFilterDefName)) { try { $oFitlerWithParams = DBObjectSearch::FromOQL(constant($sFilterDefName)); $sFilterOQL = $oFitlerWithParams->ToOQL(true, $aFilterParams); $oAllowedValues = new DBObjectSet(DBObjectSearch::FromOQL($sFilterOQL), array(), $aFilterParams); } catch (OQLException $e) { throw new Exception("Incorrect filter '{$sFilterDefName}' for attribute '{$sAttcode}': " . $e->getMessage()); } } else { $oAllowedValues = new DBObjectSet(new DBObjectSearch($sTargetClass)); } $iFieldSize = $oAttDef->GetMaxSize(); $iMaxComboLength = $oAttDef->GetMaximumComboLength(); $this->add("<label>" . MetaModel::GetFilterLabel($sClass, $sAttSpec) . ":</label> "); //$oWidget = UIExtKeyWidget::DIsplayFromAttCode($sAttSpec, $sClass, $oAttDef->GetLabel(), $oAllowedValues, $sFilterValue, $sPrefix.$sFieldName, false, '', $sPrefix, ''); //$this->add($oWidget->Display($this, $aExtraParams, true /* bSearchMode */)); $aExtKeyParams = $aExtraParams; $aExtKeyParams['iFieldSize'] = $oAttDef->GetMaxSize(); $aExtKeyParams['iMinChars'] = $oAttDef->GetMinAutoCompleteChars(); // DisplayFromAttCode($this, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false) $sHtml = UIExtKeyWidget::DisplayFromAttCode($this, $sAttSpec, $sClass, $oAttDef->GetLabel(), $oAllowedValues, $sFilterValue, $sPrefix . $sFieldName, false, $sPrefix . $sFieldName, $sPrefix, $aExtKeyParams, true); $this->add($sHtml); } else { $aAllowedValues = MetaModel::GetAllowedValues_flt($sClass, $sAttSpec, $aExtraParams); if (is_null($aAllowedValues)) { // Any value is possible, display an input box $sSanitizedValue = htmlentities($sFilterValue, ENT_QUOTES, 'UTF-8'); $this->add("<label>" . MetaModel::GetFilterLabel($sClass, $sAttSpec) . ":</label> <input class=\"textSearch\" name=\"{$sPrefix}{$sFieldName}\" value=\"{$sSanitizedValue}\"/>\n"); } else { //Enum field or external key, display a combo $sValue = "<select name=\"{$sPrefix}{$sFieldName}\">\n"; $sValue .= "<option value=\"\">" . Dict::S('UI:SearchValue:Any') . "</option>\n"; foreach ($aAllowedValues as $key => $value) { if ($sFilterValue == $key) { $sSelected = ' selected'; } else { $sSelected = ''; } $sValue .= "<option value=\"{$key}\"{$sSelected}>{$value}</option>\n"; } $sValue .= "</select>\n"; $this->add("<label>" . MetaModel::GetFilterLabel($sClass, $sAttSpec) . ":</label> {$sValue}\n"); } } unset($aExtraParams[$sFieldName]); $this->add('</span> '); $sTip = $oAttDef->GetHelpOnSmartSearch(); if (strlen($sTip) > 0) { $sTip = addslashes($sTip); $sTip = str_replace(array("\n", "\r"), " ", $sTip); // :input does represent in form visible input (INPUT, SELECT, TEXTAREA) $this->add_ready_script("\$(':input[name={$sPrefix}{$sFieldName}]').qtip( { content: '{$sTip}', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );"); } } }
public function CheckProjectionSpec($oProjectionSpec, $sProjectedClass) { $sExpression = $oProjectionSpec->Get('value'); $sAttribute = $oProjectionSpec->Get('attribute'); // Shortcut: "any value" or "no value" means no projection if (empty($sExpression)) { return; } if ($sExpression == '<any>') { return; } // 1st - compute the data type for the dimension // $sType = $this->Get('type'); if (MetaModel::IsValidClass($sType)) { $sExpectedType = $sType; } else { $sExpectedType = '_scalar_'; } // 2nd - compute the data type for the projection // $sTargetClass = ''; if ($sExpression == '<this>' || $sExpression == '<user>') { $sTargetClass = $sProjectedClass; } elseif ($sExpression == '<any>') { $sTargetClass = ''; } else { // Evaluate wether it is a constant or not try { $oObjectSearch = DBObjectSearch::FromOQL_AllData($sExpression); $sTargetClass = $oObjectSearch->GetClass(); } catch (OqlException $e) { } } if (empty($sTargetClass)) { $sFoundType = '_void_'; } else { if (empty($sAttribute)) { $sFoundType = $sTargetClass; } else { if (!MetaModel::IsValidAttCode($sTargetClass, $sAttribute)) { throw new CoreException('Unkown attribute code in projection specification', array('found' => $sAttribute, 'expecting' => MetaModel::GetAttributesList($sTargetClass), 'class' => $sTargetClass, 'projection' => $oProjectionSpec)); } $oAttDef = MetaModel::GetAttributeDef($sTargetClass, $sAttribute); if ($oAttDef->IsExternalKey()) { $sFoundType = $oAttDef->GetTargetClass(); } else { $sFoundType = '_scalar_'; } } } // Compare the dimension type and projection type if ($sFoundType != '_void_' && $sFoundType != $sExpectedType) { throw new CoreException('Wrong type in projection specification', array('found' => $sFoundType, 'expecting' => $sExpectedType, 'expression' => $sExpression, 'attribute' => $sAttribute, 'projection' => $oProjectionSpec)); } }