Spade
Mini Shell
| Directory:~$ /home/lmsyaran/public_html/joomla4/ |
| [Home] [System Details] [Kill Me] |
AdministratorRouter.php000064400000002076151155474540011316
0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Router;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Uri\Uri;
/**
* Class to create and parse routes
*
* @since 1.5
*/
class AdministratorRouter extends Router
{
/**
* Function to convert a route to an internal URI.
*
* @param Uri &$uri The uri.
*
* @return array
*
* @since 1.5
*/
public function parse(&$uri)
{
return array();
}
/**
* Function to convert an internal URI to a route
*
* @param string $url The internal URL
*
* @return Uri The absolute search engine friendly URL
*
* @since 1.5
*/
public function build($url)
{
// Create the URI object
$uri = parent::build($url);
// Get the path data
$route = $uri->getPath();
// Add basepath to the uri
$uri->setPath(Uri::root(true) . '/' .
basename(JPATH_ADMINISTRATOR) . '/' . $route);
return $uri;
}
}
Exception/RouteNotFoundException.php000064400000001637151155474540013667
0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Router\Exception;
defined('JPATH_PLATFORM') or die;
/**
* Exception class defining an error for a missing route
*
* @since 3.8.0
*/
class RouteNotFoundException extends \InvalidArgumentException
{
/**
* Constructor
*
* @param string $message The Exception message to throw.
* @param integer $code The Exception code.
* @param \Exception $previous The previous exception used for the
exception chaining.
*
* @since 3.8.0
*/
public function __construct($message = '', $code = 404,
\Exception $previous = null)
{
if (empty($message))
{
$message = 'URL was not found';
}
parent::__construct($message, $code, $previous);
}
}
Route.php000064400000012532151155474540006371 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Router;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
/**
* Route handling class
*
* @since 1.7.0
*/
class Route
{
/**
* No change, use the protocol currently used.
*
* @since 3.9.7
*/
const TLS_IGNORE = 0;
/**
* Make URI secure using http over TLS (https).
*
* @since 3.9.7
*/
const TLS_FORCE = 1;
/**
* Make URI unsecure using plain http (http).
*
* @since 3.9.7
*/
const TLS_DISABLE = 2;
/**
* The route object so we don't have to keep fetching it.
*
* @var Router[]
* @since 3.0.1
*/
private static $_router = array();
/**
* Translates an internal Joomla URL to a humanly readable URL. This
method builds links for the current active client.
*
* @param string $url Absolute or Relative URI to Joomla
resource.
* @param boolean $xhtml Replace & by & for XML
compliance.
* @param integer $tls Secure state for the resolved URI. Use
Route::TLS_* constants
* 0: (default) No change, use the protocol
currently used in the request
* 1: Make URI secure using global secure
site URI.
* 2: Make URI unsecure using the global
unsecure site URI.
* @param boolean $absolute Return an absolute URL
*
* @return string The translated humanly readable URL.
*
* @since 1.7.0
*/
public static function _($url, $xhtml = true, $tls = self::TLS_IGNORE,
$absolute = false)
{
try
{
// @deprecated 4.0 Before 3.9.7 this method silently converted $tls to
integer
if (!is_int($tls))
{
Log::add(
__METHOD__ . '() called with incompatible variable type on
parameter $tls.',
Log::WARNING,
'deprecated'
);
$tls = (int) $tls;
}
// @todo Deprecate in 4.0 Before 3.9.7 this method accepted -1.
if ($tls === -1)
{
$tls = self::TLS_DISABLE;
}
$app = Factory::getApplication();
$client = $app->getName();
return static::link($client, $url, $xhtml, $tls, $absolute);
}
catch (\RuntimeException $e)
{
// @deprecated 4.0 Before 3.9.0 this method failed silently on router
error. This B/C will be removed in Joomla 4.0.
return null;
}
}
/**
* Translates an internal Joomla URL to a humanly readable URL.
* NOTE: To build link for active client instead of a specific client, you
can use <var>JRoute::_()</var>
*
* @param string $client The client name for which to build the
link.
* @param string $url Absolute or Relative URI to Joomla
resource.
* @param boolean $xhtml Replace & by & for XML
compliance.
* @param integer $tls Secure state for the resolved URI. Use
Route::TLS_* constants
* 0: (default) No change, use the protocol
currently used in the request
* 1: Make URI secure using global secure
site URI.
* 2: Make URI unsecure using the global
unsecure site URI.
* @param boolean $absolute Return an absolute URL
*
* @return string The translated humanly readable URL.
*
* @throws \RuntimeException
*
* @since 3.9.0
*/
public static function link($client, $url, $xhtml = true, $tls =
self::TLS_IGNORE, $absolute = false)
{
// If we cannot process this $url exit early.
if (!is_array($url) && (strpos($url, '&') !== 0)
&& (strpos($url, 'index.php') !== 0))
{
return $url;
}
// Get the router instance, only attempt when a client name is given.
if ($client && !isset(self::$_router[$client]))
{
$app = Factory::getApplication();
self::$_router[$client] = $app->getRouter($client);
}
// Make sure that we have our router
if (!isset(self::$_router[$client]))
{
throw new
\RuntimeException(\JText::sprintf('JLIB_APPLICATION_ERROR_ROUTER_LOAD',
$client), 500);
}
// Build route.
$uri = self::$_router[$client]->build($url);
$scheme = array('path', 'query',
'fragment');
/*
* Get the secure/unsecure URLs.
*
* If the first 5 characters of the BASE are 'https', then we
are on an ssl connection over
* https and need to set our secure URL to the current request URL, if
not, and the scheme is
* 'http', then we need to do a quick string manipulation to
switch schemes.
*/
if ($tls === self::TLS_FORCE)
{
$uri->setScheme('https');
}
elseif ($tls === self::TLS_DISABLE)
{
$uri->setScheme('http');
}
// Set scheme if requested or
if ($absolute || $tls > 0)
{
static $scheme_host_port;
if (!is_array($scheme_host_port))
{
$uri2 = Uri::getInstance();
$scheme_host_port = array($uri2->getScheme(), $uri2->getHost(),
$uri2->getPort());
}
if (is_null($uri->getScheme()))
{
$uri->setScheme($scheme_host_port[0]);
}
$uri->setHost($scheme_host_port[1]);
$uri->setPort($scheme_host_port[2]);
$scheme = array_merge($scheme, array('host', 'port',
'scheme'));
}
$url = $uri->toString($scheme);
// Replace spaces.
$url = preg_replace('/\s/u', '%20', $url);
if ($xhtml)
{
$url = htmlspecialchars($url, ENT_COMPAT, 'UTF-8');
}
return $url;
}
}
Router.php000064400000040307151155474540006554 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Router;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Router\Exception\RouteNotFoundException;
/**
* Class to create and parse routes
*
* @since 1.5
*/
class Router
{
/**
* Mask for the before process stage
*
* @var string
* @since 3.4
*/
const PROCESS_BEFORE = 'preprocess';
/**
* Mask for the during process stage
*
* @var string
* @since 3.4
*/
const PROCESS_DURING = '';
/**
* Mask for the after process stage
*
* @var string
* @since 3.4
*/
const PROCESS_AFTER = 'postprocess';
/**
* The rewrite mode
*
* @var integer
* @since 1.5
* @deprecated 4.0
*/
protected $mode = null;
/**
* The rewrite mode
*
* @var integer
* @since 1.5
* @deprecated 4.0
*/
protected $_mode = null;
/**
* An array of variables
*
* @var array
* @since 1.5
*/
protected $vars = array();
/**
* An array of variables
*
* @var array
* @since 1.5
* @deprecated 4.0 Will convert to $vars
*/
protected $_vars = array();
/**
* An array of rules
*
* @var array
* @since 1.5
*/
protected $rules = array(
'buildpreprocess' => array(),
'build' => array(),
'buildpostprocess' => array(),
'parsepreprocess' => array(),
'parse' => array(),
'parsepostprocess' => array(),
);
/**
* An array of rules
*
* @var array
* @since 1.5
* @deprecated 4.0 Will convert to $rules
*/
protected $_rules = array(
'buildpreprocess' => array(),
'build' => array(),
'buildpostprocess' => array(),
'parsepreprocess' => array(),
'parse' => array(),
'parsepostprocess' => array(),
);
/**
* Caching of processed URIs
*
* @var array
* @since 3.3
*/
protected $cache = array();
/**
* Router instances container.
*
* @var Router[]
* @since 1.7
*/
protected static $instances = array();
/**
* Class constructor
*
* @param array $options Array of options
*
* @since 1.5
*/
public function __construct($options = array())
{
if (array_key_exists('mode', $options))
{
$this->_mode = $options['mode'];
}
else
{
$this->_mode = JROUTER_MODE_RAW;
}
}
/**
* Returns the global Router object, only creating it if it
* doesn't already exist.
*
* @param string $client The name of the client
* @param array $options An associative array of options
*
* @return Router A Router object.
*
* @since 1.5
* @throws \RuntimeException
*/
public static function getInstance($client, $options = array())
{
if (empty(self::$instances[$client]))
{
// Create a Router object
$classname = 'JRouter' . ucfirst($client);
if (!class_exists($classname))
{
// @deprecated 4.0 Everything in this block is deprecated but the
warning is only logged after the file_exists
// Load the router object
$info = ApplicationHelper::getClientInfo($client, true);
if (is_object($info))
{
$path = $info->path . '/includes/router.php';
\JLoader::register($classname, $path);
if (class_exists($classname))
{
\JLog::add('Non-autoloadable Router subclasses are deprecated,
support will be removed in 4.0.', \JLog::WARNING,
'deprecated');
}
}
}
if (class_exists($classname))
{
self::$instances[$client] = new $classname($options);
}
else
{
throw new
\RuntimeException(\JText::sprintf('JLIB_APPLICATION_ERROR_ROUTER_LOAD',
$client), 500);
}
}
return self::$instances[$client];
}
/**
* Function to convert a route to an internal URI
*
* @param \JUri &$uri The uri.
*
* @return array
*
* @since 1.5
*/
public function parse(&$uri)
{
// Do the preprocess stage of the URL build process
$vars = $this->processParseRules($uri, self::PROCESS_BEFORE);
// Process the parsed variables based on custom defined rules
// This is the main parse stage
$vars += $this->_processParseRules($uri);
// Parse RAW URL
if ($this->_mode == JROUTER_MODE_RAW)
{
$vars += $this->_parseRawRoute($uri);
}
// Parse SEF URL
if ($this->_mode == JROUTER_MODE_SEF)
{
$vars += $this->_parseSefRoute($uri);
}
// Do the postprocess stage of the URL build process
$vars += $this->processParseRules($uri, self::PROCESS_AFTER);
// Check if all parts of the URL have been parsed.
// Otherwise we have an invalid URL
if (strlen($uri->getPath()) > 0 &&
array_key_exists('option', $vars)
&&
ComponentHelper::getParams($vars['option'])->get('sef_advanced',
0))
{
throw new
RouteNotFoundException(\JText::_('JERROR_PAGE_NOT_FOUND'));
}
return array_merge($this->getVars(), $vars);
}
/**
* Function to convert an internal URI to a route
*
* @param string $url The internal URL or an associative array
*
* @return \JUri The absolute search engine friendly URL object
*
* @since 1.5
*/
public function build($url)
{
$key = md5(serialize($url));
if (isset($this->cache[$key]))
{
return clone $this->cache[$key];
}
// Create the URI object
$uri = $this->createUri($url);
// Do the preprocess stage of the URL build process
$this->processBuildRules($uri, self::PROCESS_BEFORE);
// Process the uri information based on custom defined rules.
// This is the main build stage
$this->_processBuildRules($uri);
// Build RAW URL
if ($this->_mode == JROUTER_MODE_RAW)
{
$this->_buildRawRoute($uri);
}
// Build SEF URL : mysite/route/index.php?var=x
if ($this->_mode == JROUTER_MODE_SEF)
{
$this->_buildSefRoute($uri);
}
// Do the postprocess stage of the URL build process
$this->processBuildRules($uri, self::PROCESS_AFTER);
$this->cache[$key] = clone $uri;
return $uri;
}
/**
* Get the router mode
*
* @return integer
*
* @since 1.5
* @deprecated 4.0
*/
public function getMode()
{
return $this->_mode;
}
/**
* Set the router mode
*
* @param integer $mode The routing mode.
*
* @return void
*
* @since 1.5
* @deprecated 4.0
*/
public function setMode($mode)
{
$this->_mode = $mode;
}
/**
* Set a router variable, creating it if it doesn't exist
*
* @param string $key The name of the variable
* @param mixed $value The value of the variable
* @param boolean $create If True, the variable will be created if it
doesn't exist yet
*
* @return void
*
* @since 1.5
*/
public function setVar($key, $value, $create = true)
{
if ($create || array_key_exists($key, $this->_vars))
{
$this->_vars[$key] = $value;
}
}
/**
* Set the router variable array
*
* @param array $vars An associative array with variables
* @param boolean $merge If True, the array will be merged instead of
overwritten
*
* @return void
*
* @since 1.5
*/
public function setVars($vars = array(), $merge = true)
{
if ($merge)
{
$this->_vars = array_merge($this->_vars, $vars);
}
else
{
$this->_vars = $vars;
}
}
/**
* Get a router variable
*
* @param string $key The name of the variable
*
* @return mixed Value of the variable
*
* @since 1.5
*/
public function getVar($key)
{
$result = null;
if (isset($this->_vars[$key]))
{
$result = $this->_vars[$key];
}
return $result;
}
/**
* Get the router variable array
*
* @return array An associative array of router variables
*
* @since 1.5
*/
public function getVars()
{
return $this->_vars;
}
/**
* Attach a build rule
*
* @param callable $callback The function to be called
* @param string $stage The stage of the build process that
* this should be added to. Possible values:
* 'preprocess', '' for
the main build process,
* 'postprocess'
*
* @return void
*
* @since 1.5
*/
public function attachBuildRule($callback, $stage = self::PROCESS_DURING)
{
if (!array_key_exists('build' . $stage, $this->_rules))
{
throw new \InvalidArgumentException(sprintf('The %s stage is not
registered. (%s)', $stage, __METHOD__));
}
$this->_rules['build' . $stage][] = $callback;
}
/**
* Attach a parse rule
*
* @param callable $callback The function to be called.
* @param string $stage The stage of the parse process that
* this should be added to. Possible values:
* 'preprocess', '' for
the main parse process,
* 'postprocess'
*
* @return void
*
* @since 1.5
*/
public function attachParseRule($callback, $stage = self::PROCESS_DURING)
{
if (!array_key_exists('parse' . $stage, $this->_rules))
{
throw new \InvalidArgumentException(sprintf('The %s stage is not
registered. (%s)', $stage, __METHOD__));
}
$this->_rules['parse' . $stage][] = $callback;
}
/**
* Function to convert a raw route to an internal URI
*
* @param \JUri &$uri The raw route
*
* @return boolean
*
* @since 1.5
* @deprecated 4.0 Attach your logic as rule to the main parse stage
*/
protected function _parseRawRoute(&$uri)
{
return $this->parseRawRoute($uri);
}
/**
* Function to convert a raw route to an internal URI
*
* @param \JUri &$uri The raw route
*
* @return array Array of variables
*
* @since 3.2
* @deprecated 4.0 Attach your logic as rule to the main parse stage
*/
protected function parseRawRoute(&$uri)
{
return array();
}
/**
* Function to convert a sef route to an internal URI
*
* @param \JUri &$uri The sef URI
*
* @return string Internal URI
*
* @since 1.5
* @deprecated 4.0 Attach your logic as rule to the main parse stage
*/
protected function _parseSefRoute(&$uri)
{
return $this->parseSefRoute($uri);
}
/**
* Function to convert a sef route to an internal URI
*
* @param \JUri &$uri The sef URI
*
* @return array Array of variables
*
* @since 3.2
* @deprecated 4.0 Attach your logic as rule to the main parse stage
*/
protected function parseSefRoute(&$uri)
{
return array();
}
/**
* Function to build a raw route
*
* @param \JUri &$uri The internal URL
*
* @return string Raw Route
*
* @since 1.5
* @deprecated 4.0 Attach your logic as rule to the main build stage
*/
protected function _buildRawRoute(&$uri)
{
return $this->buildRawRoute($uri);
}
/**
* Function to build a raw route
*
* @param \JUri &$uri The internal URL
*
* @return string Raw Route
*
* @since 3.2
* @deprecated 4.0 Attach your logic as rule to the main build stage
*/
protected function buildRawRoute(&$uri)
{
}
/**
* Function to build a sef route
*
* @param \JUri &$uri The uri
*
* @return string The SEF route
*
* @since 1.5
* @deprecated 4.0 Attach your logic as rule to the main build stage
*/
protected function _buildSefRoute(&$uri)
{
return $this->buildSefRoute($uri);
}
/**
* Function to build a sef route
*
* @param \JUri &$uri The uri
*
* @return string The SEF route
*
* @since 3.2
* @deprecated 4.0 Attach your logic as rule to the main build stage
*/
protected function buildSefRoute(&$uri)
{
}
/**
* Process the parsed router variables based on custom defined rules
*
* @param \JUri &$uri The URI to parse
*
* @return array The array of processed URI variables
*
* @since 1.5
* @deprecated 4.0 Use processParseRules() instead
*/
protected function _processParseRules(&$uri)
{
return $this->processParseRules($uri);
}
/**
* Process the parsed router variables based on custom defined rules
*
* @param \JUri &$uri The URI to parse
* @param string $stage The stage that should be processed.
* Possible values: 'preprocess',
'postprocess'
* and '' for the main parse stage
*
* @return array The array of processed URI variables
*
* @since 3.2
*/
protected function processParseRules(&$uri, $stage =
self::PROCESS_DURING)
{
if (!array_key_exists('parse' . $stage, $this->_rules))
{
throw new \InvalidArgumentException(sprintf('The %s stage is not
registered. (%s)', $stage, __METHOD__));
}
$vars = array();
foreach ($this->_rules['parse' . $stage] as $rule)
{
$vars += (array) call_user_func_array($rule, array(&$this,
&$uri));
}
return $vars;
}
/**
* Process the build uri query data based on custom defined rules
*
* @param \JUri &$uri The URI
*
* @return void
*
* @since 1.5
* @deprecated 4.0 Use processBuildRules() instead
*/
protected function _processBuildRules(&$uri)
{
$this->processBuildRules($uri);
}
/**
* Process the build uri query data based on custom defined rules
*
* @param \JUri &$uri The URI
* @param string $stage The stage that should be processed.
* Possible values: 'preprocess',
'postprocess'
* and '' for the main build stage
*
* @return void
*
* @since 3.2
*/
protected function processBuildRules(&$uri, $stage =
self::PROCESS_DURING)
{
if (!array_key_exists('build' . $stage, $this->_rules))
{
throw new \InvalidArgumentException(sprintf('The %s stage is not
registered. (%s)', $stage, __METHOD__));
}
foreach ($this->_rules['build' . $stage] as $rule)
{
call_user_func_array($rule, array(&$this, &$uri));
}
}
/**
* Create a uri based on a full or partial URL string
*
* @param string $url The URI
*
* @return \JUri
*
* @since 1.5
* @deprecated 4.0 Use createUri() instead
* @codeCoverageIgnore
*/
protected function _createUri($url)
{
return $this->createUri($url);
}
/**
* Create a uri based on a full or partial URL string
*
* @param string $url The URI or an associative array
*
* @return \JUri
*
* @since 3.2
*/
protected function createUri($url)
{
if (!is_array($url) && substr($url, 0, 1) !== '&')
{
return new \JUri($url);
}
$uri = new \JUri('index.php');
if (is_string($url))
{
$vars = array();
if (strpos($url, '&') !== false)
{
$url = str_replace('&', '&', $url);
}
parse_str($url, $vars);
}
else
{
$vars = $url;
}
$vars = array_merge($this->getVars(), $vars);
foreach ($vars as $key => $var)
{
if ($var == '')
{
unset($vars[$key]);
}
}
$uri->setQuery($vars);
return $uri;
}
/**
* Encode route segments
*
* @param array $segments An array of route segments
*
* @return array Array of encoded route segments
*
* @since 1.5
* @deprecated 4.0 This should be performed in the component router
instead
* @codeCoverageIgnore
*/
protected function _encodeSegments($segments)
{
return $this->encodeSegments($segments);
}
/**
* Encode route segments
*
* @param array $segments An array of route segments
*
* @return array Array of encoded route segments
*
* @since 3.2
* @deprecated 4.0 This should be performed in the component router
instead
*/
protected function encodeSegments($segments)
{
$total = count($segments);
for ($i = 0; $i < $total; $i++)
{
$segments[$i] = str_replace(':', '-',
$segments[$i]);
}
return $segments;
}
/**
* Decode route segments
*
* @param array $segments An array of route segments
*
* @return array Array of decoded route segments
*
* @since 1.5
* @deprecated 4.0 This should be performed in the component router
instead
* @codeCoverageIgnore
*/
protected function _decodeSegments($segments)
{
return $this->decodeSegments($segments);
}
/**
* Decode route segments
*
* @param array $segments An array of route segments
*
* @return array Array of decoded route segments
*
* @since 3.2
* @deprecated 4.0 This should be performed in the component router
instead
*/
protected function decodeSegments($segments)
{
$total = count($segments);
for ($i = 0; $i < $total; $i++)
{
$segments[$i] = preg_replace('/-/', ':',
$segments[$i], 1);
}
return $segments;
}
}
SiteRouter.php000064400000044637151155474540007413 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Router;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Component\Router\RouterBase;
use Joomla\CMS\Component\Router\RouterInterface;
use Joomla\CMS\Component\Router\RouterLegacy;
use Joomla\String\StringHelper;
/**
* Class to create and parse routes for the site application
*
* @since 1.5
*/
class SiteRouter extends Router
{
/**
* Component-router objects
*
* @var array
* @since 3.3
*/
protected $componentRouters = array();
/**
* Current Application-Object
*
* @var CMSApplication
* @since 3.4
*/
protected $app;
/**
* Current \JMenu-Object
*
* @var \JMenu
* @since 3.4
*/
protected $menu;
/**
* Class constructor
*
* @param array $options Array of options
* @param CMSApplication $app CMSApplication Object
* @param \JMenu $menu \JMenu object
*
* @since 3.4
*/
public function __construct($options = array(), CMSApplication $app =
null, \JMenu $menu = null)
{
parent::__construct($options);
$this->app = $app ?: CMSApplication::getInstance('site');
$this->menu = $menu ?: $this->app->getMenu();
}
/**
* Function to convert a route to an internal URI
*
* @param \JUri &$uri The uri.
*
* @return array
*
* @since 1.5
*/
public function parse(&$uri)
{
$vars = array();
if ($this->app->get('force_ssl') == 2 &&
strtolower($uri->getScheme()) !== 'https')
{
// Forward to https
$uri->setScheme('https');
$this->app->redirect((string) $uri, 301);
}
// Get the path
// Decode URL to convert percent-encoding to unicode so that strings
match when routing.
$path = urldecode($uri->getPath());
// Remove the base URI path.
$path = substr_replace($path, '', 0,
strlen(\JUri::base(true)));
// Check to see if a request to a specific entry point has been made.
if (preg_match("#.*?\.php#u", $path, $matches))
{
// Get the current entry point path relative to the site path.
$scriptPath = realpath($_SERVER['SCRIPT_FILENAME'] ?:
str_replace('\\\\', '\\',
$_SERVER['PATH_TRANSLATED']));
$relativeScriptPath = str_replace('\\', '/',
str_replace(JPATH_SITE, '', $scriptPath));
// If a php file has been found in the request path, check to see if it
is a valid file.
// Also verify that it represents the same file from the server variable
for entry script.
if (file_exists(JPATH_SITE . $matches[0]) && ($matches[0] ===
$relativeScriptPath))
{
// Remove the entry point segments from the request path for proper
routing.
$path = str_replace($matches[0], '', $path);
}
}
// Identify format
if ($this->_mode == JROUTER_MODE_SEF)
{
if ($this->app->get('sef_suffix') &&
!(substr($path, -9) === 'index.php' || substr($path, -1) ===
'/'))
{
if ($suffix = pathinfo($path, PATHINFO_EXTENSION))
{
$vars['format'] = $suffix;
}
}
}
// Set the route
$uri->setPath(trim($path, '/'));
// Set the parsepreprocess components methods
$components = ComponentHelper::getComponents();
foreach ($components as $component)
{
$componentRouter = $this->getComponentRouter($component->option);
if (method_exists($componentRouter, 'parsepreprocess'))
{
$this->attachParseRule(array($componentRouter,
'parsepreprocess'), static::PROCESS_BEFORE);
}
}
$vars += parent::parse($uri);
return $vars;
}
/**
* Function to convert an internal URI to a route
*
* @param string $url The internal URL
*
* @return string The absolute search engine friendly URL
*
* @since 1.5
*/
public function build($url)
{
$uri = parent::build($url);
// Get the path data
$route = $uri->getPath();
// Add the suffix to the uri
if ($this->_mode == JROUTER_MODE_SEF && $route)
{
if ($this->app->get('sef_suffix') &&
!(substr($route, -9) === 'index.php' || substr($route, -1) ===
'/'))
{
if ($format = $uri->getVar('format', 'html'))
{
$route .= '.' . $format;
$uri->delVar('format');
}
}
if ($this->app->get('sef_rewrite'))
{
// Transform the route
if ($route === 'index.php')
{
$route = '';
}
else
{
$route = str_replace('index.php/', '', $route);
}
}
}
// Add frontend basepath to the uri
$uri->setPath(\JUri::root(true) . '/' . $route);
return $uri;
}
/**
* Function to convert a raw route to an internal URI
*
* @param \JUri &$uri The raw route
*
* @return array
*
* @since 3.2
* @deprecated 4.0 Attach your logic as rule to the main parse stage
*/
protected function parseRawRoute(&$uri)
{
$vars = array();
// Handle an empty URL (special case)
if (!$uri->getVar('Itemid') &&
!$uri->getVar('option'))
{
$item =
$this->menu->getDefault($this->app->getLanguage()->getTag());
if (!is_object($item))
{
// No default item set
return $vars;
}
// Set the information in the request
$vars = $item->query;
// Get the itemid
$vars['Itemid'] = $item->id;
// Set the active menu item
$this->menu->setActive($vars['Itemid']);
return $vars;
}
// Get the variables from the uri
$this->setVars($uri->getQuery(true));
// Get the itemid, if it hasn't been set force it to null
$this->setVar('Itemid',
$this->app->input->getInt('Itemid', null));
// Only an Itemid OR if filter language plugin set? Get the full
information from the itemid
if (count($this->getVars()) === 1 ||
($this->app->getLanguageFilter() &&
count($this->getVars()) === 2))
{
$item =
$this->menu->getItem($this->getVar('Itemid'));
if ($item && $item->type == 'alias')
{
$newItem =
$this->menu->getItem($item->params->get('aliasoptions'));
if ($newItem)
{
$item->query = array_merge($item->query,
$newItem->query);
$item->component = $newItem->component;
}
}
if ($item !== null && is_array($item->query))
{
$vars += $item->query;
}
}
// Set the active menu item
$this->menu->setActive($this->getVar('Itemid'));
return $vars;
}
/**
* Function to convert a sef route to an internal URI
*
* @param \JUri &$uri The sef URI
*
* @return string Internal URI
*
* @since 3.2
* @deprecated 4.0 Attach your logic as rule to the main parse stage
*/
protected function parseSefRoute(&$uri)
{
$route = $uri->getPath();
// Remove the suffix
if ($this->app->get('sef_suffix'))
{
if ($suffix = pathinfo($route, PATHINFO_EXTENSION))
{
$route = str_replace('.' . $suffix, '', $route);
}
}
// Get the variables from the uri
$vars = $uri->getQuery(true);
// Handle an empty URL (special case)
if (empty($route))
{
// If route is empty AND option is set in the query, assume it's
non-sef url, and parse appropriately
if (isset($vars['option']) ||
isset($vars['Itemid']))
{
return $this->parseRawRoute($uri);
}
$item =
$this->menu->getDefault($this->app->getLanguage()->getTag());
// If user not allowed to see default menu item then avoid notices
if (is_object($item))
{
// Set query variables of default menu item into the request, but keep
existing request variables
$vars = array_merge($vars, $item->query);
// Get the itemid
$vars['Itemid'] = $item->id;
// Set the active menu item
$this->menu->setActive($vars['Itemid']);
$this->setVars($vars);
}
return $vars;
}
// Parse the application route
$segments = explode('/', $route);
if (count($segments) > 1 && $segments[0] ===
'component')
{
$vars['option'] = 'com_' . $segments[1];
$vars['Itemid'] = null;
$route = implode('/', array_slice($segments, 2));
}
else
{
// Get menu items.
$items = $this->menu->getMenu();
$found = false;
$route_lowercase = StringHelper::strtolower($route);
$lang_tag = $this->app->getLanguage()->getTag();
// Iterate through all items and check route matches.
foreach ($items as $item)
{
if ($item->route && StringHelper::strpos($route_lowercase .
'/', $item->route . '/') === 0 &&
$item->type !== 'menulink')
{
// Usual method for non-multilingual site.
if (!$this->app->getLanguageFilter())
{
// Exact route match. We can break iteration because exact item was
found.
if ($item->route === $route_lowercase)
{
$found = $item;
break;
}
// Partial route match. Item with highest level takes priority.
if (!$found || $found->level < $item->level)
{
$found = $item;
}
}
// Multilingual site.
elseif ($item->language === '*' || $item->language ===
$lang_tag)
{
// Exact route match.
if ($item->route === $route_lowercase)
{
$found = $item;
// Break iteration only if language is matched.
if ($item->language === $lang_tag)
{
break;
}
}
// Partial route match. Item with highest level or same language
takes priority.
if (!$found || $found->level < $item->level ||
$item->language === $lang_tag)
{
$found = $item;
}
}
}
}
if (!$found)
{
$found = $this->menu->getDefault($lang_tag);
}
else
{
$route = substr($route, strlen($found->route));
if ($route)
{
$route = substr($route, 1);
}
}
if ($found)
{
if ($found->type == 'alias')
{
$newItem =
$this->menu->getItem($found->params->get('aliasoptions'));
if ($newItem)
{
$found->query = array_merge($found->query,
$newItem->query);
$found->component = $newItem->component;
}
}
$vars['Itemid'] = $found->id;
$vars['option'] = $found->component;
}
}
// Set the active menu item
if (isset($vars['Itemid']))
{
$this->menu->setActive($vars['Itemid']);
}
// Set the variables
$this->setVars($vars);
// Parse the component route
if (!empty($route) && isset($this->_vars['option']))
{
$segments = explode('/', $route);
if (empty($segments[0]))
{
array_shift($segments);
}
// Handle component route
$component = preg_replace('/[^A-Z0-9_\.-]/i', '',
$this->_vars['option']);
if (count($segments))
{
$crouter = $this->getComponentRouter($component);
$vars = $crouter->parse($segments);
$this->setVars($vars);
}
$route = implode('/', $segments);
}
else
{
// Set active menu item
if ($item = $this->menu->getActive())
{
$vars = $item->query;
}
}
$uri->setPath($route);
return $vars;
}
/**
* Function to build a raw route
*
* @param \JUri &$uri The internal URL
*
* @return string Raw Route
*
* @since 3.2
* @deprecated 4.0 Attach your logic as rule to the main build stage
*/
protected function buildRawRoute(&$uri)
{
// Get the query data
$query = $uri->getQuery(true);
if (!isset($query['option']))
{
return;
}
$component = preg_replace('/[^A-Z0-9_\.-]/i', '',
$query['option']);
$crouter = $this->getComponentRouter($component);
if ($crouter instanceof RouterBase === false)
{
$query = $crouter->preprocess($query);
$uri->setQuery($query);
}
}
/**
* Function to build a sef route
*
* @param \JUri &$uri The internal URL
*
* @return void
*
* @since 1.5
* @deprecated 4.0 Attach your logic as rule to the main build stage
* @codeCoverageIgnore
*/
protected function _buildSefRoute(&$uri)
{
$this->buildSefRoute($uri);
}
/**
* Function to build a sef route
*
* @param \JUri &$uri The uri
*
* @return void
*
* @since 3.2
* @deprecated 4.0 Attach your logic as rule to the main build stage
*/
protected function buildSefRoute(&$uri)
{
// Get the route
$route = $uri->getPath();
// Get the query data
$query = $uri->getQuery(true);
if (!isset($query['option']))
{
return;
}
// Build the component route
$component = preg_replace('/[^A-Z0-9_\.-]/i', '',
$query['option']);
$itemID = !empty($query['Itemid']) ?
$query['Itemid'] : null;
$crouter = $this->getComponentRouter($component);
$parts = $crouter->build($query);
$result = implode('/', $parts);
$tmp = ($result !== '') ? $result : '';
// Build the application route
$built = false;
if (!empty($query['Itemid']))
{
$item = $this->menu->getItem($query['Itemid']);
if (is_object($item) && $query['option'] ===
$item->component)
{
if (!$item->home)
{
$tmp = !empty($tmp) ? $item->route . '/' . $tmp :
$item->route;
}
$built = true;
}
}
if (empty($query['Itemid']) && !empty($itemID))
{
$query['Itemid'] = $itemID;
}
if (!$built)
{
$tmp = 'component/' . substr($query['option'], 4) .
'/' . $tmp;
}
if ($tmp)
{
$route .= '/' . $tmp;
}
// Unset unneeded query information
if (isset($item) && $query['option'] ===
$item->component)
{
unset($query['Itemid']);
}
unset($query['option']);
// Set query again in the URI
$uri->setQuery($query);
$uri->setPath($route);
}
/**
* Process the parsed router variables based on custom defined rules
*
* @param \JUri &$uri The URI to parse
* @param string $stage The stage that should be processed.
* Possible values: 'preprocess',
'postprocess'
* and '' for the main parse stage
*
* @return array The array of processed URI variables
*
* @since 3.2
*/
protected function processParseRules(&$uri, $stage =
self::PROCESS_DURING)
{
// Process the attached parse rules
$vars = parent::processParseRules($uri, $stage);
if ($stage === self::PROCESS_DURING)
{
// Process the pagination support
if ($this->_mode == JROUTER_MODE_SEF)
{
$start = $uri->getVar('start');
if ($start !== null)
{
$uri->delVar('start');
$vars['limitstart'] = $start;
}
}
}
return $vars;
}
/**
* Process the build uri query data based on custom defined rules
*
* @param \JUri &$uri The URI
* @param string $stage The stage that should be processed.
* Possible values: 'preprocess',
'postprocess'
* and '' for the main build stage
*
* @return void
*
* @since 3.2
* @deprecated 4.0 The special logic should be implemented as rule
*/
protected function processBuildRules(&$uri, $stage =
self::PROCESS_DURING)
{
if ($stage === self::PROCESS_DURING)
{
// Make sure any menu vars are used if no others are specified
$query = $uri->getQuery(true);
if ($this->_mode != 1
&& isset($query['Itemid'])
&& (count($query) === 2 || (count($query) === 3 &&
isset($query['lang']))))
{
// Get the active menu item
$itemid = $uri->getVar('Itemid');
$lang = $uri->getVar('lang');
$item = $this->menu->getItem($itemid);
if ($item)
{
$uri->setQuery($item->query);
}
$uri->setVar('Itemid', $itemid);
if ($lang)
{
$uri->setVar('lang', $lang);
}
}
}
// Process the attached build rules
parent::processBuildRules($uri, $stage);
if ($stage === self::PROCESS_BEFORE)
{
// Get the query data
$query = $uri->getQuery(true);
if (!isset($query['option']))
{
return;
}
// Build the component route
$component = preg_replace('/[^A-Z0-9_\.-]/i', '',
$query['option']);
$router = $this->getComponentRouter($component);
$query = $router->preprocess($query);
$uri->setQuery($query);
}
if ($stage === self::PROCESS_DURING)
{
// Get the path data
$route = $uri->getPath();
if ($this->_mode == JROUTER_MODE_SEF && $route)
{
$limitstart = $uri->getVar('limitstart');
if ($limitstart !== null)
{
$uri->setVar('start', (int) $limitstart);
$uri->delVar('limitstart');
}
}
$uri->setPath($route);
}
}
/**
* Create a uri based on a full or partial URL string
*
* @param string $url The URI
*
* @return \JUri
*
* @since 3.2
*/
protected function createUri($url)
{
// Create the URI
$uri = parent::createUri($url);
// Get the itemid form the URI
$itemid = $uri->getVar('Itemid');
if ($itemid === null)
{
if ($option = $uri->getVar('option'))
{
$item =
$this->menu->getItem($this->getVar('Itemid'));
if ($item !== null && $item->component === $option)
{
$uri->setVar('Itemid', $item->id);
}
}
else
{
if ($option = $this->getVar('option'))
{
$uri->setVar('option', $option);
}
if ($itemid = $this->getVar('Itemid'))
{
$uri->setVar('Itemid', $itemid);
}
}
}
else
{
if (!$uri->getVar('option'))
{
if ($item = $this->menu->getItem($itemid))
{
$uri->setVar('option', $item->component);
}
}
}
return $uri;
}
/**
* Get component router
*
* @param string $component Name of the component including com_
prefix
*
* @return RouterInterface Component router
*
* @since 3.3
*/
public function getComponentRouter($component)
{
if (!isset($this->componentRouters[$component]))
{
$compname = ucfirst(substr($component, 4));
$class = $compname . 'Router';
if (!class_exists($class))
{
// Use the component routing handler if it exists
$path = JPATH_SITE . '/components/' . $component .
'/router.php';
// Use the custom routing handler if it exists
if (file_exists($path))
{
require_once $path;
}
}
if (class_exists($class))
{
$reflection = new \ReflectionClass($class);
if
(in_array('Joomla\\CMS\\Component\\Router\\RouterInterface',
$reflection->getInterfaceNames()))
{
$this->componentRouters[$component] = new $class($this->app,
$this->menu);
}
}
if (!isset($this->componentRouters[$component]))
{
$this->componentRouters[$component] = new RouterLegacy($compname);
}
}
return $this->componentRouters[$component];
}
/**
* Set a router for a component
*
* @param string $component Component name with com_ prefix
* @param object $router Component router
*
* @return boolean True if the router was accepted, false if not
*
* @since 3.3
*/
public function setComponentRouter($component, $router)
{
$reflection = new \ReflectionClass($router);
if (in_array('Joomla\\CMS\\Component\\Router\\RouterInterface',
$reflection->getInterfaceNames()))
{
$this->componentRouters[$component] = $router;
return true;
}
else
{
return false;
}
}
}
RouterBase.php000064400000002572151162265130007340 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router;
defined('JPATH_PLATFORM') or die;
/**
* Base component routing class
*
* @since 3.3
*/
abstract class RouterBase implements RouterInterface
{
/**
* Application object to use in the router
*
* @var \JApplicationCms
* @since 3.4
*/
public $app;
/**
* Menu object to use in the router
*
* @var \JMenu
* @since 3.4
*/
public $menu;
/**
* Class constructor.
*
* @param \JApplicationCms $app Application-object that the router
should use
* @param \JMenu $menu Menu-object that the router should
use
*
* @since 3.4
*/
public function __construct($app = null, $menu = null)
{
if ($app)
{
$this->app = $app;
}
else
{
$this->app = \JFactory::getApplication('site');
}
if ($menu)
{
$this->menu = $menu;
}
else
{
$this->menu = $this->app->getMenu();
}
}
/**
* Generic method to preprocess a URL
*
* @param array $query An associative array of URL arguments
*
* @return array The URL arguments to use to assemble the subsequent
URL.
*
* @since 3.3
*/
public function preprocess($query)
{
return $query;
}
}
RouterInterface.php000064400000003115151162265130010360 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router;
defined('JPATH_PLATFORM') or die;
/**
* Component routing interface
*
* @since 3.3
*/
interface RouterInterface
{
/**
* Prepare-method for URLs
* This method is meant to validate and complete the URL parameters.
* For example it can add the Itemid or set a language parameter.
* This method is executed on each URL, regardless of SEF mode switched
* on or not.
*
* @param array $query An associative array of URL arguments
*
* @return array The URL arguments to use to assemble the subsequent
URL.
*
* @since 3.3
*/
public function preprocess($query);
/**
* Build method for URLs
* This method is meant to transform the query parameters into a more
human
* readable form. It is only executed when SEF mode is switched on.
*
* @param array &$query An array of URL arguments
*
* @return array The URL arguments to use to assemble the subsequent
URL.
*
* @since 3.3
*/
public function build(&$query);
/**
* Parse method for URLs
* This method is meant to transform the human readable URL back into
* query parameters. It is only executed when SEF mode is switched on.
*
* @param array &$segments The segments of the URL to parse.
*
* @return array The URL attributes to be used by the application.
*
* @since 3.3
*/
public function parse(&$segments);
}
RouterLegacy.php000064400000004261151162265130007667 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router;
defined('JPATH_PLATFORM') or die;
/**
* Default routing class for missing or legacy component routers
*
* @since 3.3
*/
class RouterLegacy implements RouterInterface
{
/**
* Name of the component
*
* @var string
* @since 3.3
*/
protected $component;
/**
* Constructor
*
* @param string $component Component name without the com_ prefix
this router should react upon
*
* @since 3.3
*/
public function __construct($component)
{
$this->component = $component;
}
/**
* Generic preprocess function for missing or legacy component router
*
* @param array $query An associative array of URL arguments
*
* @return array The URL arguments to use to assemble the subsequent
URL.
*
* @since 3.3
*/
public function preprocess($query)
{
return $query;
}
/**
* Generic build function for missing or legacy component router
*
* @param array &$query An array of URL arguments
*
* @return array The URL arguments to use to assemble the subsequent
URL.
*
* @since 3.3
*/
public function build(&$query)
{
$function = $this->component . 'BuildRoute';
if (function_exists($function))
{
$segments = $function($query);
$total = count($segments);
for ($i = 0; $i < $total; $i++)
{
$segments[$i] = str_replace(':', '-',
$segments[$i]);
}
return $segments;
}
return array();
}
/**
* Generic parse function for missing or legacy component router
*
* @param array &$segments The segments of the URL to parse.
*
* @return array The URL attributes to be used by the application.
*
* @since 3.3
*/
public function parse(&$segments)
{
$function = $this->component . 'ParseRoute';
if (function_exists($function))
{
$total = count($segments);
for ($i = 0; $i < $total; $i++)
{
$segments[$i] = preg_replace('/-/', ':',
$segments[$i], 1);
}
return $function($segments);
}
return array();
}
}
RouterView.php000064400000012623151162265130007376 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Component\Router\Rules\RulesInterface;
/**
* View-based component routing class
*
* @since 3.5
*/
abstract class RouterView extends RouterBase
{
/**
* Name of the router of the component
*
* @var string
* @since 3.5
*/
protected $name;
/**
* Array of rules
*
* @var RulesInterface[]
* @since 3.5
*/
protected $rules = array();
/**
* Views of the component
*
* @var RouterViewConfiguration[]
* @since 3.5
*/
protected $views = array();
/**
* Register the views of a component
*
* @param RouterViewConfiguration $view View configuration object
*
* @return void
*
* @since 3.5
*/
public function registerView(RouterViewConfiguration $view)
{
$this->views[$view->name] = $view;
}
/**
* Return an array of registered view objects
*
* @return RouterViewConfiguration[] Array of registered view objects
*
* @since 3.5
*/
public function getViews()
{
return $this->views;
}
/**
* Get the path of views from target view to root view
* including content items of a nestable view
*
* @param array $query Array of query elements
*
* @return array List of views including IDs of content items
*
* @since 3.5
*/
public function getPath($query)
{
$views = $this->getViews();
$result = array();
// Get the right view object
if (isset($query['view']) &&
isset($views[$query['view']]))
{
$viewobj = $views[$query['view']];
}
// Get the path from the current item to the root view with all IDs
if (isset($viewobj))
{
$path = array_reverse($viewobj->path);
$start = true;
$childkey = false;
foreach ($path as $element)
{
$view = $views[$element];
if ($start)
{
$key = $view->key;
$start = false;
}
else
{
$key = $childkey;
}
$childkey = $view->parent_key;
if (($key || $view->key) && is_callable(array($this,
'get' . ucfirst($view->name) . 'Segment')))
{
if (isset($query[$key]))
{
$result[$view->name] = call_user_func_array(array($this,
'get' . ucfirst($view->name) . 'Segment'),
array($query[$key], $query));
}
elseif (isset($query[$view->key]))
{
$result[$view->name] = call_user_func_array(array($this,
'get' . ucfirst($view->name) . 'Segment'),
array($query[$view->key], $query));
}
else
{
$result[$view->name] = array();
}
}
else
{
$result[$view->name] = true;
}
}
}
return $result;
}
/**
* Get all currently attached rules
*
* @return RulesInterface[] All currently attached rules in an array
*
* @since 3.5
*/
public function getRules()
{
return $this->rules;
}
/**
* Add a number of router rules to the object
*
* @param RulesInterface[] $rules Array of
JComponentRouterRulesInterface objects
*
* @return void
*
* @since 3.5
*/
public function attachRules($rules)
{
foreach ($rules as $rule)
{
$this->attachRule($rule);
}
}
/**
* Attach a build rule
*
* @param RulesInterface $rule The function to be called.
*
* @return void
*
* @since 3.5
*/
public function attachRule(RulesInterface $rule)
{
$this->rules[] = $rule;
}
/**
* Remove a build rule
*
* @param RulesInterface $rule The rule to be removed.
*
* @return boolean Was a rule removed?
*
* @since 3.5
*/
public function detachRule(RulesInterface $rule)
{
foreach ($this->rules as $id => $r)
{
if ($r == $rule)
{
unset($this->rules[$id]);
return true;
}
}
return false;
}
/**
* Generic method to preprocess a URL
*
* @param array $query An associative array of URL arguments
*
* @return array The URL arguments to use to assemble the subsequent
URL.
*
* @since 3.5
*/
public function preprocess($query)
{
// Process the parsed variables based on custom defined rules
foreach ($this->rules as $rule)
{
$rule->preprocess($query);
}
return $query;
}
/**
* Build method for URLs
*
* @param array &$query Array of query elements
*
* @return array Array of URL segments
*
* @since 3.5
*/
public function build(&$query)
{
$segments = array();
// Process the parsed variables based on custom defined rules
foreach ($this->rules as $rule)
{
$rule->build($query, $segments);
}
return $segments;
}
/**
* Parse method for URLs
*
* @param array &$segments Array of URL string-segments
*
* @return array Associative array of query values
*
* @since 3.5
*/
public function parse(&$segments)
{
$vars = array();
// Process the parsed variables based on custom defined rules
foreach ($this->rules as $rule)
{
$rule->parse($segments, $vars);
}
return $vars;
}
/**
* Method to return the name of the router
*
* @return string Name of the router
*
* @since 3.5
*/
public function getName()
{
if (empty($this->name))
{
$r = null;
if (!preg_match('/(.*)Router/i', get_class($this), $r))
{
throw new
\Exception('JLIB_APPLICATION_ERROR_ROUTER_GET_NAME', 500);
}
$this->name = strtolower($r[1]);
}
return $this->name;
}
}
RouterViewConfiguration.php000064400000010170151162265130012121
0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router;
defined('JPATH_PLATFORM') or die;
/**
* View-configuration class for the view-based component router
*
* @since 3.5
*/
class RouterViewConfiguration
{
/**
* Name of the view
*
* @var string
* @since 3.5
*/
public $name;
/**
* Key of the view
*
* @var string
* @since 3.5
*/
public $key = false;
/**
* Parentview of this one
*
* @var RouterViewconfiguration
* @since 3.5
*/
public $parent = false;
/**
* Key of the parent view
*
* @var string
* @since 3.5
*/
public $parent_key = false;
/**
* Is this view nestable?
*
* @var bool
* @since 3.5
*/
public $nestable = false;
/**
* Layouts that are supported by this view
*
* @var array
* @since 3.5
*/
public $layouts = array('default');
/**
* Child-views of this view
*
* @var RouterViewconfiguration[]
* @since 3.5
*/
public $children = array();
/**
* Keys used for this parent view by the child views
*
* @var array
* @since 3.5
*/
public $child_keys = array();
/**
* Path of views from this one to the root view
*
* @var array
* @since 3.5
*/
public $path = array();
/**
* Constructor for the View-configuration class
*
* @param string $name Name of the view
*
* @since 3.5
*/
public function __construct($name)
{
$this->name = $name;
$this->path[] = $name;
}
/**
* Set the name of the view
*
* @param string $name Name of the view
*
* @return RouterViewconfiguration This object for chaining
*
* @since 3.5
*/
public function setName($name)
{
$this->name = $name;
array_pop($this->path);
$this->path[] = $name;
return $this;
}
/**
* Set the key-identifier for the view
*
* @param string $key Key of the view
*
* @return RouterViewconfiguration This object for chaining
*
* @since 3.5
*/
public function setKey($key)
{
$this->key = $key;
return $this;
}
/**
* Set the parent view of this view
*
* @param RouterViewconfiguration $parent Parent view object
* @param string $parentKey Key of the parent view in
this context
*
* @return RouterViewconfiguration This object for chaining
*
* @since 3.5
*/
public function setParent(RouterViewconfiguration $parent, $parentKey =
false)
{
if ($this->parent)
{
$key = array_search($this, $this->parent->children);
if ($key !== false)
{
unset($this->parent->children[$key]);
}
if ($this->parent_key)
{
$child_key = array_search($this->parent_key,
$this->parent->child_keys);
unset($this->parent->child_keys[$child_key]);
}
}
$this->parent = $parent;
$parent->children[] = $this;
$this->path = $parent->path;
$this->path[] = $this->name;
$this->parent_key = $parentKey;
if ($parentKey)
{
$parent->child_keys[] = $parentKey;
}
return $this;
}
/**
* Set if this view is nestable or not
*
* @param bool $isNestable If set to true, the view is nestable
*
* @return RouterViewconfiguration This object for chaining
*
* @since 3.5
*/
public function setNestable($isNestable = true)
{
$this->nestable = (bool) $isNestable;
return $this;
}
/**
* Add a layout to this view
*
* @param string $layout Layouts that this view supports
*
* @return RouterViewconfiguration This object for chaining
*
* @since 3.5
*/
public function addLayout($layout)
{
$this->layouts[] = $layout;
$this->layouts = array_unique($this->layouts);
return $this;
}
/**
* Remove a layout from this view
*
* @param string $layout Layouts that this view supports
*
* @return RouterViewconfiguration This object for chaining
*
* @since 3.5
*/
public function removeLayout($layout)
{
$key = array_search($layout, $this->layouts);
if ($key !== false)
{
unset($this->layouts[$key]);
}
return $this;
}
}
Rules/MenuRules.php000064400000015202151162265130010270 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router\Rules;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Component\Router\RouterView;
/**
* Rule to identify the right Itemid for a view in a component
*
* @since 3.4
*/
class MenuRules implements RulesInterface
{
/**
* Router this rule belongs to
*
* @var RouterView
* @since 3.4
*/
protected $router;
/**
* Lookup array of the menu items
*
* @var array
* @since 3.4
*/
protected $lookup = array();
/**
* Class constructor.
*
* @param RouterView $router Router this rule belongs to
*
* @since 3.4
*/
public function __construct(RouterView $router)
{
$this->router = $router;
$this->buildLookup();
}
/**
* Finds the right Itemid for this query
*
* @param array &$query The query array to process
*
* @return void
*
* @since 3.4
*/
public function preprocess(&$query)
{
$active = $this->router->menu->getActive();
/**
* If the active item id is not the same as the supplied item id or we
have a supplied item id and no active
* menu item then we just use the supplied menu item and continue
*/
if (isset($query['Itemid']) && ($active === null ||
$query['Itemid'] != $active->id))
{
return;
}
// Get query language
$language = isset($query['lang']) ? $query['lang'] :
'*';
if (!isset($this->lookup[$language]))
{
$this->buildLookup($language);
}
// Check if the active menu item matches the requested query
if ($active !== null && isset($query['Itemid']))
{
// Check if active->query and supplied query are the same
$match = true;
foreach ($active->query as $k => $v)
{
if (isset($query[$k]) && $v !== $query[$k])
{
// Compare again without alias
if (is_string($v) && $v == current(explode(':',
$query[$k], 2)))
{
continue;
}
$match = false;
break;
}
}
if ($match)
{
// Just use the supplied menu item
return;
}
}
$needles = $this->router->getPath($query);
$layout = isset($query['layout']) &&
$query['layout'] !== 'default' ? ':' .
$query['layout'] : '';
if ($needles)
{
foreach ($needles as $view => $ids)
{
$viewLayout = $view . $layout;
if ($layout && isset($this->lookup[$language][$viewLayout]))
{
if (is_bool($ids))
{
$query['Itemid'] =
$this->lookup[$language][$viewLayout];
return;
}
foreach ($ids as $id => $segment)
{
if (isset($this->lookup[$language][$viewLayout][(int) $id]))
{
$query['Itemid'] =
$this->lookup[$language][$viewLayout][(int) $id];
return;
}
}
}
if (isset($this->lookup[$language][$view]))
{
if (is_bool($ids))
{
$query['Itemid'] = $this->lookup[$language][$view];
return;
}
foreach ($ids as $id => $segment)
{
if (isset($this->lookup[$language][$view][(int) $id]))
{
$query['Itemid'] =
$this->lookup[$language][$view][(int) $id];
return;
}
}
}
}
}
// Check if the active menuitem matches the requested language
if ($active && $active->component === 'com_' .
$this->router->getName()
&& ($language === '*' ||
in_array($active->language, array('*', $language)) ||
!\JLanguageMultilang::isEnabled()))
{
$query['Itemid'] = $active->id;
return;
}
// If not found, return language specific home link
$default = $this->router->menu->getDefault($language);
if (!empty($default->id))
{
$query['Itemid'] = $default->id;
}
}
/**
* Method to build the lookup array
*
* @param string $language The language that the lookup should be
built up for
*
* @return void
*
* @since 3.4
*/
protected function buildLookup($language = '*')
{
// Prepare the reverse lookup array.
if (!isset($this->lookup[$language]))
{
$this->lookup[$language] = array();
$component = ComponentHelper::getComponent('com_' .
$this->router->getName());
$views = $this->router->getViews();
$attributes = array('component_id');
$values = array((int) $component->id);
$attributes[] = 'language';
$values[] = array($language, '*');
$items = $this->router->menu->getItems($attributes, $values);
foreach ($items as $item)
{
if (isset($item->query['view'],
$views[$item->query['view']]))
{
$view = $item->query['view'];
$layout = '';
if (isset($item->query['layout']))
{
$layout = ':' . $item->query['layout'];
}
if ($views[$view]->key)
{
if (!isset($this->lookup[$language][$view . $layout]))
{
$this->lookup[$language][$view . $layout] = array();
}
if (!isset($this->lookup[$language][$view]))
{
$this->lookup[$language][$view] = array();
}
// If menuitem has no key set, we assume 0.
if (!isset($item->query[$views[$view]->key]))
{
$item->query[$views[$view]->key] = 0;
}
/**
* Here it will become a bit tricky
* language != * can override existing entries
* language == * cannot override existing entries
*/
if (!isset($this->lookup[$language][$view .
$layout][$item->query[$views[$view]->key]]) || $item->language !==
'*')
{
$this->lookup[$language][$view .
$layout][$item->query[$views[$view]->key]] = $item->id;
$this->lookup[$language][$view][$item->query[$views[$view]->key]]
= $item->id;
}
}
else
{
/**
* Here it will become a bit tricky
* language != * can override existing entries
* language == * cannot override existing entries
*/
if (!isset($this->lookup[$language][$view . $layout]) ||
$item->language !== '*')
{
$this->lookup[$language][$view . $layout] = $item->id;
$this->lookup[$language][$view] = $item->id;
}
}
}
}
}
}
/**
* Dummymethod to fullfill the interface requirements
*
* @param array &$segments The URL segments to parse
* @param array &$vars The vars that result from the segments
*
* @return void
*
* @since 3.4
* @codeCoverageIgnore
*/
public function parse(&$segments, &$vars)
{
}
/**
* Dummymethod to fullfill the interface requirements
*
* @param array &$query The vars that should be converted
* @param array &$segments The URL segments to create
*
* @return void
*
* @since 3.4
* @codeCoverageIgnore
*/
public function build(&$query, &$segments)
{
}
}
Rules/NomenuRules.php000064400000005524151162265130010633 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router\Rules;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Component\Router\RouterView;
/**
* Rule to process URLs without a menu item
*
* @since 3.4
*/
class NomenuRules implements RulesInterface
{
/**
* Router this rule belongs to
*
* @var RouterView
* @since 3.4
*/
protected $router;
/**
* Class constructor.
*
* @param RouterView $router Router this rule belongs to
*
* @since 3.4
*/
public function __construct(RouterView $router)
{
$this->router = $router;
}
/**
* Dummymethod to fullfill the interface requirements
*
* @param array &$query The query array to process
*
* @return void
*
* @since 3.4
* @codeCoverageIgnore
*/
public function preprocess(&$query)
{
}
/**
* Parse a menu-less URL
*
* @param array &$segments The URL segments to parse
* @param array &$vars The vars that result from the segments
*
* @return void
*
* @since 3.4
*/
public function parse(&$segments, &$vars)
{
$active = $this->router->menu->getActive();
if (!is_object($active))
{
$views = $this->router->getViews();
if (isset($views[$segments[0]]))
{
$vars['view'] = array_shift($segments);
if (isset($views[$vars['view']]->key) &&
isset($segments[0]))
{
$vars[$views[$vars['view']]->key] =
preg_replace('/-/', ':', array_shift($segments), 1);
}
}
}
}
/**
* Build a menu-less URL
*
* @param array &$query The vars that should be converted
* @param array &$segments The URL segments to create
*
* @return void
*
* @since 3.4
*/
public function build(&$query, &$segments)
{
$menu_found = false;
if (isset($query['Itemid']))
{
$item =
$this->router->menu->getItem($query['Itemid']);
if (!isset($query['option']) || ($item &&
$item->query['option'] === $query['option']))
{
$menu_found = true;
}
}
if (!$menu_found && isset($query['view']))
{
$views = $this->router->getViews();
if (isset($views[$query['view']]))
{
$view = $views[$query['view']];
$segments[] = $query['view'];
if ($view->key && isset($query[$view->key]))
{
if (is_callable(array($this->router, 'get' .
ucfirst($view->name) . 'Segment')))
{
$result = call_user_func_array(array($this->router,
'get' . ucfirst($view->name) . 'Segment'),
array($query[$view->key], $query));
$segments[] = str_replace(':', '-',
array_shift($result));
}
else
{
$segments[] = str_replace(':', '-',
$query[$view->key]);
}
unset($query[$views[$query['view']]->key]);
}
unset($query['view']);
}
}
}
}
Rules/RulesInterface.php000064400000003157151162265140011273
0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router\Rules;
defined('JPATH_PLATFORM') or die;
/**
* RouterRules interface for Joomla
*
* @since 3.4
*/
interface RulesInterface
{
/**
* Prepares a query set to be handed over to the build() method.
* This should complete a partial query set to work as a complete
non-SEFed
* URL and in general make sure that all information is present and
properly
* formatted. For example, the Itemid should be retrieved and set here.
*
* @param array &$query The query array to process
*
* @return void
*
* @since 3.4
*/
public function preprocess(&$query);
/**
* Parses a URI to retrieve informations for the right route through
* the component.
* This method should retrieve all its input from its method arguments.
*
* @param array &$segments The URL segments to parse
* @param array &$vars The vars that result from the segments
*
* @return void
*
* @since 3.4
*/
public function parse(&$segments, &$vars);
/**
* Builds URI segments from a query to encode the necessary informations
* for a route in a human-readable URL.
* This method should retrieve all its input from its method arguments.
*
* @param array &$query The vars that should be converted
* @param array &$segments The URL segments to create
*
* @return void
*
* @since 3.4
*/
public function build(&$query, &$segments);
}
Rules/StandardRules.php000064400000015231151162265160011131
0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router\Rules;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Component\Router\RouterView;
/**
* Rule for the standard handling of component routing
*
* @since 3.4
*/
class StandardRules implements RulesInterface
{
/**
* Router this rule belongs to
*
* @var RouterView
* @since 3.4
*/
protected $router;
/**
* Class constructor.
*
* @param RouterView $router Router this rule belongs to
*
* @since 3.4
*/
public function __construct(RouterView $router)
{
$this->router = $router;
}
/**
* Dummymethod to fullfill the interface requirements
*
* @param array &$query The query array to process
*
* @return void
*
* @since 3.4
*/
public function preprocess(&$query)
{
}
/**
* Parse the URL
*
* @param array &$segments The URL segments to parse
* @param array &$vars The vars that result from the segments
*
* @return void
*
* @since 3.4
*/
public function parse(&$segments, &$vars)
{
// Get the views and the currently active query vars
$views = $this->router->getViews();
$active = $this->router->menu->getActive();
if ($active)
{
$vars = array_merge($active->query, $vars);
}
// We don't have a view or its not a view of this component! We stop
here
if (!isset($vars['view']) ||
!isset($views[$vars['view']]))
{
return;
}
// Copy the segments, so that we can iterate over all of them and at the
same time modify the original segments
$tempSegments = $segments;
// Iterate over the segments as long as a segment fits
foreach ($tempSegments as $segment)
{
// Our current view is nestable. We need to check first if the segment
fits to that
if ($views[$vars['view']]->nestable)
{
if (is_callable(array($this->router, 'get' .
ucfirst($views[$vars['view']]->name) . 'Id')))
{
$key = call_user_func_array(array($this->router, 'get' .
ucfirst($views[$vars['view']]->name) . 'Id'),
array($segment, $vars));
// Did we get a proper key? If not, we need to look in the child-views
if ($key)
{
$vars[$views[$vars['view']]->key] = $key;
array_shift($segments);
continue;
}
}
else
{
// The router is not complete. The get<View>Id() method is
missing.
return;
}
}
// Lets find the right view that belongs to this segment
$found = false;
foreach ($views[$vars['view']]->children as $view)
{
if (!$view->key)
{
if ($view->name === $segment)
{
// The segment is a view name
$parent = $views[$vars['view']];
$vars['view'] = $view->name;
$found = true;
if ($view->parent_key && isset($vars[$parent->key]))
{
$parent_key = $vars[$parent->key];
$vars[$view->parent_key] = $parent_key;
unset($vars[$parent->key]);
}
break;
}
}
elseif (is_callable(array($this->router, 'get' .
ucfirst($view->name) . 'Id')))
{
// Hand the data over to the router specific method and see if there
is a content item that fits
$key = call_user_func_array(array($this->router, 'get' .
ucfirst($view->name) . 'Id'), array($segment, $vars));
if ($key)
{
// Found the right view and the right item
$parent = $views[$vars['view']];
$vars['view'] = $view->name;
$found = true;
if ($view->parent_key && isset($vars[$parent->key]))
{
$parent_key = $vars[$parent->key];
$vars[$view->parent_key] = $parent_key;
unset($vars[$parent->key]);
}
$vars[$view->key] = $key;
break;
}
}
}
if (!$found)
{
return;
}
array_shift($segments);
}
}
/**
* Build a standard URL
*
* @param array &$query The vars that should be converted
* @param array &$segments The URL segments to create
*
* @return void
*
* @since 3.4
*/
public function build(&$query, &$segments)
{
if (!isset($query['Itemid'], $query['view']))
{
return;
}
// Get the menu item belonging to the Itemid that has been found
$item =
$this->router->menu->getItem($query['Itemid']);
if ($item === null
|| $item->component !== 'com_' .
$this->router->getName()
|| !isset($item->query['view']))
{
return;
}
// Get menu item layout
$mLayout = isset($item->query['layout']) ?
$item->query['layout'] : null;
// Get all views for this component
$views = $this->router->getViews();
// Return directly when the URL of the Itemid is identical with the URL
to build
if ($item->query['view'] === $query['view'])
{
$view = $views[$query['view']];
if (!$view->key)
{
unset($query['view']);
if (isset($query['layout']) && $mLayout ===
$query['layout'])
{
unset($query['layout']);
}
return;
}
if (isset($query[$view->key]) &&
$item->query[$view->key] == (int) $query[$view->key])
{
unset($query[$view->key]);
while ($view)
{
unset($query[$view->parent_key]);
$view = $view->parent;
}
unset($query['view']);
if (isset($query['layout']) && $mLayout ===
$query['layout'])
{
unset($query['layout']);
}
return;
}
}
// Get the path from the view of the current URL and parse it to the menu
item
$path = array_reverse($this->router->getPath($query), true);
$found = false;
foreach ($path as $element => $ids)
{
$view = $views[$element];
if ($found === false && $item->query['view'] ===
$element)
{
if ($view->nestable)
{
$found = true;
}
elseif ($view->children)
{
$found = true;
continue;
}
}
if ($found === false)
{
// Jump to the next view
continue;
}
if ($ids)
{
if ($view->nestable)
{
$found2 = false;
foreach (array_reverse($ids, true) as $id => $segment)
{
if ($found2)
{
$segments[] = str_replace(':', '-', $segment);
}
elseif ((int) $item->query[$view->key] === (int) $id)
{
$found2 = true;
}
}
}
elseif ($ids === true)
{
$segments[] = $element;
}
else
{
$segments[] = str_replace(':', '-',
current($ids));
}
}
if ($view->parent_key)
{
// Remove parent key from query
unset($query[$view->parent_key]);
}
}
if ($found)
{
unset($query[$views[$query['view']]->key],
$query['view']);
if (isset($query['layout']) && $mLayout ===
$query['layout'])
{
unset($query['layout']);
}
}
}
}