CodeIgniter4/system/Router/RouteCollection.php

396 lines
9.4 KiB
PHP

<?php namespace CodeIgniter\Router;
/**
* Interface RouteCollectionInterface
*
* A Route Collection's sole job is to hold a series of routes. The required
* number of methods is kept very small on purpose, but implementors may
* add a number of additional methods to customize how the routes are defined.
*
* The RouteCollection provides the Router with the routes so that it can determine
* which controller should be ran.
*
* @package CodeIgniter\Router
*/
class RouteCollection implements RouteCollectionInterface
{
/**
* The namespace to be added to any controllers.
* Defaults to the global namespaces (\)
*
* @var string
*/
protected $defaultNamespace = '\\';
/**
* The name of the default controller to use
* when no other controller is specified.
*
* @var string
*/
protected $defaultController = 'Home';
/**
* The name of the default method to use
* when no other method has been specified.
*
* @var string
*/
protected $defaultMethod = 'index';
/**
* Whether to convert dashes to underscores in URI.
*
* @var bool
*/
protected $translateURIDashes = false;
/**
* Defined placeholders that can be used
* within the
*
* @var array
*/
protected $placeholders = [
'any' => '.*',
'segment' => '[^/]+',
'num' => '[0-9]+',
'alpha' => '[a-zA-Z]+',
'alphanum' => '[a-zA-Z0-9]+',
];
/**
* An array of all routes and their mappings.
*
* @var array
*/
protected $routes = [];
/**
* The current method that the script is being called by.
*
* @var
*/
protected $http_verb;
/**
* The default list of HTTP methods (and CLI for command line usage)
* that is allowed if no other method is provided.
*
* @var array
*/
protected $default_http_methods = ['options', 'get', 'head', 'post', 'put', 'delete', 'trace', 'connect', 'cli'];
//--------------------------------------------------------------------
public function __construct()
{
// Get HTTP verb
$this->http_verb = isset($_SERVER['REQUEST_METHOD']) ? strtolower($_SERVER['REQUEST_METHOD']) : 'cli';
}
//--------------------------------------------------------------------
/**
* Adds a single route to the collection.
*
* This provides a fairly simplistic solution without a lot of options.
* A much more flexible version is to present an array elements and
* multiple options to the 'map' method below.
*
* @param string $route The pattern to match against the URI
* @param string $map The controller or path to map to.
* @param string|array $method One of more HTTP methods that are allowed. If one,
* present as a single string (i.e. 'get').
* Otherwise, present an array of methods.
*
* @return void
*/
public function add(string $route, $map, $methods = null)
{
// If methods is null, than it should work
// for any of the available methods.
if (empty($methods))
{
$methods = $this->default_http_methods;
}
if ( ! is_array($methods))
{
$methods = [$methods];
}
// Ensure that all of our methods are lower-cased for compatibility
array_walk($methods, function (&$item)
{
$item = strtolower($item);
}
);
// To save on memory and processing later, we only add
// the routes that are actually available at this time.
if ( ! in_array($this->http_verb, $methods))
{
return;
}
// Replace our regex pattern placeholders with the actual thing
// so that the Router doesn't need to know about any of this.
foreach ($this->placeholders as $tag => $pattern)
{
$route = str_ireplace(':'.$tag, $pattern, $route);
}
// We need to ensure that the current namespace is added to the final mapping
// so that it won't try to use the current namespace for the class.
if (is_string($map) && strpos($map, '\\') === false)
{
$map = $this->defaultNamespace.'\\'.$map;
// Trim out any double back-slashes
$map = str_replace('\\\\', '\\', $map);
}
// Ensure that any strings are prefixed with backslash to get
// out of the current namespace and into the proper one.
if (is_string($map))
{
$map = '\\'.ltrim($map, '\\ ');
}
$this->routes[$route] = $map;
}
//--------------------------------------------------------------------
/**
* Adds an array of routes to the class all at once. This allows additional
* settings to be specified for all incoming routes, including:
*
* namespace Sets the namespace for all routes
* hostname Route must be on the set domain
* prefix Sets a string that will be prefixed to all routes (left side)
*
* @param array|null $routes
*
* @return mixed
*/
public function map(array $routes = null, array $options = [])
{
if (empty($_SERVER['HTTP_HOST']))
{
$_SERVER['HTTP_HOST'] = null;
}
$current_host = ! empty($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
// If a hostname is provided as an option,
// then don't waste time if our hostname doesn't match.
if ( ! empty($options['hostname']) && strtolower($current_host) != strtolower($options['hostname']))
{
return;
}
// Save the current default namespace so
// that we are able to replace it with one
// the user specifies here.
$old_namespace = $this->defaultNamespace;
if ( ! empty($options['namespace']))
{
$this->defaultNamespace = $options['namespace'];
}
$prefix = ! empty($options['prefix']) ? $options['prefix'] : '';
foreach ($routes as $route => $map)
{
// Also need to trim any leading slashes to ensure
// that the add() method adds the namespace correctly.
if (is_string($map) && ! empty($options['namespace']))
{
$map = ltrim($map, '\\ ');
}
// If an array is passed in, that means that we are
// dealing with HTTP verb routing so we need
// to send all of them into the add() method
// separately.
if (is_array($map))
{
foreach ($map as $verb => $right)
{
// $route will now be the HTTP verb used.
$this->add($prefix.$route, $right, $verb);
}
continue;
}
$this->add($prefix.$route, $map);
}
// Put our namespace back.
$this->defaultNamespace = $old_namespace;
}
//--------------------------------------------------------------------
/**
* Registers a new constraint with the system. Constraints are used
* by the routes as placeholders for regular expressions to make defining
* the routes more human-friendly.
*
* Once created, they can be used within curly brackets in routes.
*
* @param $name
* @param $pattern
*
* @return mixed
*/
public function addPlaceholder(string $name, string $pattern): self
{
$this->placeholders[$name] = $pattern;
return $this;
}
//--------------------------------------------------------------------
/**
* Sets the default namespace to use for controllers when no other
* namespace has been specified.
*
* @param $value
*
* @return mixed
*/
public function setDefaultNamespace(string $value): self
{
$this->defaultNamespace = $value;
return $this;
}
//--------------------------------------------------------------------
/**
* Sets the default controller to use when no other controller has been
* specified.
*
* @param $value
*
* @return mixed
*/
public function setDefaultController(string $value): self
{
$this->defaultController = $value;
return $this;
}
//--------------------------------------------------------------------
/**
* Returns the name of the default controller. With Namespace.
*
* @return string
*/
public function defaultController(): string
{
return $this->defaultController;
}
//--------------------------------------------------------------------
/**
* Returns the name of the default method to use within the controller.
*
* @return string
*/
public function defaultMethod(): string
{
return $this->defaultMethod;
}
//--------------------------------------------------------------------
/**
* Sets the default method to call on the controller when no other
* method has been set in the route.
*
* @param $value
*
* @return mixed
*/
public function setDefaultMethod(string $value): self
{
$this->defaultMethod = $value;
return $this;
}
//--------------------------------------------------------------------
/**
* Tells the system whether to convert dashes in URI strings into
* underscores. In some search engines, including Google, dashes
* create more meaning and make it easier for the search engine to
* find words and meaning in the URI for better SEO. But it
* doesn't work well with PHP method names....
*
* @param $value
*
* @return mixed
*/
public function setTranslateURIDashes(bool $value): self
{
$this->translateURIDashes = $value;
return $this;
}
//--------------------------------------------------------------------
/**
* Returns the raw array of available routes.
*
* @return array
*/
public function routes()
{
return $this->routes;
}
//--------------------------------------------------------------------
/**
* Returns the current HTTP Verb being used.
*
* @return string
*/
public function HTTPVerb()
{
return $this->http_verb;
}
//--------------------------------------------------------------------
/**
* Returns the current Translate URI Dashes setting.
*
* @return bool
*/
public function translateURIDashes()
{
return $this->translateURIDashes;
}
//--------------------------------------------------------------------
}