Browse Source

- Fixed the combination of the "PointingTo" conditions, especially when combining several "BELOW" conditions for the same criteria (used for security and context purposes)
- Make sure that the "security" limitiation provided by GetSelectFilter is applied only once to a given filter to avoid the creation of unneeded complex queries

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@1393 a333f486-631f-4898-b8df-5754b55c2be0

dflaven 14 years ago
parent
commit
f6c87e253b
2 changed files with 157 additions and 131 deletions
  1. 86 64
      core/dbobjectsearch.class.php
  2. 71 67
      core/metamodel.class.php

+ 86 - 64
core/dbobjectsearch.class.php

@@ -39,6 +39,7 @@ class DBObjectSearch
 	private $m_aPointingTo;
 	private $m_aReferencedBy;
 	private $m_aRelatedTo;
+	private $m_bDataFiltered;
 
 	// By default, some information may be hidden to the current user
 	// But it may happen that we need to disable that feature
@@ -59,10 +60,13 @@ class DBObjectSearch
 		$this->m_aPointingTo = array();
 		$this->m_aReferencedBy = array();
 		$this->m_aRelatedTo = array();
+		$this->m_bDataFiltered = false;
 	}
 
 	public function AllowAllData() {$this->m_bAllowAllData = true;}
 	public function IsAllDataAllowed() {return $this->m_bAllowAllData;}
+	public function IsDataFiltered() {return $this->m_bDataFiltered; }
+	public function SetDataFiltered() {$this->m_bDataFiltered = true;}
 
 	public function GetClassName($sAlias) {return $this->m_aClasses[$sAlias];}
 	public function GetJoinedClasses() {return $this->m_aClasses;}
@@ -247,10 +251,11 @@ class DBObjectSearch
 
 	protected function TransferConditionExpression($oFilter, $aTranslation)
 	{
-		$oTranslated = $oFilter->GetCriteria()->Translate($aTranslation, false, false /* leave unresolved fields */);
 //echo "<p>TransferConditionExpression:<br/>";
-//echo "Adding Conditions:<br/><pre>".print_r($oTranslated, true)."</pre>\n";
+//echo "Adding Conditions:<br/><pre>oFilter:\n".print_r($oFilter, true)."\naTranslation:\n".print_r($aTranslation, true)."</pre>\n";
 //echo "</p>";
+		$oTranslated = $oFilter->GetCriteria()->Translate($aTranslation, false, false /* leave unresolved fields */);
+//echo "Adding Conditions (translated):<br/><pre>".print_r($oTranslated, true)."</pre>\n";
 		$this->AddConditionExpression($oTranslated);
 		// #@# what about collisions in parameter names ???
 		$this->m_aParams = array_merge($this->m_aParams, $oFilter->m_aParams);
@@ -441,32 +446,38 @@ class DBObjectSearch
 		);
 	}
 	
-	protected function AddToNameSpace(&$aClassAliases, &$aAliasTranslation)
+	protected function AddToNameSpace(&$aClassAliases, &$aAliasTranslation, $bTranslateMainAlias = true)
 	{
-		$sOrigAlias = $this->GetClassAlias();
-		if (array_key_exists($sOrigAlias, $aClassAliases))
+		if ($bTranslateMainAlias)
 		{
-			$sNewAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $this->GetClass());
-//echo "<h1>Generating a new alias for $sOrigAlias (already used). It is now: $sNewAlias</h1>\n";
-			$this->m_aSelectedClasses[$sNewAlias] = $this->GetClass();
-			unset($this->m_aSelectedClasses[$sOrigAlias]);
-
-			$this->m_aClasses[$sNewAlias] = $this->GetClass();
-			unset($this->m_aClasses[$sOrigAlias]);
-
-			// Translate the condition expression with the new alias
-			$aAliasTranslation[$sOrigAlias]['*'] = $sNewAlias;
+			$sOrigAlias = $this->GetClassAlias();
+			if (array_key_exists($sOrigAlias, $aClassAliases))
+			{
+				$sNewAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $this->GetClass());
+//echo "<p>Generating a new alias for $sOrigAlias (already used). It is now: $sNewAlias</p>\n";
+				$this->m_aSelectedClasses[$sNewAlias] = $this->GetClass();
+				unset($this->m_aSelectedClasses[$sOrigAlias]);
+	
+				$this->m_aClasses[$sNewAlias] = $this->GetClass();
+				unset($this->m_aClasses[$sOrigAlias]);
+	
+				// Translate the condition expression with the new alias
+				$aAliasTranslation[$sOrigAlias]['*'] = $sNewAlias;
+			}
+	
+//echo "<p>Adding the alias ".$this->GetClass()." as ".$this->GetClassAlias()."</p>\n";
+			// add the alias into the filter aliases list
+			$aClassAliases[$this->GetClassAlias()] = $this->GetClass();
 		}
