2019-03-30 12:19:46 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Core;
|
|
|
|
|
|
|
|
use mysql_xdevapi\Exception;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Router
|
|
|
|
*
|
|
|
|
* PHP version 7.0
|
|
|
|
*/
|
|
|
|
class Router
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Associative array of routes (the routing table)
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $routes = [];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parameters from the matched route
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $params = [];
|
|
|
|
protected $prefix;
|
|
|
|
/**
|
|
|
|
* Add a route to the routing table
|
|
|
|
*
|
|
|
|
* @param string $route The route URL
|
|
|
|
* @param array $params Parameters (controller, action, etc.)
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function add($route, $params = [])
|
|
|
|
{
|
|
|
|
// Convert the route to a regular expression: escape forward slashes
|
|
|
|
$route = preg_replace('/\//', '\\/', $route);
|
|
|
|
|
|
|
|
// Convert variables e.g. {controller}
|
|
|
|
$route = preg_replace('/\{([a-z]+)\}/', '(?P<\1>[a-z-]+)', $route);
|
|
|
|
|
|
|
|
// Convert variables with custom regular expressions e.g. {id:\d+}
|
|
|
|
$route = preg_replace('/\{([a-z]+):([^\}]+)\}/', '(?P<\1>\2)', $route);
|
|
|
|
|
|
|
|
// Add start and end delimiters, and case insensitive flag
|
|
|
|
$route = '/^' . $route . '$/i';
|
2019-08-28 16:26:38 +00:00
|
|
|
|
2019-03-30 12:19:46 +00:00
|
|
|
$this->routes[$route] = $params;
|
|
|
|
}
|
|
|
|
public function AddPrefix($prefix){
|
|
|
|
if (is_string($prefix)){
|
|
|
|
$this->prefix = $prefix;
|
|
|
|
}else{
|
|
|
|
throw new Exception("error prefix is not string");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Get all the routes from the routing table
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getRoutes()
|
|
|
|
{
|
|
|
|
return $this->routes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Match the route to the routes in the routing table, setting the $params
|
|
|
|
* property if a route is found.
|
|
|
|
*
|
|
|
|
* @param string $url The route URL
|
|
|
|
*
|
|
|
|
* @return boolean true if a match found, false otherwise
|
|
|
|
*/
|
|
|
|
public function match($url)
|
|
|
|
{
|
|
|
|
foreach ($this->routes as $route => $params) {
|
|
|
|
if (preg_match($route, $url, $matches)) {
|
|
|
|
// Get named capture group values
|
|
|
|
foreach ($matches as $key => $match) {
|
|
|
|
if (is_string($key)) {
|
|
|
|
$params[$key] = $match;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$this->params = $params;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Get the currently matched parameters
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getParams()
|
|
|
|
{
|
|
|
|
return $this->params;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Dispatch the route, creating the controller object and running the
|
|
|
|
* action method
|
|
|
|
*
|
|
|
|
* @param string $url The route URL
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function dispatch($url)
|
|
|
|
{
|
|
|
|
$url = $this->removeQueryStringVariables($url);
|
|
|
|
$url = str_replace($this->prefix,"",$url);
|
2020-07-11 16:51:00 +00:00
|
|
|
|
2019-03-30 12:19:46 +00:00
|
|
|
if ($this->match($url)) {
|
|
|
|
$controller = $this->params['controller'];
|
|
|
|
$controller = $this->convertToStudlyCaps($controller);
|
|
|
|
$controller = $this->getNamespace() . $controller;
|
|
|
|
if (class_exists($controller)) {
|
|
|
|
$controller_object = new $controller($this->params);
|
|
|
|
$action = $this->params['action'];
|
|
|
|
$action = $this->convertToCamelCase($action);
|
|
|
|
if (preg_match('/action$/i', $action) == 0) {
|
|
|
|
$controller_object->$action();
|
|
|
|
} else {
|
|
|
|
throw new \Exception("Method $action in controller $controller cannot be called directly - remove the Action suffix to call this method");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new \Exception("Controller class $controller not found");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new \Exception('No route matched.', 404);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert the string with hyphens to StudlyCaps,
|
|
|
|
* e.g. post-authors => PostAuthors
|
|
|
|
*
|
|
|
|
* @param string $string The string to convert
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
protected function convertToStudlyCaps($string)
|
|
|
|
{
|
|
|
|
return str_replace(' ', '', ucwords(str_replace('-', ' ', $string)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert the string with hyphens to camelCase,
|
|
|
|
* e.g. add-new => addNew
|
|
|
|
*
|
|
|
|
* @param string $string The string to convert
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
protected function convertToCamelCase($string)
|
|
|
|
{
|
|
|
|
return lcfirst($this->convertToStudlyCaps($string));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove the query string variables from the URL (if any). As the full
|
|
|
|
* query string is used for the route, any variables at the end will need
|
|
|
|
* to be removed before the route is matched to the routing table. For
|
|
|
|
* example:
|
|
|
|
*
|
|
|
|
* URL $_SERVER['QUERY_STRING'] Route
|
|
|
|
* -------------------------------------------------------------------
|
|
|
|
* localhost '' ''
|
|
|
|
* localhost/? '' ''
|
|
|
|
* localhost/?page=1 page=1 ''
|
|
|
|
* localhost/posts?page=1 posts&page=1 posts
|
|
|
|
* localhost/posts/index posts/index posts/index
|
|
|
|
* localhost/posts/index?page=1 posts/index&page=1 posts/index
|
|
|
|
*
|
|
|
|
* A URL of the format localhost/?page (one variable name, no value) won't
|
|
|
|
* work however. (NB. The .htaccess file converts the first ? to a & when
|
|
|
|
* it's passed through to the $_SERVER variable).
|
|
|
|
*
|
|
|
|
* @param string $url The full URL
|
|
|
|
*
|
|
|
|
* @return string The URL with the query string variables removed
|
|
|
|
*/
|
|
|
|
protected function removeQueryStringVariables($url)
|
|
|
|
{
|
|
|
|
if ($url != '') {
|
2019-08-28 16:26:38 +00:00
|
|
|
$parts = explode('?', $url, 2);
|
2019-03-30 12:19:46 +00:00
|
|
|
|
2019-08-28 16:26:38 +00:00
|
|
|
if (strstr($parts[0], '=') === false) {
|
2019-03-30 12:19:46 +00:00
|
|
|
$url = $parts[0];
|
|
|
|
} else {
|
|
|
|
$url = '';
|
2019-08-25 16:49:16 +00:00
|
|
|
|
2019-03-30 12:19:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $url;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the namespace for the controller class. The namespace defined in the
|
|
|
|
* route parameters is added if present.
|
|
|
|
*
|
|
|
|
* @return string The request URL
|
|
|
|
*/
|
|
|
|
protected function getNamespace()
|
|
|
|
{
|
|
|
|
$namespace = 'App\Controllers\\';
|
|
|
|
|
|
|
|
if (array_key_exists('namespace', $this->params)) {
|
2019-08-28 16:26:38 +00:00
|
|
|
$namespace .= $this->params['namespace'] . '\\';
|
2019-03-30 12:19:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return $namespace;
|
|
|
|
}
|
|
|
|
}
|