merged Router and Dispatcher
This commit is contained in:
parent
727dc01ddd
commit
80751ca62a
2 changed files with 171 additions and 230 deletions
|
@ -1,181 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2010, The volkszaehler.org project
|
||||
* @package default
|
||||
* @license http://www.opensource.org/licenses/gpl-license.php GNU Public License
|
||||
*/
|
||||
/*
|
||||
* This file is part of volkzaehler.org
|
||||
*
|
||||
* volkzaehler.org is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* volkzaehler.org is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with volkszaehler.org. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Volkszaehler;
|
||||
|
||||
use Volkszaehler\View\HTTP;
|
||||
use Volkszaehler\View;
|
||||
use Volkszaehler\Controller;
|
||||
use Volkszaehler\Util;
|
||||
|
||||
/**
|
||||
* Backend dispatcher
|
||||
*
|
||||
* This class acts as a frontcontroller to route incomming requests
|
||||
*
|
||||
* @package default
|
||||
* @author Steffen Vogel <info@steffenvogel.de>
|
||||
*/
|
||||
class Dispatcher {
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManager Doctrine EntityManager
|
||||
*/
|
||||
protected $em;
|
||||
|
||||
/**
|
||||
* @var View\View
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* @var Controller\Controller
|
||||
*/
|
||||
protected $controller;
|
||||
|
||||
/**
|
||||
* @var Router
|
||||
*/
|
||||
protected $router;
|
||||
|
||||
/**
|
||||
* @var Util\Debug optional debugging instance
|
||||
*/
|
||||
protected $debug = NULL;
|
||||
|
||||
/**
|
||||
* @var array HTTP method => action mapping
|
||||
*/
|
||||
protected static $actionMapping = array(
|
||||
'post' => 'add',
|
||||
'delete' => 'delete',
|
||||
'get' => 'get',
|
||||
'pull' => 'edit'
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
// create HTTP request & response (needed to initialize view & controller)
|
||||
$request = new HTTP\Request();
|
||||
$response = new HTTP\Response();
|
||||
|
||||
// initialize entity manager
|
||||
$this->em = Dispatcher::createEntityManager();
|
||||
|
||||
// initialize debugging
|
||||
if (($debugLevel = $request->getParameter('debug')) != NULL || $debugLevel = Util\Configuration::read('debug')) {
|
||||
if ($debugLevel > 0) {
|
||||
$this->debug = new Util\Debug($debugLevel, $this->em);
|
||||
}
|
||||
}
|
||||
|
||||
// initialize router
|
||||
$this->router = new Router($this->em);
|
||||
|
||||
// initialize view
|
||||
if ($this->router->getFormat()) {
|
||||
$format = $this->router->getFormat();
|
||||
}
|
||||
else {
|
||||
$format = 'json';
|
||||
}
|
||||
|
||||
switch ($format) {
|
||||
case 'png':
|
||||
case 'jpeg':
|
||||
case 'gif':
|
||||
$this->view = new View\JpGraph($request, $response, $format);
|
||||
break;
|
||||
|
||||
case 'xml':
|
||||
case 'csv':
|
||||
$padding = FALSE;
|
||||
case 'json':
|
||||
$padding = $request->getParameter('padding');
|
||||
|
||||
$viewClassName = 'Volkszaehler\View\\' . strtoupper($format);
|
||||
$this->view = new $viewClassName($request, $response, $padding);
|
||||
break;
|
||||
|
||||
case 'txt':
|
||||
$this->view = new View\PlainText($request, $response);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \Exception('unknown format: ' . $format);
|
||||
break;
|
||||
}
|
||||
|
||||
// initialize controller
|
||||
if (!($controllerClassName = $this->router->getController())) {
|
||||
throw new \Exception('invalid controller specified');
|
||||
}
|
||||
$this->controller = new $controllerClassName($this->view, $this->em, $this->router->getIdentifier());
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute application
|
||||
*/
|
||||
public function run() {
|
||||
if ($this->router->getAction()) {
|
||||
$action = $this->router->getAction();
|
||||
}
|
||||
elseif (self::$actionMapping[strtolower($this->view->request->getMethod())]) {
|
||||
$action = self::$actionMapping[strtolower($this->view->request->getMethod())];
|
||||
}
|
||||
else {
|
||||
throw new \Exception('can\'t determine action');
|
||||
}
|
||||
|
||||
$this->controller->run($action); // run controllers actions (usually CRUD: http://de.wikipedia.org/wiki/CRUD)
|
||||
$this->view->sendResponse(); // render view & send http response
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for doctrines entitymanager
|
||||
*
|
||||
* @todo add other caching drivers (memcache, xcache)
|
||||
* @todo put into static class? singleton?
|
||||
*/
|
||||
public static function createEntityManager() {
|
||||
$config = new \Doctrine\ORM\Configuration;
|
||||
|
||||
if (extension_loaded('apc') && Util\Configuration::read('devmode') == FALSE) {
|
||||
$cache = new \Doctrine\Common\Cache\ApcCache;
|
||||
$config->setMetadataCacheImpl($cache);
|
||||
$config->setQueryCacheImpl($cache);
|
||||
}
|
||||
|
||||
$driverImpl = $config->newDefaultAnnotationDriver(VZ_BACKEND_DIR . '/lib/Model');
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
|
||||
$config->setProxyDir(VZ_BACKEND_DIR . '/lib/Model/Proxy');
|
||||
$config->setProxyNamespace('Volkszaehler\Model\Proxy');
|
||||
$config->setAutoGenerateProxyClasses(Util\Configuration::read('devmode'));
|
||||
|
||||
return \Doctrine\ORM\EntityManager::create(Util\Configuration::read('db'), $config);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -23,73 +23,178 @@
|
|||
|
||||
namespace Volkszaehler;
|
||||
|
||||
use Volkszaehler\View;
|
||||
use Volkszaehler\Util;
|
||||
use Volkszaehler\View\HTTP;
|
||||
use Doctrine\ORM;
|
||||
|
||||
/**
|
||||
* Router
|
||||
*
|
||||
* This class acts as a frontcontroller to route incomming requests
|
||||
*
|
||||
* @package default
|
||||
* @author Steffen Vogel <info@steffenvogel.de>
|
||||
*/
|
||||
use Volkszaehler\Util;
|
||||
|
||||
use Doctrine\ORM;
|
||||
|
||||
class Router {
|
||||
protected $format;
|
||||
protected $controller;
|
||||
protected $identifier;
|
||||
protected $action;
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManager Doctrine EntityManager
|
||||
*/
|
||||
public $em;
|
||||
|
||||
/**
|
||||
* @var View\View
|
||||
*/
|
||||
public $view;
|
||||
|
||||
/**
|
||||
* @var Util\Debug optional debugging instance
|
||||
*/
|
||||
public $debug;
|
||||
|
||||
/**
|
||||
* PATH_INFO envvar
|
||||
* @var string
|
||||
*/
|
||||
protected $pathInfo;
|
||||
|
||||
/**
|
||||
* @var array HTTP-method => operation mapping
|
||||
*/
|
||||
protected static $operationMapping = array(
|
||||
'post' => 'add',
|
||||
'delete' => 'delete',
|
||||
'get' => 'get',
|
||||
'pull' => 'edit'
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array context => controller mapping
|
||||
*/
|
||||
protected static $controllerMapping = array(
|
||||
'channels' => 'Volkszaehler\Controller\ChannelController',
|
||||
'groups' => 'Volkszaehler\Controller\GroupController',
|
||||
'tokens' => 'Volkszaehler\Controller\TokenController',
|
||||
'channel' => 'Volkszaehler\Controller\ChannelController',
|
||||
'group' => 'Volkszaehler\Controller\AggregatorController',
|
||||
'token' => 'Volkszaehler\Controller\TokenController',
|
||||
'capabilities' => 'Volkszaehler\Controller\CapabilitiesController',
|
||||
'data' => 'Volkszaehler\Controller\DataController'
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ORM\EntityManager $em
|
||||
* @var array format => view mapping
|
||||
*/
|
||||
public function __construct(ORM\EntityManager $em) {
|
||||
$this->parsePathInfo();
|
||||
protected static $viewMapping = array(
|
||||
'png' => 'Volkszaehler\View\JpGraph',
|
||||
'jpeg' => 'Volkszaehler\View\JpGraph',
|
||||
'jpg' => 'Volkszaehler\View\JpGraph',
|
||||
'gif' => 'Volkszaehler\View\JpGraph',
|
||||
'xml' => 'Volkszaehler\View\XML',
|
||||
'csv' => 'Volkszaehler\View\CSV',
|
||||
'json' => 'Volkszaehler\View\JSON',
|
||||
'txt' => 'Volkszaehler\View\PlainText'
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
// initialize HTTP request & response (required to initialize view & controllers)
|
||||
$request = new HTTP\Request();
|
||||
$response = new HTTP\Response();
|
||||
|
||||
// early default format
|
||||
$this->view = new View\JSON($request, $response);
|
||||
|
||||
// initialize entity manager
|
||||
$this->em = self::createEntityManager();
|
||||
|
||||
// initialize debugging
|
||||
if (($debugLevel = $request->getParameter('debug')) != NULL || $debugLevel = Util\Configuration::read('debug')) {
|
||||
if ($debugLevel > 0) {
|
||||
$this->debug = new Util\Debug($debugLevel, $this->em);
|
||||
}
|
||||
}
|
||||
|
||||
// initialize view
|
||||
$this->pathInfo = self::getPathInfo();
|
||||
$this->format = self::getFormat($this->pathInfo);
|
||||
$this->operation = self::getOperation($request);
|
||||
|
||||
if (empty(self::$viewMapping[$this->format])) {
|
||||
if (empty($this->format)) {
|
||||
throw new \Exception('Missing format');
|
||||
}
|
||||
else {
|
||||
throw new \Exception('Unknown format: ' . $this->format);
|
||||
}
|
||||
}
|
||||
|
||||
$class = self::$viewMapping[$this->format];
|
||||
$this->view = new $class($request, $response, $this->format);
|
||||
|
||||
// some general debugging information
|
||||
//Util\Debug::log('_SERVER', $_SERVER);
|
||||
//Util\Debug::log('PATH_INFO', $this->pathInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo add alternative url schema without PATH_INFO
|
||||
* Processes the request
|
||||
*
|
||||
* Request Example: http://sub.domain.local/vz/backend/channel/550e8400-e29b-11d4-a716-446655440000/data.json?operation=edit&title=New Title
|
||||
*/
|
||||
protected function parsePathInfo() {
|
||||
// Request: http://sub.domain.local/vz/backend/channel/550e8400-e29b-11d4-a716-446655440000/edit.json?title=New Title
|
||||
// PATH_INFO: /channel/550e8400-e29b-11d4-a716-446655440000/edit.json
|
||||
$pi = $this->getPathInfo();
|
||||
public function run() {
|
||||
$pathInfo = substr($this->pathInfo, 1, strrpos($this->pathInfo, '.') -1); // remove leading slash and format
|
||||
$pathInfo = explode('/', $pathInfo); // split into path segments
|
||||
|
||||
//Util\Debug::log('PATH_INFO', $pi);
|
||||
//Util\Debug::log('_SERVER', $_SERVER);
|
||||
if (array_key_exists($pathInfo[0], self::$controllerMapping)) {
|
||||
$class = self::$controllerMapping[$pathInfo[0]];
|
||||
$controller = new $class($this->view, $this->em);
|
||||
|
||||
if ($pi) {
|
||||
$pi = substr($pi, 1);
|
||||
$pie = explode('/', $pi);
|
||||
$i = 0;
|
||||
if (isset($pathInfo[1])) {
|
||||
if (Util\UUID::validate($pathInfo[1], TRUE)) {
|
||||
if (isset($pathInfo[2])) {
|
||||
if (array_key_exists($pathInfo[2], self::$controllerMapping)) {
|
||||
$class = self::$controllerMapping[$pathInfo[2]];
|
||||
$subcontroller = new $class($this->view, $this->em);
|
||||
|
||||
if (isset($pie[$i]) && array_key_exists($pie[$i], self::$controllerMapping)) {
|
||||
$this->controller = self::$controllerMapping[$pie[$i]];
|
||||
$i++;
|
||||
$result = $subcontroller->run($this->operation, $controller->run('get', $pathInfo[1]));
|
||||
}
|
||||
else {
|
||||
throw new \Exception('Unknown subcontext: ' . $pathInfo[2]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$result = $controller->run($this->operation, $pathInfo[1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new \Exception('Invalid identifier: ' . $pathInfo[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($pie[$i]) && preg_match('/[a-f0-9\-]{5,36}/', $pie[$i])) {
|
||||
$this->identifier = $pie[$i];
|
||||
}
|
||||
$i++;
|
||||
|
||||
if (isset($pie[$i]) && strpos($pie[$i], '.') !== FALSE) {
|
||||
list($this->action, $this->format) = explode('.', $pie[$i]);
|
||||
}
|
||||
elseif (isset($pie[$i])) {
|
||||
$this->action = $pie[$i];
|
||||
else {
|
||||
$result = $controller->run($this->operation);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new \Exception('no CGI PATH_INFO envvar found');
|
||||
throw new \Exception('Unknown context: ' . $pathInfo[0]);
|
||||
}
|
||||
|
||||
$this->view->add($result);
|
||||
}
|
||||
|
||||
protected static function getOperation(HTTP\Request $request) {
|
||||
if ($operation = $request->getParameter('operation')) {
|
||||
return $operation;
|
||||
}
|
||||
elseif (isset(self::$operationMapping[strtolower($request->getMethod())])) {
|
||||
return self::$operationMapping[strtolower($request->getMethod())];
|
||||
}
|
||||
else {
|
||||
throw new \Exception('Can\'t determine operation');
|
||||
}
|
||||
}
|
||||
|
||||
protected static function getFormat($pathInfo) {
|
||||
return pathinfo($pathInfo, PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,17 +213,34 @@ class Router {
|
|||
return substr($_SERVER['PHP_SELF'], strlen($_SERVER['SCRIPT_NAME']));
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
throw new \Exception('Can\'t get PATH_INFO');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Getter & setter
|
||||
/**
|
||||
* Factory for doctrines entitymanager
|
||||
*
|
||||
* @todo add other caching drivers (memcache, xcache)
|
||||
* @todo put into static class? singleton? function or state class?
|
||||
*/
|
||||
public function getFormat() { return $this->format; }
|
||||
public function getController() { return $this->controller; }
|
||||
public function getIdentifier() { return $this->identifier; }
|
||||
public function getAction() { return $this->action; }
|
||||
public static function createEntityManager() {
|
||||
$config = new \Doctrine\ORM\Configuration;
|
||||
|
||||
if (extension_loaded('apc') && Util\Configuration::read('devmode') == FALSE) {
|
||||
$cache = new \Doctrine\Common\Cache\ApcCache;
|
||||
$config->setMetadataCacheImpl($cache);
|
||||
$config->setQueryCacheImpl($cache);
|
||||
}
|
||||
|
||||
$driverImpl = $config->newDefaultAnnotationDriver(VZ_BACKEND_DIR . '/lib/Model');
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
|
||||
$config->setProxyDir(VZ_BACKEND_DIR . '/lib/Model/Proxy');
|
||||
$config->setProxyNamespace('Volkszaehler\Model\Proxy');
|
||||
$config->setAutoGenerateProxyClasses(Util\Configuration::read('devmode'));
|
||||
|
||||
return \Doctrine\ORM\EntityManager::create(Util\Configuration::read('db'), $config);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
Loading…
Add table
Reference in a new issue