-
-//echo "<h1>Adding the alias for ".$this->GetClass().". as ".$this->GetClassAlias()."</h1>\n";
-		// add the alias into the filter aliases list
-		$aClassAliases[$this->GetClassAlias()] = $this->GetClass();
 		
 		foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
 		{
-			foreach($aPointingTo as $iOperatorCode => $oFilter)
+			foreach($aPointingTo as $iOperatorCode => $aFilter)
 			{
-				$oFilter->AddToNameSpace($aClassAliases, $aAliasTranslation);
+				foreach($aFilter as $sAlias => $oFilter)
+				{
+					$oFilter->AddToNameSpace($aClassAliases, $aAliasTranslation);
+				}
 			}
 		}
 
@@ -489,7 +500,7 @@ class DBObjectSearch
 
 	protected function AddCondition_PointingTo_InNameSpace(DBObjectSearch $oFilter, $sExtKeyAttCode, &$aClassAliases, &$aAliasTranslation, $iOperatorCode)
 	{
-//echo "<p style=\"color:green\">Calling: AddCondition_PointingTo_InNameSpace([".implode(',', $aClassAliases)."], [".implode(',', $aAliasTranslation)."]);</p>";
+//echo "<p style=\"color:green\">Calling: AddCondition_PointingTo_InNameSpace([<pre>".print_r($aClassAliases, true)."</pre></br>], [<pre>".print_r($aAliasTranslation, true)."</pre>]);</p>";
 		if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode))
 		{
 			throw new CoreWarning("The attribute code '$sExtKeyAttCode' is not an external key of the class '{$this->GetClass()}' - the condition will be ignored");
@@ -504,31 +515,36 @@ class DBObjectSearch
 			throw new CoreException("The specified tree operator $isOperatorCode is not applicable to the key '{$this->GetClass()}::$sExtKeyAttCode', which is not a HierarchicalKey");
 		}
 
+		$bSamePointingTo = false;
 		if (array_key_exists($sExtKeyAttCode, $this->m_aPointingTo))
 		{
 			if (array_key_exists($iOperatorCode, $this->m_aPointingTo[$sExtKeyAttCode]))
 			{
-				// Same ext key and same operator, merge the filters together
-				$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode]->MergeWith_InNamespace($oFilter, $aClassAliases, $aAliasTranslation);
-			}
-			else
-			{
-//echo "<p style=\"color:red\">Calling: AddToNameSpace([".implode(',', $aClassAliases)."], [".implode(',', $aAliasTranslation)."]);</p>";
-				$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation);
-	
-				$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode] = $oFilter;
+				if (array_key_exists($oFilter->GetClassAlias(), $this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode]))
+				{
+//echo "<p style=\"color:red\">[".__LINE__."]this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetFirstJoinedClassAlias()."]:<pre>\n".print_r($this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode], true)."</pre>;</p>";
+					$bSamePointingTo = true;
+				}
 			}
 		}
