Browse Source

Convert cookies from CakePHP responses to PSR7 ones.

I missed this before, but we'll need to handle cookie data conversion.
I really wanted to use one of the predefined date constants, but none of
them seemed to match RFC6265.
Mark Story 9 years ago
parent
commit
b2f1c72d21
2 changed files with 98 additions and 0 deletions
  1. 36 0
      src/Http/ResponseTransformer.php
  2. 62 0
      tests/TestCase/Http/ResponseTransformerTest.php

+ 36 - 0
src/Http/ResponseTransformer.php

@@ -95,11 +95,47 @@ class ResponseTransformer
         if (!isset($headers['Content-Type'])) {
             $headers['Content-Type'] = $response->type();
         }
+        if ($response->cookie()) {
+            $headers['Set-Cookie'] = static::buildCookieHeader($response->cookie());
+        }
         $stream = static::getStream($response);
         return new DiactorosResponse($stream, $status, $headers);
     }
 
     /**
+     * Convert an array of cookies into header lines.
+     *
+     * @param array $cookies The cookies to serialize.
+     * @return array A list of cookie header values.
+     */
+    protected static function buildCookieHeader($cookies)
+    {
+        $headers = [];
+        foreach ($cookies as $cookie) {
+            $parts = [
+                sprintf('%s=%s', urlencode($cookie['name']), urlencode($cookie['value']))
+            ];
+            if ($cookie['expire']) {
+                $cookie['expire'] = gmdate('D, d M Y H:i:s T', $cookie['expire']);
+            }
+            $attributes = [
+                'expire' => 'Expires=%s',
+                'path' => 'Path=%s',
+                'domain' => 'Domain=%s',
+                'httpOnly' => 'HttpOnly',
+                'secure' => 'Secure',
+            ];
+            foreach ($attributes as $key => $attr) {
+                if ($cookie[$key]) {
+                    $parts[] = sprintf($attr, $cookie[$key]);
+                }
+            }
+            $headers[] = implode('; ', $parts);
+        }
+        return $headers;
+    }
+
+    /**
      * Get the stream for the new response.
      *
      * @param \Cake\Network\Response $response The cake response to extract the body from.

+ 62 - 0
tests/TestCase/Http/ResponseTransformerTest.php

@@ -131,6 +131,68 @@ class ResponseTransformerTest extends TestCase
     }
 
     /**
+     * Test conversion setting cookies
+     *
+     * @return void
+     */
+    public function testToPsrCookieSimple()
+    {
+        $cake = new CakeResponse(['status' => 200]);
+        $cake->cookie([
+            'name' => 'remember_me',
+            'value' => 1
+        ]);
+        $result = ResponseTransformer::toPsr($cake);
+        $this->assertEquals('remember_me=1; Path=/', $result->getHeader('Set-Cookie')[0]);
+    }
+
+    /**
+     * Test conversion setting multiple cookies
+     *
+     * @return void
+     */
+    public function testToPsrCookieMultiple()
+    {
+        $cake = new CakeResponse(['status' => 200]);
+        $cake->cookie([
+            'name' => 'remember_me',
+            'value' => 1
+        ]);
+        $cake->cookie([
+            'name' => 'forever',
+            'value' => 2
+        ]);
+        $result = ResponseTransformer::toPsr($cake);
+        $this->assertEquals('remember_me=1; Path=/', $result->getHeader('Set-Cookie')[0]);
+        $this->assertEquals('forever=2; Path=/', $result->getHeader('Set-Cookie')[1]);
+    }
+
+    /**
+     * Test conversion setting cookie attributes
+     *
+     * @return void
+     */
+    public function testToPsrCookieAttributes()
+    {
+        $cake = new CakeResponse(['status' => 200]);
+        $cake->cookie([
+            'name' => 'remember me',
+            'value' => '1 1',
+            'path' => '/some/path',
+            'domain' => 'example.com',
+            'expire' => strtotime('2021-01-13 12:30:40'),
+            'secure' => true,
+            'httpOnly' => true,
+        ]);
+        $result = ResponseTransformer::toPsr($cake);
+        $this->assertEquals(
+            'remember+me=1+1; Expires=Wed, 13 Jan 2021 12:30:40 GMT; Path=/some/path; Domain=example.com; HttpOnly; Secure',
+            $result->getHeader('Set-Cookie')[0],
+            'Cookie attributes should exist, and name/value should be encoded'
+        );
+    }
+
+    /**
      * Test conversion setting the content-type.
      *
      * @return void