1<?php 2// Copyright (C) 2010-2018 Combodo SARL 3// 4// This file is part of iTop. 5// 6// iTop is free software; you can redistribute it and/or modify 7// it under the terms of the GNU Affero General Public License as published by 8// the Free Software Foundation, either version 3 of the License, or 9// (at your option) any later version. 10// 11// iTop is distributed in the hope that it will be useful, 12// but WITHOUT ANY WARRANTY; without even the implied warranty of 13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14// GNU Affero General Public License for more details. 15// 16// You should have received a copy of the GNU Affero General Public License 17// along with iTop. If not, see <http://www.gnu.org/licenses/> 18 19 20/** 21 * Class ApplicationContext 22 * 23 * @copyright Copyright (C) 2010-2018 Combodo SARL 24 * @license http://opensource.org/licenses/AGPL-3.0 25 */ 26 27require_once(APPROOT."/application/utils.inc.php"); 28 29/** 30 * Interface for directing end-users to the relevant application 31 */ 32interface iDBObjectURLMaker 33{ 34 /** 35 * @param string $sClass 36 * @param string $iId 37 * 38 * @return string 39 */ 40 public static function MakeObjectURL($sClass, $iId); 41} 42 43/** 44 * Direct end-users to the standard iTop application: UI.php 45 */ 46class iTopStandardURLMaker implements iDBObjectURLMaker 47{ 48 /** 49 * @param string $sClass 50 * @param string $iId 51 * 52 * @return string 53 * @throws \Exception 54 */ 55 public static function MakeObjectURL($sClass, $iId) 56 { 57 $sPage = DBObject::ComputeStandardUIPage($sClass); 58 $sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot(); 59 $sUrl = "{$sAbsoluteUrl}pages/$sPage?operation=details&class=$sClass&id=$iId"; 60 return $sUrl; 61 } 62} 63 64/** 65 * Direct end-users to the standard Portal application 66 */ 67class PortalURLMaker implements iDBObjectURLMaker 68{ 69 /** 70 * @param string $sClass 71 * @param string $iId 72 * 73 * @return string 74 * @throws \Exception 75 */ 76 public static function MakeObjectURL($sClass, $iId) 77 { 78 $sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot(); 79 $sUrl = "{$sAbsoluteUrl}portal/index.php?operation=details&class=$sClass&id=$iId"; 80 return $sUrl; 81 } 82} 83 84 85/** 86 * Helper class to store and manipulate the parameters that make the application's context 87 * 88 * Usage: 89 * 1) Build the application's context by constructing the object 90 * (the object will read some of the page's parameters) 91 * 92 * 2) Add these parameters to hyperlinks or to forms using the helper, functions 93 * GetForLink(), GetForForm() or GetAsHash() 94 */ 95class ApplicationContext 96{ 97 public static $m_sUrlMakerClass = null; 98 protected static $m_aPluginProperties = null; 99 protected static $aDefaultValues; // Cache shared among all instances 100 101 protected $aNames; 102 protected $aValues; 103 104 /** 105 * ApplicationContext constructor. 106 * 107 * @param bool $bReadContext 108 * 109 * @throws \Exception 110 */ 111 public function __construct($bReadContext = true) 112 { 113 $this->aNames = array( 114 'org_id', 'menu' 115 ); 116 if ($bReadContext) 117 { 118 $this->ReadContext(); 119 } 120 121 } 122 123 /** 124 * Read the context directly in the PHP parameters (either POST or GET) 125 * return nothing 126 * 127 * @throws \Exception 128 */ 129 protected function ReadContext() 130 { 131 if (!isset(self::$aDefaultValues)) 132 { 133 self::$aDefaultValues = array(); 134 $aContext = utils::ReadParam('c', array(), false, 'context_param'); 135 foreach($this->aNames as $sName) 136 { 137 $sValue = isset($aContext[$sName]) ? $aContext[$sName] : ''; 138 // TO DO: check if some of the context parameters are mandatory (or have default values) 139 if (!empty($sValue)) 140 { 141 self::$aDefaultValues[$sName] = $sValue; 142 } 143 // Hmm, there must be a better (more generic) way to handle the case below: 144 // When there is only one possible (allowed) organization, the context must be 145 // fixed to this org unless there is only one organization in the system then 146 // no filter is applied 147 if ($sName == 'org_id') 148 { 149 if (MetaModel::IsValidClass('Organization')) 150 { 151 $oSearchFilter = new DBObjectSearch('Organization'); 152 $oSet = new CMDBObjectSet($oSearchFilter); 153 $iCount = $oSet->CountWithLimit(2); 154 if ($iCount > 1) 155 { 156 $oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true); 157 $oSet = new CMDBObjectSet($oSearchFilter); 158 $iCount = $oSet->CountWithLimit(2); 159 if ($iCount == 1) 160 { 161 // Only one possible value for org_id, set it in the context 162 $oOrg = $oSet->Fetch(); 163 self::$aDefaultValues[$sName] = $oOrg->GetKey(); 164 } 165 } 166 } 167 } 168 } 169 } 170 $this->aValues = self::$aDefaultValues; 171 } 172 173 /** 174 * Returns the current value for the given parameter 175 * 176 * @param string $sParamName Name of the parameter to read 177 * @param string $defaultValue 178 * 179 * @return mixed The value for this parameter 180 */ 181 public function GetCurrentValue($sParamName, $defaultValue = '') 182 { 183 if (isset($this->aValues[$sParamName])) 184 { 185 return $this->aValues[$sParamName]; 186 } 187 return $defaultValue; 188 } 189 190 /** 191 * Returns the context as string with the format name1=value1&name2=value2.... 192 * @return string The context as a string to be appended to an href property 193 */ 194 public function GetForLink() 195 { 196 $aParams = array(); 197 foreach($this->aValues as $sName => $sValue) 198 { 199 $aParams[] = "c[$sName]".'='.urlencode($sValue); 200 } 201 return implode("&", $aParams); 202 } 203 204 /** 205 * Returns the context as sequence of input tags to be inserted inside a <form> tag 206 * @return string The context as a sequence of <input type="hidden" /> tags 207 */ 208 public function GetForForm() 209 { 210 $sContext = ""; 211 foreach($this->aValues as $sName => $sValue) 212 { 213 $sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n"; 214 } 215 return $sContext; 216 } 217 218 /** 219 * Returns the context as a hash array 'parameter_name' => value 220 * @return array The context information 221 */ 222 public function GetAsHash() 223 { 224 $aReturn = array(); 225 foreach($this->aValues as $sName => $sValue) 226 { 227 $aReturn["c[$sName]"] = $sValue; 228 } 229 return $aReturn; 230 } 231 232 /** 233 * Returns an array of the context parameters NAMEs 234 * @return array The list of context parameters 235 */ 236 public function GetNames() 237 { 238 return $this->aNames; 239 } 240 /** 241 * Removes the specified parameter from the context, for example when the same parameter 242 * is already a search parameter 243 * @param string $sParamName Name of the parameter to remove 244 */ 245 public function Reset($sParamName) 246 { 247 if (isset($this->aValues[$sParamName])) 248 { 249 unset($this->aValues[$sParamName]); 250 } 251 } 252 253 /** 254 * Initializes the given object with the default values provided by the context 255 * 256 * @param \DBObject $oObj 257 * 258 * @throws \Exception 259 * @throws \CoreUnexpectedValue 260 */ 261 public function InitObjectFromContext(DBObject &$oObj) 262 { 263 $sClass = get_class($oObj); 264 foreach($this->GetNames() as $key) 265 { 266 $aCallSpec = array($sClass, 'MapContextParam'); 267 if (is_callable($aCallSpec)) 268 { 269 $sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter 270 271 if (MetaModel::IsValidAttCode($sClass, $sAttCode)) 272 { 273 $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); 274 if ($oAttDef->IsWritable()) 275 { 276 $value = $this->GetCurrentValue($key, null); 277 if (!is_null($value)) 278 { 279 $oObj->Set($sAttCode, $value); 280 } 281 } 282 } 283 } 284 } 285 } 286 287 /** 288 * Set the current application url provider 289 * @param string $sClass Class implementing iDBObjectURLMaker 290 * @return string 291 */ 292 public static function SetUrlMakerClass($sClass = 'iTopStandardURLMaker') 293 { 294 $sPrevious = self::GetUrlMakerClass(); 295 296 self::$m_sUrlMakerClass = $sClass; 297 $_SESSION['UrlMakerClass'] = $sClass; 298 299 return $sPrevious; 300 } 301 302 /** 303 * Get the current application url provider 304 * @return string the name of the class 305 */ 306 public static function GetUrlMakerClass() 307 { 308 if (is_null(self::$m_sUrlMakerClass)) 309 { 310 if (isset($_SESSION['UrlMakerClass'])) 311 { 312 self::$m_sUrlMakerClass = $_SESSION['UrlMakerClass']; 313 } 314 else 315 { 316 self::$m_sUrlMakerClass = 'iTopStandardURLMaker'; 317 } 318 } 319 return self::$m_sUrlMakerClass; 320 } 321 322 /** 323 * Get the current application url provider 324 * 325 * @param string $sObjClass 326 * @param string $sObjKey 327 * @param null $sUrlMakerClass 328 * @param bool $bWithNavigationContext 329 * 330 * @return string the name of the class 331 * @throws \Exception 332 */ 333 public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true) 334 { 335 $oAppContext = new ApplicationContext(); 336 337 if (is_null($sUrlMakerClass)) 338 { 339 $sUrlMakerClass = self::GetUrlMakerClass(); 340 } 341 $sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey); 342 if (strlen($sUrl) > 0) 343 { 344 if ($bWithNavigationContext) 345 { 346 return $sUrl."&".$oAppContext->GetForLink(); 347 } 348 else 349 { 350 return $sUrl; 351 } 352 } 353 else 354 { 355 return ''; 356 } 357 } 358 359 /** 360 * Load plugin properties for the current session 361 * @return void 362 */ 363 protected static function LoadPluginProperties() 364 { 365 if (isset($_SESSION['PluginProperties'])) 366 { 367 self::$m_aPluginProperties = $_SESSION['PluginProperties']; 368 } 369 else 370 { 371 self::$m_aPluginProperties = array(); 372 } 373 } 374 375 /** 376 * Set plugin properties 377 * @param string $sPluginClass Class implementing any plugin interface 378 * @param string $sProperty Name of the property 379 * @param mixed $value Value (numeric or string) 380 * @return void 381 */ 382 public static function SetPluginProperty($sPluginClass, $sProperty, $value) 383 { 384 if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties(); 385 386 self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value; 387 $_SESSION['PluginProperties'][$sPluginClass][$sProperty] = $value; 388 } 389 390 /** 391 * Get plugin properties 392 * @param string $sPluginClass Class implementing any plugin interface 393 * @return array of sProperty=>value pairs 394 */ 395 public static function GetPluginProperties($sPluginClass) 396 { 397 if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties(); 398 399 if (array_key_exists($sPluginClass, self::$m_aPluginProperties)) 400 { 401 return self::$m_aPluginProperties[$sPluginClass]; 402 } 403 else 404 { 405 return array(); 406 } 407 } 408 409} 410