+
+//echo "<p style=\"color:red\">[".__LINE__."]Calling: AddToNameSpace([".implode(',', $aClassAliases)."], [".implode(',', $aAliasTranslation)."]);</p>";
+		if ($bSamePointingTo)
+		{
+//echo "<p style=\"color:red\">[".__LINE__."]AddPointingTo: Merging filters for [$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetClassAlias()."]</p>";
+			// Same ext key, alias and same operator, merge the filters together
+//			$sAlias = $oFilter->GetClassAlias();
+//echo "<p style=\"color:red\">[".__LINE__."]before: AddToNameSpace(aClassAliases[<pre>\n".print_r($aClassAliases, true)."</pre>], aAliasTranslation[<pre>\n".print_r($aAliasTranslation, true)."</pre>]);</p>";
+			$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation, true /* Don't translate the main alias */);
+//echo "<p style=\"color:blue\">[".__LINE__."]after: AddToNameSpace(aClassAliases[<pre>\n".print_r($aClassAliases, true)."</pre>], aAliasTranslation[<pre>\n".print_r($aAliasTranslation, true)."</pre>]);</p>";
+//			$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$sAlias]->MergeWith($oFilter, $aClassAliases, $aAliasTranslation);
+			$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$oFilter->GetClassAlias()] = $oFilter;
+		}
 		else
 		{
-//echo "<p style=\"color:red\">Calling: AddToNameSpace([".implode(',', $aClassAliases)."], [".implode(',', $aAliasTranslation)."]);</p>";
+//echo "<p style=\"color:red\">[".__LINE__."]AddPointingTo: Adding a new PointingTo filter for [$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetClassAlias()."]</p>";
 			$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 = clone $oFilter;
-			// $oNewFilter->ResetCondition();
-
-			$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode] = $oFilter;
+			$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$oFilter->GetClassAlias()] = $oFilter;
 		}
 	}
 
@@ -607,9 +623,12 @@ class DBObjectSearch
 
 		foreach($oFilter->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
 		{
-			foreach($aPointingTo as $iOperatorCode => $oExtFilter)
+			foreach($aPointingTo as $iOperatorCode => $aFilter)
 			{
-				$this->AddCondition_PointingTo_InNamespace($oExtFilter, $sExtKeyAttCode, $aClassAliases, $aAliasTranslation, $iOperatorCode);
+				foreach($aFilter as $sAlias => $oExtFilter)
+				{
+					$this->AddCondition_PointingTo_InNamespace($oExtFilter, $sExtKeyAttCode, $aClassAliases, $aAliasTranslation, $iOperatorCode);
+				}
 			}
 		}
 		foreach($oFilter->m_aReferencedBy as $sForeignClass => $aReferences)
@@ -797,33 +816,36 @@ class DBObjectSearch
 		$sRes = '';
 		foreach($this->m_aPointingTo as $sExtKey => $aPointingTo)
 		{
-			foreach($aPointingTo as $iOperatorCode => $oFilter)
+			foreach($aPointingTo as $iOperatorCode => $aFilter)
 			{
-				switch($iOperatorCode)
+				foreach($aFilter as $sAlias => $oFilter)
 				{
-					case TREE_OPERATOR_EQUALS:
-					$sOperator = ' = ';
-					break;
-					
-					case TREE_OPERATOR_BELOW:
-					$sOperator = ' BELOW ';
-					break;
-					
-					case TREE_OPERATOR_BELOW_STRICT:
-					$sOperator = ' BELOW STRICT ';
-					break;
-					
-					case TREE_OPERATOR_NOT_BELOW:
-					$sOperator = ' NOT BELOW ';
-					break;
-					
-					case TREE_OPERATOR_NOT_BELOW_STRICT:
-					$sOperator = ' NOT BELOW STRICT ';
-					break;
-					
+					switch($iOperatorCode)
+					{
+						case TREE_OPERATOR_EQUALS:
+						$sOperator = ' = ';
+						break;
+						
+						case TREE_OPERATOR_BELOW:
+						$sOperator = ' BELOW ';
+						break;
+						
+						case TREE_OPERATOR_BELOW_STRICT:
+						$sOperator = ' BELOW STRICT ';
+						break;
+						
+						case TREE_OPERATOR_NOT_BELOW:
+						$sOperator = ' NOT BELOW ';
+						break;
+						
+						case TREE_OPERATOR_NOT_BELOW_STRICT:
+						$sOperator = ' NOT BELOW STRICT ';
+						break;
+						
+					}
+					$sRes .= ' JOIN '.$oFilter->GetClass().' AS '.$oFilter->GetClassAlias().' ON '.$this->GetClassAlias().'.'.$sExtKey.$sOperator.$oFilter->GetClassAlias().'.id';
+					$sRes .= $oFilter->ToOQL_Joins();				
 				}
-				$sRes .= ' JOIN '.$oFilter->GetClass().' AS '.$oFilter->GetClassAlias().' ON '.$this->GetClassAlias().'.'.$sExtKey.$sOperator.$oFilter->GetClassAlias().'.id';
-				$sRes .= $oFilter->ToOQL_Joins();				
 			}
 		}
 		foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences)

