diff --git a/application/displayblock.class.inc.php b/application/displayblock.class.inc.php index 5b430845b..d87a6c69f 100644 --- a/application/displayblock.class.inc.php +++ b/application/displayblock.class.inc.php @@ -52,7 +52,7 @@ class DisplayBlock public function __construct(DBObjectSearch $oFilter, $sStyle = 'list', $bAsynchronous = false, $aParams = array(), $oSet = null) { - $this->m_oFilter = clone $oFilter; + $this->m_oFilter = $oFilter->DeepClone(); $this->m_aConditions = array(); $this->m_sStyle = $sStyle; $this->m_bAsynchronous = $bAsynchronous; @@ -414,7 +414,7 @@ class DisplayBlock foreach($aGroupBy as $iRow => $iCount) { // Build the search for this subset - $oSubsetSearch = clone $this->m_oFilter; + $oSubsetSearch = $this->m_oFilter->DeepClone(); $oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($aValues[$iRow])); $oSubsetSearch->AddConditionExpression($oCondition); $sFilter = urlencode($oSubsetSearch->serialize()); @@ -492,7 +492,7 @@ class DisplayBlock $sHtml .= "\n"; // Construct a new (parametric) query that will return the content of this block - $oBlockFilter = clone $this->m_oFilter; + $oBlockFilter = $this->m_oFilter->DeepClone(); $aExpressions = array(); $index = 0; foreach($aGroupByFields as $aField) @@ -726,7 +726,7 @@ class DisplayBlock $oAttDef = MetaModel::GetAttributeDef($sClass, $sStateAttrCode); foreach($aStates as $sStateValue) { - $oFilter = clone($this->m_oFilter); + $oFilter = $this->m_oFilter->DeepClone(); $oFilter->AddCondition($sStateAttrCode, $sStateValue, '='); $oSet = new DBObjectSet($oFilter); $aCounts[$sStateValue] = $oSet->Count(); @@ -911,7 +911,7 @@ EOF foreach($aGroupBy as $iRow => $iCount) { // Build the search for this subset - $oSubsetSearch = clone $this->m_oFilter; + $oSubsetSearch = $this->m_oFilter->DeepClone(); $oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($aValues[$iRow])); $oSubsetSearch->AddConditionExpression($oCondition); $aURLs[$idx] = $oSubsetSearch->serialize(); diff --git a/core/dbobjectsearch.class.php b/core/dbobjectsearch.class.php index 9dd7ee8b0..2e65d725c 100644 --- a/core/dbobjectsearch.class.php +++ b/core/dbobjectsearch.class.php @@ -71,6 +71,14 @@ class DBObjectSearch $this->m_aModifierProperties = array(); } + /** + * Perform a deep clone (as opposed to "clone" which does copy a reference to the underlying objects + **/ + public function DeepClone() + { + return unserialize(serialize($this)); + } + public function AllowAllData() {$this->m_bAllowAllData = true;} public function IsAllDataAllowed() {return $this->m_bAllowAllData;} public function IsDataFiltered() {return $this->m_bDataFiltered; } @@ -658,6 +666,10 @@ class DBObjectSearch public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS) { + // Note: though it seems to be a good practice to clone the given source filter + // (as it was done and fixed an issue in MergeWith()) + // this was not implemented here because it was causing a regression (login as admin, select an org, click on any badge) + // buggy: $oFilter = $oFilter->DeepClone(); $aAliasTranslation = array(); $res = $this->AddCondition_PointingTo_InNameSpace($oFilter, $sExtKeyAttCode, $this->m_aClasses, $aAliasTranslation, $iOperatorCode); $this->TransferConditionExpression($oFilter, $aAliasTranslation); @@ -689,6 +701,7 @@ class DBObjectSearch public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode) { + $oFilter = $oFilter->DeepClone(); $aAliasTranslation = array(); $res = $this->AddCondition_ReferencedBy_InNameSpace($oFilter, $sForeignExtKeyAttCode, $this->m_aClasses, $aAliasTranslation); $this->TransferConditionExpression($oFilter, $aAliasTranslation); @@ -721,22 +734,13 @@ class DBObjectSearch $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 = $oFilter->DeepClone(); //$oNewFilter->ResetCondition(); $oReceivingFilter->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode]= $oFilter; } } - public function AddCondition_LinkedTo(DBObjectSearch $oLinkFilter, $sExtKeyAttCodeToMe, $sExtKeyAttCodeTarget, DBObjectSearch $oFilterTarget) - { - $oLinkFilterFinal = clone $oLinkFilter; - // todo : new function prototype - $oLinkFilterFinal->AddCondition_PointingTo($sExtKeyAttCodeToMe); - - $this->AddCondition_ReferencedBy($oLinkFilterFinal, $sExtKeyAttCodeToMe); - } - public function AddCondition_RelatedTo(DBObjectSearch $oFilter, $sRelCode, $iMaxDepth) { MyHelpers::CheckValueInArray('relation code', $sRelCode, MetaModel::EnumRelations()); @@ -745,6 +749,7 @@ class DBObjectSearch public function MergeWith($oFilter) { + $oFilter = $oFilter->DeepClone(); $aAliasTranslation = array(); $res = $this->MergeWith_InNamespace($oFilter, $this->m_aClasses, $aAliasTranslation); $this->TransferConditionExpression($oFilter, $aAliasTranslation); @@ -1166,7 +1171,7 @@ class DBObjectSearch if ($bOQLCacheEnabled && array_key_exists($sQuery, self::$m_aOQLQueries)) { // hit! - $oClone = clone self::$m_aOQLQueries[$sQuery]; + $oClone = self::$m_aOQLQueries[$sQuery]->DeepClone(); if (!is_null($aParams)) { $oClone->m_aParams = $aParams; @@ -1316,7 +1321,7 @@ class DBObjectSearch if ($bOQLCacheEnabled) { - self::$m_aOQLQueries[$sQuery] = clone $oResultFilter; + self::$m_aOQLQueries[$sQuery] = $oResultFilter->DeepClone(); } return $oResultFilter; diff --git a/core/dbobjectset.class.php b/core/dbobjectset.class.php index d6d7a1f68..ee81bd7f1 100644 --- a/core/dbobjectset.class.php +++ b/core/dbobjectset.class.php @@ -42,7 +42,7 @@ class DBObjectSet public function __construct(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0) { - $this->m_oFilter = clone $oFilter; + $this->m_oFilter = $oFilter->DeepClone(); $this->m_aAddedIds = array(); $this->m_aOrderBy = $aOrderBy; $this->m_aArgs = $aArgs; @@ -271,7 +271,7 @@ class DBObjectSet public function GetFilter() { // Make sure that we carry on the parameters of the set with the filter - $oFilter = clone $this->m_oFilter; + $oFilter = $this->m_oFilter->DeepClone(); $oFilter->SetInternalParams(array_merge($oFilter->GetInternalParams(), $this->m_aArgs)); if (count($this->m_aAddedIds) == 0) diff --git a/core/metamodel.class.php b/core/metamodel.class.php index c1829cd69..d2013ed1a 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -2305,7 +2305,7 @@ abstract class MetaModel $oKPI->ComputeStats('Query APC (store)', $sOqlQuery); } - self::$m_aQueryStructCache[$sOqlId] = clone $oSelect; + self::$m_aQueryStructCache[$sOqlId] = $oSelect->DeepClone(); } } diff --git a/core/sqlquery.class.inc.php b/core/sqlquery.class.inc.php index 58e11406c..ecaa1a3c7 100644 --- a/core/sqlquery.class.inc.php +++ b/core/sqlquery.class.inc.php @@ -72,6 +72,14 @@ class SQLQuery $this->m_oSelectedIdField = $oSelectedIdField; } + /** + * Perform a deep clone (as opposed to "clone" which does copy a reference to the underlying objects + **/ + public function DeepClone() + { + return unserialize(serialize($this)); + } + public function GetTableAlias() { return $this->m_sTableAlias; diff --git a/pages/audit.php b/pages/audit.php index f9eb316c4..852f61564 100644 --- a/pages/audit.php +++ b/pages/audit.php @@ -94,7 +94,7 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) if ($oRule->Get('valid_flag') == 'false') { // The query returns directly the invalid elements - $oFilter = $oRuleFilter; + $oFilter = $oRuleFilter; $oFilter->MergeWith($oDefinitionFilter); } else @@ -106,7 +106,7 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) { $aValidIds[] = $aRow['id']; } - $oFilter = clone $oDefinitionFilter; + $oFilter = $oDefinitionFilter->DeepClone(); if (count($aValidIds) > 0) { $aInDefSet = array();