diff --git a/core/dbobjectset.class.php b/core/dbobjectset.class.php index 959e88cd8..6b55e5b66 100644 --- a/core/dbobjectset.class.php +++ b/core/dbobjectset.class.php @@ -1,5 +1,5 @@ ExpandArgs(); + $aScalarArgs = array_merge($this->m_oFilter->GetInternalParams(), $this->m_aArgs); $aConst = $this->m_oFilter->ListConstantFields(); foreach($aConst as $sClassAlias => $aVals) @@ -1089,39 +1089,9 @@ class DBObjectSet return $aConst; } - protected function ExpandArgs() - { - $aScalarArgs = $this->m_oFilter->GetInternalParams(); - foreach($this->m_aArgs as $sArgName => $value) - { - if (MetaModel::IsValidObject($value)) - { - if (strpos($sArgName, '->object()') === false) - { - // Lazy syntax - develop the object contextual parameters - $aScalarArgs = array_merge($aScalarArgs, $value->ToArgsForQuery($sArgName)); - } - else - { - // Leave as is - $aScalarArgs[$sArgName] = $value; - } - } - else - { - if (!is_array($value)) // Sometimes ExtraParams contains a mix (like defaults[]) so non scalar parameters are ignored - { - $aScalarArgs[$sArgName] = (string) $value; - } - } - } - $aScalarArgs['current_contact_id'] = UserRights::GetContactId(); - return $aScalarArgs; - } - public function ApplyParameters() { - $aScalarArgs = $this->ExpandArgs(); + $aScalarArgs = MetaModel::PrepareQueryArguments($this->m_aArgs, $this->m_oFilter->GetInternalParams()); $this->m_oFilter->ApplyParameters($aScalarArgs); } } diff --git a/core/dbsearch.class.php b/core/dbsearch.class.php index a779c1268..df149dc47 100644 --- a/core/dbsearch.class.php +++ b/core/dbsearch.class.php @@ -1,5 +1,5 @@ .]attcode' => bAscending - */ - public function MakeSelectQuery($aOrderBy = array(), $aArgs = array(), $aAttToLoad = null, $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false) + * @param array|hash $aOrderBy Array of '[.]attcode' => bAscending + * @param array $aArgs + * @param null $aAttToLoad + * @param null $aExtendedDataSpec + * @param int $iLimitCount + * @param int $iLimitStart + * @param bool $bGetCount + * @param bool $bNoArguments + * @return string + * @throws CoreException + * @throws Exception + * @throws MissingQueryArgument + */ + public function MakeSelectQuery($aOrderBy = array(), $aArgs = array(), $aAttToLoad = null, $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false, $bNoArguments = false) { // Check the order by specification, and prefix with the class alias // and make sure that the ordering columns are going to be selected @@ -402,7 +413,16 @@ abstract class DBSearch $oSQLQuery = $this->GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount); - $aScalarArgs = array_merge(MetaModel::PrepareQueryArguments($aArgs), $this->GetInternalParams()); + if ($bNoArguments) + { + // Only internal parameters + $aScalarArgs = $this->GetInternalParams(); + } + else + { + // The complete list of arguments will include magic arguments (e.g. current_user->attcode) + $aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams()); + } try { $bBeautifulSQL = self::$m_bTraceQueries || self::$m_bDebugQuery || self::$m_bIndentQueries; diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 5567bd4a9..641bda9e8 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -30,25 +30,11 @@ require_once(APPROOT.'core/relationgraph.class.inc.php'); * @license http://opensource.org/licenses/AGPL-3.0 */ -// #@# todo: change into class const (see Doctrine) -// Doctrine example -// class toto -// { -// /** -// * VERSION -// */ -// const VERSION = '1.0.0'; -// } - /** - * add some description here... - * * @package iTopORM */ define('ENUM_PARENT_CLASSES_EXCLUDELEAF', 1); /** - * add some description here... - * * @package iTopORM */ define('ENUM_PARENT_CLASSES_ALL', 2); @@ -2463,19 +2449,26 @@ abstract class MetaModel return $oReflection->isAbstract(); } - public static function PrepareQueryArguments($aArgs) + /** + * Normalizes query arguments and adds magic parameters: + * - current_contact_id + * - current_contact (DBObject) + * - current_user (DBObject) + * + * @param array $aArgs Context arguments (some can be persistent objects) + * @param array $aScalarArgs Other query parameters (only scalars allowed here) + * @return array + */ + public static function PrepareQueryArguments($aArgs, $aScalarArgs = array()) { - // Translate any object into scalars - // - $aScalarArgs = array(); foreach($aArgs as $sArgName => $value) { if (self::IsValidObject($value)) { if (strpos($sArgName, '->object()') === false) { - // Lazy syntax - develop the object contextual parameters - $aScalarArgs = array_merge($aScalarArgs, $value->ToArgsForQuery($sArgName)); + // Normalize object arguments + $aScalarArgs[$sArgName.'->object()'] = $value; } else { @@ -2493,11 +2486,24 @@ abstract class MetaModel { $aScalarArgs[$sArgName] = null; } + // otherwise... could be an array coming from the extra params... } } - // Add standard contextual arguments + // Add standard magic arguments // - $aScalarArgs['current_contact_id'] = UserRights::GetContactId(); + $aScalarArgs['current_contact_id'] = UserRights::GetContactId(); // legacy + + $oUser = UserRights::GetUserObject(); + if (!is_null($oUser)) + { + $aScalarArgs['current_user->object()'] = $oUser; + + $oContact = UserRights::GetContactObject(); + if (!is_null($oContact)) + { + $aScalarArgs['current_contact->object()'] = $oContact; + } + } return $aScalarArgs; } @@ -4481,7 +4487,7 @@ abstract class MetaModel $oFilter->AllowAllData(); } - $sSQL = $oFilter->MakeSelectQuery(); + $sSQL = $oFilter->MakeSelectQuery(array(), array(), null, null, 0, 0, false, true); // bNoMagicArguments = true self::$aQueryCacheGetObject[$sQuerySign] = $sSQL; self::$aQueryCacheGetObjectHits[$sQuerySign] = 0; } diff --git a/core/userrights.class.inc.php b/core/userrights.class.inc.php index a457243c4..4cc348ed6 100644 --- a/core/userrights.class.inc.php +++ b/core/userrights.class.inc.php @@ -1,5 +1,5 @@ Get('login'); } + protected $oContactObject; + + /** + * Fetch and memoize the associated contact (if any) + */ + public function GetContactObject() + { + if (is_null($this->oContactObject)) + { + if ($this->Get('contactid') != 0) + { + $this->oContactObject = MetaModel::GetObject('Contact', $this->Get('contactid')); + } + } + return $this->oContactObject; + } + /* * Overload the standard behavior */ @@ -752,6 +769,18 @@ class UserRights return $oUser->Get('contactid'); } + public static function GetContactObject() + { + if (is_null(self::$m_oUser)) + { + return null; + } + else + { + return self::$m_oUser->GetContactObject(); + } + } + // Render the user name in best effort mode public static function GetUserFriendlyName($sName = '') { diff --git a/pages/run_query.php b/pages/run_query.php index 9fa76b01f..babc4d728 100644 --- a/pages/run_query.php +++ b/pages/run_query.php @@ -1,5 +1,5 @@ getMessage(); } } - + + $aNakedMagicArguments = array(); + foreach (MetaModel::PrepareQueryArguments(array()) as $sArgName => $value) + { + $iPos = strpos($sArgName, '->object()'); + if ($iPos === false) + { + $aNakedMagicArguments[$sArgName] = $value; + } + else + { + $aNakedMagicArguments[substr($sArgName, 0, $iPos)] = true; + } + } if ($oFilter) { $aArgs = array(); foreach($oFilter->GetQueryParams() as $sParam => $foo) { + // Skip magic parameters + $iPos = strpos($sArgName, '->'); + if ($iPos === false) + { + $sRefName = $sParam; + } + else + { + $sRefName = substr($sParam, 0, $iPos); + } + if (array_key_exists($sRefName, $aNakedMagicArguments)) continue; + $value = utils::ReadParam('arg_'.$sParam, null, true, 'raw_data'); if (!is_null($value)) {