summaryrefslogtreecommitdiff
path: root/app/Core/Http
diff options
context:
space:
mode:
authorFrederic Guillot <fred@kanboard.net>2015-12-22 19:06:03 +0100
committerFrederic Guillot <fred@kanboard.net>2015-12-22 19:06:03 +0100
commit6f9af3659c9146a2ac1b08d70610bf96398ec073 (patch)
tree21cbbca979a30d133d421881d6aa6e6af8096199 /app/Core/Http
parentc83f589b22cd548c6de10bfb0c18f767ba7dffd8 (diff)
Added the possiblity to define custom routes from plugins
Diffstat (limited to 'app/Core/Http')
-rw-r--r--app/Core/Http/Request.php49
-rw-r--r--app/Core/Http/Route.php188
-rw-r--r--app/Core/Http/Router.php199
3 files changed, 298 insertions, 138 deletions
diff --git a/app/Core/Http/Request.php b/app/Core/Http/Request.php
index c626f5b2..da95f2d4 100644
--- a/app/Core/Http/Request.php
+++ b/app/Core/Http/Request.php
@@ -42,6 +42,16 @@ class Request extends Base
}
/**
+ * Set GET parameters
+ *
+ * @param array $params
+ */
+ public function setParams(array $params)
+ {
+ $this->get = array_merge($this->get, $params);
+ }
+
+ /**
* Get query string string parameter
*
* @access public
@@ -147,6 +157,17 @@ class Request extends Base
}
/**
+ * Return HTTP method
+ *
+ * @access public
+ * @return bool
+ */
+ public function getMethod()
+ {
+ return $this->getServerVariable('REQUEST_METHOD');
+ }
+
+ /**
* Return true if the HTTP request is sent with the POST method
*
* @access public
@@ -154,7 +175,7 @@ class Request extends Base
*/
public function isPost()
{
- return isset($this->server['REQUEST_METHOD']) && $this->server['REQUEST_METHOD'] === 'POST';
+ return $this->getServerVariable('REQUEST_METHOD') === 'POST';
}
/**
@@ -203,7 +224,7 @@ class Request extends Base
public function getHeader($name)
{
$name = 'HTTP_'.str_replace('-', '_', strtoupper($name));
- return isset($this->server[$name]) ? $this->server[$name] : '';
+ return $this->getServerVariable($name);
}
/**
@@ -214,18 +235,18 @@ class Request extends Base
*/
public function getRemoteUser()
{
- return isset($this->server[REVERSE_PROXY_USER_HEADER]) ? $this->server[REVERSE_PROXY_USER_HEADER] : '';
+ return $this->getServerVariable(REVERSE_PROXY_USER_HEADER);
}
/**
- * Returns current request's query string, useful for redirecting
+ * Returns query string
*
* @access public
* @return string
*/
public function getQueryString()
{
- return isset($this->server['QUERY_STRING']) ? $this->server['QUERY_STRING'] : '';
+ return $this->getServerVariable('QUERY_STRING');
}
/**
@@ -236,7 +257,7 @@ class Request extends Base
*/
public function getUri()
{
- return isset($this->server['REQUEST_URI']) ? $this->server['REQUEST_URI'] : '';
+ return $this->getServerVariable('REQUEST_URI');
}
/**
@@ -269,7 +290,7 @@ class Request extends Base
);
foreach ($keys as $key) {
- if (! empty($this->server[$key])) {
+ if ($this->getServerVariable($key) !== '') {
foreach (explode(',', $this->server[$key]) as $ipAddress) {
return trim($ipAddress);
}
@@ -287,6 +308,18 @@ class Request extends Base
*/
public function getStartTime()
{
- return isset($this->server['REQUEST_TIME_FLOAT']) ? $this->server['REQUEST_TIME_FLOAT'] : 0;
+ return $this->getServerVariable('REQUEST_TIME_FLOAT') ?: 0;
+ }
+
+ /**
+ * Get server variable
+ *
+ * @access public
+ * @param string $variable
+ * @return string
+ */
+ public function getServerVariable($variable)
+ {
+ return isset($this->server[$variable]) ? $this->server[$variable] : '';
}
}
diff --git a/app/Core/Http/Route.php b/app/Core/Http/Route.php
new file mode 100644
index 00000000..ed831467
--- /dev/null
+++ b/app/Core/Http/Route.php
@@ -0,0 +1,188 @@
+<?php
+
+namespace Kanboard\Core\Http;
+
+use RuntimeException;
+use Kanboard\Core\Base;
+
+/**
+ * Route Handler
+ *
+ * @package http
+ * @author Frederic Guillot
+ */
+class Route extends Base
+{
+ /**
+ * Flag that enable the routing table
+ *
+ * @access private
+ * @var boolean
+ */
+ private $activated = false;
+
+ /**
+ * Store routes for path lookup
+ *
+ * @access private
+ * @var array
+ */
+ private $paths = array();
+
+ /**
+ * Store routes for url lookup
+ *
+ * @access private
+ * @var array
+ */
+ private $urls = array();
+
+ /**
+ * Enable routing table
+ *
+ * @access public
+ * @return Route
+ */
+ public function enable()
+ {
+ $this->activated = true;
+ return $this;
+ }
+
+ /**
+ * Add route
+ *
+ * @access public
+ * @param string $path
+ * @param string $controller
+ * @param string $action
+ * @param string $plugin
+ * @return Route
+ */
+ public function addRoute($path, $controller, $action, $plugin = '')
+ {
+ if ($this->activated) {
+ $path = ltrim($path, '/');
+ $items = explode('/', $path);
+ $params = $this->findParams($items);
+
+ $this->paths[] = array(
+ 'items' => $items,
+ 'count' => count($items),
+ 'controller' => $controller,
+ 'action' => $action,
+ 'plugin' => $plugin,
+ );
+
+ $this->urls[$plugin][$controller][$action][] = array(
+ 'path' => $path,
+ 'params' => $params,
+ 'count' => count($params),
+ );
+ }
+
+ return $this;
+ }
+
+ /**
+ * Find a route according to the given path
+ *
+ * @access public
+ * @param string $path
+ * @return array
+ */
+ public function findRoute($path)
+ {
+ $items = explode('/', ltrim($path, '/'));
+ $count = count($items);
+
+ foreach ($this->paths as $route) {
+ if ($count === $route['count']) {
+ $params = array();
+
+ for ($i = 0; $i < $count; $i++) {
+ if ($route['items'][$i]{0} === ':') {
+ $params[substr($route['items'][$i], 1)] = $items[$i];
+ } elseif ($route['items'][$i] !== $items[$i]) {
+ break;
+ }
+ }
+
+ if ($i === $count) {
+ $this->request->setParams($params);
+ return array(
+ 'controller' => $route['controller'],
+ 'action' => $route['action'],
+ 'plugin' => $route['plugin'],
+ );
+ }
+ }
+ }
+
+ return array(
+ 'controller' => 'app',
+ 'action' => 'index',
+ 'plugin' => '',
+ );
+ }
+
+ /**
+ * Find route url
+ *
+ * @access public
+ * @param string $controller
+ * @param string $action
+ * @param array $params
+ * @param string $plugin
+ * @return string
+ */
+ public function findUrl($controller, $action, array $params = array(), $plugin = '')
+ {
+ if ($plugin === '' && isset($params['plugin'])) {
+ $plugin = $params['plugin'];
+ unset($params['plugin']);
+ }
+
+ if (! isset($this->urls[$plugin][$controller][$action])) {
+ return '';
+ }
+
+ foreach ($this->urls[$plugin][$controller][$action] as $route) {
+ if (array_diff_key($params, $route['params']) === array()) {
+ $url = $route['path'];
+ $i = 0;
+
+ foreach ($params as $variable => $value) {
+ $url = str_replace(':'.$variable, $value, $url);
+ $i++;
+ }
+
+ if ($i === $route['count']) {
+ return $url;
+ }
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * Find url params
+ *
+ * @access public
+ * @param array $items
+ * @return array
+ */
+ public function findParams(array $items)
+ {
+ $params = array();
+
+ foreach ($items as $item) {
+ if ($item !== '' && $item{0} === ':') {
+ $params[substr($item, 1)] = true;
+ }
+ }
+
+ return $params;
+ }
+}
diff --git a/app/Core/Http/Router.php b/app/Core/Http/Router.php
index 0080b23a..8b58a947 100644
--- a/app/Core/Http/Router.php
+++ b/app/Core/Http/Router.php
@@ -6,7 +6,7 @@ use RuntimeException;
use Kanboard\Core\Base;
/**
- * Router class
+ * Route Dispatcher
*
* @package http
* @author Frederic Guillot
@@ -14,46 +14,38 @@ use Kanboard\Core\Base;
class Router extends Base
{
/**
- * Controller
+ * Plugin name
*
* @access private
* @var string
*/
- private $controller = '';
+ private $plugin = '';
/**
- * Action
+ * Controller
*
* @access private
* @var string
*/
- private $action = '';
-
- /**
- * Store routes for path lookup
- *
- * @access private
- * @var array
- */
- private $paths = array();
+ private $controller = '';
/**
- * Store routes for url lookup
+ * Action
*
* @access private
- * @var array
+ * @var string
*/
- private $urls = array();
+ private $action = '';
/**
- * Get action
+ * Get plugin name
*
* @access public
* @return string
*/
- public function getAction()
+ public function getPlugin()
{
- return $this->action;
+ return $this->plugin;
}
/**
@@ -68,163 +60,110 @@ class Router extends Base
}
/**
- * Get the path to compare patterns
+ * Get action
*
* @access public
- * @param string $uri
- * @param string $query_string
* @return string
*/
- public function getPath($uri, $query_string = '')
+ public function getAction()
{
- $path = substr($uri, strlen($this->helper->url->dir()));
-
- if (! empty($query_string)) {
- $path = substr($path, 0, - strlen($query_string) - 1);
- }
-
- if (! empty($path) && $path{0} === '/') {
- $path = substr($path, 1);
- }
-
- return $path;
+ return $this->action;
}
/**
- * Add route
+ * Get the path to compare patterns
*
* @access public
- * @param string $path
- * @param string $controller
- * @param string $action
- * @param array $params
+ * @return string
*/
- public function addRoute($path, $controller, $action, array $params = array())
+ public function getPath()
{
- $pattern = explode('/', $path);
-
- $this->paths[] = array(
- 'pattern' => $pattern,
- 'count' => count($pattern),
- 'controller' => $controller,
- 'action' => $action,
- );
-
- $this->urls[$controller][$action][] = array(
- 'path' => $path,
- 'params' => array_flip($params),
- 'count' => count($params),
- );
- }
+ $path = substr($this->request->getUri(), strlen($this->helper->url->dir()));
- /**
- * Find a route according to the given path
- *
- * @access public
- * @param string $path
- * @return array
- */
- public function findRoute($path)
- {
- $parts = explode('/', $path);
- $count = count($parts);
-
- foreach ($this->paths as $route) {
- if ($count === $route['count']) {
- $params = array();
-
- for ($i = 0; $i < $count; $i++) {
- if ($route['pattern'][$i]{0} === ':') {
- $params[substr($route['pattern'][$i], 1)] = $parts[$i];
- } elseif ($route['pattern'][$i] !== $parts[$i]) {
- break;
- }
- }
-
- if ($i === $count) {
- $_GET = array_merge($_GET, $params);
- return array($route['controller'], $route['action']);
- }
- }
+ if ($this->request->getQueryString() !== '') {
+ $path = substr($path, 0, - strlen($this->request->getQueryString()) - 1);
}
- return array('app', 'index');
+ if ($path !== '' && $path{0} === '/') {
+ $path = substr($path, 1);
+ }
+
+ return $path;
}
/**
- * Find route url
+ * Find controller/action from the route table or from get arguments
*
* @access public
- * @param string $controller
- * @param string $action
- * @param array $params
- * @return string
*/
- public function findUrl($controller, $action, array $params = array())
+ public function dispatch()
{
- if (! isset($this->urls[$controller][$action])) {
- return '';
+ $controller = $this->request->getStringParam('controller');
+ $action = $this->request->getStringParam('action');
+ $plugin = $this->request->getStringParam('plugin');
+
+ if ($controller === '') {
+ $route = $this->route->findRoute($this->getPath());
+ $controller = $route['controller'];
+ $action = $route['action'];
+ $plugin = $route['plugin'];
}
- foreach ($this->urls[$controller][$action] as $pattern) {
- if (array_diff_key($params, $pattern['params']) === array()) {
- $url = $pattern['path'];
- $i = 0;
-
- foreach ($params as $variable => $value) {
- $url = str_replace(':'.$variable, $value, $url);
- $i++;
- }
-
- if ($i === $pattern['count']) {
- return $url;
- }
- }
- }
+ $this->controller = ucfirst($this->sanitize($controller, 'app'));
+ $this->action = $this->sanitize($action, 'index');
+ $this->plugin = ucfirst($this->sanitize($plugin));
- return '';
+ return $this->executeAction();
}
/**
* Check controller and action parameter
*
* @access public
- * @param string $value Controller or action name
- * @param string $default_value Default value if validation fail
+ * @param string $value
+ * @param string $default
* @return string
*/
- public function sanitize($value, $default_value)
+ public function sanitize($value, $default = '')
{
- return ! preg_match('/^[a-zA-Z_0-9]+$/', $value) ? $default_value : $value;
+ return preg_match('/^[a-zA-Z_0-9]+$/', $value) ? $value : $default;
}
/**
- * Find controller/action from the route table or from get arguments
+ * Execute controller action
*
- * @access public
- * @param string $uri
- * @param string $query_string
+ * @access private
*/
- public function dispatch($uri, $query_string = '')
+ private function executeAction()
{
- if (! empty($_GET['controller']) && ! empty($_GET['action'])) {
- $this->controller = $this->sanitize($_GET['controller'], 'app');
- $this->action = $this->sanitize($_GET['action'], 'index');
- $plugin = ! empty($_GET['plugin']) ? $this->sanitize($_GET['plugin'], '') : '';
- } else {
- list($this->controller, $this->action) = $this->findRoute($this->getPath($uri, $query_string)); // TODO: add plugin for routes
- $plugin = '';
- }
+ $class = $this->getControllerClassName();
- $class = '\Kanboard\\';
- $class .= empty($plugin) ? 'Controller\\'.ucfirst($this->controller) : 'Plugin\\'.ucfirst($plugin).'\Controller\\'.ucfirst($this->controller);
+ if (! class_exists($class)) {
+ throw new RuntimeException('Controller not found');
+ }
- if (! class_exists($class) || ! method_exists($class, $this->action)) {
- throw new RuntimeException('Controller or method not found for the given url!');
+ if (! method_exists($class, $this->action)) {
+ throw new RuntimeException('Action not implemented');
}
$instance = new $class($this->container);
$instance->beforeAction($this->controller, $this->action);
$instance->{$this->action}();
+ return $instance;
+ }
+
+ /**
+ * Get controller class name
+ *
+ * @access private
+ * @return string
+ */
+ private function getControllerClassName()
+ {
+ if ($this->plugin !== '') {
+ return '\Kanboard\Plugin\\'.$this->plugin.'\Controller\\'.$this->controller;
+ }
+
+ return '\Kanboard\Controller\\'.$this->controller;
}
}