<?php /** * Structural design pattern namespace. * * Structural design patterns are design patterns that ease the design by * identifying a simple way to realize relationships between entities. * * @package Atom * @subpackage Design */ namespace Atom\Design\Structural; // Aliasing rules use Atom\Config; /** * Front Controller Pattern * * The Front controller pattern is designed for centralized request logic. A * front controller can help eliminate duplicate code on a series of requests * through the front controller and factoring the duplicate code from the * requests into the front controller. * * [!!] Althought MVC isn't directly related to the FrontController pattern, the * current implementation of this class executes it. This may change in the * future, but as for now, please understand what you're getting into when you * use this pattern. * * @package Atom * @subpackage Design */ class FrontController { /** * The request URI * * The request URI will always be prepended with a slash. As a result, if * the request is to the root of the application, a single forward slash * will be returned. * * @return string */ protected static $uri; /** * Magic method called when a class is first encountered by the Loader * during file inclusion. * * ## Usage * * $uri = FrontController::getUri(); * * @return void No value is returned */ public static function getUri() { if(static::$uri == null) { if(isset($_SERVER['PATH_INFO'])) { $uri = $_SERVER['PATH_INFO']; } elseif(isset($_SERVER['REQUEST_URI'])) { $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); } else { throw new \Exception('Unable to determine the request URI'); } if($uri === false) { throw new \Exception('Malformed request URI. Request terminated.'); } if(strpos($uri, $base = parse_url(Config::get('application.url'), PHP_URL_PATH)) === 0) { $uri = substr($uri, strlen($base)); } if(strpos($uri, $index = '/index.php') === 0) { $uri = substr($uri, strlen($index)); } static::$uri = (($uri = trim($uri, '/')) == '') ? '/' : '/'.$uri; } return static::$uri; } /** * The dispatcher extracts the active URI and routes to a namespaced * Controller for further handling. * * [!!] This method could use some serious optimization, and modularity. * * ## Usage * * $request = FrontController::dispatch(); * * Once you've dispatched your request, you can handle everything after * as you would a \Http\Response. * * @return Response Returns the response instance for further execution */ public static function dispatch() { $url = parse_url('http://ignore.me'.static::getUri()); $url['method'] = strtoupper($_SERVER['REQUEST_METHOD']); $url['query'] = parse_str($url['query']); $url['http'] = $url['method'].' '$url['path']; $url['route'] = $url['path']; $response = \Atom\Http\Response::make(); // Check for default route... if($url['path'] == '/' and !$route = Config::get('routes._default_', false)) { throw new \Atom\Http\Exception(404, $response); } else { // Do it! } // Check for HTTP Verb route if(($route = Config::get('routes.'.$url['http'], false)) !== false) { // Do it! } // Check for normal route if(($route = Config::get('routes.'.$url['route'], false)) !== false) { // Do it! } // Check for MVC route preg_match("/([^/]+)/uis", "item", $url['path'], $segments); array_shift($segments); // Remove full string match. if(!strcasecmp($segments[0], APPLICATION_NS) and is_dir(LIBRARY_PATH.'/'.$segments[0])) { $path = LIBRARY_PATH.'/'.strtolower(array_shift($segments)).'/controller/'; } else { $path = LIBRARY_PATH.'/'.strtolower(APPLICATION_NS).'/controller/'; } $possibilities = array(); while(count($segments) > 0 and is_dir($path.$segments[0])) { $path .= $segments[0].'/'; $possibilities []= array_shift($segments); } if(!file_exists($path.$segments[0].'.php') { throw new \Atom\Http\Exception(404, $response); } $possibilities []= array_shift($segments); $controller = ''; foreach($possibilities as $p) { $controller .= ucfirst($p).'\\'; } $controller = rtrim($controller, '\\'); $action = 'action'.ucfirst(array_shift($segments)); class_exists($controller) and $controller = new $controller($response); if(!is_object($controller) or !method_exists($controller, $action)) { throw new \Atom\Http\Exception(404, $response); } $controller->before(); $response->setBody(call_user_func_array(array($controller, $action), $segments)); $controller->after(); return $response; } } /* End of file frontcontroller.php */