| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174 |
- <?php
- /**
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- * @link https://cakephp.org CakePHP(tm) Project
- * @since 0.2.9
- * @license https://opensource.org/licenses/mit-license.php MIT License
- */
- namespace Cake\Routing;
- use Cake\Core\Configure;
- use Cake\Http\ServerRequest;
- use Cake\Routing\Exception\MissingRouteException;
- use Cake\Utility\Inflector;
- use Psr\Http\Message\ServerRequestInterface;
- use RuntimeException;
- /**
- * Parses the request URL into controller, action, and parameters. Uses the connected routes
- * to match the incoming URL string to parameters that will allow the request to be dispatched. Also
- * handles converting parameter lists into URL strings, using the connected routes. Routing allows you to decouple
- * the way the world interacts with your application (URLs) and the implementation (controllers and actions).
- *
- * ### Connecting routes
- *
- * Connecting routes is done using Router::connect(). When parsing incoming requests or reverse matching
- * parameters, routes are enumerated in the order they were connected. For more information on routes and
- * how to connect them see Router::connect().
- */
- class Router
- {
- /**
- * Have routes been loaded
- *
- * @var bool
- * @deprecated 3.5.0 Routes will be loaded via the Application::routes() hook in 4.0.0
- */
- public static $initialized = false;
- /**
- * Default route class.
- *
- * @var string
- */
- protected static $_defaultRouteClass = 'Cake\Routing\Route\Route';
- /**
- * Contains the base string that will be applied to all generated URLs
- * For example `https://example.com`
- *
- * @var string
- */
- protected static $_fullBaseUrl;
- /**
- * Regular expression for action names
- *
- * @var string
- */
- const ACTION = 'index|show|add|create|edit|update|remove|del|delete|view|item';
- /**
- * Regular expression for years
- *
- * @var string
- */
- const YEAR = '[12][0-9]{3}';
- /**
- * Regular expression for months
- *
- * @var string
- */
- const MONTH = '0[1-9]|1[012]';
- /**
- * Regular expression for days
- *
- * @var string
- */
- const DAY = '0[1-9]|[12][0-9]|3[01]';
- /**
- * Regular expression for auto increment IDs
- *
- * @var string
- */
- const ID = '[0-9]+';
- /**
- * Regular expression for UUIDs
- *
- * @var string
- */
- const UUID = '[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}';
- /**
- * The route collection routes would be added to.
- *
- * @var \Cake\Routing\RouteCollection
- */
- protected static $_collection;
- /**
- * A hash of request context data.
- *
- * @var array
- */
- protected static $_requestContext = [];
- /**
- * Named expressions
- *
- * @var array
- */
- protected static $_namedExpressions = [
- 'Action' => Router::ACTION,
- 'Year' => Router::YEAR,
- 'Month' => Router::MONTH,
- 'Day' => Router::DAY,
- 'ID' => Router::ID,
- 'UUID' => Router::UUID
- ];
- /**
- * Maintains the request object stack for the current request.
- * This will contain more than one request object when requestAction is used.
- *
- * @var array
- */
- protected static $_requests = [];
- /**
- * Initial state is populated the first time reload() is called which is at the bottom
- * of this file. This is a cheat as get_class_vars() returns the value of static vars even if they
- * have changed.
- *
- * @var array
- */
- protected static $_initialState = [];
- /**
- * The stack of URL filters to apply against routing URLs before passing the
- * parameters to the route collection.
- *
- * @var callable[]
- */
- protected static $_urlFilters = [];
- /**
- * Default extensions defined with Router::extensions()
- *
- * @var array
- */
- protected static $_defaultExtensions = [];
- /**
- * Get or set default route class.
- *
- * @param string|null $routeClass Class name.
- * @return string|null
- */
- public static function defaultRouteClass($routeClass = null)
- {
- if ($routeClass === null) {
- return static::$_defaultRouteClass;
- }
- static::$_defaultRouteClass = $routeClass;
- }
- /**
- * Gets the named route patterns for use in config/routes.php
- *
- * @return array Named route elements
- * @see \Cake\Routing\Router::$_namedExpressions
- */
- public static function getNamedExpressions()
- {
- return static::$_namedExpressions;
- }
- /**
- * Connects a new Route in the router.
- *
- * Compatibility proxy to \Cake\Routing\RouteBuilder::connect() in the `/` scope.
- *
- * @param string $route A string describing the template of the route
- * @param array|string $defaults An array describing the default route parameters. These parameters will be used by default
- * and can supply routing parameters that are not dynamic. See above.
- * @param array $options An array matching the named elements in the route to regular expressions which that
- * element should match. Also contains additional parameters such as which routed parameters should be
- * shifted into the passed arguments, supplying patterns for routing parameters and supplying the name of a
- * custom routing class.
- * @return void
- * @throws \Cake\Core\Exception\Exception
- * @see \Cake\Routing\RouteBuilder::connect()
- * @see \Cake\Routing\Router::scope()
- */
- public static function connect($route, $defaults = [], $options = [])
- {
- static::$initialized = true;
- static::scope('/', function ($routes) use ($route, $defaults, $options) {
- $routes->connect($route, $defaults, $options);
- });
- }
- /**
- * Connects a new redirection Route in the router.
- *
- * Compatibility proxy to \Cake\Routing\RouteBuilder::redirect() in the `/` scope.
- *
- * @param string $route A string describing the template of the route
- * @param array $url A URL to redirect to. Can be a string or a Cake array-based URL
- * @param array $options An array matching the named elements in the route to regular expressions which that
- * element should match. Also contains additional parameters such as which routed parameters should be
- * shifted into the passed arguments. As well as supplying patterns for routing parameters.
- * @return void
- * @see \Cake\Routing\RouteBuilder::redirect()
- * @deprecated 3.3.0 Use Router::scope() and RouteBuilder::redirect() instead.
- */
- public static function redirect($route, $url, $options = [])
- {
- deprecationWarning(
- 'Router::redirect() is deprecated. ' .
- 'Use Router::scope() and RouteBuilder::redirect() instead.'
- );
- if (is_string($url)) {
- $url = ['redirect' => $url];
- }
- if (!isset($options['routeClass'])) {
- $options['routeClass'] = 'Cake\Routing\Route\RedirectRoute';
- }
- static::connect($route, $url, $options);
- }
- /**
- * Generate REST resource routes for the given controller(s).
- *
- * Compatibility proxy to \Cake\Routing\RouteBuilder::resources(). Additional, compatibility
- * around prefixes and plugins and prefixes is handled by this method.
- *
- * A quick way to generate a default routes to a set of REST resources (controller(s)).
- *
- * ### Usage
- *
- * Connect resource routes for an app controller:
- *
- * ```
- * Router::mapResources('Posts');
- * ```
- *
- * Connect resource routes for the Comment controller in the
- * Comments plugin:
- *
- * ```
- * Router::mapResources('Comments.Comment');
- * ```
- *
- * Plugins will create lower_case underscored resource routes. e.g
- * `/comments/comment`
- *
- * Connect resource routes for the Posts controller in the
- * Admin prefix:
- *
- * ```
- * Router::mapResources('Posts', ['prefix' => 'admin']);
- * ```
- *
- * Prefixes will create lower_case underscored resource routes. e.g
- * `/admin/posts`
- *
- * ### Options:
- *
- * - 'id' - The regular expression fragment to use when matching IDs. By default, matches
- * integer values and UUIDs.
- * - 'prefix' - Routing prefix to use for the generated routes. Defaults to ''.
- * Using this option will create prefixed routes, similar to using Routing.prefixes.
- * - 'only' - Only connect the specific list of actions.
- * - 'actions' - Override the method names used for connecting actions.
- * - 'map' - Additional resource routes that should be connected. If you define 'only' and 'map',
- * make sure that your mapped methods are also in the 'only' list.
- * - 'path' - Change the path so it doesn't match the resource name. E.g ArticlesController
- * is available at `/posts`
- *
- * @param string|array $controller A controller name or array of controller names (i.e. "Posts" or "ListItems")
- * @param array $options Options to use when generating REST routes
- * @see \Cake\Routing\RouteBuilder::resources()
- * @deprecated 3.3.0 Use Router::scope() and RouteBuilder::resources() instead.
- * @return void
- */
- public static function mapResources($controller, $options = [])
- {
- deprecationWarning(
- 'Router::mapResources() is deprecated. ' .
- 'Use Router::scope() and RouteBuilder::resources() instead.'
- );
- foreach ((array)$controller as $name) {
- list($plugin, $name) = pluginSplit($name);
- $prefix = $pluginUrl = false;
- if (!empty($options['prefix'])) {
- $prefix = $options['prefix'];
- unset($options['prefix']);
- }
- if ($plugin) {
- $pluginUrl = Inflector::underscore($plugin);
- }
- $callback = function ($routes) use ($name, $options) {
- $routes->resources($name, $options);
- };
- if ($plugin && $prefix) {
- $path = '/' . implode('/', [$prefix, $pluginUrl]);
- $params = ['prefix' => $prefix, 'plugin' => $plugin];
- static::scope($path, $params, $callback);
- return;
- }
- if ($prefix) {
- static::prefix($prefix, $callback);
- return;
- }
- if ($plugin) {
- static::plugin($plugin, $callback);
- return;
- }
- static::scope('/', $callback);
- return;
- }
- }
- /**
- * Parses given URL string. Returns 'routing' parameters for that URL.
- *
- * @param string $url URL to be parsed.
- * @param string $method The HTTP method being used.
- * @return array Parsed elements from URL.
- * @throws \Cake\Routing\Exception\MissingRouteException When a route cannot be handled
- * @deprecated 3.4.0 Use Router::parseRequest() instead.
- */
- public static function parse($url, $method = '')
- {
- deprecationWarning(
- 'Router::parse() is deprecated. ' .
- 'Use Router::parseRequest() instead. This will require adopting the Http\Server library.'
- );
- if (!static::$initialized) {
- static::_loadRoutes();
- }
- if (strpos($url, '/') !== 0) {
- $url = '/' . $url;
- }
- return static::$_collection->parse($url, $method);
- }
- /**
- * Get the routing parameters for the request is possible.
- *
- * @param \Psr\Http\Message\ServerRequestInterface $request The request to parse request data from.
- * @return array Parsed elements from URL.
- * @throws \Cake\Routing\Exception\MissingRouteException When a route cannot be handled
- */
- public static function parseRequest(ServerRequestInterface $request)
- {
- if (!static::$initialized) {
- static::_loadRoutes();
- }
- return static::$_collection->parseRequest($request);
- }
- /**
- * Takes parameter and path information back from the Dispatcher, sets these
- * parameters as the current request parameters that are merged with URL arrays
- * created later in the request.
- *
- * Nested requests will create a stack of requests. You can remove requests using
- * Router::popRequest(). This is done automatically when using Object::requestAction().
- *
- * Will accept either a Cake\Http\ServerRequest object or an array of arrays. Support for
- * accepting arrays may be removed in the future.
- *
- * @param \Cake\Http\ServerRequest|array $request Parameters and path information or a Cake\Http\ServerRequest object.
- * @return void
- * @deprecatd 3.6.0 Support for arrays will be removed in 4.0.0
- */
- public static function setRequestInfo($request)
- {
- if ($request instanceof ServerRequest) {
- static::pushRequest($request);
- } else {
- deprecationWarning(
- 'Passing an array into Router::setRequestInfo() is deprecated. ' .
- 'Pass an instance of ServerRequest instead.'
- );
- $requestData = $request;
- $requestData += [[], []];
- $requestData[0] += [
- 'controller' => false,
- 'action' => false,
- 'plugin' => null
- ];
- $request = new ServerRequest([
- 'params' => $requestData[0],
- 'url' => isset($requestData[1]['here']) ? $requestData[1]['here'] : '/',
- 'base' => isset($requestData[1]['base']) ? $requestData[1]['base'] : '',
- 'webroot' => isset($requestData[1]['webroot']) ? $requestData[1]['webroot'] : '/',
- ]);
- static::pushRequest($request);
- }
- }
- /**
- * Push a request onto the request stack. Pushing a request
- * sets the request context used when generating URLs.
- *
- * @param \Cake\Http\ServerRequest $request Request instance.
- * @return void
- */
- public static function pushRequest(ServerRequest $request)
- {
- static::$_requests[] = $request;
- static::setRequestContext($request);
- }
- /**
- * Store the request context for a given request.
- *
- * @param \Psr\Http\Message\ServerRequestInterface $request The request instance.
- * @return void
- * @throws InvalidArgumentException When parameter is an incorrect type.
- */
- public static function setRequestContext(ServerRequestInterface $request)
- {
- $uri = $request->getUri();
- static::$_requestContext = [
- '_base' => $request->getAttribute('base'),
- '_port' => $uri->getPort(),
- '_scheme' => $uri->getScheme(),
- '_host' => $uri->getHost(),
- ];
- }
- /**
- * Pops a request off of the request stack. Used when doing requestAction
- *
- * @return \Cake\Http\ServerRequest The request removed from the stack.
- * @see \Cake\Routing\Router::pushRequest()
- * @see \Cake\Routing\RequestActionTrait::requestAction()
- */
- public static function popRequest()
- {
- $removed = array_pop(static::$_requests);
- $last = end(static::$_requests);
- if ($last) {
- static::setRequestContext($last);
- reset(static::$_requests);
- }
- return $removed;
- }
- /**
- * Get the current request object, or the first one.
- *
- * @param bool $current True to get the current request, or false to get the first one.
- * @return \Cake\Http\ServerRequest|null
- */
- public static function getRequest($current = false)
- {
- if ($current) {
- $request = end(static::$_requests);
- return $request ?: null;
- }
- return isset(static::$_requests[0]) ? static::$_requests[0] : null;
- }
- /**
- * Reloads default Router settings. Resets all class variables and
- * removes all connected routes.
- *
- * @return void
- */
- public static function reload()
- {
- if (empty(static::$_initialState)) {
- static::$_collection = new RouteCollection();
- static::$_initialState = get_class_vars(get_called_class());
- return;
- }
- foreach (static::$_initialState as $key => $val) {
- if ($key !== '_initialState') {
- static::${$key} = $val;
- }
- }
- static::$_collection = new RouteCollection();
- }
- /**
- * Add a URL filter to Router.
- *
- * URL filter functions are applied to every array $url provided to
- * Router::url() before the URLs are sent to the route collection.
- *
- * Callback functions should expect the following parameters:
- *
- * - `$params` The URL params being processed.
- * - `$request` The current request.
- *
- * The URL filter function should *always* return the params even if unmodified.
- *
- * ### Usage
- *
- * URL filters allow you to easily implement features like persistent parameters.
- *
- * ```
- * Router::addUrlFilter(function ($params, $request) {
- * if ($request->getParam('lang') && !isset($params['lang'])) {
- * $params['lang'] = $request->getParam('lang');
- * }
- * return $params;
- * });
- * ```
- *
- * @param callable $function The function to add
- * @return void
- */
- public static function addUrlFilter(callable $function)
- {
- static::$_urlFilters[] = $function;
- }
- /**
- * Applies all the connected URL filters to the URL.
- *
- * @param array $url The URL array being modified.
- * @return array The modified URL.
- * @see \Cake\Routing\Router::url()
- * @see \Cake\Routing\Router::addUrlFilter()
- */
- protected static function _applyUrlFilters($url)
- {
- $request = static::getRequest(true);
- foreach (static::$_urlFilters as $filter) {
- $url = $filter($url, $request);
- }
- return $url;
- }
- /**
- * Finds URL for specified action.
- *
- * Returns a URL pointing to a combination of controller and action.
- *
- * ### Usage
- *
- * - `Router::url('/posts/edit/1');` Returns the string with the base dir prepended.
- * This usage does not use reverser routing.
- * - `Router::url(['controller' => 'posts', 'action' => 'edit']);` Returns a URL
- * generated through reverse routing.
- * - `Router::url(['_name' => 'custom-name', ...]);` Returns a URL generated
- * through reverse routing. This form allows you to leverage named routes.
- *
- * There are a few 'special' parameters that can change the final URL string that is generated
- *
- * - `_base` - Set to false to remove the base path from the generated URL. If your application
- * is not in the root directory, this can be used to generate URLs that are 'cake relative'.
- * cake relative URLs are required when using requestAction.
- * - `_scheme` - Set to create links on different schemes like `webcal` or `ftp`. Defaults
- * to the current scheme.
- * - `_host` - Set the host to use for the link. Defaults to the current host.
- * - `_port` - Set the port if you need to create links on non-standard ports.
- * - `_full` - If true output of `Router::fullBaseUrl()` will be prepended to generated URLs.
- * - `#` - Allows you to set URL hash fragments.
- * - `_ssl` - Set to true to convert the generated URL to https, or false to force http.
- * - `_name` - Name of route. If you have setup named routes you can use this key
- * to specify it.
- *
- * @param string|array|null $url An array specifying any of the following:
- * 'controller', 'action', 'plugin' additionally, you can provide routed
- * elements or query string parameters. If string it can be name any valid url
- * string.
- * @param bool $full If true, the full base URL will be prepended to the result.
- * Default is false.
- * @return string Full translated URL with base path.
- * @throws \Cake\Core\Exception\Exception When the route name is not found
- */
- public static function url($url = null, $full = false)
- {
- if (!static::$initialized) {
- static::_loadRoutes();
- }
- $params = [
- 'plugin' => null,
- 'controller' => null,
- 'action' => 'index',
- '_ext' => null,
- ];
- $here = $base = $output = $frag = null;
- // In 4.x this should be replaced with state injected via setRequestContext
- $request = static::getRequest(true);
- if ($request) {
- $params = $request->getAttribute('params');
- $here = $request->getRequestTarget();
- $base = $request->getAttribute('base');
- } else {
- $base = Configure::read('App.base');
- if (isset(static::$_requestContext['_base'])) {
- $base = static::$_requestContext['_base'];
- }
- }
- if (empty($url)) {
- $output = $base . (isset($here) ? $here : '/');
- if ($full) {
- $output = static::fullBaseUrl() . $output;
- }
- return $output;
- }
- if (is_array($url)) {
- if (isset($url['_ssl'])) {
- $url['_scheme'] = ($url['_ssl'] === true) ? 'https' : 'http';
- }
- if (isset($url['_full']) && $url['_full'] === true) {
- $full = true;
- }
- if (isset($url['#'])) {
- $frag = '#' . $url['#'];
- }
- unset($url['_ssl'], $url['_full'], $url['#']);
- $url = static::_applyUrlFilters($url);
- if (!isset($url['_name'])) {
- // Copy the current action if the controller is the current one.
- if (empty($url['action']) &&
- (empty($url['controller']) || $params['controller'] === $url['controller'])
- ) {
- $url['action'] = $params['action'];
- }
- // Keep the current prefix around if none set.
- if (isset($params['prefix']) && !isset($url['prefix'])) {
- $url['prefix'] = $params['prefix'];
- }
- $url += [
- 'plugin' => $params['plugin'],
- 'controller' => $params['controller'],
- 'action' => 'index',
- '_ext' => null
- ];
- }
- // If a full URL is requested with a scheme the host should default
- // to App.fullBaseUrl to avoid corrupt URLs
- if ($full && isset($url['_scheme']) && !isset($url['_host'])) {
- $url['_host'] = parse_url(static::fullBaseUrl(), PHP_URL_HOST);
- }
- $output = static::$_collection->match($url, static::$_requestContext + ['params' => $params]);
- } else {
- $plainString = (
- strpos($url, 'javascript:') === 0 ||
- strpos($url, 'mailto:') === 0 ||
- strpos($url, 'tel:') === 0 ||
- strpos($url, 'sms:') === 0 ||
- strpos($url, '#') === 0 ||
- strpos($url, '?') === 0 ||
- strpos($url, '//') === 0 ||
- strpos($url, '://') !== false
- );
- if ($plainString) {
- return $url;
- }
- $output = $base . $url;
- }
- $protocol = preg_match('#^[a-z][a-z0-9+\-.]*\://#i', $output);
- if ($protocol === 0) {
- $output = str_replace('//', '/', '/' . $output);
- if ($full) {
- $output = static::fullBaseUrl() . $output;
- }
- }
- return $output . $frag;
- }
- /**
- * Finds URL for specified action.
- *
- * Returns a bool if the url exists
- *
- * ### Usage
- *
- * @see Router::url()
- *
- * @param string|array|null $url An array specifying any of the following:
- * 'controller', 'action', 'plugin' additionally, you can provide routed
- * elements or query string parameters. If string it can be name any valid url
- * string.
- * @param bool $full If true, the full base URL will be prepended to the result.
- * Default is false.
- * @return bool
- */
- public static function routeExists($url = null, $full = false)
- {
- try {
- $route = static::url($url, $full);
- return true;
- } catch (MissingRouteException $e) {
- return false;
- }
- }
- /**
- * Sets the full base URL that will be used as a prefix for generating
- * fully qualified URLs for this application. If not parameters are passed,
- * the currently configured value is returned.
- *
- * ### Note:
- *
- * If you change the configuration value `App.fullBaseUrl` during runtime
- * and expect the router to produce links using the new setting, you are
- * required to call this method passing such value again.
- *
- * @param string|null $base the prefix for URLs generated containing the domain.
- * For example: `http://example.com`
- * @return string
- */
- public static function fullBaseUrl($base = null)
- {
- if ($base !== null) {
- static::$_fullBaseUrl = $base;
- Configure::write('App.fullBaseUrl', $base);
- }
- if (empty(static::$_fullBaseUrl)) {
- static::$_fullBaseUrl = Configure::read('App.fullBaseUrl');
- }
- return static::$_fullBaseUrl;
- }
- /**
- * Reverses a parsed parameter array into an array.
- *
- * Works similarly to Router::url(), but since parsed URL's contain additional
- * 'pass' as well as 'url.url' keys. Those keys need to be specially
- * handled in order to reverse a params array into a string URL.
- *
- * This will strip out 'autoRender', 'bare', 'requested', and 'return' param names as those
- * are used for CakePHP internals and should not normally be part of an output URL.
- *
- * @param \Cake\Http\ServerRequest|array $params The params array or
- * Cake\Http\ServerRequest object that needs to be reversed.
- * @return array The URL array ready to be used for redirect or HTML link.
- */
- public static function reverseToArray($params)
- {
- $url = [];
- if ($params instanceof ServerRequest) {
- $url = $params->getQueryParams();
- $params = $params->getAttribute('params');
- } elseif (isset($params['url'])) {
- $url = $params['url'];
- }
- $pass = isset($params['pass']) ? $params['pass'] : [];
- unset(
- $params['pass'],
- $params['paging'],
- $params['models'],
- $params['url'],
- $url['url'],
- $params['autoRender'],
- $params['bare'],
- $params['requested'],
- $params['return'],
- $params['_Token'],
- $params['_matchedRoute'],
- $params['_name']
- );
- $params = array_merge($params, $pass);
- if (!empty($url)) {
- $params['?'] = $url;
- }
- return $params;
- }
- /**
- * Reverses a parsed parameter array into a string.
- *
- * Works similarly to Router::url(), but since parsed URL's contain additional
- * 'pass' as well as 'url.url' keys. Those keys need to be specially
- * handled in order to reverse a params array into a string URL.
- *
- * This will strip out 'autoRender', 'bare', 'requested', and 'return' param names as those
- * are used for CakePHP internals and should not normally be part of an output URL.
- *
- * @param \Cake\Http\ServerRequest|array $params The params array or
- * Cake\Network\Request object that needs to be reversed.
- * @param bool $full Set to true to include the full URL including the
- * protocol when reversing the URL.
- * @return string The string that is the reversed result of the array
- */
- public static function reverse($params, $full = false)
- {
- $params = static::reverseToArray($params);
- return static::url($params, $full);
- }
- /**
- * Normalizes a URL for purposes of comparison.
- *
- * Will strip the base path off and replace any double /'s.
- * It will not unify the casing and underscoring of the input value.
- *
- * @param array|string $url URL to normalize Either an array or a string URL.
- * @return string Normalized URL
- */
- public static function normalize($url = '/')
- {
- if (is_array($url)) {
- $url = static::url($url);
- }
- if (preg_match('/^[a-z\-]+:\/\//', $url)) {
- return $url;
- }
- $request = static::getRequest();
- if ($request) {
- $base = $request->getAttribute('base');
- if (strlen($base) && stristr($url, $base)) {
- $url = preg_replace('/^' . preg_quote($base, '/') . '/', '', $url, 1);
- }
- }
- $url = '/' . $url;
- while (strpos($url, '//') !== false) {
- $url = str_replace('//', '/', $url);
- }
- $url = preg_replace('/(?:(\/$))/', '', $url);
- if (empty($url)) {
- return '/';
- }
- return $url;
- }
- /**
- * Get or set valid extensions for all routes connected later.
- *
- * Instructs the router to parse out file extensions
- * from the URL. For example, http://example.com/posts.rss would yield a file
- * extension of "rss". The file extension itself is made available in the
- * controller as `$this->request->getParam('_ext')`, and is used by the RequestHandler
- * component to automatically switch to alternate layouts and templates, and
- * load helpers corresponding to the given content, i.e. RssHelper. Switching
- * layouts and helpers requires that the chosen extension has a defined mime type
- * in `Cake\Http\Response`.
- *
- * A string or an array of valid extensions can be passed to this method.
- * If called without any parameters it will return current list of set extensions.
- *
- * @param array|string|null $extensions List of extensions to be added.
- * @param bool $merge Whether to merge with or override existing extensions.
- * Defaults to `true`.
- * @return array Array of extensions Router is configured to parse.
- */
- public static function extensions($extensions = null, $merge = true)
- {
- $collection = static::$_collection;
- if ($extensions === null) {
- if (!static::$initialized) {
- static::_loadRoutes();
- }
- return array_unique(array_merge(static::$_defaultExtensions, $collection->getExtensions()));
- }
- $extensions = (array)$extensions;
- if ($merge) {
- $extensions = array_unique(array_merge(static::$_defaultExtensions, $extensions));
- }
- return static::$_defaultExtensions = $extensions;
- }
- /**
- * Provides legacy support for named parameters on incoming URLs.
- *
- * Checks the passed parameters for elements containing `$options['separator']`
- * Those parameters are split and parsed as if they were old style named parameters.
- *
- * The parsed parameters will be moved from params['pass'] to params['named'].
- *
- * ### Options
- *
- * - `separator` The string to use as a separator. Defaults to `:`.
- *
- * @param \Cake\Http\ServerRequest $request The request object to modify.
- * @param array $options The array of options.
- * @return \Cake\Http\ServerRequest The modified request
- * @deprecated 3.3.0 Named parameter backwards compatibility will be removed in 4.0.
- */
- public static function parseNamedParams(ServerRequest $request, array $options = [])
- {
- deprecationWarning(
- 'Router::parseNamedParams() is deprecated. ' .
- '2.x backwards compatible named parameter support will be removed in 4.0'
- );
- $options += ['separator' => ':'];
- if (!$request->getParam('pass')) {
- return $request->withParam('named', []);
- }
- $named = [];
- $pass = $request->getParam('pass');
- foreach ((array)$pass as $key => $value) {
- if (strpos($value, $options['separator']) === false) {
- continue;
- }
- unset($pass[$key]);
- list($key, $value) = explode($options['separator'], $value, 2);
- if (preg_match_all('/\[([A-Za-z0-9_-]+)?\]/', $key, $matches, PREG_SET_ORDER)) {
- $matches = array_reverse($matches);
- $parts = explode('[', $key);
- $key = array_shift($parts);
- $arr = $value;
- foreach ($matches as $match) {
- if (empty($match[1])) {
- $arr = [$arr];
- } else {
- $arr = [
- $match[1] => $arr
- ];
- }
- }
- $value = $arr;
- }
- $named = array_merge_recursive($named, [$key => $value]);
- }
- return $request
- ->withParam('pass', $pass)
- ->withParam('named', $named);
- }
- /**
- * Create a RouteBuilder for the provided path.
- *
- * @param string $path The path to set the builder to.
- * @param array $options The options for the builder
- * @return \Cake\Routing\RouteBuilder
- */
- public static function createRouteBuilder($path, array $options = [])
- {
- $defaults = [
- 'routeClass' => static::defaultRouteClass(),
- 'extensions' => static::$_defaultExtensions,
- ];
- $options += $defaults;
- return new RouteBuilder(static::$_collection, $path, [], [
- 'routeClass' => $options['routeClass'],
- 'extensions' => $options['extensions'],
- ]);
- }
- /**
- * Create a routing scope.
- *
- * Routing scopes allow you to keep your routes DRY and avoid repeating
- * common path prefixes, and or parameter sets.
- *
- * Scoped collections will be indexed by path for faster route parsing. If you
- * re-open or re-use a scope the connected routes will be merged with the
- * existing ones.
- *
- * ### Options
- *
- * The `$params` array allows you to define options for the routing scope.
- * The options listed below *are not* available to be used as routing defaults
- *
- * - `routeClass` The route class to use in this scope. Defaults to
- * `Router::defaultRouteClass()`
- * - `extensions` The extensions to enable in this scope. Defaults to the globally
- * enabled extensions set with `Router::extensions()`
- *
- * ### Example
- *
- * ```
- * Router::scope('/blog', ['plugin' => 'Blog'], function ($routes) {
- * $routes->connect('/', ['controller' => 'Articles']);
- * });
- * ```
- *
- * The above would result in a `/blog/` route being created, with both the
- * plugin & controller default parameters set.
- *
- * You can use `Router::plugin()` and `Router::prefix()` as shortcuts to creating
- * specific kinds of scopes.
- *
- * @param string $path The path prefix for the scope. This path will be prepended
- * to all routes connected in the scoped collection.
- * @param array|callable $params An array of routing defaults to add to each connected route.
- * If you have no parameters, this argument can be a callable.
- * @param callable|null $callback The callback to invoke with the scoped collection.
- * @throws \InvalidArgumentException When an invalid callable is provided.
- * @return void
- */
- public static function scope($path, $params = [], $callback = null)
- {
- $options = [];
- if (is_array($params)) {
- $options = $params;
- unset($params['routeClass'], $params['extensions']);
- }
- $builder = static::createRouteBuilder('/', $options);
- $builder->scope($path, $params, $callback);
- }
- /**
- * Create prefixed routes.
- *
- * This method creates a scoped route collection that includes
- * relevant prefix information.
- *
- * The path parameter is used to generate the routing parameter name.
- * For example a path of `admin` would result in `'prefix' => 'admin'` being
- * applied to all connected routes.
- *
- * The prefix name will be inflected to the underscore version to create
- * the routing path. If you want a custom path name, use the `path` option.
- *
- * You can re-open a prefix as many times as necessary, as well as nest prefixes.
- * Nested prefixes will result in prefix values like `admin/api` which translates
- * to the `Controller\Admin\Api\` namespace.
- *
- * @param string $name The prefix name to use.
- * @param array|callable $params An array of routing defaults to add to each connected route.
- * If you have no parameters, this argument can be a callable.
- * @param callable|null $callback The callback to invoke that builds the prefixed routes.
- * @return void
- */
- public static function prefix($name, $params = [], $callback = null)
- {
- if ($callback === null) {
- $callback = $params;
- $params = [];
- }
- $name = Inflector::underscore($name);
- if (empty($params['path'])) {
- $path = '/' . $name;
- } else {
- $path = $params['path'];
- unset($params['path']);
- }
- $params = array_merge($params, ['prefix' => $name]);
- static::scope($path, $params, $callback);
- }
- /**
- * Add plugin routes.
- *
- * This method creates a scoped route collection that includes
- * relevant plugin information.
- *
- * The plugin name will be inflected to the underscore version to create
- * the routing path. If you want a custom path name, use the `path` option.
- *
- * Routes connected in the scoped collection will have the correct path segment
- * prepended, and have a matching plugin routing key set.
- *
- * @param string $name The plugin name to build routes for
- * @param array|callable $options Either the options to use, or a callback
- * @param callable|null $callback The callback to invoke that builds the plugin routes.
- * Only required when $options is defined
- * @return void
- */
- public static function plugin($name, $options = [], $callback = null)
- {
- if ($callback === null) {
- $callback = $options;
- $options = [];
- }
- $params = ['plugin' => $name];
- if (empty($options['path'])) {
- $options['path'] = '/' . Inflector::underscore($name);
- }
- if (isset($options['_namePrefix'])) {
- $params['_namePrefix'] = $options['_namePrefix'];
- }
- static::scope($options['path'], $params, $callback);
- }
- /**
- * Get the route scopes and their connected routes.
- *
- * @return \Cake\Routing\Route\Route[]
- */
- public static function routes()
- {
- if (!static::$initialized) {
- static::_loadRoutes();
- }
- return static::$_collection->routes();
- }
- /**
- * Get the RouteCollection inside the Router
- *
- * @return \Cake\Routing\RouteCollection
- */
- public static function getRouteCollection()
- {
- return static::$_collection;
- }
- /**
- * Set the RouteCollection inside the Router
- *
- * @param RouteCollection $routeCollection route collection
- * @return void
- */
- public static function setRouteCollection($routeCollection)
- {
- static::$_collection = $routeCollection;
- static::$initialized = true;
- }
- /**
- * Loads route configuration
- *
- * @deprecated 3.5.0 Routes will be loaded via the Application::routes() hook in 4.0.0
- * @return void
- */
- protected static function _loadRoutes()
- {
- static::$initialized = true;
- include CONFIG . 'routes.php';
- }
- }
|