mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-12 23:14:18 +01:00
N°6085 - UNION is not supported in UserRightsProfile::GetSelectFilter
This commit is contained in:
@@ -1103,22 +1103,39 @@ class DBObjectSearch extends DBSearch
|
||||
public function Filter($sClassAlias, DBSearch $oFilter)
|
||||
{
|
||||
// If the conditions are the correct ones for Intersect
|
||||
if (MetaModel::IsParentClass($oFilter->GetFirstJoinedClass(),$this->GetFirstJoinedClass()))
|
||||
{
|
||||
if (MetaModel::IsParentClass($oFilter->GetFirstJoinedClass(), $this->GetFirstJoinedClass())) {
|
||||
return $this->Intersect($oFilter);
|
||||
}
|
||||
|
||||
/** @var \DBObjectSearch $oFilteredSearch */
|
||||
$oFilteredSearch = $this->DeepClone();
|
||||
$oFilterExpression = self::FilterSubClass($oFilteredSearch, $sClassAlias, $oFilter, $this->m_aClasses);
|
||||
if ($oFilterExpression === false)
|
||||
{
|
||||
throw new CoreException("Limitation: cannot filter search");
|
||||
if ($oFilter instanceof DBUnionSearch) {
|
||||
$aFilters = $oFilter->GetSearches();
|
||||
} else {
|
||||
$aFilters = [$oFilter];
|
||||
}
|
||||
|
||||
$oFilteredSearch->AddConditionExpression($oFilterExpression);
|
||||
$aSearches = [];
|
||||
foreach ($aFilters as $oRightFilter) {
|
||||
/** @var \DBObjectSearch $oFilteredSearch */
|
||||
$oFilteredSearch = $this->DeepClone();
|
||||
$oFilterExpression = self::FilterSubClass($oFilteredSearch, $sClassAlias, $oRightFilter, $this->m_aClasses);
|
||||
if ($oFilterExpression === false) {
|
||||
throw new CoreException("Limitation: cannot filter search");
|
||||
}
|
||||
|
||||
return $oFilteredSearch;
|
||||
$oFilteredSearch->AddConditionExpression($oFilterExpression);
|
||||
$aSearches[] = $oFilteredSearch;
|
||||
}
|
||||
|
||||
if (count($aSearches) == 0) {
|
||||
throw new CoreException('Filtering '.$this->ToOQL().' by '.$oFilter->ToOQL().' failed');
|
||||
}
|
||||
|
||||
if (count($aSearches) == 1) {
|
||||
// return a DBObjectSearch
|
||||
return $aSearches[0];
|
||||
}
|
||||
|
||||
return new DBUnionSearch($aSearches);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1184,22 +1201,10 @@ class DBObjectSearch extends DBSearch
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function Intersect(DBSearch $oFilter)
|
||||
{
|
||||
return $this->IntersectSubClass($oFilter, $this->m_aClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBSearch $oFilter
|
||||
* @param array $aRootClasses classes of the root search (for aliases)
|
||||
*
|
||||
* @return \DBUnionSearch|mixed
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function IntersectSubClass(DBSearch $oFilter, $aRootClasses)
|
||||
{
|
||||
if ($oFilter instanceof DBUnionSearch)
|
||||
{
|
||||
// Develop!
|
||||
// Develop!
|
||||
$aFilters = $oFilter->GetSearches();
|
||||
}
|
||||
else
|
||||
@@ -1210,56 +1215,61 @@ class DBObjectSearch extends DBSearch
|
||||
$aSearches = array();
|
||||
foreach ($aFilters as $oRightFilter)
|
||||
{
|
||||
// Limitation: the queried class must be the first declared class
|
||||
if ($oRightFilter->GetFirstJoinedClassAlias() != $oRightFilter->GetClassAlias())
|
||||
{
|
||||
throw new CoreException("Limitation: cannot merge two queries if the queried class ({$oRightFilter->GetClass()} AS {$oRightFilter->GetClassAlias()}) is not the first joined class ({$oRightFilter->GetFirstJoinedClass()} AS {$oRightFilter->GetFirstJoinedClassAlias()})");
|
||||
}
|
||||
|
||||
/** @var \DBObjectSearch $oLeftFilter */
|
||||
$oLeftFilter = $this->DeepClone();
|
||||
$oRightFilter = $oRightFilter->DeepClone();
|
||||
|
||||
$bAllowAllData = ($oLeftFilter->IsAllDataAllowed() && $oRightFilter->IsAllDataAllowed());
|
||||
if ($bAllowAllData)
|
||||
{
|
||||
$oLeftFilter->AllowAllData();
|
||||
}
|
||||
|
||||
if ($oLeftFilter->GetFirstJoinedClass() != $oRightFilter->GetClass())
|
||||
{
|
||||
if (MetaModel::IsParentClass($oLeftFilter->GetFirstJoinedClass(), $oRightFilter->GetClass()))
|
||||
{
|
||||
// Specialize $oLeftFilter
|
||||
$oLeftFilter->ChangeClass($oRightFilter->GetClass(), $oLeftFilter->GetFirstJoinedClassAlias());
|
||||
}
|
||||
elseif (MetaModel::IsParentClass($oRightFilter->GetFirstJoinedClass(), $oLeftFilter->GetClass()))
|
||||
{
|
||||
// Specialize $oRightFilter
|
||||
$oRightFilter->ChangeClass($oLeftFilter->GetFirstJoinedClass());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new CoreException("Attempting to merge a filter of class '{$oLeftFilter->GetClass()}' with a filter of class '{$oRightFilter->GetClass()}'");
|
||||
}
|
||||
}
|
||||
|
||||
$aAliasTranslation = array();
|
||||
$oLeftFilter->RenameNestedQueriesAliasesInNameSpace($aRootClasses, $aAliasTranslation);
|
||||
$oLeftFilter->MergeWith_InNamespace($oRightFilter, $aRootClasses, $aAliasTranslation);
|
||||
$oRightFilter->RenameNestedQueriesAliasesInNameSpace($aRootClasses, $aAliasTranslation);
|
||||
$oLeftFilter->TransferConditionExpression($oRightFilter, $aAliasTranslation);
|
||||
$aSearches[] = $oLeftFilter;
|
||||
$aSearches[] = $this->IntersectSubClass($oRightFilter, $this->m_aClasses);
|
||||
}
|
||||
|
||||
if (count($aSearches) == 1)
|
||||
{
|
||||
// return a DBObjectSearch
|
||||
return $aSearches[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return new DBUnionSearch($aSearches);
|
||||
|
||||
return new DBUnionSearch($aSearches);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObjectSearch $oRightFilter
|
||||
* @param array $aRootClasses classes of the root search (for aliases)
|
||||
*
|
||||
* @return \DBObjectSearch
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function IntersectSubClass(DBObjectSearch $oRightFilter, array $aRootClasses): DBObjectSearch
|
||||
{
|
||||
// Limitation: the queried class must be the first declared class
|
||||
if ($oRightFilter->GetFirstJoinedClassAlias() != $oRightFilter->GetClassAlias()) {
|
||||
throw new CoreException("Limitation: cannot merge two queries if the queried class ({$oRightFilter->GetClass()} AS {$oRightFilter->GetClassAlias()}) is not the first joined class ({$oRightFilter->GetFirstJoinedClass()} AS {$oRightFilter->GetFirstJoinedClassAlias()})");
|
||||
}
|
||||
|
||||
/** @var \DBObjectSearch $oLeftFilter */
|
||||
$oLeftFilter = $this->DeepClone();
|
||||
/** @var DBObjectSearch $oRightFilter */
|
||||
$oRightFilter = $oRightFilter->DeepClone();
|
||||
|
||||
$bAllowAllData = ($oLeftFilter->IsAllDataAllowed() && $oRightFilter->IsAllDataAllowed());
|
||||
if ($bAllowAllData) {
|
||||
$oLeftFilter->AllowAllData();
|
||||
}
|
||||
|
||||
if ($oLeftFilter->GetFirstJoinedClass() != $oRightFilter->GetClass()) {
|
||||
if (MetaModel::IsParentClass($oLeftFilter->GetFirstJoinedClass(), $oRightFilter->GetClass())) {
|
||||
// Specialize $oLeftFilter
|
||||
$oLeftFilter->ChangeClass($oRightFilter->GetClass(), $oLeftFilter->GetFirstJoinedClassAlias());
|
||||
} elseif (MetaModel::IsParentClass($oRightFilter->GetFirstJoinedClass(), $oLeftFilter->GetClass())) {
|
||||
// Specialize $oRightFilter
|
||||
$oRightFilter->ChangeClass($oLeftFilter->GetFirstJoinedClass());
|
||||
} else {
|
||||
throw new CoreException("Attempting to merge a filter of class '{$oLeftFilter->GetClass()}' with a filter of class '{$oRightFilter->GetClass()}'");
|
||||
}
|
||||
}
|
||||
|
||||
$aAliasTranslation = array();
|
||||
$oLeftFilter->RenameNestedQueriesAliasesInNameSpace($aRootClasses, $aAliasTranslation);
|
||||
$oLeftFilter->MergeWith_InNamespace($oRightFilter, $aRootClasses, $aAliasTranslation);
|
||||
$oRightFilter->RenameNestedQueriesAliasesInNameSpace($aRootClasses, $aAliasTranslation);
|
||||
$oLeftFilter->TransferConditionExpression($oRightFilter, $aAliasTranslation);
|
||||
|
||||
return $oLeftFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class DBUnionSearchTest extends ItopDataTestCase
|
||||
{
|
||||
|
||||
public function testFilterOnFirstSelectedClass()
|
||||
{
|
||||
$sSourceOQL = 'SELECT `Person`, `Location` FROM Person AS `Person` JOIN Location AS `Location` ON `Person`.location_id = `Location`.id WHERE (`Location`.`id` = 1)';
|
||||
$oSearch = DBSearch::FromOQL($sSourceOQL);
|
||||
|
||||
$sFilterOQL = 'SELECT `Person` FROM Person AS `Person` WHERE (`Person`.`id` = 2) UNION SELECT `Person` FROM Person AS `Person` WHERE (`Person`.`id` = 3)';
|
||||
$oVisibleObjects = DBSearch::FromOQL($sFilterOQL);
|
||||
$sClassAlias = 'Person';
|
||||
$oVisibleObjects->AllowAllData();
|
||||
$oSearch = $oSearch->Filter($sClassAlias, $oVisibleObjects);
|
||||
$this->InvokeNonPublicMethod(get_class($oSearch), 'SetDataFiltered', $oSearch, []);
|
||||
|
||||
$this->debug($oSearch->ToOQL());
|
||||
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$oSet->Count();
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignored test (provokes PHP Error)
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function testFilterOnSecondSelectedClass()
|
||||
{
|
||||
$sSourceOQL = 'SELECT P1, L1 FROM Person AS P1 JOIN Location AS L1 ON P1.location_id = L1.id WHERE L1.id = 1';
|
||||
$oSearch = DBSearch::FromOQL($sSourceOQL);
|
||||
|
||||
$sFilterOQL = 'SELECT Location AS L2 WHERE L2.id = 2 UNION SELECT Location AS L3 WHERE L3.id = 3';
|
||||
$oVisibleObjects = DBSearch::FromOQL($sFilterOQL);
|
||||
$sClassAlias = 'L1';
|
||||
$oVisibleObjects->AllowAllData();
|
||||
$oSearch = $oSearch->Filter($sClassAlias, $oVisibleObjects);
|
||||
|
||||
$oSearch->ToOQL();
|
||||
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$oSet->CountWithLimit(1);
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user