+ 71 - 67
core/metamodel.class.php

@@ -1811,7 +1811,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
 	{
 		// Hide objects that are not visible to the current user
 		//
-		if (!$oFilter->IsAllDataAllowed())
+		if (!$oFilter->IsAllDataAllowed() && !$oFilter->IsDataFiltered())
 		{
 			$oVisibleObjects = UserRights::GetSelectFilter($oFilter->GetClass());
 			if ($oVisibleObjects === false)
@@ -1822,6 +1822,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
 			if (is_object($oVisibleObjects))
 			{
 				$oFilter->MergeWith($oVisibleObjects);
+				$oFilter->SetDataFiltered();
 			}
 			else
 			{
@@ -2423,7 +2424,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
 					$sKeyClassAlias = self::GenerateUniqueAlias($aClassAliases, $sKeyClass.'_'.$sKeyAttCode, $sKeyClass);
 					$oExtFilter = new DBObjectSearch($sKeyClass, $sKeyClassAlias);
 
-					$aAllPointingTo[$sKeyAttCode][TREE_OPERATOR_EQUALS] = $oExtFilter;
+					$aAllPointingTo[$sKeyAttCode][TREE_OPERATOR_EQUALS][$sKeyClassAlias] = $oExtFilter;
 				}
 			}
 		}
