diff --git a/admin/code/AdminRootController.php b/admin/code/AdminRootController.php index 77a394ce6..370751a89 100644 --- a/admin/code/AdminRootController.php +++ b/admin/code/AdminRootController.php @@ -77,9 +77,8 @@ class AdminRootController extends Controller { $base = $this->config()->url_base; $segment = Config::inst()->get($this->config()->default_panel, 'url_segment'); - $this->response = new SS_HTTPResponse(); $this->redirect(Controller::join_links($base, $segment)); - return $this->response; + return $this->getResponse(); } // Otherwise diff --git a/admin/code/LeftAndMain.php b/admin/code/LeftAndMain.php index f1b3d4a9d..2a9a79254 100644 --- a/admin/code/LeftAndMain.php +++ b/admin/code/LeftAndMain.php @@ -227,7 +227,7 @@ class LeftAndMain extends Controller implements PermissionProvider { // Allow customisation of the access check by a extension // Also all the canView() check to execute Controller::redirect() - if(!$this->canView() && !$this->response->isFinished()) { + if(!$this->canView() && !$this->getResponse()->isFinished()) { // When access /admin/, we should try a redirect to another part of the admin rather than be locked out $menu = $this->MainMenu(); foreach($menu as $candidate) { @@ -445,8 +445,10 @@ class LeftAndMain extends Controller implements PermissionProvider { $msgs = _t('LeftAndMain.ValidationError', 'Validation error') . ': ' . $e->getMessage(); $e = new SS_HTTPResponse_Exception($msgs, 403); - $e->getResponse()->addHeader('Content-Type', 'text/plain'); - $e->getResponse()->addHeader('X-Status', rawurlencode($msgs)); + $errorResponse = $e->getResponse(); + $errorResponse->addHeader('Content-Type', 'text/plain'); + $errorResponse->addHeader('X-Status', rawurlencode($msgs)); + $e->setResponse($errorResponse); throw $e; } @@ -455,9 +457,10 @@ class LeftAndMain extends Controller implements PermissionProvider { if(!$response->getHeader('X-Title')) $response->addHeader('X-Title', urlencode($title)); // Prevent clickjacking, see https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options - $this->response->addHeader('X-Frame-Options', 'SAMEORIGIN'); - $this->response->addHeader('Vary', 'X-Requested-With'); - + $originalResponse = $this->getResponse(); + $originalResponse->addHeader('X-Frame-Options', 'SAMEORIGIN'); + $originalResponse->addHeader('Vary', 'X-Requested-With'); + return $response; } @@ -471,21 +474,21 @@ class LeftAndMain extends Controller implements PermissionProvider { */ public function redirect($url, $code=302) { if($this->getRequest()->isAjax()) { - $this->response->addHeader('X-ControllerURL', $url); - if($this->getRequest()->getHeader('X-Pjax') && !$this->response->getHeader('X-Pjax')) { - $this->response->addHeader('X-Pjax', $this->getRequest()->getHeader('X-Pjax')); + $response = $this->getResponse(); + $response->addHeader('X-ControllerURL', $url); + if($this->getRequest()->getHeader('X-Pjax') && !$response->getHeader('X-Pjax')) { + $response->addHeader('X-Pjax', $this->getRequest()->getHeader('X-Pjax')); } - $oldResponse = $this->response; $newResponse = new LeftAndMain_HTTPResponse( - $oldResponse->getBody(), - $oldResponse->getStatusCode(), - $oldResponse->getStatusDescription() + $response->getBody(), + $response->getStatusCode(), + $response->getStatusDescription() ); - foreach($oldResponse->getHeaders() as $k => $v) { + foreach($response->getHeaders() as $k => $v) { $newResponse->addHeader($k, $v); } $newResponse->setIsFinished(true); - $this->response = $newResponse; + $this->setResponse($newResponse); return ''; // Actual response will be re-requested by client } else { parent::redirect($url, $code); @@ -590,7 +593,7 @@ class LeftAndMain extends Controller implements PermissionProvider { return $controller->renderWith($controller->getViewer('show')); } ), - $this->response + $this->getResponse() ); } return $this->responseNegotiator; @@ -789,7 +792,7 @@ class LeftAndMain extends Controller implements PermissionProvider { if(!$filterInfo->implementsInterface('LeftAndMain_SearchFilter')) { throw new InvalidArgumentException(sprintf('Invalid filter class passed: %s', $filterClass)); } - + return Injector::inst()->createWithArgs($filterClass, array($params)); } @@ -835,7 +838,7 @@ class LeftAndMain extends Controller implements PermissionProvider { // causes the Hierarchy::$marked cache to be flushed (@see CMSMain::getRecord) // which means that deleted pages stored in the marked tree would be removed $currentPage = $this->currentPage(); - + // Mark the nodes of the tree to return if ($filterFunction) $obj->setMarkingFilterFunction($filterFunction); @@ -998,7 +1001,7 @@ class LeftAndMain extends Controller implements PermissionProvider { 'PrevID' => $prev ? $prev->ID : null ); } - $this->response->addHeader('Content-Type', 'text/json'); + $this->getResponse()->addHeader('Content-Type', 'text/json'); return Convert::raw2json($data); } @@ -1025,7 +1028,7 @@ class LeftAndMain extends Controller implements PermissionProvider { $this->extend('onAfterSave', $record); $this->setCurrentPageID($record->ID); - $this->response->addHeader('X-Status', rawurlencode(_t('LeftAndMain.SAVEDUP', 'Saved.'))); + $this->getResponse()->addHeader('X-Status', rawurlencode(_t('LeftAndMain.SAVEDUP', 'Saved.'))); return $this->getResponseNegotiator()->respond($this->getRequest()); } @@ -1039,7 +1042,7 @@ class LeftAndMain extends Controller implements PermissionProvider { $record->delete(); - $this->response->addHeader('X-Status', rawurlencode(_t('LeftAndMain.DELETED', 'Deleted.'))); + $this->getResponse()->addHeader('X-Status', rawurlencode(_t('LeftAndMain.DELETED', 'Deleted.'))); return $this->getResponseNegotiator()->respond( $this->getRequest(), array('currentform' => array($this, 'EmptyForm')) @@ -1060,7 +1063,7 @@ class LeftAndMain extends Controller implements PermissionProvider { */ public function savetreenode($request) { if (!Permission::check('SITETREE_REORGANISE') && !Permission::check('ADMIN')) { - $this->response->setStatusCode( + $this->getResponse()->setStatusCode( 403, _t('LeftAndMain.CANT_REORGANISE', "You do not have permission to rearange the site tree. Your change was not saved.") @@ -1076,7 +1079,7 @@ class LeftAndMain extends Controller implements PermissionProvider { if($className == 'SiteTree' && $page = DataObject::get_by_id('Page', $id)){ $root = $page->getParentType(); if(($parentID == '0' || $root == 'root') && !SiteConfig::current_site_config()->canCreateTopLevel()){ - $this->response->setStatusCode( + $this->getResponse()->setStatusCode( 403, _t('LeftAndMain.CANT_REORGANISE', "You do not have permission to alter Top level pages. Your change was not saved.") @@ -1093,7 +1096,7 @@ class LeftAndMain extends Controller implements PermissionProvider { if($node && !$node->canEdit()) return Security::permissionFailure($this); if(!$node) { - $this->response->setStatusCode( + $this->getResponse()->setStatusCode( 500, _t('LeftAndMain.PLEASESAVE', "Please Save Page: This page could not be updated because it hasn't been saved yet." @@ -1121,7 +1124,7 @@ class LeftAndMain extends Controller implements PermissionProvider { } } - $this->response->addHeader('X-Status', + $this->getResponse()->addHeader('X-Status', rawurlencode(_t('LeftAndMain.REORGANISATIONSUCCESSFUL', 'Reorganised the site tree successfully.'))); } @@ -1146,7 +1149,7 @@ class LeftAndMain extends Controller implements PermissionProvider { } } - $this->response->addHeader('X-Status', + $this->getResponse()->addHeader('X-Status', rawurlencode(_t('LeftAndMain.REORGANISATIONSUCCESSFUL', 'Reorganised the site tree successfully.'))); } @@ -1626,7 +1629,7 @@ class LeftAndMain extends Controller implements PermissionProvider { /** * Sets the href for the anchor on the Silverstripe logo in the menu - * + * * @deprecated since version 4.0 * * @param String $link @@ -1754,7 +1757,7 @@ class LeftAndMain extends Controller implements PermissionProvider { /** * Register the given javascript file as required in the CMS. * Filenames should be relative to the base, eg, FRAMEWORK_DIR . '/javascript/loader.js' - * + * * @deprecated since version 4.0 */ public static function require_javascript($file) { @@ -1779,7 +1782,7 @@ class LeftAndMain extends Controller implements PermissionProvider { * Register the given "themeable stylesheet" as required. * Themeable stylesheets have globally unique names, just like templates and PHP files. * Because of this, they can be replaced by similarly named CSS files in the theme directory. - * + * * @deprecated since version 4.0 * * @param $name String The identifier of the file. For example, css/MyFile.css would have the identifier "MyFile" @@ -1920,7 +1923,7 @@ class LeftAndMain_TreeNode extends ViewableData { /** * Name of method to count the number of children - * + * * @var string */ protected $numChildrenMethod; diff --git a/control/Controller.php b/control/Controller.php index 43a93b8ae..8dde3d897 100644 --- a/control/Controller.php +++ b/control/Controller.php @@ -119,7 +119,6 @@ class Controller extends RequestHandler implements TemplateGlobalProvider { $this->pushCurrent(); $this->urlParams = $request->allParams(); $this->setRequest($request); - $this->response = new SS_HTTPResponse(); $this->setDataModel($model); $this->extend('onBeforeInit'); @@ -134,10 +133,11 @@ class Controller extends RequestHandler implements TemplateGlobalProvider { $this->extend('onAfterInit'); + $response = $this->getResponse(); // If we had a redirection or something, halt processing. - if($this->response->isFinished()) { + if($response->isFinished()) { $this->popCurrent(); - return $this->response; + return $response; } $body = parent::handleRequest($request, $model); @@ -146,7 +146,8 @@ class Controller extends RequestHandler implements TemplateGlobalProvider { Debug::message("Request handler returned SS_HTTPResponse object to $this->class controller;" . "returning it without modification."); } - $this->response = $body; + $response = $body; + $this->setResponse($response); } else { if($body instanceof Object && $body->hasMethod('getViewer')) { @@ -157,15 +158,15 @@ class Controller extends RequestHandler implements TemplateGlobalProvider { $body = $body->getViewer($this->getAction())->process($body); } - $this->response->setBody($body); + $response->setBody($body); } - ContentNegotiator::process($this->response); - HTTP::add_cache_headers($this->response); + ContentNegotiator::process($response); + HTTP::add_cache_headers($response); $this->popCurrent(); - return $this->response; + return $response; } /** @@ -212,9 +213,23 @@ class Controller extends RequestHandler implements TemplateGlobalProvider { * Can be used to set the status code and headers */ public function getResponse() { + if (!$this->response) { + $this->setResponse(new SS_HTTPResponse()); + } return $this->response; } + /** + * Sets the SS_HTTPResponse object that this controller is building up. + * + * @param SS_HTTPResponse $response + * @return Controller + */ + public function setResponse(SS_HTTPResponse $response) { + $this->response = $response; + return $this; + } + protected $baseInitCalled = false; /** @@ -454,10 +469,9 @@ class Controller extends RequestHandler implements TemplateGlobalProvider { * @return SS_HTTPResponse */ public function redirect($url, $code=302) { - if(!$this->response) $this->response = new SS_HTTPResponse(); - if($this->response->getHeader('Location') && $this->response->getHeader('Location') != $url) { - user_error("Already directed to " . $this->response->getHeader('Location') + if($this->getResponse()->getHeader('Location') && $this->getResponse()->getHeader('Location') != $url) { + user_error("Already directed to " . $this->getResponse()->getHeader('Location') . "; now trying to direct to $url", E_USER_WARNING); return; } @@ -467,7 +481,7 @@ class Controller extends RequestHandler implements TemplateGlobalProvider { $url = Director::baseURL() . $url; } - return $this->response->redirect($url, $code); + return $this->getResponse()->redirect($url, $code); } /** @@ -515,7 +529,7 @@ class Controller extends RequestHandler implements TemplateGlobalProvider { * return null; */ public function redirectedTo() { - return $this->response && $this->response->getHeader('Location'); + return $this->getResponse() && $this->getResponse()->getHeader('Location'); } /** diff --git a/docs/en/02_Developer_Guides/02_Controllers/01_Introduction.md b/docs/en/02_Developer_Guides/02_Controllers/01_Introduction.md index bbd5ed239..6decd4373 100644 --- a/docs/en/02_Developer_Guides/02_Controllers/01_Introduction.md +++ b/docs/en/02_Developer_Guides/02_Controllers/01_Introduction.md @@ -89,20 +89,20 @@ Action methods can return one of four main things: * We can manually create a response and return that to ignore any previous data. */ public function someaction(SS_HTTPRequest $request) { - $this->response = new SS_HTTPResponse(); - $this->response->setStatusCode(400); - $this->response->setBody('invalid'); + $this->setResponse(new SS_HTTPResponse()); + $this->getResponse()->setStatusCode(400); + $this->getResponse()->setBody('invalid'); - return $this->response; + return $this->getResponse(); } /** * Or, we can modify the response that is waiting to go out. */ public function anotheraction(SS_HTTPRequest $request) { - $this->response->setStatusCode(400); + $this->getResponse()->setStatusCode(400); - return $this->response; + return $this->getResponse(); } /** @@ -118,13 +118,13 @@ Action methods can return one of four main things: * We can send stuff to the browser which isn't HTML */ public function ajaxaction() { - $this->response->setBody(json_encode(array( + $this->getResponse()->setBody(json_encode(array( 'json' => true ))); - $this->response->addHeader("Content-type", "application/json"); + $this->getResponse()->addHeader("Content-type", "application/json"); - return $this->response. + return $this->getResponse(). } For more information on how a URL gets mapped to an action see the [Routing](routing) documentation. diff --git a/docs/en/02_Developer_Guides/02_Controllers/02_Routing.md b/docs/en/02_Developer_Guides/02_Controllers/02_Routing.md index 899fe44bb..bfd30e446 100644 --- a/docs/en/02_Developer_Guides/02_Controllers/02_Routing.md +++ b/docs/en/02_Developer_Guides/02_Controllers/02_Routing.md @@ -44,7 +44,7 @@ which will be filled when the user makes their request. Request parameters are a and able to be pulled out from a controller using `$this->getRequest()->param($name)`.
-All Controllers have access to `$this->getRequest()` for the request object and `$this->response` for the response. +All Controllers have access to `$this->getRequest()` for the request object and `$this->getResponse()` for the response.
Here is what those parameters would look like for certain requests diff --git a/docs/en/02_Developer_Guides/09_Security/04_Secure_Coding.md b/docs/en/02_Developer_Guides/09_Security/04_Secure_Coding.md index 974791c93..f250c4721 100644 --- a/docs/en/02_Developer_Guides/09_Security/04_Secure_Coding.md +++ b/docs/en/02_Developer_Guides/09_Security/04_Secure_Coding.md @@ -543,7 +543,7 @@ controller's `init()` method: class MyController extends Controller { public function init() { parent::init(); - $this->response->addHeader('X-Frame-Options', 'SAMEORIGIN'); + $this->getResponse()->addHeader('X-Frame-Options', 'SAMEORIGIN'); } } diff --git a/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/05_CMS_Architecture.md b/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/05_CMS_Architecture.md index 640836c15..d218d0a21 100644 --- a/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/05_CMS_Architecture.md +++ b/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/05_CMS_Architecture.md @@ -360,7 +360,7 @@ without affecting the response body. class MyController extends LeftAndMain { class myaction() { // ... - $this->response->addHeader('X-Controller', 'MyOtherController'); + $this->getResponse()->addHeader('X-Controller', 'MyOtherController'); return $html; } } diff --git a/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/06_Javascript_Development.md b/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/06_Javascript_Development.md index a91150247..5f846c393 100644 --- a/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/06_Javascript_Development.md +++ b/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/06_Javascript_Development.md @@ -376,7 +376,7 @@ PHP: if(!$results) return new HTTPResponse("Not found", 404); // Use HTTPResponse to pass custom status messages - $this->response->setStatusCode(200, "Found " . $results->Count() . " elements"); + $this->getResponse()->setStatusCode(200, "Found " . $results->Count() . " elements"); // render all results with a custom template $vd = new ViewableData(); @@ -582,4 +582,4 @@ Example: JSpec Shopping cart test (from [visionmedia.github.com](http://visionme ## Related * [Unobtrusive Javascript](http://www.onlinetools.org/articles/unobtrusivejavascript/chapter1.html) -* [Quirksmode: In-depth Javascript Resources](http://www.quirksmode.org/resources.html) \ No newline at end of file +* [Quirksmode: In-depth Javascript Resources](http://www.quirksmode.org/resources.html) diff --git a/forms/HtmlEditorField.php b/forms/HtmlEditorField.php index e96b73db5..54454d42d 100644 --- a/forms/HtmlEditorField.php +++ b/forms/HtmlEditorField.php @@ -27,7 +27,7 @@ class HtmlEditorField extends TextareaField { private static $sanitise_server_side = false; protected $rows = 30; - + /** * @deprecated since version 4.0 */ @@ -47,7 +47,7 @@ class HtmlEditorField extends TextareaField { * @param string $title The human-readable field label. * @param mixed $value The value of the field. * @param string $config HTMLEditorConfig identifier to be used. Default to the active one. - */ + */ public function __construct($name, $title = null, $value = '', $config = null) { parent::__construct($name, $title, $value); @@ -101,7 +101,7 @@ class HtmlEditorField extends TextareaField { // Add default empty title & alt attributes. if(!$img->getAttribute('alt')) $img->setAttribute('alt', ''); if(!$img->getAttribute('title')) $img->setAttribute('title', ''); - + // Use this extension point to manipulate images inserted using TinyMCE, e.g. add a CSS class, change default title // $image is the image, $img is the DOM model $this->extend('processImage', $image, $img); @@ -893,16 +893,17 @@ class HtmlEditorField_Embed extends HtmlEditorField_File { $this->oembed = Oembed::get_oembed_from_url($url); if(!$this->oembed) { $controller = Controller::curr(); - $controller->response->addHeader('X-Status', + $response = $controller->getResponse(); + $response->addHeader('X-Status', rawurlencode(_t( 'HtmlEditorField.URLNOTANOEMBEDRESOURCE', "The URL '{url}' could not be turned into a media resource.", "The given URL is not a valid Oembed resource; the embed element couldn't be created.", array('url' => $url) ))); - $controller->response->setStatusCode(404); + $response->setStatusCode(404); - throw new SS_HTTPResponse_Exception($controller->response); + throw new SS_HTTPResponse_Exception($response); } } diff --git a/security/CMSSecurity.php b/security/CMSSecurity.php index 3fb66ef8f..39c12bc54 100644 --- a/security/CMSSecurity.php +++ b/security/CMSSecurity.php @@ -107,8 +107,9 @@ class CMSSecurity extends Security { 'Message displayed to user if their session cannot be restored', array('link' => $loginURLATT) ); - $this->response->setStatusCode(200); - $this->response->setBody(<<getResponse(); + $response->setStatusCode(200); + $response->setBody(<< $message @@ -118,7 +119,8 @@ setTimeout(function(){top.location.href = "$loginURLJS";}, 0); PHP ); - return $this->response; + $this->setResponse($response); + return $response; } protected function preLogin() { @@ -126,7 +128,7 @@ PHP if(!$this->getTargetMember()) { return $this->redirectToExternalLogin(); } - + return parent::preLogin(); } @@ -150,7 +152,7 @@ PHP public static function enabled() { // Disable shortcut if(!static::config()->reauth_enabled) return false; - + // Count all cms-supported methods $authenticators = Authenticator::get_authenticators(); foreach($authenticators as $authenticator) { @@ -205,7 +207,7 @@ PHP array('link' => $backURL) ) )); - + return $controller->renderWith($this->getTemplatesFor('success')); } } diff --git a/security/Security.php b/security/Security.php index 736464791..17af9bba1 100644 --- a/security/Security.php +++ b/security/Security.php @@ -305,7 +305,7 @@ class Security extends Controller implements TemplateGlobalProvider { parent::init(); // Prevent clickjacking, see https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options - $this->response->addHeader('X-Frame-Options', 'SAMEORIGIN'); + $this->getResponse()->addHeader('X-Frame-Options', 'SAMEORIGIN'); } public function index() { @@ -391,7 +391,7 @@ class Security extends Controller implements TemplateGlobalProvider { $member = Member::currentUser(); if($member) $member->logOut(); - if($redirect && (!$this->response || !$this->response->isFinished())) { + if($redirect && (!$this->getResponse()->isFinished())) { $this->redirectBack(); } } @@ -406,7 +406,7 @@ class Security extends Controller implements TemplateGlobalProvider { // Event handler for pre-login, with an option to let it break you out of the login form $eventResults = $this->extend('onBeforeSecurityLogin'); // If there was a redirection, return - if($this->redirectedTo()) return $this->response; + if($this->redirectedTo()) return $this->getResponse(); // If there was an SS_HTTPResponse object returned, then return that if($eventResults) { foreach($eventResults as $result) { @@ -528,13 +528,13 @@ class Security extends Controller implements TemplateGlobalProvider { Session::clear('Security.Message'); // only display tabs when more than one authenticator is provided - // to save bandwidth and reduce the amount of custom styling needed + // to save bandwidth and reduce the amount of custom styling needed if(count($forms) > 1) { $content = $this->generateLoginFormSet($forms); } else { $content = $forms[0]->forTemplate(); } - + // Finally, customise the controller to add any form messages and the form. $customisedController = $controller->customise(array( "Content" => $message, diff --git a/tests/FakeController.php b/tests/FakeController.php index f24f0bf56..b54af6a6e 100644 --- a/tests/FakeController.php +++ b/tests/FakeController.php @@ -17,8 +17,8 @@ class FakeController extends Controller { '/' ); $this->setRequest($request); - - $this->response = new SS_HTTPResponse(); + + $this->setResponse(new SS_HTTPResponse()); $this->init(); } diff --git a/tests/api/RestfulServiceTest.php b/tests/api/RestfulServiceTest.php index 36fcf2765..aa1ef35c1 100644 --- a/tests/api/RestfulServiceTest.php +++ b/tests/api/RestfulServiceTest.php @@ -365,10 +365,11 @@ class RestfulServiceTest_Controller extends Controller implements TestOnly { $body XML; - $this->response->setBody($out); - $this->response->addHeader('Content-type', 'text/xml'); + $response = $this->getResponse(); + $response->setBody($out); + $response->addHeader('Content-type', 'text/xml'); - return $this->response; + return $response; } public function invalid() { @@ -390,11 +391,11 @@ XML; XML; - $this->response->setBody($out); - $this->response->setStatusCode(400); - $this->response->addHeader('Content-type', 'text/xml'); + $this->getResponse()->setBody($out); + $this->getResponse()->setStatusCode(400); + $this->getResponse()->addHeader('Content-type', 'text/xml'); - return $this->response; + return $this->getResponse(); } /** diff --git a/tests/security/SecurityTest.php b/tests/security/SecurityTest.php index 9aff40097..e824cb6f3 100644 --- a/tests/security/SecurityTest.php +++ b/tests/security/SecurityTest.php @@ -79,7 +79,7 @@ class SecurityTest extends FunctionalTest { // Controller that doesn't attempt redirections $controller = new SecurityTest_NullController(); - $controller->response = new SS_HTTPResponse(); + $controller->setResponse(new SS_HTTPResponse()); Security::permissionFailure($controller, array('default' => 'Oops, not allowed')); $this->assertEquals('Oops, not allowed', Session::get('Security.Message.message')); @@ -104,12 +104,12 @@ class SecurityTest extends FunctionalTest { Config::inst()->update('Security', 'default_message_set', array('default' => 'default', 'alreadyLoggedIn' => 'You are already logged in!')); Security::permissionFailure($controller); - $this->assertContains('You are already logged in!', $controller->response->getBody(), + $this->assertContains('You are already logged in!', $controller->getResponse()->getBody(), 'Custom permission failure message was ignored'); Security::permissionFailure($controller, array('default' => 'default', 'alreadyLoggedIn' => 'One-off failure message')); - $this->assertContains('One-off failure message', $controller->response->getBody(), + $this->assertContains('One-off failure message', $controller->getResponse()->getBody(), "Message set passed to Security::permissionFailure() didn't override Config values"); Config::unnest(); @@ -130,7 +130,7 @@ class SecurityTest extends FunctionalTest { } return $response; } - + public function testAutomaticRedirectionOnLogin() { // BackURL with permission error (not authenticated) should not redirect if($member = Member::currentUser()) $member->logOut();