/** * 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); } } } } } }
/** * 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 } }
/** * Display the hierarchy of the 'target' class */ public function DisplayHierarchy(WebPage $oPage, $sFilter, $currValue, $oObj) { $sDialogTitle = addslashes(Dict::Format('UI:HierarchyOf_Class', MetaModel::GetName($this->sTargetClass))); $oPage->add('<div id="dlg_tree_' . $this->iId . '"><div class="wizContainer" style="vertical-align:top;"><div style="overflow:auto;background:#fff;margin-bottom:5px;" id="tree_' . $this->iId . '">'); $oPage->add('<table style="width:100%"><tr><td>'); if (is_null($sFilter)) { throw new Exception('Implementation: null value for allowed values definition'); } try { $oFilter = DBObjectSearch::FromOQL($sFilter); $oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode); $oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj)); } catch (MissingQueryArgument $e) { // When used in a search form the $this parameter may be missing, in this case return all possible values... // TODO check if we can improve this behavior... $sOQL = 'SELECT ' . $this->m_sTargetClass; $oFilter = DBObjectSearch::FromOQL($sOQL); $oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode); $oSet = new DBObjectSet($oFilter); } $sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass); $this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue); $oPage->add('</td></tr></table>'); $oPage->add('</div>'); $oPage->add("<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"" . Dict::S('UI:Button:Cancel') . "\" onClick=\"\$('#dlg_tree_{$this->iId}').dialog('close');\"> "); $oPage->add("<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"" . Dict::S('UI:Button:Ok') . "\" onClick=\"oACWidget_{$this->iId}.DoHKOk();\">"); $oPage->add('</div></div>'); $oPage->add_ready_script("\$('#tree_{$this->iId} ul').treeview();\n"); $oPage->add_ready_script("\$('#dlg_tree_{$this->iId}').dialog({ width: 'auto', height: 'auto', autoOpen: true, modal: true, title: '{$sDialogTitle}', resizeStop: oACWidget_{$this->iId}.OnHKResize, close: oACWidget_{$this->iId}.OnHKClose });\n"); }
/** * Applies the defined parameters into the SQL query * @return string the SQL query to execute */ public function BuildQuery() { $oAppContext = new ApplicationContext(); $sQuery = $this->m_sQuery; $sQuery = str_replace('$DB_PREFIX$', MetaModel::GetConfig()->GetDBSubname(), $sQuery); // put the tables DB prefix (if any) foreach ($this->m_aParams as $sName => $aParam) { if ($aParam['type'] == 'context') { $sSearchPattern = '/\\$CONDITION\\(' . $sName . ',([^\\)]+)\\)\\$/'; $value = $oAppContext->GetCurrentValue($aParam['mapping']); if (empty($value)) { $sSQLExpr = '(1)'; } else { // Special case for managing the hierarchy of organizations if ($aParam['mapping'] == 'org_id' && MetaModel::IsValidClass('Organization')) { $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization'); if ($sHierarchicalKeyCode != false) { // organizations are in hierarchy... gather all the orgs below the given one... $sOQL = "SELECT Organization AS node JOIN Organization AS root ON node.{$sHierarchicalKeyCode} BELOW root.id WHERE root.id = :value"; $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array(), array('value' => $value)); $aOrgIds = array(); while ($oOrg = $oSet->Fetch()) { $aOrgIds[] = $oOrg->GetKey(); } $sSQLExpr = '($1 IN(' . implode(',', $aOrgIds) . '))'; } else { $sSQLExpr = '($1 = ' . CMDBSource::Quote($value) . ')'; } } else { $sSQLExpr = '($1 = ' . CMDBSource::Quote($value) . ')'; } } $sQuery = preg_replace($sSearchPattern, $sSQLExpr, $sQuery); } } return $sQuery; }
/** * Read and cache organizations allowed to the given user * * @param oUser * @param sClass -not used here but can be used in overloads */ protected function GetUserOrgs($oUser, $sClass) { $iUser = $oUser->GetKey(); if (!array_key_exists($iUser, $this->m_aUserOrgs)) { $this->m_aUserOrgs[$iUser] = array(); $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization'); if ($sHierarchicalKeyCode !== false) { $sUserOrgQuery = 'SELECT UserOrg, Org FROM Organization AS Org JOIN Organization AS Root ON Org.' . $sHierarchicalKeyCode . ' BELOW Root.id JOIN URP_UserOrg AS UserOrg ON UserOrg.allowed_org_id = Root.id WHERE UserOrg.userid = :userid'; $oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData($sUserOrgQuery), array(), array('userid' => $iUser)); while ($aRow = $oUserOrgSet->FetchAssoc()) { $oUserOrg = $aRow['UserOrg']; $oOrg = $aRow['Org']; $this->m_aUserOrgs[$iUser][] = $oOrg->GetKey(); } } else { $oSearch = new DBObjectSearch('URP_UserOrg'); $oSearch->AllowAllData(); $oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid')); $oSearch->AddConditionExpression($oCondition); $oUserOrgSet = new DBObjectSet($oSearch, array(), array('userid' => $iUser)); while ($oUserOrg = $oUserOrgSet->Fetch()) { $this->m_aUserOrgs[$iUser][] = $oUserOrg->Get('allowed_org_id'); } } } return $this->m_aUserOrgs[$iUser]; }
/** * ... */ public function MakeSelectFilter($sClass, $aAllowedOrgs, $aSettings = array(), $sAttCode = null) { if ($sAttCode == null) { $sAttCode = $this->GetOwnerOrganizationAttCode($sClass); } if (empty($sAttCode)) { return $oFilter = new DBObjectSearch($sClass); } $oExpression = new FieldExpression($sAttCode, $sClass); $oFilter = new DBObjectSearch($sClass); $oListExpr = ListExpression::FromScalars($aAllowedOrgs); $oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr); $oFilter->AddConditionExpression($oCondition); if ($this->HasSharing()) { if ($sAttCode == 'id' && isset($aSettings['bSearchMode']) && $aSettings['bSearchMode']) { // Querying organizations (or derived) // and the expected list of organizations will be used as a search criteria // Therefore the query can also return organization having objects shared with the allowed organizations // // 1) build the list of organizations sharing something with the allowed organizations // Organization <== sharing_org_id == SharedObject having org_id IN {user orgs} $oShareSearch = new DBObjectSearch('SharedObject'); $oOrgField = new FieldExpression('org_id', 'SharedObject'); $oShareSearch->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr)); $oSearchSharers = new DBObjectSearch('Organization'); $oSearchSharers->AllowAllData(); $oSearchSharers->AddCondition_ReferencedBy($oShareSearch, 'sharing_org_id'); $aSharers = array(); foreach ($oSearchSharers->ToDataArray(array('id')) as $aRow) { $aSharers[] = $aRow['id']; } // 2) Enlarge the overall results: ... OR id IN(id1, id2, id3) if (count($aSharers) > 0) { $oSharersList = ListExpression::FromScalars($aSharers); $oFilter->MergeConditionExpression(new BinaryExpression($oExpression, 'IN', $oSharersList)); } } $aShareProperties = SharedObject::GetSharedClassProperties($sClass); if ($aShareProperties) { $sShareClass = $aShareProperties['share_class']; $sShareAttCode = $aShareProperties['attcode']; $oSearchShares = new DBObjectSearch($sShareClass); $oSearchShares->AllowAllData(); $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization'); $oOrgField = new FieldExpression('org_id', $sShareClass); $oSearchShares->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr)); $aShared = array(); foreach ($oSearchShares->ToDataArray(array($sShareAttCode)) as $aRow) { $aShared[] = $aRow[$sShareAttCode]; } if (count($aShared) > 0) { $oObjId = new FieldExpression('id', $sClass); $oSharedIdList = ListExpression::FromScalars($aShared); $oFilter->MergeConditionExpression(new BinaryExpression($oObjId, 'IN', $oSharedIdList)); } } } // if HasSharing return $oFilter; }