<?php
namespace gnomephp\mvc;
use \gnomephp\mvc\router\Router,
\gnomephp\mvc\router\RouterParseException;
/**
* The dispatcher is the entry point of where all gnomephp
* applications will start.
*
* @see gnomephp\mvc\Dispatcher.dispatch()
* @author peec
*
*/
class Dispatcher{
/**
*
* Keeps the microtime of when dispatch() was initialized.
* @var float
*/
protected $startTime = 0;
/**
* Router object.
*
* @var gnomephp\mvc\router\Router
*/
public $router = null;
/**
* The active router rule.
* @var gnomephp\mvc\router\Rule
*/
public $activeRoute = null;
/**
* Singleton instance of dispatcher when dispatch() method is run.
* @var gnomephp\mvc\Dispatcher
*/
static public $dispatcher = null;
public function __construct(\gnomephp\mvc\router\Router $router){
$this->router = $router;
}
/**
* Runs the router and tries to find a route.
* If we get
* @throws RouterException
*/
public function run(){
$route = $this->router->route();
if ($route === null){
// no route object was returned
throw new RouterException("404 - No application route was found for that URI path.", 404);
}
$route->setBaseNamespace(GNOME_APP_NS.'\controller');
$controller = $route->getController();
$action = $route->getMethod();
// instantiate the controller class
$page = new $controller();
if (!method_exists($page, $action)){
throw new RouterException("404 - No Route found for URL: ".self::getUrl().". Could not load Action.");
}
$this->activeRoute = $route;
// invoke the action method with the route values
$args = $route->getArguments();
// Try security check.
$this->securityCheck($page, $action);
try{
call_user_func_array(array($page, $action), array_values($args));
}catch(\gnomephp\cache\CatchedCacheException $e){
// Do nothing, this is totally OK.
}
// Delete data that should not be here anymore.
// This is one time data that should be deleted.
$session = new \gnomephp\Session();
$session->delete('gnomephp.messages');
$session->save();
}
/**
* Throws AccessException if user has no access.
*
*
* @param object $page Controller object
* @param string $action String method
* @throws gnomephp\security\AccessException
*/
protected function securityCheck($page, $action){
$refObject = new \ReflectionObject($page);
// Lets do a security check if it does implement the Secure interface.
if ($refObject->implementsInterface('gnomephp\security\Secure')){
\gnomephp\doctrine\Doctrine::load();
$ns = \gnomephp\security\Security::getSessionModelPath();
$userSession = $ns::getValidSession($page->session->get(\gnomephp\security\Security::SECURITY_TOKEN), $ns);
if (!$page->hasAccessTo($action, $userSession)){
throw new \gnomephp\security\AccessException();
}
}
unset($refObject);
}
/**
* Gets the amount of time since Router::route() was called.
*/
public function getRuntime(){
return microtime(true) - self::$startTime;
}
/**
* Gets the current URL.
*/
static public function getUrl(){
$len = strlen($_SERVER['SCRIPT_NAME']);
$out = substr($_SERVER['PHP_SELF'], $len, strlen($_SERVER['PHP_SELF']));
if (!$out)$out = '/';
return $out;
}
/**
* Returns the current dispatcher if dispatch() is run.
* @return gnomephp\mvc\Dispatcher
*/
static public function getInstance(){
return self::$dispatcher;
}
/**
* Static method for normal runs.
* This is the absolute entry point of where your website php code starts.
* Do not change this if you do not know what you are doing.
*/
static public function dispatch(){
session_start();
// get the incoming request URI path
$path = self::getUrl();
// Setup router.
$router = new Router($path, $_SERVER);
$router->parse(file_get_contents(GNOME_APP_PATH.DIRECTORY_SEPARATOR.'config'. DIRECTORY_SEPARATOR . 'routes.conf'));
self::$dispatcher = new Dispatcher($router);
try{
self::$dispatcher->run();
}catch(\gnomephp\security\AccessException $e){
$controller = new DispatcherController();
$controller->redirect($controller->view->url->linkTo('Auth', 'login'));
}catch(\Exception $e){
// Send header.
header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
header('Status: 404 Not Found');
// Deal with the error in a good way.
// Create dispatcher controller.
$errorExceptionHandlers = (array)\gnomephp\Configuration::get('application', 'errors');
$controller = new DispatcherController();
if ($e instanceof \gnomephp\mvc\RouterException || $e instanceof \gnomephp\AutoLoaderException){
$method = 'routerException';
}else{
$method = 'index';
}
foreach($errorExceptionHandlers as $exName => $set){
if ($e instanceof $exName){
if (isset($set['backend'])){
$ex = explode('.',$set['backend']);
$c = $ex[0];
$controller = new $c();
$method = $ex[1];
$controller->$method($e);
}else{
$controller->view->render($set['view']);
}
return;
}
}
// Run controller / method.
$controller->$method($e);
}
}
}