N°436 Core API: Correctly (mathematically!) handle the "allow all data" flag, with UNIONS and INTERSECTIONS. Requires testing

SVN:trunk[4404]
This commit is contained in:
Romain Quetiez
2016-09-19 13:08:32 +00:00
parent a908dcd752
commit 23193153c6
3 changed files with 72 additions and 44 deletions

View File

@@ -35,6 +35,11 @@ class DBObjectSearch extends DBSearch
private $m_aPointingTo;
private $m_aReferencedBy;
// By default, some information may be hidden to the current user
// But it may happen that we need to disable that feature
protected $m_bAllowAllData = false;
protected $m_bDataFiltered = false;
public function __construct($sClass, $sClassAlias = null)
{
parent::__construct();
@@ -52,6 +57,11 @@ class DBObjectSearch extends DBSearch
$this->m_aReferencedBy = array();
}
public function AllowAllData($bAllowAllData = true) {$this->m_bAllowAllData = $bAllowAllData;}
public function IsAllDataAllowed() {return $this->m_bAllowAllData;}
protected function IsDataFiltered() {return $this->m_bDataFiltered; }
protected function SetDataFiltered() {$this->m_bDataFiltered = true;}
// Create a search definition that leads to 0 result, still a valid search object
static public function FromEmptySet($sClass)
{
@@ -654,7 +664,10 @@ class DBObjectSearch extends DBSearch
$oLeftFilter = $this->DeepClone();
$oRightFilter = $oRightFilter->DeepClone();
$bAllowAllData = ($oLeftFilter->IsAllDataAllowed() && $oRightFilter->IsAllDataAllowed());
$oLeftFilter->AllowAllData($bAllowAllData);
if ($oLeftFilter->GetClass() != $oRightFilter->GetClass())
{
if (MetaModel::IsParentClass($oLeftFilter->GetClass(), $oRightFilter->GetClass()))
@@ -810,7 +823,7 @@ class DBObjectSearch extends DBSearch
return $this->m_oSearchCondition->ApplyParameters(array_merge($this->m_aParams, $aArgs));
}
public function ToOQL($bDevelopParams = false, $aContextParams = null)
public function ToOQL($bDevelopParams = false, $aContextParams = null, $bWithAllowAllFlag = false)
{
// Currently unused, but could be useful later
$bRetrofitParams = false;
@@ -850,6 +863,10 @@ class DBObjectSearch extends DBSearch
{
$sRes .= " AND MATCHES '$sFullText'";
}
if ($bWithAllowAllFlag && $this->m_bAllowAllData)
{
$sRes .= " ALLOW ALL DATA";
}
return $sRes;
}
@@ -1131,9 +1148,33 @@ class DBObjectSearch extends DBSearch
public function MakeSQLQuery($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr = null, $aSelectedClasses = null)
{
$oBuild = new QueryBuilderContext($this, $aModifierProperties, $aGroupByExpr, $aSelectedClasses);
// Hide objects that are not visible to the current user
//
$oSearch = $this;
if (!$this->IsAllDataAllowed() && !$this->IsDataFiltered())
{
$oVisibleObjects = UserRights::GetSelectFilter($this->GetClass(), $this->GetModifierProperties('UserRightsGetSelectFilter'));
if ($oVisibleObjects === false)
{
// Make sure this is a valid search object, saying NO for all
$oVisibleObjects = DBObjectSearch::FromEmptySet($this->GetClass());
}
if (is_object($oVisibleObjects))
{
$oVisibleObjects->AllowAllData();
$oSearch = $this->Intersect($oVisibleObjects);
$oSearch->SetDataFiltered();
}
else
{
// should be true at this point, meaning that no additional filtering
// is required
}
}
$oSQLQuery = $this->MakeSQLObjectQuery($oBuild, $aAttToLoad, array());
$oBuild = new QueryBuilderContext($oSearch, $aModifierProperties, $aGroupByExpr, $aSelectedClasses);
$oSQLQuery = $oSearch->MakeSQLObjectQuery($oBuild, $aAttToLoad, array());
$oSQLQuery->SetCondition($oBuild->m_oQBExpressions->GetCondition());
if ($aGroupByExpr)
{

View File

@@ -42,14 +42,9 @@ abstract class DBSearch
const JOIN_POINTING_TO = 0;
const JOIN_REFERENCED_BY = 1;
protected $m_bDataFiltered = false;
protected $m_bNoContextParameters = false;
protected $m_aModifierProperties = array();
// By default, some information may be hidden to the current user
// But it may happen that we need to disable that feature
protected $m_bAllowAllData = false;
public function __construct()
{
}
@@ -62,12 +57,11 @@ abstract class DBSearch
return unserialize(serialize($this)); // Beware this serializes/unserializes the search and its parameters as well
}
public function AllowAllData() {$this->m_bAllowAllData = true;}
public function IsAllDataAllowed() {return $this->m_bAllowAllData;}
abstract public function AllowAllData();
abstract public function IsAllDataAllowed();
public function NoContextParameters() {$this->m_bNoContextParameters = true;}
public function HasContextParameters() {return $this->m_bNoContextParameters;}
public function IsDataFiltered() {return $this->m_bDataFiltered; }
public function SetDataFiltered() {$this->m_bDataFiltered = true;}
public function SetModifierProperty($sPluginClass, $sProperty, $value)
{
@@ -219,7 +213,7 @@ abstract class DBSearch
return $oSearchWithAlias;
}
abstract public function ToOQL($bDevelopParams = false, $aContextParams = null);
abstract public function ToOQL($bDevelopParams = false, $aContextParams = null, $bWithAllowAllFlag = false);
static protected $m_aOQLQueries = array();
@@ -492,39 +486,16 @@ abstract class DBSearch
protected function GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null)
{
// Hide objects that are not visible to the current user
//
$oSearch = $this;
if (!$this->IsAllDataAllowed() && !$this->IsDataFiltered())
{
$oVisibleObjects = UserRights::GetSelectFilter($this->GetClass(), $this->GetModifierProperties('UserRightsGetSelectFilter'));
if ($oVisibleObjects === false)
{
// Make sure this is a valid search object, saying NO for all
$oVisibleObjects = DBObjectSearch::FromEmptySet($this->GetClass());
}
if (is_object($oVisibleObjects))
{
$oSearch = $this->Intersect($oVisibleObjects);
$oSearch->SetDataFiltered();
}
else
{
// should be true at this point, meaning that no additional filtering
// is required
}
}
// Compute query modifiers properties (can be set in the search itself, by the context, etc.)
//
$aModifierProperties = MetaModel::MakeModifierProperties($oSearch);
$aModifierProperties = MetaModel::MakeModifierProperties($this);
// Create a unique cache id
//
if (self::$m_bQueryCacheEnabled || self::$m_bTraceQueries)
{
// Need to identify the query
$sOqlQuery = $oSearch->ToOql();
$sOqlQuery = $this->ToOql(false, null, true);
if (count($aModifierProperties))
{
@@ -553,7 +524,7 @@ abstract class DBSearch
}
else
{
$sOqlQuery = "SELECTING... ".$oSearch->GetClass();
$sOqlQuery = "SELECTING... ".$this->GetClass();
$sOqlId = "query id ? n/a";
}
@@ -599,7 +570,7 @@ abstract class DBSearch
if (!isset($oSQLQuery))
{
$oKPI = new ExecutionKPI();
$oSQLQuery = $oSearch->MakeSQLQuery($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr);
$oSQLQuery = $this->MakeSQLQuery($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr);
$oSQLQuery->SetSourceOQL($sOqlQuery);
$oKPI->ComputeStats('MakeSQLQuery', $sOqlQuery);
@@ -624,7 +595,7 @@ abstract class DBSearch
$aExtendedFields = array();
foreach($aExtendedDataSpec['fields'] as $sColumn)
{
$sColRef = $oSearch->GetClassAlias().'_extdata_'.$sColumn;
$sColRef = $this->GetClassAlias().'_extdata_'.$sColumn;
$aExtendedFields[$sColRef] = new FieldExpressionResolved($sColumn, $sTableAlias);
}
$oSQLQueryExt = new SQLObjectQuery($aExtendedDataSpec['table'], $sTableAlias, $aExtendedFields);

View File

@@ -55,6 +55,22 @@ class DBUnionSearch extends DBSearch
$this->ComputeSelectedClasses();
}
public function AllowAllData()
{
foreach ($this->aSearches as $oSearch)
{
$oSearch->AllowAllData();
}
}
public function IsAllDataAllowed()
{
foreach ($this->aSearches as $oSearch)
{
if ($oSearch->IsAllDataAllowed() === false) return false;
}
return true;
}
/**
* Find the lowest common ancestor for each of the selected class
*/
@@ -357,12 +373,12 @@ class DBUnionSearch extends DBSearch
/**
* Overloads for query building
*/
public function ToOQL($bDevelopParams = false, $aContextParams = null)
public function ToOQL($bDevelopParams = false, $aContextParams = null, $bWithAllowAllFlag = false)
{
$aSubQueries = array();
foreach ($this->aSearches as $oSearch)
{
$aSubQueries[] = $oSearch->ToOQL($bDevelopParams, $aContextParams);
$aSubQueries[] = $oSearch->ToOQL($bDevelopParams, $aContextParams, $bWithAllowAllFlag);
}
$sRet = implode(' UNION ', $aSubQueries);
return $sRet;