123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747 |
- <?php
- // Copyright (C) 2010-2015 Combodo SARL
- //
- // This file is part of iTop.
- //
- // iTop is free software; you can redistribute it and/or modify
- // it under the terms of the GNU Affero General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // iTop is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Affero General Public License for more details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with iTop. If not, see <http://www.gnu.org/licenses/>
- /**
- * Classes defined for lexical analyze (see oql-parser.y)
- *
- * @copyright Copyright (C) 2010-2015 Combodo SARL
- * @license http://opensource.org/licenses/AGPL-3.0
- */
- define('TREE_OPERATOR_EQUALS', 0);
- define('TREE_OPERATOR_BELOW', 1);
- define('TREE_OPERATOR_BELOW_STRICT', 2);
- define('TREE_OPERATOR_NOT_BELOW', 3);
- define('TREE_OPERATOR_NOT_BELOW_STRICT', 4);
- define('TREE_OPERATOR_ABOVE', 5);
- define('TREE_OPERATOR_ABOVE_STRICT', 6);
- define('TREE_OPERATOR_NOT_ABOVE', 7);
- define('TREE_OPERATOR_NOT_ABOVE_STRICT', 8);
- // Position a string within an OQL query
- // This is a must if we want to be able to pinpoint an error at any stage of the query interpretation
- // In particular, the normalization phase requires this
- class OqlName
- {
- protected $m_sValue;
- protected $m_iPos;
- public function __construct($sValue, $iPos)
- {
- $this->m_iPos = $iPos;
- $this->m_sValue = $sValue;
- }
- public function GetValue()
- {
- return $this->m_sValue;
- }
- public function GetPos()
- {
- return $this->m_iPos;
- }
-
- public function __toString()
- {
- return $this->m_sValue;
- }
- }
- /**
- *
- * Store hexadecimal values as strings so that we can support 64-bit values
- *
- */
- class OqlHexValue
- {
- protected $m_sValue;
- public function __construct($sValue)
- {
- $this->m_sValue = $sValue;
- }
-
- public function __toString()
- {
- return $this->m_sValue;
- }
-
- }
- class OqlJoinSpec
- {
- protected $m_oClass;
- protected $m_oClassAlias;
- protected $m_oLeftField;
- protected $m_oRightField;
- protected $m_sOperator;
- protected $m_oNextJoinspec;
- public function __construct($oClass, $oClassAlias, BinaryExpression $oExpression)
- {
- $this->m_oClass = $oClass;
- $this->m_oClassAlias = $oClassAlias;
- $this->m_oLeftField = $oExpression->GetLeftExpr();
- $this->m_oRightField = $oExpression->GetRightExpr();
- $this->m_oRightField = $oExpression->GetRightExpr();
- $this->m_sOperator = $oExpression->GetOperator();
- }
- public function GetClass()
- {
- return $this->m_oClass->GetValue();
- }
- public function GetClassAlias()
- {
- return $this->m_oClassAlias->GetValue();
- }
- public function GetClassDetails()
- {
- return $this->m_oClass;
- }
- public function GetClassAliasDetails()
- {
- return $this->m_oClassAlias;
- }
- public function GetLeftField()
- {
- return $this->m_oLeftField;
- }
- public function GetRightField()
- {
- return $this->m_oRightField;
- }
- public function GetOperator()
- {
- return $this->m_sOperator;
- }
- }
- interface CheckableExpression
- {
- /**
- * Check the validity of the expression with regard to the data model
- * and the query in which it is used
- *
- * @param ModelReflection $oModelReflection MetaModel to consider
- * @param array $aAliases Aliases to class names (for the current query)
- * @param string $sSourceQuery For the reporting
- * @throws OqlNormalizeException
- */
- public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery);
- }
- class BinaryOqlExpression extends BinaryExpression implements CheckableExpression
- {
- public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
- {
- $this->m_oLeftExpr->Check($oModelReflection, $aAliases, $sSourceQuery);
- $this->m_oRightExpr->Check($oModelReflection, $aAliases, $sSourceQuery);
- }
- }
- class ScalarOqlExpression extends ScalarExpression implements CheckableExpression
- {
- public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
- {
- // a scalar is always fine
- }
- }
- class FieldOqlExpression extends FieldExpression implements CheckableExpression
- {
- protected $m_oParent;
- protected $m_oName;
- public function __construct($oName, $oParent = null)
- {
- if (is_null($oParent))
- {
- $oParent = new OqlName('', 0);
- }
- $this->m_oParent = $oParent;
- $this->m_oName = $oName;
- parent::__construct($oName->GetValue(), $oParent->GetValue());
- }
- public function GetParentDetails()
- {
- return $this->m_oParent;
- }
- public function GetNameDetails()
- {
- return $this->m_oName;
- }
- public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
- {
- $sClassAlias = $this->GetParent();
- $sFltCode = $this->GetName();
- if (empty($sClassAlias))
- {
- // Try to find an alias
- // Build an array of field => array of aliases
- $aFieldClasses = array();
- foreach($aAliases as $sAlias => $sReal)
- {
- foreach($oModelReflection->GetFiltersList($sReal) as $sAnFltCode)
- {
- $aFieldClasses[$sAnFltCode][] = $sAlias;
- }
- }
- if (!array_key_exists($sFltCode, $aFieldClasses))
- {
- throw new OqlNormalizeException('Unknown filter code', $sSourceQuery, $this->GetNameDetails(), array_keys($aFieldClasses));
- }
- if (count($aFieldClasses[$sFltCode]) > 1)
- {
- throw new OqlNormalizeException('Ambiguous filter code', $sSourceQuery, $this->GetNameDetails());
- }
- $sClassAlias = $aFieldClasses[$sFltCode][0];
- }
- else
- {
- if (!array_key_exists($sClassAlias, $aAliases))
- {
- throw new OqlNormalizeException('Unknown class [alias]', $sSourceQuery, $this->GetParentDetails(), array_keys($aAliases));
- }
- $sClass = $aAliases[$sClassAlias];
- if (!$oModelReflection->IsValidFilterCode($sClass, $sFltCode))
- {
- throw new OqlNormalizeException('Unknown filter code', $sSourceQuery, $this->GetNameDetails(), $oModelReflection->GetFiltersList($sClass));
- }
- }
- }
- }
- class VariableOqlExpression extends VariableExpression implements CheckableExpression
- {
- public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
- {
- // a scalar is always fine
- }
- }
- class ListOqlExpression extends ListExpression implements CheckableExpression
- {
- public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
- {
- foreach ($this->GetItems() as $oItemExpression)
- {
- $oItemExpression->Check($oModelReflection, $aAliases, $sSourceQuery);
- }
- }
- }
- class FunctionOqlExpression extends FunctionExpression implements CheckableExpression
- {
- public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
- {
- foreach ($this->GetArgs() as $oArgExpression)
- {
- $oArgExpression->Check($oModelReflection, $aAliases, $sSourceQuery);
- }
- }
- }
- class IntervalOqlExpression extends IntervalExpression implements CheckableExpression
- {
- public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
- {
- // an interval is always fine (made of a scalar and unit)
- }
- }
- abstract class OqlQuery
- {
- public function __construct()
- {
- }
- /**
- * Check the validity of the expression with regard to the data model
- * and the query in which it is used
- *
- * @param ModelReflection $oModelReflection MetaModel to consider
- * @throws OqlNormalizeException
- */
- abstract public function Check(ModelReflection $oModelReflection, $sSourceQuery);
- /**
- * Determine the class
- *
- * @param ModelReflection $oModelReflection MetaModel to consider
- * @return string
- * @throws Exception
- */
- abstract public function GetClass(ModelReflection $oModelReflection);
- /**
- * Determine the class alias
- *
- * @return string
- * @throws Exception
- */
- abstract public function GetClassAlias();
- }
- class OqlObjectQuery extends OqlQuery
- {
- protected $m_aSelect; // array of selected classes
- protected $m_oClass;
- protected $m_oClassAlias;
- protected $m_aJoins; // array of OqlJoinSpec
- protected $m_oCondition; // condition tree (expressions)
- public function __construct($oClass, $oClassAlias, $oCondition = null, $aJoins = null, $aSelect = null)
- {
- $this->m_aSelect = $aSelect;
- $this->m_oClass = $oClass;
- $this->m_oClassAlias = $oClassAlias;
- $this->m_aJoins = $aJoins;
- $this->m_oCondition = $oCondition;
- parent::__construct();
- }
- public function GetSelectedClasses()
- {
- return $this->m_aSelect;
- }
- /**
- * Determine the class
- *
- * @param ModelReflection $oModelReflection MetaModel to consider
- * @return string
- * @throws Exception
- */
- public function GetClass(ModelReflection $oModelReflection)
- {
- return $this->m_oClass->GetValue();
- }
- /**
- * Determine the class alias
- *
- * @return string
- * @throws Exception
- */
- public function GetClassAlias()
- {
- return $this->m_oClassAlias->GetValue();
- }
- public function GetClassDetails()
- {
- return $this->m_oClass;
- }
- public function GetClassAliasDetails()
- {
- return $this->m_oClassAlias;
- }
- public function GetJoins()
- {
- return $this->m_aJoins;
- }
- public function GetCondition()
- {
- return $this->m_oCondition;
- }
- /**
- * Recursively check the validity of the expression with regard to the data model
- * and the query in which it is used
- *
- * @param ModelReflection $oModelReflection MetaModel to consider
- * @throws OqlNormalizeException
- */
- public function Check(ModelReflection $oModelReflection, $sSourceQuery)
- {
- $sClass = $this->GetClass($oModelReflection);
- $sClassAlias = $this->GetClassAlias();
- if (!$oModelReflection->IsValidClass($sClass))
- {
- throw new UnknownClassOqlException($sSourceQuery, $this->GetClassDetails(), $oModelReflection->GetClasses());
- }
- $aAliases = array($sClassAlias => $sClass);
- $aJoinSpecs = $this->GetJoins();
- if (is_array($aJoinSpecs))
- {
- foreach ($aJoinSpecs as $oJoinSpec)
- {
- $sJoinClass = $oJoinSpec->GetClass();
- $sJoinClassAlias = $oJoinSpec->GetClassAlias();
- if (!$oModelReflection->IsValidClass($sJoinClass))
- {
- throw new UnknownClassOqlException($sSourceQuery, $oJoinSpec->GetClassDetails(), $oModelReflection->GetClasses());
- }
- if (array_key_exists($sJoinClassAlias, $aAliases))
- {
- if ($sJoinClassAlias != $sJoinClass)
- {
- throw new OqlNormalizeException('Duplicate class alias', $sSourceQuery, $oJoinSpec->GetClassAliasDetails());
- }
- else
- {
- throw new OqlNormalizeException('Duplicate class name', $sSourceQuery, $oJoinSpec->GetClassDetails());
- }
- }
- // 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();
- $sPKeyDescriptor = $oRightField->GetName();
- if ($sPKeyDescriptor != 'id')
- {
- throw new OqlNormalizeException('Wrong format for Join clause (right hand), expecting an id', $sSourceQuery, $oRightField->GetNameDetails(), array('id'));
- }
- $aAliases[$sJoinClassAlias] = $sJoinClass;
- if (!array_key_exists($sFromClass, $aAliases))
- {
- throw new OqlNormalizeException('Unknown class in join condition (left expression)', $sSourceQuery, $oLeftField->GetParentDetails(), array_keys($aAliases));
- }
- if (!array_key_exists($sToClass, $aAliases))
- {
- throw new OqlNormalizeException('Unknown class in join condition (right expression)', $sSourceQuery, $oRightField->GetParentDetails(), array_keys($aAliases));
- }
- $aExtKeys = $oModelReflection->ListAttributes($aAliases[$sFromClass], 'AttributeExternalKey');
- $aObjKeys = $oModelReflection->ListAttributes($aAliases[$sFromClass], 'AttributeObjectKey');
- $aAllKeys = array_merge($aExtKeys, $aObjKeys);
- if (!array_key_exists($sExtKeyAttCode, $aAllKeys))
- {
- throw new OqlNormalizeException('Unknown key in join condition (left expression)', $sSourceQuery, $oLeftField->GetNameDetails(), array_keys($aAllKeys));
- }
- if ($sFromClass == $sJoinClassAlias)
- {
- if (array_key_exists($sExtKeyAttCode, $aExtKeys)) // Skip that check for object keys
- {
- $sTargetClass = $oModelReflection->GetAttributeProperty($aAliases[$sFromClass], $sExtKeyAttCode, 'targetclass');
- if(!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass))
- {
- throw new OqlNormalizeException("The joined class ($aAliases[$sFromClass]) is not compatible with the external key, which is pointing to $sTargetClass", $sSourceQuery, $oLeftField->GetNameDetails());
- }
- }
- }
- 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;
- }
- if (array_key_exists($sExtKeyAttCode, $aExtKeys)) // Skip that check for object keys
- {
- $sTargetClass = $oModelReflection->GetAttributeProperty($aAliases[$sFromClass], $sExtKeyAttCode, 'targetclass');
- if(!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass))
- {
- throw new OqlNormalizeException("The joined class ($aAliases[$sToClass]) is not compatible with the external key, which is pointing to $sTargetClass", $sSourceQuery, $oLeftField->GetNameDetails());
- }
- }
- $aAttList = $oModelReflection->ListAttributes($aAliases[$sFromClass]);
- $sAttType = $aAttList[$sExtKeyAttCode];
- if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !is_subclass_of($sAttType, 'AttributeHierarchicalKey') && ($sAttType != 'AttributeHierarchicalKey'))
- {
- throw new OqlNormalizeException("The specified tree operator $sOperator is not applicable to the key", $sSourceQuery, $oLeftField->GetNameDetails());
- }
- }
- }
- }
- // Check the select information
- //
- foreach ($this->GetSelectedClasses() as $oClassDetails)
- {
- $sClassToSelect = $oClassDetails->GetValue();
- if (!array_key_exists($sClassToSelect, $aAliases))
- {
- throw new OqlNormalizeException('Unknown class [alias]', $sSourceQuery, $oClassDetails, array_keys($aAliases));
- }
- }
- // Check the condition tree
- //
- if ($this->m_oCondition instanceof Expression)
- {
- $this->m_oCondition->Check($oModelReflection, $aAliases, $sSourceQuery);
- }
- }
- /**
- * Make the relevant DBSearch instance (FromOQL)
- */
- public function ToDBSearch($sQuery)
- {
- $sClass = $this->GetClass(new ModelReflectionRuntime());
- $sClassAlias = $this->GetClassAlias();
- $oSearch = new DBObjectSearch($sClass, $sClassAlias);
- $oSearch->InitFromOqlQuery($this, $sQuery);
- return $oSearch;
- }
- }
- class OqlUnionQuery extends OqlQuery
- {
- protected $aQueries;
- public function __construct(OqlObjectQuery $oLeftQuery, OqlQuery $oRightQueryOrUnion)
- {
- $this->aQueries[] = $oLeftQuery;
- if ($oRightQueryOrUnion instanceof OqlUnionQuery)
- {
- foreach ($oRightQueryOrUnion->GetQueries() as $oSingleQuery)
- {
- $this->aQueries[] = $oSingleQuery;
- }
- }
- else
- {
- $this->aQueries[] = $oRightQueryOrUnion;
- }
- }
-
- public function GetQueries()
- {
- return $this->aQueries;
- }
- /**
- * Check the validity of the expression with regard to the data model
- * and the query in which it is used
- *
- * @param ModelReflection $oModelReflection MetaModel to consider
- * @throws OqlNormalizeException
- */
- public function Check(ModelReflection $oModelReflection, $sSourceQuery)
- {
- $aColumnToClasses = array();
- foreach ($this->aQueries as $iQuery => $oQuery)
- {
- $oQuery->Check($oModelReflection, $sSourceQuery);
- $aAliasToClass = array($oQuery->GetClassAlias() => $oQuery->GetClass($oModelReflection));
- $aJoinSpecs = $oQuery->GetJoins();
- if (is_array($aJoinSpecs))
- {
- foreach ($aJoinSpecs as $oJoinSpec)
- {
- $aAliasToClass[$oJoinSpec->GetClassAlias()] = $oJoinSpec->GetClass();
- }
- }
- $aSelectedClasses = $oQuery->GetSelectedClasses();
- if ($iQuery != 0)
- {
- if (count($aSelectedClasses) < count($aColumnToClasses))
- {
- $oLastClass = end($aSelectedClasses);
- throw new OqlNormalizeException('Too few selected classes in the subquery', $sSourceQuery, $oLastClass);
- }
- if (count($aSelectedClasses) > count($aColumnToClasses))
- {
- $oLastClass = end($aSelectedClasses);
- throw new OqlNormalizeException('Too many selected classes in the subquery', $sSourceQuery, $oLastClass);
- }
- }
- foreach ($aSelectedClasses as $iColumn => $oClassDetails)
- {
- $sAlias = $oClassDetails->GetValue();
- $sClass = $aAliasToClass[$sAlias];
- $aColumnToClasses[$iColumn][] = array(
- 'alias' => $sAlias,
- 'class' => $sClass,
- 'class_name' => $oClassDetails,
- );
- }
- }
- foreach ($aColumnToClasses as $iColumn => $aClasses)
- {
- foreach ($aClasses as $iQuery => $aData)
- {
- if ($iQuery == 0)
- {
- // Establish the reference
- $sRootClass = $oModelReflection->GetRootClass($aData['class']);
- }
- else
- {
- if ($oModelReflection->GetRootClass($aData['class']) != $sRootClass)
- {
- $aSubclasses = $oModelReflection->EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_ALL);
- throw new OqlNormalizeException('Incompatible classes: could not find a common ancestor', $sSourceQuery, $aData['class_name'], $aSubclasses);
- }
- }
- }
- }
- }
- /**
- * Determine the class
- *
- * @param ModelReflection $oModelReflection MetaModel to consider
- * @return string
- * @throws Exception
- */
- public function GetClass(ModelReflection $oModelReflection)
- {
- $aFirstColClasses = array();
- foreach ($this->aQueries as $iQuery => $oQuery)
- {
- $aFirstColClasses[] = $oQuery->GetClass($oModelReflection);
- }
- $sClass = self::GetLowestCommonAncestor($oModelReflection, $aFirstColClasses);
- if (is_null($sClass))
- {
- throw new Exception('Could not determine the class of the union query. This issue should have been detected earlier by calling OqlQuery::Check()');
- }
- return $sClass;
- }
- /**
- * Determine the class alias
- *
- * @return string
- * @throws Exception
- */
- public function GetClassAlias()
- {
- $sAlias = $this->aQueries[0]->GetClassAlias();
- return $sAlias;
- }
- /**
- * Check the validity of the expression with regard to the data model
- * and the query in which it is used
- *
- * @param ModelReflection $oModelReflection MetaModel to consider
- * @param array $aClasses Flat list of classes
- * @return string the lowest common ancestor amongst classes, null if none has been found
- * @throws Exception
- */
- public static function GetLowestCommonAncestor(ModelReflection $oModelReflection, $aClasses)
- {
- $sAncestor = null;
- foreach($aClasses as $sClass)
- {
- if (is_null($sAncestor))
- {
- // first loop
- $sAncestor = $sClass;
- }
- elseif ($sClass == $sAncestor)
- {
- // remains the same
- }
- elseif ($oModelReflection->GetRootClass($sClass) != $oModelReflection->GetRootClass($sAncestor))
- {
- $sAncestor = null;
- break;
- }
- else
- {
- $sAncestor = self::LowestCommonAncestor($oModelReflection, $sAncestor, $sClass);
- }
- }
- return $sAncestor;
- }
- /**
- * Note: assumes that class A and B have a common ancestor
- */
- protected static function LowestCommonAncestor(ModelReflection $oModelReflection, $sClassA, $sClassB)
- {
- if ($sClassA == $sClassB)
- {
- $sRet = $sClassA;
- }
- elseif (in_array($sClassA, $oModelReflection->EnumChildClasses($sClassB)))
- {
- $sRet = $sClassB;
- }
- elseif (in_array($sClassB, $oModelReflection->EnumChildClasses($sClassA)))
- {
- $sRet = $sClassA;
- }
- else
- {
- // Recurse
- $sRet = self::LowestCommonAncestor($oModelReflection, $sClassA, $oModelReflection->GetParentClass($sClassB));
- }
- return $sRet;
- }
- /**
- * Make the relevant DBSearch instance (FromOQL)
- */
- public function ToDBSearch($sQuery)
- {
- $aSearches = array();
- foreach ($this->aQueries as $oQuery)
- {
- $aSearches[] = $oQuery->ToDBSearch($sQuery);
- }
- $oSearch = new DBUnionSearch($aSearches);
- return $oSearch;
- }
- }
|