Add functions to modify cookies to response class
Currently there is no AppFramework way to modify cookies, which makes it unusable for quite some use-cases or results in untestable code. This PR adds some basic functionalities to add and invalidate cookies. Usage: ```php $response = new TemplateResponse(...); $response->addCookie('foo', 'bar'); $response->invalidateCookie('foo'); $response->addCookie('bar', 'foo', new \DateTime('2015-01-01 00:00')); ``` Existing cookies can be accessed with the AppFramework using `$this->request->getCookie($name)`.
This commit is contained in:
parent
e306b588d2
commit
048139074d
|
@ -53,7 +53,7 @@ class App {
|
||||||
// initialize the dispatcher and run all the middleware before the controller
|
// initialize the dispatcher and run all the middleware before the controller
|
||||||
$dispatcher = $container['Dispatcher'];
|
$dispatcher = $container['Dispatcher'];
|
||||||
|
|
||||||
list($httpHeaders, $responseHeaders, $output) =
|
list($httpHeaders, $responseHeaders, $responseCookies, $output) =
|
||||||
$dispatcher->dispatch($controller, $methodName);
|
$dispatcher->dispatch($controller, $methodName);
|
||||||
|
|
||||||
if(!is_null($httpHeaders)) {
|
if(!is_null($httpHeaders)) {
|
||||||
|
@ -64,6 +64,14 @@ class App {
|
||||||
header($name . ': ' . $value);
|
header($name . ': ' . $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach($responseCookies as $name => $value) {
|
||||||
|
$expireDate = null;
|
||||||
|
if($value['expireDate'] instanceof \DateTime) {
|
||||||
|
$expireDate = $value['expireDate']->getTimestamp();
|
||||||
|
}
|
||||||
|
setcookie($name, $value['value'], $expireDate, \OC::$WEBROOT, null, \OC::$server->getConfig()->getSystemValue('forcessl', false), true);
|
||||||
|
}
|
||||||
|
|
||||||
if(!is_null($output)) {
|
if(!is_null($output)) {
|
||||||
header('Content-Length: ' . strlen($output));
|
header('Content-Length: ' . strlen($output));
|
||||||
print($output);
|
print($output);
|
||||||
|
|
|
@ -48,7 +48,7 @@ class Dispatcher {
|
||||||
* @param Http $protocol the http protocol with contains all status headers
|
* @param Http $protocol the http protocol with contains all status headers
|
||||||
* @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which
|
* @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which
|
||||||
* runs the middleware
|
* runs the middleware
|
||||||
* @param ControllerMethodReflector the reflector that is used to inject
|
* @param ControllerMethodReflector $reflector the reflector that is used to inject
|
||||||
* the arguments for the controller
|
* the arguments for the controller
|
||||||
* @param IRequest $request the incoming request
|
* @param IRequest $request the incoming request
|
||||||
*/
|
*/
|
||||||
|
@ -71,6 +71,7 @@ class Dispatcher {
|
||||||
* @return array $array[0] contains a string with the http main header,
|
* @return array $array[0] contains a string with the http main header,
|
||||||
* $array[1] contains headers in the form: $key => value, $array[2] contains
|
* $array[1] contains headers in the form: $key => value, $array[2] contains
|
||||||
* the response output
|
* the response output
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function dispatch(Controller $controller, $methodName) {
|
public function dispatch(Controller $controller, $methodName) {
|
||||||
$out = array(null, array(), null);
|
$out = array(null, array(), null);
|
||||||
|
@ -102,13 +103,14 @@ class Dispatcher {
|
||||||
// get the output which should be printed and run the after output
|
// get the output which should be printed and run the after output
|
||||||
// middleware to modify the response
|
// middleware to modify the response
|
||||||
$output = $response->render();
|
$output = $response->render();
|
||||||
$out[2] = $this->middlewareDispatcher->beforeOutput(
|
$out[3] = $this->middlewareDispatcher->beforeOutput(
|
||||||
$controller, $methodName, $output);
|
$controller, $methodName, $output);
|
||||||
|
|
||||||
// depending on the cache object the headers need to be changed
|
// depending on the cache object the headers need to be changed
|
||||||
$out[0] = $this->protocol->getStatusHeader($response->getStatus(),
|
$out[0] = $this->protocol->getStatusHeader($response->getStatus(),
|
||||||
$response->getLastModified(), $response->getETag());
|
$response->getLastModified(), $response->getETag());
|
||||||
$out[1] = $response->getHeaders();
|
$out[1] = array_merge($response->getHeaders());
|
||||||
|
$out[2] = $response->getCookies();
|
||||||
|
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,9 +45,16 @@ class Response {
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cookies that will be need to be constructed as header
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $cookies = array();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP status code - defaults to STATUS OK
|
* HTTP status code - defaults to STATUS OK
|
||||||
* @var string
|
* @var int
|
||||||
*/
|
*/
|
||||||
private $status = Http::STATUS_OK;
|
private $status = Http::STATUS_OK;
|
||||||
|
|
||||||
|
@ -70,6 +77,7 @@ class Response {
|
||||||
* Caches the response
|
* Caches the response
|
||||||
* @param int $cacheSeconds the amount of seconds that should be cached
|
* @param int $cacheSeconds the amount of seconds that should be cached
|
||||||
* if 0 then caching will be disabled
|
* if 0 then caching will be disabled
|
||||||
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function cacheFor($cacheSeconds) {
|
public function cacheFor($cacheSeconds) {
|
||||||
|
|
||||||
|
@ -83,13 +91,68 @@ class Response {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new cookie to the response
|
||||||
|
* @param string $name The name of the cookie
|
||||||
|
* @param string $value The value of the cookie
|
||||||
|
* @param \DateTime|null $expireDate Date on that the cookie should expire, if set
|
||||||
|
* to null cookie will be considered as session
|
||||||
|
* cookie.
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function addCookie($name, $value, \DateTime $expireDate = null) {
|
||||||
|
$this->cookies[$name] = array('value' => $value, 'expireDate' => $expireDate);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the specified cookies
|
||||||
|
* @param array $cookies array('foo' => array('value' => 'bar', 'expire' => null))
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setCookies(array $cookies) {
|
||||||
|
$this->cookies = $cookies;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates the specified cookie
|
||||||
|
* @param string $name
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function invalidateCookie($name) {
|
||||||
|
$this->addCookie($name, 'expired', new \DateTime('1971-01-01 00:00'));
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates the specified cookies
|
||||||
|
* @param array $cookieNames array('foo', 'bar')
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function invalidateCookies(array $cookieNames) {
|
||||||
|
foreach($cookieNames as $cookieName) {
|
||||||
|
$this->invalidateCookie($cookieName);
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cookies
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getCookies() {
|
||||||
|
return $this->cookies;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new header to the response that will be called before the render
|
* Adds a new header to the response that will be called before the render
|
||||||
* function
|
* function
|
||||||
* @param string $name The name of the HTTP header
|
* @param string $name The name of the HTTP header
|
||||||
* @param string $value The value, null will delete it
|
* @param string $value The value, null will delete it
|
||||||
* @return Response Reference to this object
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function addHeader($name, $value) {
|
public function addHeader($name, $value) {
|
||||||
$name = trim($name); // always remove leading and trailing whitespace
|
$name = trim($name); // always remove leading and trailing whitespace
|
||||||
|
@ -108,10 +171,10 @@ class Response {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the headers
|
* Set the headers
|
||||||
* @param array key value header pairs
|
* @param array $headers value header pairs
|
||||||
* @return Response Reference to this object
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setHeaders($headers) {
|
public function setHeaders(array $headers) {
|
||||||
$this->headers = $headers;
|
$this->headers = $headers;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
|
|
@ -63,7 +63,7 @@ class AppTest extends \Test\TestCase {
|
||||||
|
|
||||||
|
|
||||||
public function testControllerNameAndMethodAreBeingPassed(){
|
public function testControllerNameAndMethodAreBeingPassed(){
|
||||||
$return = array(null, array(), null);
|
$return = array(null, array(), array(), null);
|
||||||
$this->dispatcher->expects($this->once())
|
$this->dispatcher->expects($this->once())
|
||||||
->method('dispatch')
|
->method('dispatch')
|
||||||
->with($this->equalTo($this->controller),
|
->with($this->equalTo($this->controller),
|
||||||
|
|
|
@ -227,7 +227,7 @@ class DispatcherTest extends \Test\TestCase {
|
||||||
|
|
||||||
$this->assertEquals($httpHeaders, $response[0]);
|
$this->assertEquals($httpHeaders, $response[0]);
|
||||||
$this->assertEquals($responseHeaders, $response[1]);
|
$this->assertEquals($responseHeaders, $response[1]);
|
||||||
$this->assertEquals($out, $response[2]);
|
$this->assertEquals($out, $response[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -246,7 +246,7 @@ class DispatcherTest extends \Test\TestCase {
|
||||||
|
|
||||||
$this->assertEquals($httpHeaders, $response[0]);
|
$this->assertEquals($httpHeaders, $response[0]);
|
||||||
$this->assertEquals($responseHeaders, $response[1]);
|
$this->assertEquals($responseHeaders, $response[1]);
|
||||||
$this->assertEquals($out, $response[2]);
|
$this->assertEquals($out, $response[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -301,7 +301,7 @@ class DispatcherTest extends \Test\TestCase {
|
||||||
$this->dispatcherPassthrough();
|
$this->dispatcherPassthrough();
|
||||||
$response = $this->dispatcher->dispatch($controller, 'exec');
|
$response = $this->dispatcher->dispatch($controller, 'exec');
|
||||||
|
|
||||||
$this->assertEquals('[3,true,4,1]', $response[2]);
|
$this->assertEquals('[3,true,4,1]', $response[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -324,7 +324,7 @@ class DispatcherTest extends \Test\TestCase {
|
||||||
$this->dispatcherPassthrough();
|
$this->dispatcherPassthrough();
|
||||||
$response = $this->dispatcher->dispatch($controller, 'exec');
|
$response = $this->dispatcher->dispatch($controller, 'exec');
|
||||||
|
|
||||||
$this->assertEquals('[3,true,4,7]', $response[2]);
|
$this->assertEquals('[3,true,4,7]', $response[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -350,7 +350,7 @@ class DispatcherTest extends \Test\TestCase {
|
||||||
$this->dispatcherPassthrough();
|
$this->dispatcherPassthrough();
|
||||||
$response = $this->dispatcher->dispatch($controller, 'exec');
|
$response = $this->dispatcher->dispatch($controller, 'exec');
|
||||||
|
|
||||||
$this->assertEquals('{"text":[3,false,4,1]}', $response[2]);
|
$this->assertEquals('{"text":[3,false,4,1]}', $response[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -375,7 +375,7 @@ class DispatcherTest extends \Test\TestCase {
|
||||||
$this->dispatcherPassthrough();
|
$this->dispatcherPassthrough();
|
||||||
$response = $this->dispatcher->dispatch($controller, 'execDataResponse');
|
$response = $this->dispatcher->dispatch($controller, 'execDataResponse');
|
||||||
|
|
||||||
$this->assertEquals('{"text":[3,false,4,1]}', $response[2]);
|
$this->assertEquals('{"text":[3,false,4,1]}', $response[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -401,7 +401,7 @@ class DispatcherTest extends \Test\TestCase {
|
||||||
$this->dispatcherPassthrough();
|
$this->dispatcherPassthrough();
|
||||||
$response = $this->dispatcher->dispatch($controller, 'exec');
|
$response = $this->dispatcher->dispatch($controller, 'exec');
|
||||||
|
|
||||||
$this->assertEquals('{"text":[3,false,4,1]}', $response[2]);
|
$this->assertEquals('{"text":[3,false,4,1]}', $response[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -429,7 +429,7 @@ class DispatcherTest extends \Test\TestCase {
|
||||||
$this->dispatcherPassthrough();
|
$this->dispatcherPassthrough();
|
||||||
$response = $this->dispatcher->dispatch($controller, 'exec');
|
$response = $this->dispatcher->dispatch($controller, 'exec');
|
||||||
|
|
||||||
$this->assertEquals('{"text":[3,true,4,1]}', $response[2]);
|
$this->assertEquals('{"text":[3,true,4,1]}', $response[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,92 @@ class ResponseTest extends \Test\TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testAddCookie() {
|
||||||
|
$this->childResponse->addCookie('foo', 'bar');
|
||||||
|
$this->childResponse->addCookie('bar', 'foo', new \DateTime('1970-01-01'));
|
||||||
|
|
||||||
|
$expectedResponse = array(
|
||||||
|
'foo' => array(
|
||||||
|
'value' => 'bar',
|
||||||
|
'expireDate' => null,
|
||||||
|
),
|
||||||
|
'bar' => array(
|
||||||
|
'value' => 'foo',
|
||||||
|
'expireDate' => new \DateTime('1970-01-01')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->assertEquals($expectedResponse, $this->childResponse->getCookies());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function testSetCookies() {
|
||||||
|
$expected = array(
|
||||||
|
'foo' => array(
|
||||||
|
'value' => 'bar',
|
||||||
|
'expireDate' => null,
|
||||||
|
),
|
||||||
|
'bar' => array(
|
||||||
|
'value' => 'foo',
|
||||||
|
'expireDate' => new \DateTime('1970-01-01')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->childResponse->setCookies($expected);
|
||||||
|
$cookies = $this->childResponse->getCookies();
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $cookies);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function testInvalidateCookie() {
|
||||||
|
$this->childResponse->addCookie('foo', 'bar');
|
||||||
|
$this->childResponse->invalidateCookie('foo');
|
||||||
|
$expected = array(
|
||||||
|
'foo' => array(
|
||||||
|
'value' => 'expired',
|
||||||
|
'expireDate' => new \DateTime('1971-01-01')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$cookies = $this->childResponse->getCookies();
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $cookies);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function testInvalidateCookies() {
|
||||||
|
$this->childResponse->addCookie('foo', 'bar');
|
||||||
|
$this->childResponse->addCookie('bar', 'foo');
|
||||||
|
$expected = array(
|
||||||
|
'foo' => array(
|
||||||
|
'value' => 'bar',
|
||||||
|
'expireDate' => null
|
||||||
|
),
|
||||||
|
'bar' => array(
|
||||||
|
'value' => 'foo',
|
||||||
|
'expireDate' => null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$cookies = $this->childResponse->getCookies();
|
||||||
|
$this->assertEquals($expected, $cookies);
|
||||||
|
|
||||||
|
$this->childResponse->invalidateCookies(array('foo', 'bar'));
|
||||||
|
$expected = array(
|
||||||
|
'foo' => array(
|
||||||
|
'value' => 'expired',
|
||||||
|
'expireDate' => new \DateTime('1971-01-01')
|
||||||
|
),
|
||||||
|
'bar' => array(
|
||||||
|
'value' => 'expired',
|
||||||
|
'expireDate' => new \DateTime('1971-01-01')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$cookies = $this->childResponse->getCookies();
|
||||||
|
$this->assertEquals($expected, $cookies);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testRenderReturnNullByDefault(){
|
public function testRenderReturnNullByDefault(){
|
||||||
$this->assertEquals(null, $this->childResponse->render());
|
$this->assertEquals(null, $this->childResponse->render());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue