HummingBirdAnimeClient/src/Dispatcher.php

368 lines
8.1 KiB
PHP
Raw Normal View History

2016-10-20 22:09:36 -04:00
<?php declare(strict_types=1);
/**
* Hummingbird Anime List Client
2015-11-16 11:40:01 -05:00
*
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
2015-11-16 11:40:01 -05:00
*
2016-10-20 22:09:36 -04:00
* PHP version 7
2016-08-30 10:01:18 -04:00
*
2015-11-16 11:40:01 -05:00
* @package HummingbirdAnimeClient
2016-08-30 10:01:18 -04:00
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2017 Timothy J. Warren
2016-08-30 10:01:18 -04:00
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 4.0
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/
2016-10-20 22:09:36 -04:00
2015-09-15 13:19:29 -04:00
namespace Aviat\AnimeClient;
2015-05-22 12:36:26 -04:00
use const Aviat\AnimeClient\{
DEFAULT_CONTROLLER,
DEFAULT_CONTROLLER_NAMESPACE,
ERROR_MESSAGE_METHOD,
NOT_FOUND_METHOD,
SRC_DIR
};
2017-02-22 14:46:35 -05:00
use function Aviat\AnimeClient\_dir;
2015-09-17 23:11:18 -04:00
use Aviat\Ion\Di\ContainerInterface;
2016-03-03 16:53:17 -05:00
use Aviat\Ion\Friend;
2015-09-17 23:11:18 -04:00
/**
* Basic routing/ dispatch
*/
2015-10-09 14:34:55 -04:00
class Dispatcher extends RoutingBase {
2015-05-22 12:36:26 -04:00
/**
* The route-matching object
* @var object $router
*/
protected $router;
/**
* The route matcher
* @var object $matcher
*/
protected $matcher;
/**
* Class wrapper for input superglobals
2017-02-22 14:46:35 -05:00
* @var \Psr\Http\Message\ServerRequestInterface
*/
protected $request;
/**
* Routes added to router
2017-02-16 14:30:06 -05:00
* @var array $outputRoutes
*/
2017-02-16 14:30:06 -05:00
protected $outputRoutes;
/**
* Constructor
2015-06-29 09:46:49 -04:00
*
* @param ContainerInterface $container
*/
2015-09-17 23:11:18 -04:00
public function __construct(ContainerInterface $container)
2015-05-22 12:36:26 -04:00
{
2015-09-14 15:49:20 -04:00
parent::__construct($container);
$this->router = $container->get('aura-router')->getMap();
$this->matcher = $container->get('aura-router')->getMatcher();
$this->request = $container->get('request');
2015-05-22 12:36:26 -04:00
2017-02-16 14:30:06 -05:00
$this->outputRoutes = $this->setupRoutes();
2015-05-22 12:36:26 -04:00
}
/**
* Get the current route object, if one matches
*
* @return object
*/
2016-12-20 12:58:37 -05:00
public function getRoute()
2015-05-22 12:36:26 -04:00
{
$logger = $this->container->getLogger('default');
2017-02-16 14:30:06 -05:00
$rawRoute = $this->request->getUri()->getPath();
$routePath = "/" . trim($rawRoute, '/');
$logger->info('Dispatcher - Routing data from get_route method');
$logger->info(print_r([
2017-02-16 14:30:06 -05:00
'route_path' => $routePath
], TRUE));
return $this->matcher->match($this->request);
2015-05-22 12:36:26 -04:00
}
/**
* Get list of routes applied
*
* @return array
*/
2016-12-20 12:58:37 -05:00
public function getOutputRoutes()
{
2017-02-16 14:30:06 -05:00
return $this->outputRoutes;
}
2015-05-22 12:36:26 -04:00
/**
* Handle the current route
*
2015-10-12 14:27:20 -04:00
* @param object|null $route
2015-05-22 12:36:26 -04:00
* @return void
*/
2015-10-09 14:34:55 -04:00
public function __invoke($route = NULL)
2015-05-22 12:36:26 -04:00
{
$logger = $this->container->getLogger('default');
2015-05-27 09:03:42 -04:00
2015-05-22 12:36:26 -04:00
if (is_null($route))
{
2016-12-20 12:58:37 -05:00
$route = $this->getRoute();
$logger->info('Dispatcher - Route invoke arguments');
$logger->info(print_r($route, TRUE));
2015-05-22 12:36:26 -04:00
}
2016-02-02 21:38:38 -05:00
if ($route)
2016-01-08 16:39:18 -05:00
{
2016-12-20 12:58:37 -05:00
$parsed = $this->processRoute(new Friend($route));
$controllerName = $parsed['controller_name'];
$actionMethod = $parsed['action_method'];
2016-01-08 16:39:18 -05:00
$params = $parsed['params'];
}
else
2015-05-22 12:36:26 -04:00
{
2016-01-08 15:54:21 -05:00
// If not route was matched, return an appropriate http
// error message
2017-02-16 14:30:06 -05:00
$errorRoute = $this->getErrorParams();
$controllerName = DEFAULT_CONTROLLER;
2017-02-16 14:30:06 -05:00
$actionMethod = $errorRoute['action_method'];
$params = $errorRoute['params'];
2016-01-08 16:39:18 -05:00
}
$this->call($controllerName, $actionMethod, $params);
2016-01-08 16:39:18 -05:00
}
/**
* Parse out the arguments for the appropriate controller for
* the current route
*
* @param \Aura\Router\Route $route
2016-08-30 10:57:41 -04:00
* @throws \LogicException
2016-01-08 16:39:18 -05:00
* @return array
*/
2016-12-20 12:58:37 -05:00
protected function processRoute($route)
2016-01-08 16:39:18 -05:00
{
if (array_key_exists('controller', $route->attributes))
2016-01-08 16:39:18 -05:00
{
2017-02-16 14:30:06 -05:00
$controllerName = $route->attributes['controller'];
2015-05-22 12:36:26 -04:00
}
else
{
2016-01-08 16:39:18 -05:00
throw new \LogicException("Missing controller");
}
2015-11-13 11:33:27 -05:00
2016-01-08 16:39:18 -05:00
// Get the full namespace for a controller if a short name is given
2017-02-16 14:30:06 -05:00
if (strpos($controllerName, '\\') === FALSE)
2016-01-08 16:39:18 -05:00
{
2016-12-20 12:58:37 -05:00
$map = $this->getControllerList();
2017-02-16 14:30:06 -05:00
$controllerName = $map[$controllerName];
2016-01-08 16:39:18 -05:00
}
2015-10-01 16:30:46 -04:00
2017-02-16 14:30:06 -05:00
$actionMethod = (array_key_exists('action', $route->attributes))
? $route->attributes['action']
: NOT_FOUND_METHOD;
2015-10-01 16:30:46 -04:00
2016-03-03 16:53:17 -05:00
$params = [];
if ( ! empty($route->__get('tokens')))
2016-01-08 16:39:18 -05:00
{
2016-03-03 16:53:17 -05:00
$tokens = array_keys($route->__get('tokens'));
foreach ($tokens as $param)
{
2016-03-03 16:53:17 -05:00
if (array_key_exists($param, $route->attributes))
{
2016-03-03 16:53:17 -05:00
$params[$param] = $route->attributes[$param];
}
}
2015-05-22 12:36:26 -04:00
}
2016-03-03 16:53:17 -05:00
$logger = $this->container->getLogger('default');
$logger->info(json_encode($params));
2015-05-22 12:36:26 -04:00
2016-01-08 16:39:18 -05:00
return [
2017-02-16 14:30:06 -05:00
'controller_name' => $controllerName,
'action_method' => $actionMethod,
2016-01-08 16:39:18 -05:00
'params' => $params
];
2015-05-22 12:36:26 -04:00
}
/**
* Get the type of route, to select the current controller
*
* @return string
*/
2016-12-20 12:58:37 -05:00
public function getController()
{
2017-02-16 14:30:06 -05:00
$routeType = $this->__get('default_list');
$requestUri = $this->request->getUri()->getPath();
$path = trim($requestUri, '/');
$segments = explode('/', $path);
2015-09-14 15:49:20 -04:00
$controller = reset($segments);
if (empty($controller))
{
2017-02-16 14:30:06 -05:00
$controller = $routeType;
}
2015-09-14 15:49:20 -04:00
return $controller;
}
/**
* Get the list of controllers in the default namespace
*
* @return array
*/
2016-12-20 12:58:37 -05:00
public function getControllerList()
{
2017-02-16 14:30:06 -05:00
$defaultNamespace = DEFAULT_CONTROLLER_NAMESPACE;
$path = str_replace('\\', '/', $defaultNamespace);
2016-08-29 16:36:13 -04:00
$path = str_replace('Aviat/AnimeClient/', '', $path);
$path = trim($path, '/');
2017-02-16 14:30:06 -05:00
$actualPath = realpath(_dir(SRC_DIR, $path));
$classFiles = glob("{$actualPath}/*.php");
$controllers = [];
2017-02-16 14:30:06 -05:00
foreach ($classFiles as $file)
{
2017-02-16 14:30:06 -05:00
$rawClassName = basename(str_replace(".php", "", $file));
$path = strtolower(basename($rawClassName));
$className = trim($defaultNamespace . '\\' . $rawClassName, '\\');
2017-02-16 14:30:06 -05:00
$controllers[$path] = $className;
}
return $controllers;
}
2016-01-08 15:54:21 -05:00
/**
* Create the controller object and call the appropriate
* method
*
2016-12-20 12:58:37 -05:00
* @param string $controllerName - The full namespace of the controller class
2016-01-08 15:54:21 -05:00
* @param string $method
* @param array $params
* @return void
*/
2016-12-20 12:58:37 -05:00
protected function call($controllerName, $method, array $params)
2016-01-08 15:54:21 -05:00
{
$logger = $this->container->getLogger('default');
2016-01-08 15:54:21 -05:00
2016-12-20 12:58:37 -05:00
$controller = new $controllerName($this->container);
2016-01-08 15:54:21 -05:00
// Run the appropriate controller method
$logger->debug('Dispatcher - controller arguments');
$logger->debug(print_r($params, TRUE));
2016-01-08 16:39:18 -05:00
call_user_func_array([$controller, $method], $params);
2016-01-08 15:54:21 -05:00
}
/**
* Get the appropriate params for the error page
* pased on the failed route
*
* @return array|false
*/
2016-12-20 12:58:37 -05:00
protected function getErrorParams()
2016-01-08 15:54:21 -05:00
{
$logger = $this->container->getLogger('default');
$failure = $this->matcher->getFailedRoute();
$logger->info('Dispatcher - failed route');
$logger->info(print_r($failure, TRUE));
2017-02-16 14:30:06 -05:00
$actionMethod = ERROR_MESSAGE_METHOD;
2016-01-08 15:54:21 -05:00
$params = [];
switch($failure->failedRule) {
2016-08-29 16:36:13 -04:00
case 'Aura\Router\Rule\Allows':
$params = [
'http_code' => 405,
'title' => '405 Method Not Allowed',
'message' => 'Invalid HTTP Verb'
];
break;
case 'Aura\Router\Rule\Accepts':
$params = [
'http_code' => 406,
'title' => '406 Not Acceptable',
'message' => 'Unacceptable content type'
];
break;
default:
// Fall back to a 404 message
2017-02-16 14:30:06 -05:00
$actionMethod = NOT_FOUND_METHOD;
break;
2016-01-08 15:54:21 -05:00
}
return [
'params' => $params,
2017-02-16 14:30:06 -05:00
'action_method' => $actionMethod
2016-01-08 15:54:21 -05:00
];
}
/**
* Select controller based on the current url, and apply its relevent routes
*
* @return array
*/
2017-02-16 14:30:06 -05:00
protected function setupRoutes()
2015-05-22 12:36:26 -04:00
{
2017-02-16 14:30:06 -05:00
$routeType = $this->getController();
// Add routes
2016-01-06 11:08:56 -05:00
$routes = [];
foreach ($this->routes as $name => &$route)
2015-05-22 12:36:26 -04:00
{
$path = $route['path'];
unset($route['path']);
2017-02-16 14:30:06 -05:00
$controllerMap = $this->getControllerList();
$controllerClass = (array_key_exists($routeType, $controllerMap))
? $controllerMap[$routeType]
: DEFAULT_CONTROLLER;
2016-01-06 17:06:30 -05:00
2017-02-16 14:30:06 -05:00
if (array_key_exists($routeType, $controllerMap))
2015-11-13 11:33:27 -05:00
{
2017-02-16 14:30:06 -05:00
$controllerClass = $controllerMap[$routeType];
2015-11-13 11:33:27 -05:00
}
// Prepend the controller to the route parameters
2017-02-16 14:30:06 -05:00
$route['controller'] = $controllerClass;
2015-06-17 08:50:01 -04:00
// Select the appropriate router method based on the http verb
2015-09-17 23:11:18 -04:00
$add = (array_key_exists('verb', $route))
? strtolower($route['verb'])
: "get";
2015-06-17 08:50:01 -04:00
// Add the route to the router object
if ( ! array_key_exists('tokens', $route))
{
$routes[] = $this->router->$add($name, $path)->defaults($route);
}
else
{
$tokens = $route['tokens'];
unset($route['tokens']);
2015-06-17 08:50:01 -04:00
2015-11-11 14:53:09 -05:00
$routes[] = $this->router->$add($name, $path)
->defaults($route)
->tokens($tokens);
}
2015-06-17 08:50:01 -04:00
}
2015-11-11 14:53:09 -05:00
return $routes;
2015-05-22 12:36:26 -04:00
}
}
2015-10-09 14:34:55 -04:00
// End of Dispatcher.php