Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Commit 12117d8

Browse files
committed
Merge branch 'feature/redirect-response' into develop
Close #59
2 parents 6864b29 + f6045df commit 12117d8

File tree

4 files changed

+156
-0
lines changed

4 files changed

+156
-0
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ All notable changes to this project will be documented in this file, in reverse
1414
- [#58](https://github.com/zendframework/zend-diactoros/pull/58) adds
1515
`Zend\Diactoros\Response\EmptyResponse`, a `Zend\Diactoros\Response` extension
1616
for quickly creating empty, read-only responses.
17+
- [#59](https://github.com/zendframework/zend-diactoros/pull/59) adds
18+
`Zend\Diactoros\Response\RedirectResponse`, a `Zend\Diactoros\Response` extension
19+
for quickly creating redirect responses.
1720

1821
### Deprecated
1922

doc/book/custom-responses.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Some standard use cases, however, make this un-wieldy:
1717
- Returning a response containing JSON; in this case, you likely want to provide the data to
1818
seriazlize to JSON, not a stream containing serialized JSON.
1919
- Returning a response with no content; in this case, you don't want to bother with the body at all.
20+
- Returning a redirect response; in this case, you likely just want to specify the target for the
21+
`Location` header, and optionally the status code.
2022

2123
Starting with version 1.1, Diactoros offers several custom response types and factories for
2224
simplifying these common tasks.
@@ -95,6 +97,34 @@ $response = new EmptyResponse(201, [
9597
$response = ( new EmptyResponse(201) )->withHeader('Location', $url);
9698
```
9799

100+
## Redirects
101+
102+
`Zend\Diactoros\Response\RedirectResponse` is a `Zend\Diactoros\Response` extension for producing
103+
redirect responses. The only required argument is a URI, which may be provided as either a string or
104+
`Psr\Http\Message\UriInterface` instance. By default, the status 302 is used, and no other headers
105+
are produced; you may alter these via the additional optional arguments:
106+
107+
```php
108+
class RedirectResponse extends Response
109+
{
110+
public function __construct($uri, $status = 302, array $headers = []);
111+
}
112+
```
113+
114+
Typical usage is:
115+
116+
```php
117+
// 302 redirect:
118+
$response = new RedirectResponse('/user/login');
119+
120+
// 301 redirect:
121+
$response = new RedirectResponse('/user/login', 301);
122+
123+
// using a URI instance (e.g., by altering the request URI instance)
124+
$uri = $request->getUri();
125+
$response = new RedirectResponse($uri->withPath('/login'));
126+
```
127+
98128
## Creating custom responses
99129

100130
PHP allows constructor overloading. What this means is that constructors of extending classes can

src/Response/RedirectResponse.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
/**
3+
* Zend Framework (http://framework.zend.com/)
4+
*
5+
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
6+
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
7+
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
8+
*/
9+
10+
namespace Zend\Diactoros\Response;
11+
12+
use InvalidArgumentException;
13+
use Psr\Http\Message\UriInterface;
14+
use Zend\Diactoros\Response;
15+
use Zend\Diactoros\Stream;
16+
17+
/**
18+
* Produce a redirect response.
19+
*/
20+
class RedirectResponse extends Response
21+
{
22+
/**
23+
* Create a redirect response.
24+
*
25+
* Produces a redirect response with a Location header and the given status
26+
* (302 by default).
27+
*
28+
* Note: this method overwrites the `location` $headers value.
29+
*
30+
* @param string|UriInterface $uri URI for the Location header.
31+
* @param int $status Integer status code for the redirect; 302 by default.
32+
* @param array $headers Array of headers to use at initialization.
33+
*/
34+
public function __construct($uri, $status = 302, array $headers = [])
35+
{
36+
if (! is_string($uri) && ! $uri instanceof UriInterface) {
37+
throw new InvalidArgumentException(sprintf(
38+
'Uri provided to %s MUST be a string or Psr\Http\Message\UriInterface instance; received "%s"',
39+
__CLASS__,
40+
(is_object($uri) ? get_class($uri) : gettype($uri))
41+
));
42+
}
43+
44+
$headers['location'] = [$uri];
45+
parent::__construct('php://temp', $status, $headers);
46+
}
47+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
/**
3+
* Zend Framework (http://framework.zend.com/)
4+
*
5+
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
6+
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
7+
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
8+
*/
9+
10+
namespace ZendTest\Diactoros\Response;
11+
12+
use PHPUnit_Framework_TestCase as TestCase;
13+
use Zend\Diactoros\Response\RedirectResponse;
14+
use Zend\Diactoros\Uri;
15+
16+
class RedirectResponseTest extends TestCase
17+
{
18+
public function testConstructorAcceptsStringUriAndProduces302ResponseWithLocationHeader()
19+
{
20+
$response = new RedirectResponse('/foo/bar');
21+
$this->assertEquals(302, $response->getStatusCode());
22+
$this->assertTrue($response->hasHeader('Location'));
23+
$this->assertEquals('/foo/bar', $response->getHeaderLine('Location'));
24+
}
25+
26+
public function testConstructorAcceptsUriInstanceAndProduces302ResponseWithLocationHeader()
27+
{
28+
$uri = new Uri('https://example.com:10082/foo/bar');
29+
$response = new RedirectResponse($uri);
30+
$this->assertEquals(302, $response->getStatusCode());
31+
$this->assertTrue($response->hasHeader('Location'));
32+
$this->assertEquals((string) $uri, $response->getHeaderLine('Location'));
33+
}
34+
35+
public function testConstructorAllowsSpecifyingAlternateStatusCode()
36+
{
37+
$response = new RedirectResponse('/foo/bar', 301);
38+
$this->assertEquals(301, $response->getStatusCode());
39+
$this->assertTrue($response->hasHeader('Location'));
40+
$this->assertEquals('/foo/bar', $response->getHeaderLine('Location'));
41+
}
42+
43+
public function testConstructorAllowsSpecifyingHeaders()
44+
{
45+
$response = new RedirectResponse('/foo/bar', 302, ['X-Foo' => ['Bar']]);
46+
$this->assertEquals(302, $response->getStatusCode());
47+
$this->assertTrue($response->hasHeader('Location'));
48+
$this->assertEquals('/foo/bar', $response->getHeaderLine('Location'));
49+
$this->assertTrue($response->hasHeader('X-Foo'));
50+
$this->assertEquals('Bar', $response->getHeaderLine('X-Foo'));
51+
}
52+
53+
public function invalidUris()
54+
{
55+
return [
56+
'null' => [ null ],
57+
'false' => [ false ],
58+
'true' => [ true ],
59+
'zero' => [ 0 ],
60+
'int' => [ 1 ],
61+
'zero-float' => [ 0.0 ],
62+
'float' => [ 1.1 ],
63+
'array' => [ [ '/foo/bar' ] ],
64+
'object' => [ (object) [ '/foo/bar' ] ],
65+
];
66+
}
67+
68+
/**
69+
* @dataProvider invalidUris
70+
* @expectedException InvalidArgumentException Uri
71+
*/
72+
public function testConstructorRaisesExceptionOnInvalidUri($uri)
73+
{
74+
$response = new RedirectResponse($uri);
75+
}
76+
}

0 commit comments

Comments
 (0)