public static function FromOQL($sQuery, $aParams = null) { if (empty($sQuery)) { return null; } // Query caching $bOQLCacheEnabled = true; if ($bOQLCacheEnabled && array_key_exists($sQuery, self::$m_aOQLQueries)) { // hit! $oClone = self::$m_aOQLQueries[$sQuery]->DeepClone(); if (!is_null($aParams)) { $oClone->m_aParams = $aParams; } return $oClone; } $oOql = new OqlInterpreter($sQuery); $oOqlQuery = $oOql->ParseObjectQuery(); $oMetaModel = new ModelReflectionRuntime(); $oOqlQuery->Check($oMetaModel, $sQuery); // Exceptions thrown in case of issue $sClass = $oOqlQuery->GetClass(); $sClassAlias = $oOqlQuery->GetClassAlias(); $oResultFilter = new DBObjectSearch($sClass, $sClassAlias); $aAliases = array($sClassAlias => $sClass); // Maintain an array of filters, because the flat list is in fact referring to a tree // And this will be an easy way to dispatch the conditions // $oResultFilter will be referenced by the other filters, or the other way around... $aJoinItems = array($sClassAlias => $oResultFilter); $aJoinSpecs = $oOqlQuery->GetJoins(); if (is_array($aJoinSpecs)) { foreach ($aJoinSpecs as $oJoinSpec) { $sJoinClass = $oJoinSpec->GetClass(); $sJoinClassAlias = $oJoinSpec->GetClassAlias(); // Assumption: ext key on the left only !!! // normalization should take care of this $oLeftField = $oJoinSpec->GetLeftField(); $sFromClass = $oLeftField->GetParent(); $sExtKeyAttCode = $oLeftField->GetName(); $oRightField = $oJoinSpec->GetRightField(); $sToClass = $oRightField->GetParent(); $aAliases[$sJoinClassAlias] = $sJoinClass; $aJoinItems[$sJoinClassAlias] = new DBObjectSearch($sJoinClass, $sJoinClassAlias); if ($sFromClass == $sJoinClassAlias) { $oReceiver = $aJoinItems[$sToClass]; $oNewComer = $aJoinItems[$sFromClass]; $aAliasTranslation = array(); $oReceiver->AddCondition_ReferencedBy_InNameSpace($oNewComer, $sExtKeyAttCode, $oReceiver->m_aClasses, $aAliasTranslation); } else { $sOperator = $oJoinSpec->GetOperator(); switch ($sOperator) { case '=': $iOperatorCode = TREE_OPERATOR_EQUALS; break; case 'BELOW': $iOperatorCode = TREE_OPERATOR_BELOW; break; case 'BELOW_STRICT': $iOperatorCode = TREE_OPERATOR_BELOW_STRICT; break; case 'NOT_BELOW': $iOperatorCode = TREE_OPERATOR_NOT_BELOW; break; case 'NOT_BELOW_STRICT': $iOperatorCode = TREE_OPERATOR_NOT_BELOW_STRICT; break; case 'ABOVE': $iOperatorCode = TREE_OPERATOR_ABOVE; break; case 'ABOVE_STRICT': $iOperatorCode = TREE_OPERATOR_ABOVE_STRICT; break; case 'NOT_ABOVE': $iOperatorCode = TREE_OPERATOR_NOT_ABOVE; break; case 'NOT_ABOVE_STRICT': $iOperatorCode = TREE_OPERATOR_NOT_ABOVE_STRICT; break; } $oReceiver = $aJoinItems[$sFromClass]; $oNewComer = $aJoinItems[$sToClass]; $aAliasTranslation = array(); $oReceiver->AddCondition_PointingTo_InNameSpace($oNewComer, $sExtKeyAttCode, $oReceiver->m_aClasses, $aAliasTranslation, $iOperatorCode); } } } // Check and prepare the select information $aSelected = array(); foreach ($oOqlQuery->GetSelectedClasses() as $oClassDetails) { $sClassToSelect = $oClassDetails->GetValue(); $aSelected[$sClassToSelect] = $aAliases[$sClassToSelect]; } $oResultFilter->m_aClasses = $aAliases; $oResultFilter->SetSelectedClasses($aSelected); $oConditionTree = $oOqlQuery->GetCondition(); if ($oConditionTree instanceof Expression) { $oResultFilter->m_oSearchCondition = $oResultFilter->OQLExpressionToCondition($sQuery, $oConditionTree, $aAliases); } if (!is_null($aParams)) { $oResultFilter->m_aParams = $aParams; } if ($bOQLCacheEnabled) { self::$m_aOQLQueries[$sQuery] = $oResultFilter->DeepClone(); } return $oResultFilter; }