[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/src/Router/ -> Router.php (source)

   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, '&amp;') !== false) {
 430                  $url = str_replace('&amp;', '&', $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  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer