[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Joomla! Content Management System 5 * 6 * @copyright (C) 2007 Open Source Matters, Inc. <https://www.joomla.org> 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 */ 9 10 namespace Joomla\CMS\Router; 11 12 use Joomla\CMS\Factory; 13 use Joomla\CMS\Language\Text; 14 use Joomla\CMS\Router\Exception\RouteNotFoundException; 15 use Joomla\CMS\Uri\Uri; 16 17 // phpcs:disable PSR1.Files.SideEffects 18 \defined('JPATH_PLATFORM') or die; 19 // phpcs:enable PSR1.Files.SideEffects 20 21 /** 22 * Class to create and parse routes 23 * 24 * @since 1.5 25 */ 26 class Router 27 { 28 /** 29 * Mask for the before process stage 30 * 31 * @var string 32 * @since 3.4 33 */ 34 public const PROCESS_BEFORE = 'preprocess'; 35 36 /** 37 * Mask for the during process stage 38 * 39 * @var string 40 * @since 3.4 41 */ 42 public const PROCESS_DURING = ''; 43 44 /** 45 * Mask for the after process stage 46 * 47 * @var string 48 * @since 3.4 49 */ 50 public const PROCESS_AFTER = 'postprocess'; 51 52 /** 53 * An array of variables 54 * 55 * @var array 56 * @since 1.5 57 */ 58 protected $vars = array(); 59 60 /** 61 * An array of rules 62 * 63 * @var array 64 * @since 1.5 65 */ 66 protected $rules = array( 67 'buildpreprocess' => array(), 68 'build' => array(), 69 'buildpostprocess' => array(), 70 'parsepreprocess' => array(), 71 'parse' => array(), 72 'parsepostprocess' => array(), 73 ); 74 75 /** 76 * Caching of processed URIs 77 * 78 * @var array 79 * @since 3.3 80 */ 81 protected $cache = array(); 82 83 /** 84 * Router instances container. 85 * 86 * @var Router[] 87 * @since 1.7 88 */ 89 protected static $instances = array(); 90 91 /** 92 * Returns the global Router object, only creating it if it 93 * doesn't already exist. 94 * 95 * @param string $client The name of the client 96 * @param array $options An associative array of options 97 * 98 * @return Router A Router object. 99 * 100 * @since 1.5 101 * 102 * @throws \RuntimeException 103 * 104 * @deprecated 5.0 Inject the router or load it from the dependency injection container 105 */ 106 public static function getInstance($client, $options = array()) 107 { 108 if (empty(self::$instances[$client])) { 109 // Create a Router object 110 $classname = 'JRouter' . ucfirst($client); 111 112 if (!class_exists($classname)) { 113 throw new \RuntimeException(Text::sprintf('JLIB_APPLICATION_ERROR_ROUTER_LOAD', $client), 500); 114 } 115 116 // Check for a possible service from the container otherwise manually instantiate the class 117 if (Factory::getContainer()->has($classname)) { 118 self::$instances[$client] = Factory::getContainer()->get($classname); 119 } else { 120 self::$instances[$client] = new $classname(); 121 } 122 } 123 124 return self::$instances[$client]; 125 } 126 127 /** 128 * Function to convert a route to an internal URI 129 * 130 * @param Uri &$uri The uri. 131 * @param bool $setVars Set the parsed data in the internal 132 * storage for current-request-URLs 133 * 134 * @return array 135 * 136 * @since 1.5 137 * @throws \Exception 138 */ 139 public function parse(&$uri, $setVars = false) 140 { 141 // Do the preprocess stage of the URL parse process 142 $this->processParseRules($uri, self::PROCESS_BEFORE); 143 144 // Do the main stage of the URL parse process 145 $this->processParseRules($uri); 146 147 // Do the postprocess stage of the URL parse process 148 $this->processParseRules($uri, self::PROCESS_AFTER); 149 150 // Check if all parts of the URL have been parsed. 151 // Otherwise we have an invalid URL 152 if (\strlen($uri->getPath()) > 0) { 153 throw new RouteNotFoundException(Text::_('JERROR_PAGE_NOT_FOUND')); 154 } 155 156 if ($setVars) { 157 $this->setVars($uri->getQuery(true)); 158 159 return $this->getVars(); 160 } 161 162 return $uri->getQuery(true); 163 } 164 165 /** 166 * Function to convert an internal URI to a route 167 * 168 * @param string|array|Uri $url The internal URL or an associative array 169 * 170 * @return Uri The absolute search engine friendly URL object 171 * 172 * @since 1.5 173 */ 174 public function build($url) 175 { 176 $key = md5(serialize($url)); 177 178 if (isset($this->cache[$key])) { 179 return clone $this->cache[$key]; 180 } 181 182 if ($url instanceof Uri) { 183 $uri = $url; 184 } else { 185 $uri = $this->createUri($url); 186 } 187 188 // Do the preprocess stage of the URL build process 189 $this->processBuildRules($uri, self::PROCESS_BEFORE); 190 191 // Do the main stage of the URL build process 192 $this->processBuildRules($uri); 193 194 // Do the postprocess stage of the URL build process 195 $this->processBuildRules($uri, self::PROCESS_AFTER); 196 197 $this->cache[$key] = clone $uri; 198 199 return $uri; 200 } 201 202 /** 203 * Set a router variable, creating it if it doesn't exist 204 * 205 * @param string $key The name of the variable 206 * @param mixed $value The value of the variable 207 * @param boolean $create If True, the variable will be created if it doesn't exist yet 208 * 209 * @return void 210 * 211 * @since 1.5 212 */ 213 public function setVar($key, $value, $create = true) 214 { 215 if ($create || \array_key_exists($key, $this->vars)) { 216 $this->vars[$key] = $value; 217 } 218 } 219 220 /** 221 * Set the router variable array 222 * 223 * @param array $vars An associative array with variables 224 * @param boolean $merge If True, the array will be merged instead of overwritten 225 * 226 * @return void 227 * 228 * @since 1.5 229 */ 230 public function setVars($vars = array(), $merge = true) 231 { 232 if ($merge) { 233 $this->vars = array_merge($this->vars, $vars); 234 } else { 235 $this->vars = $vars; 236 } 237 } 238 239 /** 240 * Get a router variable 241 * 242 * @param string $key The name of the variable 243 * 244 * @return mixed Value of the variable 245 * 246 * @since 1.5 247 */ 248 public function getVar($key) 249 { 250 $result = null; 251 252 if (isset($this->vars[$key])) { 253 $result = $this->vars[$key]; 254 } 255 256 return $result; 257 } 258 259 /** 260 * Get the router variable array 261 * 262 * @return array An associative array of router variables 263 * 264 * @since 1.5 265 */ 266 public function getVars() 267 { 268 return $this->vars; 269 } 270 271 /** 272 * Attach a build rule 273 * 274 * @param callable $callback The function to be called 275 * @param string $stage The stage of the build process that 276 * this should be added to. Possible values: 277 * 'preprocess', '' for the main build process, 278 * 'postprocess' 279 * 280 * @return void 281 * 282 * @since 1.5 283 */ 284 public function attachBuildRule(callable $callback, $stage = self::PROCESS_DURING) 285 { 286 if (!\array_key_exists('build' . $stage, $this->rules)) { 287 throw new \InvalidArgumentException(sprintf('The %s stage is not registered. (%s)', $stage, __METHOD__)); 288 } 289 290 $this->rules['build' . $stage][] = $callback; 291 } 292 293 /** 294 * Attach a parse rule 295 * 296 * @param callable $callback The function to be called. 297 * @param string $stage The stage of the parse process that 298 * this should be added to. Possible values: 299 * 'preprocess', '' for the main parse process, 300 * 'postprocess' 301 * 302 * @return void 303 * 304 * @since 1.5 305 */ 306 public function attachParseRule(callable $callback, $stage = self::PROCESS_DURING) 307 { 308 if (!\array_key_exists('parse' . $stage, $this->rules)) { 309 throw new \InvalidArgumentException(sprintf('The %s stage is not registered. (%s)', $stage, __METHOD__)); 310 } 311 312 $this->rules['parse' . $stage][] = $callback; 313 } 314 315 /** 316 * Remove a rule 317 * 318 * @param string $type Type of rule to remove (parse or build) 319 * @param callable $rule The rule to be removed. 320 * @param string $stage The stage of the parse process that 321 * this should be added to. Possible values: 322 * 'preprocess', '' for the main parse process, 323 * 'postprocess' 324 * 325 * @return boolean Was a rule removed? 326 * 327 * @since 4.0.0 328 * @throws \InvalidArgumentException 329 */ 330 public function detachRule($type, $rule, $stage = self::PROCESS_DURING) 331 { 332 if (!\in_array($type, array('parse', 'build'))) { 333 throw new \InvalidArgumentException(sprintf('The %s type is not supported. (%s)', $type, __METHOD__)); 334 } 335 336 if (!\array_key_exists($type . $stage, $this->rules)) { 337 throw new \InvalidArgumentException(sprintf('The %s stage is not registered. (%s)', $stage, __METHOD__)); 338 } 339 340 foreach ($this->rules[$type . $stage] as $id => $r) { 341 if ($r == $rule) { 342 unset($this->rules[$type . $stage][$id]); 343 344 return true; 345 } 346 } 347 348 return false; 349 } 350 351 /** 352 * Get all currently attached rules 353 * 354 * @return array All currently attached rules in an array 355 * 356 * @since 4.0.0 357 */ 358 public function getRules() 359 { 360 return $this->rules; 361 } 362 363 /** 364 * Process the parsed router variables based on custom defined rules 365 * 366 * @param \Joomla\CMS\Uri\Uri &$uri The URI to parse 367 * @param string $stage The stage that should be processed. 368 * Possible values: 'preprocess', 'postprocess' 369 * and '' for the main parse stage 370 * 371 * @return void 372 * 373 * @since 3.2 374 */ 375 protected function processParseRules(&$uri, $stage = self::PROCESS_DURING) 376 { 377 if (!\array_key_exists('parse' . $stage, $this->rules)) { 378 throw new \InvalidArgumentException(sprintf('The %s stage is not registered. (%s)', $stage, __METHOD__)); 379 } 380 381 foreach ($this->rules['parse' . $stage] as $rule) { 382 $rule($this, $uri); 383 } 384 } 385 386 /** 387 * Process the build uri query data based on custom defined rules 388 * 389 * @param \Joomla\CMS\Uri\Uri &$uri The URI 390 * @param string $stage The stage that should be processed. 391 * Possible values: 'preprocess', 'postprocess' 392 * and '' for the main build stage 393 * 394 * @return void 395 * 396 * @since 3.2 397 */ 398 protected function processBuildRules(&$uri, $stage = self::PROCESS_DURING) 399 { 400 if (!\array_key_exists('build' . $stage, $this->rules)) { 401 throw new \InvalidArgumentException(sprintf('The %s stage is not registered. (%s)', $stage, __METHOD__)); 402 } 403 404 foreach ($this->rules['build' . $stage] as $rule) { 405 \call_user_func_array($rule, array(&$this, &$uri)); 406 } 407 } 408 409 /** 410 * Create a uri based on a full or partial URL string 411 * 412 * @param string $url The URI or an associative array 413 * 414 * @return Uri 415 * 416 * @since 3.2 417 */ 418 protected function createUri($url) 419 { 420 if (!\is_array($url) && substr($url, 0, 1) !== '&') { 421 return new Uri($url); 422 } 423 424 $uri = new Uri('index.php'); 425 426 if (\is_string($url)) { 427 $vars = array(); 428 429 if (strpos($url, '&') !== false) { 430 $url = str_replace('&', '&', $url); 431 } 432 433 parse_str($url, $vars); 434 } else { 435 $vars = $url; 436 } 437 438 $vars = array_merge($this->getVars(), $vars); 439 440 foreach ($vars as $key => $var) { 441 if ($var == '') { 442 unset($vars[$key]); 443 } 444 } 445 446 $uri->setQuery($vars); 447 448 return $uri; 449 } 450 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |