From 8a0688aa5d92a10e8b9a2af85a33eaa48dcc0fcc Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Fri, 17 Aug 2007 03:09:46 +0000 Subject: [PATCH] Added HTTPResponse object, to encapsulate Controller responses for aid testing and other 'quirky' uses of Controllers git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@40390 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- core/control/ContentController.php | 2 +- core/control/ContentNegotiator.php | 36 +++++++++++++---------- core/control/Controller.php | 47 +++++++++++++++++++++++++----- core/control/Director.php | 23 +++++---------- core/control/ModelAsController.php | 3 +- core/control/RootURLController.php | 16 ++++++---- core/model/RedirectorPage.php | 1 - forms/Form.php | 10 +++++++ security/Security.php | 2 +- 9 files changed, 91 insertions(+), 49 deletions(-) diff --git a/core/control/ContentController.php b/core/control/ContentController.php index 50f251d6c..a2d78232e 100644 --- a/core/control/ContentController.php +++ b/core/control/ContentController.php @@ -88,7 +88,7 @@ class ContentController extends Controller { if($getVars) $url = "./?" . http_build_query($getVars); else $url = "./"; Director::redirect($url); - die(); + return; } singleton('SiteTree')->extend('contentcontrollerInit', $this); diff --git a/core/control/ContentNegotiator.php b/core/control/ContentNegotiator.php index 81b681dd3..b8a65406e 100755 --- a/core/control/ContentNegotiator.php +++ b/core/control/ContentNegotiator.php @@ -23,8 +23,8 @@ class ContentNegotiator { } - static function process($content) { - if(self::$disabled) return $content; + static function process(HTTPResponse $response) { + if(self::$disabled) return; $mimes = array( "xhtml" => "application/xhtml+xml", @@ -56,35 +56,39 @@ class ContentNegotiator { } $negotiator = new ContentNegotiator(); - return $negotiator->$chosenFormat($content); + $negotiator->$chosenFormat( $response ); } - function xhtml($content) { + function xhtml(HTTPResponse $response) { + $content = $response->getBody(); + // Only serve "pure" XHTML if the XML header is present - if(substr($content,0,5) == '<' . '?xml' /*|| $_REQUEST['ajax']*/ ) { - header("Content-type: application/xhtml+xml; charset=" . self::$encoding); - header("Vary: Accept"); + if(substr($content,0,5) == '<' . '?xml' ) { + $response->addHeader("Content-type", "application/xhtml+xml; charset=" . self::$encoding); + $response->addHeader("Vary" , "Accept"); + $content = str_replace(' ',' ', $content); $content = str_replace('
','
', $content); $content = eregi_replace('(]*[^/>])>','\\1/>', $content); - return $content; + + $response->setBody($content); } else { - return $this->html($content); + return $this->html($response); } } - function html($content) { - if(!headers_sent()) { - header("Content-type: text/html; charset=" . self::$encoding); - header("Vary: Accept"); - } + function html(HTTPResponse $response) { + $response->addHeader("Content-type", "text/html; charset=" . self::$encoding); + $response->addHeader("Vary", "Accept"); + + $content = $response->getBody(); $content = ereg_replace("<\\?xml[^>]+\\?>\n?",'',$content); $content = str_replace(array('/>','xml:lang','application/xhtml+xml'),array('>','lang','text/html'), $content); $content = ereg_replace(']+>', '', $content); $content = ereg_replace('setBody($content); } protected static $disabled; diff --git a/core/control/Controller.php b/core/control/Controller.php index fd25ea188..2deee1db1 100644 --- a/core/control/Controller.php +++ b/core/control/Controller.php @@ -19,6 +19,11 @@ class Controller extends ViewableData { protected static $currentController; protected $basicAuthEnabled = true; + + /** + * The HTTPResponse object that the controller returns + */ + protected $response; function setURLParams($urlParams) { $this->urlParams = $urlParams; @@ -38,14 +43,20 @@ class Controller extends ViewableData { protected $baseInitCalled = false; function run($requestParams) { if(isset($_GET['debug_profile'])) Profiler::mark("Controller", "run"); - + Controller::$currentController = $this; + + $this->response = new HTTPResponse(); $this->requestParams = $requestParams; + $this->action = isset($this->urlParams['Action']) ? str_replace("-","_",$this->urlParams['Action']) : "index"; // Init $this->baseInitCalled = false; $this->init(); if(!$this->baseInitCalled) user_error("init() method on class '$this->class' doesn't call Controller::init(). Make sure that you have parent::init() included.", E_USER_WARNING); + + // If we had a redirection or something, halt processing. + if($this->response->isFinished()) return $this->response; // Look at the action variables for forms foreach($this->requestParams as $paramName => $paramVal) { @@ -93,7 +104,7 @@ class Controller extends ViewableData { // disregard validation if a single field is called if(!isset($_REQUEST['action_callfieldmethod'])) { $valid = $form->beforeProcessing(); - if(!$valid) exit(); + if(!$valid) return $this->response; } // If the action wasnt' set, choose the default on the form. @@ -143,6 +154,7 @@ class Controller extends ViewableData { if(isset($_GET['debug_controller'])) Debug::show("Found function $funcName on the $this->class controller"); if(isset($_GET['debug_profile'])) Profiler::mark("$this->class::$funcName (controller action)"); + $result = $this->$funcName($this->urlParams); if(isset($_GET['debug_profile'])) Profiler::unmark("$this->class::$funcName (controller action)"); @@ -163,14 +175,17 @@ class Controller extends ViewableData { $result = $viewer->process($extended); } + + $this->response->setBody($result); - if($result) $result = ContentNegotiator::process($result); + if($result) ContentNegotiator::process($this->response); // Set up HTTP cache headers - HTTP::add_cache_headers(); + HTTP::add_cache_headers($this->response); if(isset($_GET['debug_profile'])) Profiler::unmark("Controller", "run"); - return $result; + + return $this->response; } function defaultAction($action) { @@ -234,8 +249,6 @@ class Controller extends ViewableData { Cookie::set("PastMember", true); DB::query("UPDATE Member SET LastVisited = NOW() WHERE ID = $member->ID", null); } - Controller::$currentController = $this; - // This is used to test that subordinate controllers are actually calling parent::init() - a common bug $this->baseInitCalled = true; @@ -244,6 +257,13 @@ class Controller extends ViewableData { public static function currentController() { return Controller::$currentController; } + + /** + * Returns the current controller + */ + public static function curr() { + return Controller::$currentController; + } /** * Returns true if the member is allowed to do the given action. @@ -303,6 +323,19 @@ class Controller extends ViewableData { function PastMember() { return Cookie::get("PastMember") ? true : false; } + + /** + * Handle redirection + */ + + function redirect($url) { + // Attach site-root to relative links, if they have a slash in them + if(substr($url,0,4) != "http" && $url[0] != "/" && strpos($url,'/') !== false){ + $url = Director::baseURL() . $url; + } + + $this->response->redirect($url); + } } ?> diff --git a/core/control/Director.php b/core/control/Director.php index 3d392e735..b5a7c8f77 100644 --- a/core/control/Director.php +++ b/core/control/Director.php @@ -42,13 +42,17 @@ class Director { function direct($url) { if(isset($_GET['debug_profile'])) Profiler::mark("Director","direct"); $controllerObj = Director::getControllerForURL($url); + if(is_string($controllerObj) && substr($controllerObj,0,9) == 'redirect:') { Director::redirect(substr($controllerObj, 9)); + } else if($controllerObj) { - $output = $controllerObj->run(array_merge((array)$_GET, (array)$_POST, (array)$_FILES)); + $response = $controllerObj->run(array_merge((array)$_GET, (array)$_POST, (array)$_FILES)); + if(isset($_GET['debug_profile'])) Profiler::mark("Outputting to browser"); - echo $output; + $response->output(); if(isset($_GET['debug_profile'])) Profiler::unmark("Outputting to browser"); + } if(isset($_GET['debug_profile'])) Profiler::unmark("Director","direct"); } @@ -158,20 +162,7 @@ class Director { * - if it is just a word without an slashes, then it redirects to another action on the current controller. */ static function redirect($url) { - // Attach site-root to relative links, if they have a slash in them - if(substr($url,0,4) != "http" && $url[0] != "/" && strpos($url,'/') !== false){ - $url = Director::baseURL() . $url; - } - if(headers_sent($file, $line)) { - echo - "

Redirecting to $url... (output started on $file, line $line)

- - "; - - } else { - header("Location: $url"); - } - die(); + Controller::curr()->redirect($url); } /** diff --git a/core/control/ModelAsController.php b/core/control/ModelAsController.php index 54ebc49cd..3e65569df 100644 --- a/core/control/ModelAsController.php +++ b/core/control/ModelAsController.php @@ -9,7 +9,8 @@ class ModelAsController extends Controller implements NestedController { public function run($requestParams) { $this->init(); - return $this->getNestedController()->run($requestParams); + $nested = $this->getNestedController(); + return $nested->run($requestParams); } public function init() { diff --git a/core/control/RootURLController.php b/core/control/RootURLController.php index bc9a816fb..6fe63b9ff 100755 --- a/core/control/RootURLController.php +++ b/core/control/RootURLController.php @@ -5,13 +5,17 @@ */ class RootURLController extends Controller { protected static $is_at_root = false; - - /** - * Marks at that we are actually at the root URL before handing control over to another controller - */ - function index() { + + public function run($requestParams) { self::$is_at_root = true; - Director::direct(self::get_homepage_urlsegment() . '/'); + + $controller = new ModelAsController(); + $controller->setUrlParams(array( + 'URLSegment' => self::get_homepage_urlsegment(), + 'Action' => '', + )); + + return $controller->run($requestParams); } /** diff --git a/core/model/RedirectorPage.php b/core/model/RedirectorPage.php index 088b9b496..96dcb68d7 100755 --- a/core/model/RedirectorPage.php +++ b/core/model/RedirectorPage.php @@ -87,7 +87,6 @@ class RedirectorPage_Controller extends Page_Controller { } parent::init(); - die(); } } ?> diff --git a/forms/Form.php b/forms/Form.php index 55e8971ca..0e0f9bfc0 100644 --- a/forms/Form.php +++ b/forms/Form.php @@ -637,4 +637,14 @@ class Form extends ViewableData { static function set_current_action($action) { self::$current_action = $action; } + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // TESTING HELPERS + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + function testSubmission($action, $data) { + $data['action_' . $action] = true; + + //$this->controller->run() + } } diff --git a/security/Security.php b/security/Security.php index 2b06de2de..c5c246cf2 100644 --- a/security/Security.php +++ b/security/Security.php @@ -70,7 +70,7 @@ class Security extends Controller { } else { Director::redirect("Security/login"); } - exit(); + return; } function LoginForm() {