Пример #1
0
/**
 * Adds the context parameters to the audit query
 */
function FilterByContext(DBObjectSearch &$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);
                    }
                }
            }
        }
    }
}
 public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode)
 {
     $sForeignClass = $oFilter->GetClass();
     if (!MetaModel::IsValidKeyAttCode($sForeignClass, $sForeignExtKeyAttCode)) {
         throw new CoreException("The attribute code '{$sForeignExtKeyAttCode}' is not an external key of the class '{$sForeignClass}'");
     }
     $oAttExtKey = MetaModel::GetAttributeDef($sForeignClass, $sForeignExtKeyAttCode);
     if (!MetaModel::IsSameFamilyBranch($this->GetClass(), $oAttExtKey->GetTargetClass())) {
         // à refaire en spécifique dans FromOQL
         throw new CoreException("The specified filter (objects referencing an object of class {$this->GetClass()}) is not compatible with the key '{$sForeignClass}::{$sForeignExtKeyAttCode}', which is pointing to {$oAttExtKey->GetTargetClass()}");
     }
     // Note: though it seems to be a good practice to clone the given source filter
     //       (as it was done and fixed an issue in Intersect())
     //       this was not implemented here because it was causing a regression (login as admin, select an org, click on any badge)
     //       root cause: FromOQL relies on the fact that the passed filter can be modified later
     // NO: $oFilter = $oFilter->DeepClone();
     // See also: Trac #639, and self::AddCondition_PointingTo()
     $aAliasTranslation = array();
     $res = $this->AddCondition_ReferencedBy_InNameSpace($oFilter, $sForeignExtKeyAttCode, $this->m_aClasses, $aAliasTranslation);
     $this->TransferConditionExpression($oFilter, $aAliasTranslation);
     return $res;
 }
 protected function AddCondition_ReferencedBy_InNameSpace(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, &$aClassAliases, &$aAliasTranslation)
 {
     $sForeignClass = $oFilter->GetClass();
     // Find the node on which the new tree must be attached (most of the time it is "this")
     $oReceivingFilter = $this->GetNode($this->GetClassAlias());
     if (array_key_exists($sForeignClass, $this->m_aReferencedBy) && array_key_exists($sForeignExtKeyAttCode, $this->m_aReferencedBy[$sForeignClass])) {
         $oReceivingFilter->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode]->MergeWith_InNamespace($oFilter, $aClassAliases, $aAliasTranslation);
     } else {
         $oFilter->AddToNamespace($aClassAliases, $aAliasTranslation);
         // #@# The condition expression found in that filter should not be used - could be another kind of structure like a join spec tree !!!!
         //$oNewFilter = $oFilter->DeepClone();
         //$oNewFilter->ResetCondition();
         $oReceivingFilter->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode] = $oFilter;
     }
 }
 /**
  * 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);
             }
         }
     }
 }
Пример #5
0
 protected static function MakeSelectStructure(DBObjectSearch $oFilter, $aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null)
 {
     // Hide objects that are not visible to the current user
     //
     if (!$oFilter->IsAllDataAllowed() && !$oFilter->IsDataFiltered()) {
         $oVisibleObjects = UserRights::GetSelectFilter($oFilter->GetClass(), $oFilter->GetModifierProperties('UserRightsGetSelectFilter'));
         if ($oVisibleObjects === false) {
             // Make sure this is a valid search object, saying NO for all
             $oVisibleObjects = DBObjectSearch::FromEmptySet($oFilter->GetClass());
         }
         if (is_object($oVisibleObjects)) {
             $oFilter->MergeWith($oVisibleObjects);
             $oFilter->SetDataFiltered();
         } else {
             // should be true at this point, meaning that no additional filtering
             // is required
         }
     }
     // Compute query modifiers properties (can be set in the search itself, by the context, etc.)
     //
     $aModifierProperties = self::MakeModifierProperties($oFilter);
     // Create a unique cache id
     //
     if (self::$m_bQueryCacheEnabled || self::$m_bTraceQueries) {
         // Need to identify the query
         $sOqlQuery = $oFilter->ToOql();
         if (count($aModifierProperties)) {
             array_multisort($aModifierProperties);
             $sModifierProperties = json_encode($aModifierProperties);
         } else {
             $sModifierProperties = '';
         }
         $sRawId = $sOqlQuery . $sModifierProperties;
         if (!is_null($aAttToLoad)) {
             $sRawId .= json_encode($aAttToLoad);
         }
         if (!is_null($aGroupByExpr)) {
             foreach ($aGroupByExpr as $sAlias => $oExpr) {
                 $sRawId .= 'g:' . $sAlias . '!' . $oExpr->Render();
             }
         }
         $sRawId .= $bGetCount;
         $sOqlId = md5($sRawId);
     } else {
         $sOqlQuery = "SELECTING... " . $oFilter->GetClass();
         $sOqlId = "query id ? n/a";
     }
     // Query caching
     //
     if (self::$m_bQueryCacheEnabled) {
         // Warning: using directly the query string as the key to the hash array can FAIL if the string
         // is long and the differences are only near the end... so it's safer (but not bullet proof?)
         // to use a hash (like md5) of the string as the key !
         //
         // Example of two queries that were found as similar by the hash array:
         // SELECT SLT JOIN lnkSLTToSLA AS L1 ON L1.slt_id=SLT.id JOIN SLA ON L1.sla_id = SLA.id JOIN lnkContractToSLA AS L2 ON L2.sla_id = SLA.id JOIN CustomerContract ON L2.contract_id = CustomerContract.id WHERE SLT.ticket_priority = 1 AND SLA.service_id = 3 AND SLT.metric = 'TTO' AND CustomerContract.customer_id = 2
         // and
         // SELECT SLT JOIN lnkSLTToSLA AS L1 ON L1.slt_id=SLT.id JOIN SLA ON L1.sla_id = SLA.id JOIN lnkContractToSLA AS L2 ON L2.sla_id = SLA.id JOIN CustomerContract ON L2.contract_id = CustomerContract.id WHERE SLT.ticket_priority = 1 AND SLA.service_id = 3 AND SLT.metric = 'TTR' AND CustomerContract.customer_id = 2
         // the only difference is R instead or O at position 285 (TTR instead of TTO)...
         //
         if (array_key_exists($sOqlId, self::$m_aQueryStructCache)) {
             // hit!
             $oSelect = unserialize(serialize(self::$m_aQueryStructCache[$sOqlId]));
             // Note: cloning is not enough because the subtree is made of objects
         } elseif (self::$m_bUseAPCCache) {
             // Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
             //
             $sOqlAPCCacheId = 'itop-' . MetaModel::GetEnvironmentId() . '-query-cache-' . $sOqlId;
             $oKPI = new ExecutionKPI();
             $result = apc_fetch($sOqlAPCCacheId);
             $oKPI->ComputeStats('Query APC (fetch)', $sOqlQuery);
             if (is_object($result)) {
                 $oSelect = $result;
                 self::$m_aQueryStructCache[$sOqlId] = $oSelect;
             }
         }
     }
     if (!isset($oSelect)) {
         $oBuild = new QueryBuilderContext($oFilter, $aModifierProperties, $aGroupByExpr);
         $oKPI = new ExecutionKPI();
         $oSelect = self::MakeQuery($oBuild, $oFilter, $aAttToLoad, array(), true);
         $oSelect->SetCondition($oBuild->m_oQBExpressions->GetCondition());
         $oSelect->SetSourceOQL($sOqlQuery);
         if ($aGroupByExpr) {
             $aCols = $oBuild->m_oQBExpressions->GetGroupBy();
             $oSelect->SetGroupBy($aCols);
             $oSelect->SetSelect($aCols);
         } else {
             $oSelect->SetSelect($oBuild->m_oQBExpressions->GetSelect());
         }
         if (self::$m_bOptimizeQueries) {
             if ($bGetCount) {
                 // Simplify the query if just getting the count
                 $oSelect->SetSelect(array());
             }
             $oBuild->m_oQBExpressions->GetMandatoryTables($aMandatoryTables);
             $oSelect->OptimizeJoins($aMandatoryTables);
         }
         $oKPI->ComputeStats('MakeQuery (select)', $sOqlQuery);
         if (self::$m_bQueryCacheEnabled) {
             if (self::$m_bUseAPCCache) {
                 $oKPI = new ExecutionKPI();
                 apc_store($sOqlAPCCacheId, $oSelect, self::$m_iQueryCacheTTL);
                 $oKPI->ComputeStats('Query APC (store)', $sOqlQuery);
             }
             self::$m_aQueryStructCache[$sOqlId] = $oSelect->DeepClone();
         }
     }
     // Join to an additional table, if required...
     //
     if ($aExtendedDataSpec != null) {
         $sTableAlias = '_extended_data_';
         $aExtendedFields = array();
         foreach ($aExtendedDataSpec['fields'] as $sColumn) {
             $sColRef = $oFilter->GetClassAlias() . '_extdata_' . $sColumn;
             $aExtendedFields[$sColRef] = new FieldExpressionResolved($sColumn, $sTableAlias);
         }
         $oSelectExt = new SQLQuery($aExtendedDataSpec['table'], $sTableAlias, $aExtendedFields);
         $oSelect->AddInnerJoin($oSelectExt, 'id', $aExtendedDataSpec['join_key']);
     }
     return $oSelect;
 }