@@ -2431,94 +2432,97 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
 				
 		foreach ($aAllPointingTo as $sKeyAttCode => $aPointingTo)
 		{
-			foreach($aPointingTo as $iOperatorCode => $oExtFilter)
+			foreach($aPointingTo as $iOperatorCode => $aFilter)
 			{
-				if (!MetaModel::IsValidAttCode($sTableClass, $sKeyAttCode)) continue; // Not defined in the class, skip it
-				// The aliases should not conflict because normalization occured while building the filter
-				$oKeyAttDef = self::GetAttributeDef($sTableClass, $sKeyAttCode);
-				$sKeyClass =  $oExtFilter->GetFirstJoinedClass();
-				$sKeyClassAlias = $oExtFilter->GetFirstJoinedClassAlias();
+				foreach($aFilter as $sAlias => $oExtFilter)
+				{
+					if (!MetaModel::IsValidAttCode($sTableClass, $sKeyAttCode)) continue; // Not defined in the class, skip it
+					// The aliases should not conflict because normalization occured while building the filter
+					$oKeyAttDef = self::GetAttributeDef($sTableClass, $sKeyAttCode);
+					$sKeyClass =  $oExtFilter->GetFirstJoinedClass();
+					$sKeyClassAlias = $oExtFilter->GetFirstJoinedClassAlias();
 
 //echo "MAKEQUERY-$sTableClass::$sKeyAttCode Foreach PointingTo($iOperatorCode) <span style=\"color:red\">$sKeyClass (alias:$sKeyClassAlias)</span><br/>\n";
 				
-				// Note: there is no search condition in $oExtFilter, because normalization did merge the condition onto the top of the filter tree 
+					// Note: there is no search condition in $oExtFilter, because normalization did merge the condition onto the top of the filter tree 
 
-				if ($iOperatorCode == TREE_OPERATOR_EQUALS)
-				{
-					// Specify expected attributes for the target class query
-					// ... and use the current alias !
-					$aTranslateNow = array(); // Translation for external fields - must be performed before the join is done (recursion...)
-//echo "MAKEQUERY-array_key_exists($sTableClass, \$aExtKeys)<br/>\n";
-					if (array_key_exists($sTableClass, $aExtKeys) && array_key_exists($sKeyAttCode, $aExtKeys[$sTableClass]))
+					if ($iOperatorCode == TREE_OPERATOR_EQUALS)
 					{
-						foreach($aExtKeys[$sTableClass][$sKeyAttCode] as $sAttCode => $oAtt)
+						// Specify expected attributes for the target class query
+						// ... and use the current alias !
+						$aTranslateNow = array(); // Translation for external fields - must be performed before the join is done (recursion...)
+//echo "MAKEQUERY-array_key_exists($sTableClass, \$aExtKeys)<br/>\n";
+						if (array_key_exists($sTableClass, $aExtKeys) && array_key_exists($sKeyAttCode, $aExtKeys[$sTableClass]))
 						{
-//echo "MAKEQUERY aExtKeys[$sTableClass][$sKeyAttCode] => $sAttCode-oAtt: <pre>".print_r($oAtt, true)."</pre><br/>\n";
-							if ($oAtt instanceof AttributeFriendlyName)
+							foreach($aExtKeys[$sTableClass][$sKeyAttCode] as $sAttCode => $oAtt)
 							{
-								// Note: for a given ext key, there is one single attribute "friendly name"
-								$aTranslateNow[$sTargetAlias][$sAttCode] = new FieldExpression('friendlyname', $sKeyClassAlias);
+//echo "MAKEQUERY aExtKeys[$sTableClass][$sKeyAttCode] => $sAttCode-oAtt: <pre>".print_r($oAtt, true)."</pre><br/>\n";
+								if ($oAtt instanceof AttributeFriendlyName)
+								{
+									// Note: for a given ext key, there is one single attribute "friendly name"
+									$aTranslateNow[$sTargetAlias][$sAttCode] = new FieldExpression('friendlyname', $sKeyClassAlias);
 //echo "<p><b>aTranslateNow[$sTargetAlias][$sAttCode] = new FieldExpression('friendlyname', $sKeyClassAlias);</b></p>\n";
-							}
-							else
-							{
-								$sExtAttCode = $oAtt->GetExtAttCode();
-								// Translate mainclass.extfield => remoteclassalias.remotefieldcode
-								$oRemoteAttDef = self::GetAttributeDef($sKeyClass, $sExtAttCode);
-								foreach ($oRemoteAttDef->GetSQLExpressions() as $sColID => $sRemoteAttExpr)
+								}
+								else
 								{
-									$aTranslateNow[$sTargetAlias][$sAttCode.$sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias);
+									$sExtAttCode = $oAtt->GetExtAttCode();
+									// Translate mainclass.extfield => remoteclassalias.remotefieldcode
+									$oRemoteAttDef = self::GetAttributeDef($sKeyClass, $sExtAttCode);
+									foreach ($oRemoteAttDef->GetSQLExpressions() as $sColID => $sRemoteAttExpr)
+									{
+										$aTranslateNow[$sTargetAlias][$sAttCode.$sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias);
 //echo "<p><b>aTranslateNow[$sTargetAlias][$sAttCode.$sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias);</b></p>\n";
-								}
+									}
 //echo "<p><b>ExtAttr2: $sTargetAlias.$sAttCode to $sKeyClassAlias.$sRemoteAttExpr (class: $sKeyClass)</b></p>\n";
+								}
 							}
-						}
-						// Translate prior to recursing
-						//
+							// Translate prior to recursing
+							//
 //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."\n".print_r($aTranslateNow, true)."</pre></p>\n";
-						$oQBExpr->Translate($aTranslateNow, false);
+							$oQBExpr->Translate($aTranslateNow, false);
 //echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."</pre></p>\n";
 		
 //echo "<p>External key $sKeyAttCode (class: $sKeyClass), call MakeQuery()/p>\n";
-						self::DbgTrace("External key $sKeyAttCode (class: $sKeyClass), call MakeQuery()");
-						$oQBExpr->PushJoinField(new FieldExpression('id', $sKeyClassAlias));
-		
+							self::DbgTrace("External key $sKeyAttCode (class: $sKeyClass), call MakeQuery()");
+							$oQBExpr->PushJoinField(new FieldExpression('id', $sKeyClassAlias));
+			
 //echo "<p>Recursive MakeQuery ".__LINE__.": <pre>\n".print_r($aSelectedClasses, true)."</pre></p>\n";
+							$oSelectExtKey = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oExtFilter);
+			
+							$oJoinExpr = $oQBExpr->PopJoinField();
+							$sExternalKeyTable = $oJoinExpr->GetParent();
+							$sExternalKeyField = $oJoinExpr->GetName();
+			
+							$aCols = $oKeyAttDef->GetSQLExpressions(); // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc())
+							$sLocalKeyField = current($aCols); // get the first column for an external key
+			
+							self::DbgTrace("External key $sKeyAttCode, Join on $sLocalKeyField = $sExternalKeyField");
+							if ($oKeyAttDef->IsNullAllowed())
+							{
+								$oSelectBase->AddLeftJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable);
+							}
+							else
+							{
+								$oSelectBase->AddInnerJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable);
+							}
+						}
+					}
+					else
+					{
+						$oQBExpr->PushJoinField(new FieldExpression($sKeyAttCode, $sKeyClassAlias));
 						$oSelectExtKey = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oExtFilter);
