Quellcode durchsuchen

Internal: dehardcoded OqlUnionQuery::GetClass against the metamodel reflection API

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@3836 a333f486-631f-4898-b8df-5754b55c2be0
romainq vor 9 Jahren
Ursprung
Commit
b5c84b99ca
2 geänderte Dateien mit 132 neuen und 5 gelöschten Zeilen
  1. 2 1
      core/dbobjectsearch.class.php
  2. 130 4
      core/oql/oqlquery.class.inc.php

+ 2 - 1
core/dbobjectsearch.class.php

@@ -922,7 +922,8 @@ class DBObjectSearch extends DBSearch
 
 	public function InitFromOqlQuery(OqlQuery $oOqlQuery, $sQuery)
 	{
-		$sClass = $oOqlQuery->GetClass();
+		$oModelReflection = new ModelReflectionRuntime();
+		$sClass = $oOqlQuery->GetClass($oModelReflection);
 		$sClassAlias = $oOqlQuery->GetClassAlias();
 
 		$aAliases = array($sClassAlias => $sClass);

+ 130 - 4
core/oql/oqlquery.class.inc.php

@@ -288,6 +288,23 @@ abstract class OqlQuery
 	 * @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
@@ -313,10 +330,25 @@ class OqlObjectQuery extends OqlQuery
 	{
 		return $this->m_aSelect;
 	}
-	public function GetClass()
+
+	/**
+	 * 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();
@@ -349,7 +381,7 @@ class OqlObjectQuery extends OqlQuery
 	 */	 	
 	public function Check(ModelReflection $oModelReflection, $sSourceQuery)
 	{
-		$sClass = $this->GetClass();
+		$sClass = $this->GetClass($oModelReflection);
 		$sClassAlias = $this->GetClassAlias();
 
 		if (!$oModelReflection->IsValidClass($sClass))
@@ -500,7 +532,7 @@ class OqlObjectQuery extends OqlQuery
 	 */	 	
 	public function ToDBSearch($sQuery)
 	{
-		$sClass = $this->GetClass();
+		$sClass = $this->GetClass(new ModelReflectionRuntime());
 		$sClassAlias = $this->GetClassAlias();
 
 		$oSearch = new DBObjectSearch($sClass, $sClassAlias);
@@ -548,7 +580,7 @@ class OqlUnionQuery extends OqlQuery
 		{
 			$oQuery->Check($oModelReflection, $sSourceQuery);
 
-			$aAliasToClass = array($oQuery->GetClassAlias() => $oQuery->GetClass());
+			$aAliasToClass = array($oQuery->GetClassAlias() => $oQuery->GetClass($oModelReflection));
 			$aJoinSpecs = $oQuery->GetJoins();
 			if (is_array($aJoinSpecs))
 			{
@@ -605,6 +637,100 @@ class OqlUnionQuery extends OqlQuery
 	}
 
 	/**
+	 * 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($sClassA)))
+		{
+			$sRet = $sClassB;
+		}
+		elseif (in_array($sClassB, $oModelReflection->EnumChildClasses($sClassB)))
+		{
+			$sRet = $sClassA;
+		}
+		else
+		{
+			// Recurse
+			$sRet = self::LowestCommonAncestor($oModelReflection, $sClassA, $oModelReflection->GetParentClass($sClassB));
+		}
+		return $sRet;
+	}
+	/**
 	 * Make the relevant DBSearch instance (FromOQL)
 	 */	 	
 	public function ToDBSearch($sQuery)