. */ 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 */ class Router { /** * @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( 'channel' => 'Volkszaehler\Controller\ChannelController', 'group' => 'Volkszaehler\Controller\AggregatorController', 'group' => 'Volkszaehler\Controller\AggregatorController', 'entity' => 'Volkszaehler\Controller\EntityController', 'data' => 'Volkszaehler\Controller\DataController', 'capabilities' => 'Volkszaehler\Controller\CapabilitiesController' ); /** * @var array format => view mapping */ 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(); // 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 = pathinfo($this->pathInfo, PATHINFO_EXTENSION); if (!array_key_exists($this->format, self::$viewMapping)) { $this->view = new View\JSON($request, $response); // fallback view if (empty($this->pathInfo)) { throw new \Exception('Missing or invalid PATH_INFO'); } elseif (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); } /** * Processes the request * * Example: http://sub.domain.local/backend.php/channel/550e8400-e29b-11d4-a716-446655440000/data.json?operation=edit&title=New Title */ public function run() { $operation = self::getOperation($this->view->request); $context = explode('/', substr($this->pathInfo, 1, strrpos($this->pathInfo, '.')-1)); // parse pathinfo if (!array_key_exists($context[0], self::$controllerMapping)) { if (empty($context[0])) { throw new \Exception('Missing context'); } else { throw new \Exception('Unknown context: ' . $context[0]); } } $class = self::$controllerMapping[$context[0]]; $controller = new $class($this->view, $this->em); $result = $controller->run($operation, array_slice($context, 1)); $this->view->add($result); } protected static function getOperation(HTTP\Request $request) { if ($operation = $request->getParameter('operation')) { return $operation; } else { return self::$operationMapping[strtolower($request->getMethod())]; } } /** * Get CGI environmental var PATH_INFO from webserver * * @return string */ protected static function getPathInfo() { if (isset($_SERVER['PATH_INFO'])) { return $_SERVER['PATH_INFO']; } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { return $_SERVER['ORIG_PATH_INFO']; } elseif (strlen($_SERVER['PHP_SELF']) > strlen($_SERVER['SCRIPT_NAME'])) { return substr($_SERVER['PHP_SELF'], strlen($_SERVER['SCRIPT_NAME'])); } } /** * Factory for doctrines entitymanager * * @todo add other caching drivers (memcache, xcache) * @todo put into static class? singleton? function or state class? */ public static function createEntityManager($admin = FALSE) { $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_DIR . '/lib/Model'); $config->setMetadataDriverImpl($driverImpl); $config->setProxyDir(VZ_DIR . '/lib/Model/Proxy'); $config->setProxyNamespace('Volkszaehler\Model\Proxy'); $config->setAutoGenerateProxyClasses(Util\Configuration::read('devmode')); $dbConfig = Util\Configuration::read('db'); if ($admin && isset($dbConfig['admin'])) { $dbConfig = array_merge($dbConfig, $dbConfig['admin']); } return \Doctrine\ORM\EntityManager::create($dbConfig, $config); } } ?>