Magic query arguments:

- In addition to current_contact_id, the following arguments can be used in any OQL query (provided that the page running the query requires a  login): current_contact->attcode and current_user->attcode
- Code refactoring: magic arguments in one single place
- The "Run queries" page is now taking into account those magic arguments (do not prompt the end-user with these arguments!)

SVN:trunk[3912]
This commit is contained in:
Romain Quetiez
2016-02-17 18:55:46 +00:00
parent 77f8129fac
commit e0fad5e0e6
5 changed files with 118 additions and 68 deletions

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
/**
* Object set management
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -1072,7 +1072,7 @@ class DBObjectSet
*/
public function ListConstantFields()
{
$aScalarArgs = $this->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);
}
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2015 Combodo SARL
// Copyright (C) 2015-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -33,7 +33,7 @@ require_once('dbunionsearch.class.php');
* - do not provide a type-hint for function parameters defined in the modules
* - leave the statements DBObjectSearch::FromOQL in the modules, though DBSearch is more relevant
*
* @copyright Copyright (C) 2015 Combodo SARL
* @copyright Copyright (C) 2015-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -347,9 +347,20 @@ abstract class DBSearch
/**
* @param hash $aOrderBy Array of '[<classalias>.]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 '[<classalias>.]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;

View File

@@ -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;
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
/**
* User rights management API
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -235,6 +235,23 @@ abstract class User extends cmdbAbstractObject
return $this->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 = '')
{

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
/**
* Tools to design OQL queries and test them
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -142,12 +142,37 @@ try
$sSyntaxError = $e->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))
{