Sfoglia il codice sorgente

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!)

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@3912 a333f486-631f-4898-b8df-5754b55c2be0

romainq 9 anni fa
parent
commit
1c5dc468d5

+ 4 - 34
core/dbobjectset.class.php

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

+ 26 - 6
core/dbsearch.class.php

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

+ 29 - 23
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;
 		}

+ 31 - 2
core/userrights.class.inc.php

@@ -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 = '')
 	{

+ 28 - 3
pages/run_query.php

@@ -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))
 				{