diff --git a/control/Cookie.php b/control/Cookie.php index 8c0adf388..6c6ade4f9 100644 --- a/control/Cookie.php +++ b/control/Cookie.php @@ -14,17 +14,19 @@ class Cookie { private static $report_errors = true; /** - * @var string cookie class + * Fetch the current instance of the cookie backend + * + * @return Cookie_Backend The cookie backend */ - static $cookie_class = 'Cookie'; - - private static $inst = null; - public static function get_inst() { - if(is_null(self::$inst)) { - self::$inst = new self::$cookie_class(); + //if we don't have a CookieJar service yet, register it + if(!Injector::inst()->hasService('Cookie_Backend')) { + Injector::inst()->registerService( + Injector::inst()->create('CookieJar', $_COOKIE), + 'Cookie_Backend' + ); } - return self::$inst; + return Injector::inst()->get('Cookie_Backend'); } /** @@ -41,7 +43,7 @@ class Cookie { public static function set($name, $value, $expiry = 90, $path = null, $domain = null, $secure = false, $httpOnly = true ) { - return self::get_inst()->inst_set($name, $value, $expiry, $path, $domain, $secure, $httpOnly); + return self::get_inst()->set($name, $value, $expiry, $path, $domain, $secure, $httpOnly); } /** @@ -51,7 +53,7 @@ class Cookie { * @return mixed */ public static function get($name) { - return self::get_inst()->inst_get($name); + return self::get_inst()->get($name); } /** @@ -59,77 +61,15 @@ class Cookie { * @param string * @param string */ - public static function force_expiry($name, $path = null, $domain = null) { - return self::get_inst()->inst_force_expiry($name, $path, $domain); - } - - /** - * @deprecated 3.2 Use "Cookie.report_errors" config setting instead - * @param bool - */ - public static function set_report_errors($reportErrors) { - Deprecation::notice('3.2', 'Use "Cookie.report_errors" config setting instead'); - self::get_inst()->inst_set_report_errors($reportErrors); - } - - /** - * @deprecated 3.2 Use "Cookie.report_errors" config setting instead - * @return bool - */ - public static function report_errors() { - Deprecation::notice('3.2', 'Use "Cookie.report_errors" config setting instead'); - return self::get_inst()->inst_report_errors(); - } - - /** - * Set a cookie variable - * - * @param string $name The variable name - * @param mixed $value The variable value. - * @param int $expiry The expiry time, in days. Defaults to 90. - * @param string $path See http://php.net/set_session - * @param string $domain See http://php.net/set_session - * @param boolean $secure See http://php.net/set_session - * @param boolean $httpOnly See http://php.net/set_session - */ - protected function inst_set($name, $value, $expiry = 90, $path = null, - $domain = null, $secure = false, $httpOnly = true - ) { - if(!headers_sent($file, $line)) { - $expiry = $expiry > 0 ? time()+(86400*$expiry) : $expiry; - $path = ($path) ? $path : Director::baseURL(); - setcookie($name, $value, $expiry, $path, $domain, $secure, $httpOnly); - $_COOKIE[$name] = $value; - } else { - if(Config::inst()->get('Cookie', 'report_errors')) { - user_error("Cookie '$name' can't be set. The site started outputting content at line $line in $file", - E_USER_WARNING); - } - } - } - - /** - * @param string - * @return mixed - */ - protected function inst_get($name) { - return isset($_COOKIE[$name]) ? $_COOKIE[$name] : null; - } - - /** - * @param string - */ - protected function inst_force_expiry($name, $path = null, $domain = null) { - if(!headers_sent($file, $line)) { - self::set($name, null, -20, $path, $domain); - } + public static function force_expiry($name, $path = null, $domain = null, $secure = false, $httpOnly = false) { + return self::get_inst()->forceExpiry($name, $path, $domain, $secure, $httpOnly); } /** * @deprecated 3.2 Use the "Cookie.report_errors" config setting instead * @param bool */ - protected function inst_set_report_errors($reportErrors) { + protected function set_report_errors($reportErrors) { Deprecation::notice('3.2', 'Use the "Cookie.report_errors" config setting instead'); Config::inst()->update('Cookie', 'report_errors', $reportErrors); } @@ -138,7 +78,7 @@ class Cookie { * @deprecated 3.2 Use the "Cookie.report_errors" config setting instead * @return bool */ - protected function inst_report_errors() { + protected function report_errors() { Deprecation::notice('3.2', 'Use the "Cookie.report_errors" config setting instead'); return Config::inst()->get('Cookie', 'report_errors'); } diff --git a/control/CookieJar.php b/control/CookieJar.php new file mode 100644 index 000000000..7b295cd29 --- /dev/null +++ b/control/CookieJar.php @@ -0,0 +1,156 @@ +current = $this->existing = !empty($cookies) ? $cookies : $this->existing; + } + + /** + * Set a cookie + * + * @param string $name The name of the cookie + * @param string $value The value for the cookie to hold + * @param int $expiry The number of days until expiry; 0 indicates a cookie valid for the current session + * @param string $path The path to save the cookie on (falls back to site base) + * @param string $domain The domain to make the cookie available on + * @param boolean $secure Can the cookie only be sent over SSL? + * @param boolean $httpOnly Prevent the cookie being accessible by JS + */ + public function set($name, $value, $expiry = 90, $path = null, $domain = null, $secure = false, $httpOnly = true) { + //are we setting or clearing a cookie? false values are reserved for clearing cookies (see PHP manual) + $clear = false; + if ($value === false || $value === '' || $expiry < 0) { + $clear = true; + $value = false; + } + + //expiry === 0 is a special case where we set a cookie for the current user session + if ($expiry !== 0) { + //don't do the maths if we are clearing + $expiry = $clear ? -1 : SS_Datetime::now()->Format('U') + (86400 * $expiry); + } + //set the path up + $path = $path ? $path : Director::baseURL(); + //send the cookie + $this->outputCookie($name, $value, $expiry, $path, $domain, $secure, $httpOnly); + //keep our variables in check + if ($clear) { + unset ($this->new[$name], $this->current[$name]); + } + else { + $this->new[$name] = $this->current[$name] = $value; + } + + } + + /** + * Get the cookie value by name + * + * @param string $name The name of the cookie to get + * @param boolean $includeUnsent Include cookies we've yet to send when fetching values + * + * @return string|null The cookie value or null if unset + */ + public function get($name, $includeUnsent = true) { + $cookies = $includeUnsent ? $this->current : $this->existing; + if (isset($cookies[$name])) { + return $cookies[$name]; + } + } + + /** + * Get all the cookies + * + * @param boolean $includeUnsent Include cookies we've yet to send + * + * @return array All the cookies + */ + public function getAll($includeUnsent = true) { + return $includeUnsent ? $this->current : $this->existing; + } + + /** + * Force the expiry of a cookie by name + * + * @param string $name The name of the cookie to expire + * @param string $path The path to save the cookie on (falls back to site base) + * @param string $domain The domain to make the cookie available on + * @param boolean $secure Can the cookie only be sent over SSL? + * @param boolean $httpOnly Prevent the cookie being accessible by JS + */ + public function forceExpiry($name, $path = null, $domain = null, $secure = false, $httpOnly = false) { + $this->set($name, false,-1, $path, $domain, $secure, $httpOnly); + } + + /** + * The function that actually sets the cookie using PHP + * + * @see http://uk3.php.net/manual/en/function.setcookie.php + * + * @param string $name The name of the cookie + * @param string|array $value The value for the cookie to hold + * @param int $expiry The number of days until expiry + * @param string $path The path to save the cookie on (falls back to site base) + * @param string $domain The domain to make the cookie available on + * @param boolean $secure Can the cookie only be sent over SSL? + * @param boolean $httpOnly Prevent the cookie being accessible by JS + * + * @return boolean If the cookie was set or not; doesn't mean it's accepted by the browser + */ + protected function outputCookie( + $name, $value, $expiry = 90, $path = null, $domain = null, $secure = false, $httpOnly = false + ) { + // if headers aren't sent, we can set the cookie + if(!headers_sent($file, $line)) { + return setcookie($name, $value, $expiry, $path, $domain, $secure, $httpOnly); + } else if(Config::inst()->get('Cookie', 'report_errors')) { + throw new LogicException( + "Cookie '$name' can't be set. The site started outputting content at line $line in $file" + ); + } + } + +} diff --git a/control/Cookie_Backend.php b/control/Cookie_Backend.php new file mode 100644 index 000000000..ffbf1a7e5 --- /dev/null +++ b/control/Cookie_Backend.php @@ -0,0 +1,59 @@ +create('Session', array()); + if(!$cookies) $cookies = new CookieJar(null); // Back up the current values of the superglobals $existingRequestVars = isset($_REQUEST) ? $_REQUEST : array(); @@ -235,6 +236,7 @@ class Director implements TemplateGlobalProvider { $existingSessionVars = isset($_SESSION) ? $_SESSION : array(); $existingCookies = isset($_COOKIE) ? $_COOKIE : array(); $existingServer = isset($_SERVER) ? $_SERVER : array(); + $existingCookieJar = Cookie::get_inst(); $existingRequirementsBackend = Requirements::backend(); @@ -269,7 +271,8 @@ class Director implements TemplateGlobalProvider { $_GET = (array)$getVars; $_POST = (array)$postVars; $_SESSION = $session ? $session->inst_getAll() : array(); - $_COOKIE = (array) $cookies; + $_COOKIE = $cookies->getAll(false); + Injector::inst()->registerService($cookies, 'CookieJar'); $_SERVER['REQUEST_URI'] = Director::baseURL() . $urlWithQuerystring; $request = new SS_HTTPRequest($httpMethod, $url, $getVars, $postVars, $body); @@ -311,6 +314,8 @@ class Director implements TemplateGlobalProvider { $_COOKIE = $existingCookies; $_SERVER = $existingServer; + Injector::inst()->registerService($existingCookieJar, 'CookieJar'); + Requirements::set_backend($existingRequirementsBackend); // These are needed so that calling Director::test() doesnt muck with whoever is calling it. diff --git a/control/Session.php b/control/Session.php index a20d18222..d7d447d09 100644 --- a/control/Session.php +++ b/control/Session.php @@ -609,6 +609,7 @@ class Session { */ public static function destroy($removeCookie = true) { self::current_session()->inst_destroy($removeCookie); + Cookie::force_expiry(session_name(), $path, null, $secure, true); } /** diff --git a/control/injector/Injector.php b/control/injector/Injector.php index a92ddf205..59b4496b1 100644 --- a/control/injector/Injector.php +++ b/control/injector/Injector.php @@ -740,12 +740,21 @@ class Injector { $this->inject($service); } + /** + * Remove a service that has been registered + * + * @param string $service The service to clear + */ + public function clearService($service) { + unset($this->specs[$service], $this->serviceCache[$service]); + } /** * Register a service with an explicit name * * @deprecated since 3.1.1 */ public function registerNamedService($name, $service) { + Deprecation::notice('3.2', 'registerNamedService is deprecated, use registerService instead'); return $this->registerService($service, $name); } @@ -882,4 +891,4 @@ class Injector { public function createWithArgs($name, $constructorArgs) { return $this->get($name, false, $constructorArgs); } -} +} \ No newline at end of file diff --git a/dev/TestSession.php b/dev/TestSession.php index bb60b1e9b..ee25f61e2 100644 --- a/dev/TestSession.php +++ b/dev/TestSession.php @@ -16,6 +16,7 @@ class TestSession { /** * @var SS_HTTPResponse */ + private $cookies; private $lastResponse; /** @@ -36,6 +37,7 @@ class TestSession { public function __construct() { $this->session = Injector::inst()->create('Session', array()); + $this->cookies = new CookieJar(); $this->controller = new Controller(); $this->controller->setSession($this->session); $this->controller->pushCurrent(); @@ -62,8 +64,15 @@ class TestSession { public function get($url, $session = null, $headers = null, $cookies = null) { $headers = (array) $headers; if($this->lastUrl && !isset($headers['Referer'])) $headers['Referer'] = $this->lastUrl; - $this->lastResponse - = Director::test($url, null, $session ? $session : $this->session, null, null, $headers, $cookies); + $this->lastResponse = Director::test( + $url, + null, + $session ? $session : $this->session, + null, + null, + $headers, + $cookies ? $cookies : $this->cookies + ); $this->lastUrl = $url; if(!$this->lastResponse) user_error("Director::test($url) returned null", E_USER_WARNING); return $this->lastResponse; @@ -84,8 +93,15 @@ class TestSession { public function post($url, $data, $headers = null, $session = null, $body = null, $cookies = null) { $headers = (array) $headers; if($this->lastUrl && !isset($headers['Referer'])) $headers['Referer'] = $this->lastUrl; - $this->lastResponse - = Director::test($url, $data, $session ? $session : $this->session, null, $body, $headers, $cookies); + $this->lastResponse = Director::test( + $url, + $data, + $session ? $session : $this->session, + null, + $body, + $headers, + $cookies ? $cookies : $this->cookies + ); $this->lastUrl = $url; if(!$this->lastResponse) user_error("Director::test($url) returned null", E_USER_WARNING); return $this->lastResponse; diff --git a/docs/en/reference/cookies.md b/docs/en/reference/cookies.md new file mode 100644 index 000000000..691f89163 --- /dev/null +++ b/docs/en/reference/cookies.md @@ -0,0 +1,128 @@ +# Cookies + +## Accessing and Manipulating Cookies + +Cookies can be set/get/expired using the `Cookie` class and its static methods + +setting: + +```php +Cookie::set('CookieName', 'CookieValue'); +``` + +getting: + +```php +Cookie::get('CookieName'); //returns null if not set or the value if set +``` + +expiring / removing / clearing: + +```php +Cookie::force_expiry('CookieName'); +``` + + +## The `Cookie_Backend` + +The `Cookie` class manipulates and sets cookies using a `Cookie_Backend`. The backend is in charge of the logic +that fetches, sets and expires cookies. By default we use a the `CookieJar` backend which uses PHP's +(`setcookie`)[http://www.php.net/manual/en/function.setcookie.php] function. + +The `CookieJar` keeps track of cookies that have been set by the current process as well as those that were recieved +from the browser. + +By default the `Cookie` class will load the `$_COOKIE` superglobal into the `Cookie_Backend`. If you want to change +the initial state of the `Cookie_Backend` you can load your own backend into the `CookieJar` service registered with +the `Injector`. + +eg: + +```php +$myCookies = array( + 'cookie1' => 'value1', +); + +$newBackend = new CookieJar($myCookies); + +Injector::inst()->registerService($newBackend, 'CookieJar'); + +Cookie::get('cookie1'); //will return 'value1' +``` + +### Resetting the Cookie_Backend state + +Assuming that your appliation hasn't messed around with the `$_COOKIE` superglobal, you can reset the state of your +`Cookie_Backend` by simply unregistering the `CookieJar` service with `Injector`. Next time you access `Cookie` it'll +create a new service for you using the `$_COOKIE` superglobal + +eg: + +```php + +Injector::inst()->unregisterNamedObject('CookieJar'); + +Cookie::get('cookiename'); //will return $_COOKIE['cookiename'] if set + +``` + +Alternatively, if you know that the superglobal has been changed (or you aren't sure it hasn't) you can attempt to use +the current `CookieJar` service to tell you what it was like when it was registered. + +eg: + +```php + +//store the cookies that were loaded into the `CookieJar` +$recievedCookie = Cookie::get_inst()->getAll(false); + +//set a new `CookieJar` +Injector::inst()->registerService(new CookieJar($recievedCookie), 'CookieJar'); + +``` + + +### Using your own Cookie_Backend + +If you need to implement your own Cookie_Backend you can use the injector system to force a different class to be used. + +example: + +```yml +Injector: + CookieJar: + class: MyCookieJar +``` + +To be a valid backend your class must implement the `Cookie_Backend` interface. + +## Advanced Usage + +### Sent vs Received Cookies + +Sometimes it's useful to be able to tell if a cookie was set by the process (thus will be sent to the browser) or if it +came from the browser as part of the request. + +Using the `Cookie_Backend` we can do this like such: + +```php + +Cookie::set('CookieName', 'CookieVal'); + +Cookie::get('CookieName'); //gets the cookie as we set it + +//will return the cookie as it was when it was sent in the request +Cookie::get_inst()->get('CookieName', false); +``` + +### Accessing all the cookies at once + +One can also access all of the cookies in one go using the `Cookie_Backend` + +```php + +Cookie::get_inst()->getAll(); //returns all the cookies including ones set during the current process + +Cookie::get_inst()->getAll(false); //returns all the cookies in the request + +``` diff --git a/model/DB.php b/model/DB.php index aad84ef74..5d56efcb8 100644 --- a/model/DB.php +++ b/model/DB.php @@ -162,8 +162,8 @@ class DB { Cookie::set("alternativeDatabaseName", base64_encode($encrypted), 0, null, null, false, true); Cookie::set("alternativeDatabaseNameIv", base64_encode($iv), 0, null, null, false, true); } else { - Cookie::set("alternativeDatabaseName", null, 0, null, null, false, true); - Cookie::set("alternativeDatabaseNameIv", null, 0, null, null, false, true); + Cookie::force_expiry("alternativeDatabaseName", null, null, false, true); + Cookie::force_expiry("alternativeDatabaseNameIv", null, null, false, true); } } diff --git a/model/Versioned.php b/model/Versioned.php index 557f55cf4..99666aa3f 100644 --- a/model/Versioned.php +++ b/model/Versioned.php @@ -1032,15 +1032,13 @@ class Versioned extends DataExtension implements TemplateGlobalProvider { if(!headers_sent() && !Director::is_cli()) { if(Versioned::current_stage() == 'Live') { // clear the cookie if it's set - if(!empty($_COOKIE['bypassStaticCache'])) { - Cookie::set('bypassStaticCache', null, 0, null, null, false, true /* httponly */); - unset($_COOKIE['bypassStaticCache']); + if(Cookie::get('bypassStaticCache')) { + Cookie::force_expiry('bypassStaticCache', null, null, false, true /* httponly */); } } else { // set the cookie if it's cleared - if(empty($_COOKIE['bypassStaticCache'])) { + if(!Cookie::get('bypassStaticCache')) { Cookie::set('bypassStaticCache', '1', 0, null, null, false, true /* httponly */); - $_COOKIE['bypassStaticCache'] = 1; } } } diff --git a/security/Member.php b/security/Member.php index ca5a79479..c9d2d80d3 100644 --- a/security/Member.php +++ b/security/Member.php @@ -394,7 +394,6 @@ class Member extends DataObject implements TemplateGlobalProvider { Cookie::set('alc_enc', $this->ID . ':' . $token, 90, null, null, null, true); } else { $this->RememberLoginToken = null; - Cookie::set('alc_enc', null); Cookie::force_expiry('alc_enc'); } @@ -489,7 +488,6 @@ class Member extends DataObject implements TemplateGlobalProvider { $this->extend('memberLoggedOut'); $this->RememberLoginToken = null; - Cookie::set('alc_enc', null); // // Clear the Remember Me cookie Cookie::force_expiry('alc_enc'); // Switch back to live in order to avoid infinite loops when diff --git a/tests/control/CookieJarTest.php b/tests/control/CookieJarTest.php new file mode 100644 index 000000000..10197589b --- /dev/null +++ b/tests/control/CookieJarTest.php @@ -0,0 +1,135 @@ + 1, + 'cookie2' => 'cookies', + 'cookie3' => 'test', + ); + + $cookieJar = new CookieJar($defaultCookies); + + //make sure all the "recieved" cookies are as expected + $this->assertEquals($defaultCookies, $cookieJar->getAll(false)); + + //make sure there are no "phantom" cookies + $this->assertEquals($defaultCookies, $cookieJar->getAll(false)); + + //check an empty array is accepted + $cookieJar = new CookieJar(array()); + $this->assertEmpty($cookieJar->getAll(false)); + + + //check no argument is accepted + $cookieJar = new CookieJar(); + $this->assertEmpty($cookieJar->getAll(false)); + } + + /** + * Test that we can set and get cookies + */ + public function testSetAndGet() { + $cookieJar = new CookieJar(); + + $this->assertEmpty($cookieJar->get('testCookie')); + + //set a test cookie + $cookieJar->set('testCookie', 'testVal'); + + //make sure it was set + $this->assertEquals('testVal', $cookieJar->get('testCookie')); + + //make sure we can distinguise it from ones that were "existing" + $this->assertEmpty($cookieJar->get('testCookie', false)); + } + + /** + * Test that we can distinguish between vars that were loaded on instantiation + * and those added later + */ + public function testExistingVersusNew() { + //load with a cookie + $cookieJar = new CookieJar(array( + 'cookieExisting' => 'i woz here', + )); + + //set a new cookie + $cookieJar->set('cookieNew', 'i am new'); + + //check we can fetch new and old cookie values + $this->assertEquals('i woz here', $cookieJar->get('cookieExisting')); + $this->assertEquals('i woz here', $cookieJar->get('cookieExisting', false)); + $this->assertEquals('i am new', $cookieJar->get('cookieNew')); + //there should be no original value for the new cookie + $this->assertEmpty($cookieJar->get('cookieNew', false)); + + //change the existing cookie, can we fetch the new and old value + $cookieJar->set('cookieExisting', 'i woz changed'); + + $this->assertEquals('i woz changed', $cookieJar->get('cookieExisting')); + $this->assertEquals('i woz here', $cookieJar->get('cookieExisting', false)); + + //check we can get all cookies + $this->assertEquals(array( + 'cookieExisting' => 'i woz changed', + 'cookieNew' => 'i am new', + ), $cookieJar->getAll()); + + //check we can get all original cookies + $this->assertEquals(array( + 'cookieExisting' => 'i woz here', + ), $cookieJar->getAll(false)); + } + + /** + * Check we can remove cookies and we can access their original values + */ + public function testForceExpiry() { + //load an existing cookie + $cookieJar = new CookieJar(array( + 'cookieExisting' => 'i woz here', + )); + + //make sure it's available + $this->assertEquals('i woz here', $cookieJar->get('cookieExisting')); + + //remove the cookie + $cookieJar->forceExpiry('cookieExisting'); + + //check it's gone + $this->assertEmpty($cookieJar->get('cookieExisting')); + + //check we can get it's original value + $this->assertEquals('i woz here', $cookieJar->get('cookieExisting', false)); + + + //check we can add a new cookie and remove it and it doesn't leave any phantom values + $cookieJar->set('newCookie', 'i am new'); + + //check it's set by not recieved + $this->assertEquals('i am new', $cookieJar->get('newCookie')); + $this->assertEmpty($cookieJar->get('newCookie', false)); + + //remove it + $cookieJar->forceExpiry('newCookie'); + + //check it's neither set nor reveived + $this->assertEmpty($cookieJar->get('newCookie')); + $this->assertEmpty($cookieJar->get('newCookie', false)); + } + +} diff --git a/tests/control/CookieTest.php b/tests/control/CookieTest.php new file mode 100644 index 000000000..2725161ac --- /dev/null +++ b/tests/control/CookieTest.php @@ -0,0 +1,104 @@ +registerService(new CookieJar($_COOKIE), 'Cookie_Backend'); + } + + public function tearDown() { + parent::tearDown(); + Injector::inst()->unregisterNamedObject('Cookie_Backend'); + } + + /** + * Check a new cookie inst will be loaded with the superglobal by default + */ + public function testCheckNewInstTakesSuperglobal() { + //store the superglobal state + $existingCookies = $_COOKIE; + + //set a mock state for the superglobal + $_COOKIE = array( + 'cookie1' => 1, + 'cookie2' => 'cookies', + 'cookie3' => 'test', + ); + + Injector::inst()->unregisterNamedObject('Cookie_Backend'); + + $this->assertEquals($_COOKIE['cookie1'], Cookie::get('cookie1')); + $this->assertEquals($_COOKIE['cookie2'], Cookie::get('cookie2')); + $this->assertEquals($_COOKIE['cookie3'], Cookie::get('cookie3')); + + //for good measure check the CookieJar hasn't stored anything extra + $this->assertEquals($_COOKIE, Cookie::get_inst()->getAll(false)); + + //restore the superglobal state + $_COOKIE = $existingCookies; + } + + /** + * Check we don't mess with super globals when manipulating cookies + * + * State should be managed sperately to the super global + */ + public function testCheckSuperglobalsArentTouched() { + + //store the current state + $before = $_COOKIE; + + //change some cookies + Cookie::set('cookie', 'not me'); + Cookie::force_expiry('cookie2'); + + //assert it hasn't changed + $this->assertEquals($before, $_COOKIE); + + } + + /** + * Check we can actually change a backend + */ + public function testChangeBackend() { + + Cookie::set('test', 'testvalue'); + + $this->assertEquals('testvalue', Cookie::get('test')); + + Injector::inst()->registerService(new CookieJar(array()), 'Cookie_Backend'); + + $this->assertEmpty(Cookie::get('test')); + + } + + /** + * Check we can actually get the backend inst out + */ + public function testGetInst() { + + $inst = new CookieJar(array('test' => 'testvalue')); + + Injector::inst()->registerService($inst, 'Cookie_Backend'); + + $this->assertEquals($inst, Cookie::get_inst()); + + $this->assertEquals('testvalue', Cookie::get('test')); + + } + +} diff --git a/tests/control/DirectorTest.php b/tests/control/DirectorTest.php index 5ec0ee58b..878e2d58a 100644 --- a/tests/control/DirectorTest.php +++ b/tests/control/DirectorTest.php @@ -271,8 +271,10 @@ class DirectorTest extends SapphireTest { $_POST = array('somekey' => 'postvalue'); $_COOKIE = array('somekey' => 'cookievalue'); + $cookies = new CookieJar(array('somekey' => 'sometestcookievalue')); + $getresponse = Director::test('errorpage?somekey=sometestgetvalue', array('somekey' => 'sometestpostvalue'), - null, null, null, null, array('somekey' => 'sometestcookievalue')); + null, null, null, null, $cookies); $this->assertEquals('getvalue', $_GET['somekey'], '$_GET reset to original value after Director::test()'); @@ -288,7 +290,16 @@ class DirectorTest extends SapphireTest { foreach(array('return%sValue', 'returnRequestValue', 'returnCookieValue') as $testfunction) { $url = 'DirectorTestRequest_Controller/' . sprintf($testfunction, ucfirst($method)) . '?' . http_build_query($fixture); - $getresponse = Director::test($url, $fixture, null, strtoupper($method), null, null, $fixture); + + $getresponse = Director::test( + $url, + $fixture, + null, + strtoupper($method), + null, + null, + new CookieJar($fixture) + ); $this->assertInstanceOf('SS_HTTPResponse', $getresponse, 'Director::test() returns SS_HTTPResponse'); $this->assertEquals($fixture['somekey'], $getresponse->getBody(), 'Director::test() ' . $testfunction);