-		
 						$oJoinExpr = $oQBExpr->PopJoinField();
+//echo "MAKEQUERY-PopJoinField pour $sKeyAttCode, $sKeyClassAlias: <pre>".print_r($oJoinExpr, true)."</pre><br/>\n";
 						$sExternalKeyTable = $oJoinExpr->GetParent();
 						$sExternalKeyField = $oJoinExpr->GetName();
-		
-						$aCols = $oKeyAttDef->GetSQLExpressions(); // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc())
-						$sLocalKeyField = current($aCols); // get the first column for an external key
-		
-						self::DbgTrace("External key $sKeyAttCode, Join on $sLocalKeyField = $sExternalKeyField");
-						if ($oKeyAttDef->IsNullAllowed())
-						{
-							$oSelectBase->AddLeftJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable);
-						}
-						else
-						{
-							$oSelectBase->AddInnerJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable);
-						}
-					}
-				}
-				else
-				{
-					$oQBExpr->PushJoinField(new FieldExpression($sKeyAttCode, $sKeyClassAlias));
-					$oSelectExtKey = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oExtFilter);
-					$oJoinExpr = $oQBExpr->PopJoinField();
-//echo "MAKEQUERY-PopJoinField pour $sKeyAttCode, $sKeyClassAlias: <pre>".print_r($oJoinExpr, true)."</pre><br/>\n";
-					$sExternalKeyTable = $oJoinExpr->GetParent();
-					$sExternalKeyField = $oJoinExpr->GetName();
-					$sLeftIndex = $sExternalKeyField.'_left'; // TODO use GetSQLLeft()
-					$sRightIndex = $sExternalKeyField.'_right'; // TODO use GetSQLRight()
-
-					$LocalKeyLeft = $oKeyAttDef->GetSQLLeft();
+						$sLeftIndex = $sExternalKeyField.'_left'; // TODO use GetSQLLeft()
+						$sRightIndex = $sExternalKeyField.'_right'; // TODO use GetSQLRight()
+	
+						$LocalKeyLeft = $oKeyAttDef->GetSQLLeft();
 //echo "MAKEQUERY-LocalKeyLeft pour $sKeyAttCode => $LocalKeyLeft<br/>\n";
-
-					$oSelectBase->AddInnerJoinTree($oSelectExtKey, $LocalKeyLeft, $sLeftIndex, $sRightIndex, $sExternalKeyTable, $iOperatorCode);
+	
+						$oSelectBase->AddInnerJoinTree($oSelectExtKey, $LocalKeyLeft, $sLeftIndex, $sRightIndex, $sExternalKeyTable, $iOperatorCode);
+					}
 				}
 			}
 		}