Skip to content

Commit 8d43ce5

Browse files
thoresuenertbrendt
andauthored
feat(router): add redirect back response (#1050)
Co-authored-by: Brent Roose <[email protected]>
1 parent 237e501 commit 8d43ce5

File tree

6 files changed

+172
-0
lines changed

6 files changed

+172
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Router\Responses;
6+
7+
use Tempest\Http\Status;
8+
use Tempest\Router\IsResponse;
9+
use Tempest\Router\Request;
10+
use Tempest\Router\Response;
11+
use Tempest\Router\Session\Session;
12+
13+
use function Tempest\get;
14+
15+
final class Back implements Response
16+
{
17+
use IsResponse;
18+
19+
public function __construct(?string $fallback = null)
20+
{
21+
$this->status = Status::FOUND;
22+
$request = get(Request::class);
23+
24+
$url = $request->headers['referer'] ?? $request->getSessionValue(Session::PREVIOUS_URL);
25+
26+
if ($url) {
27+
$this->addHeader('Location', $url);
28+
return;
29+
}
30+
31+
if ($fallback) {
32+
$this->addHeader('Location', $fallback);
33+
return;
34+
}
35+
36+
$this->addHeader('Location', '/');
37+
}
38+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Router\Responses;
6+
7+
use Tempest\Core\Priority;
8+
use Tempest\Http\Method;
9+
use Tempest\Router\HttpMiddleware;
10+
use Tempest\Router\HttpMiddlewareCallable;
11+
use Tempest\Router\Request;
12+
use Tempest\Router\Response;
13+
use Tempest\Router\Session\Session;
14+
15+
#[Priority(Priority::FRAMEWORK)]
16+
final readonly class SetCurrentUrlMiddleware implements HttpMiddleware
17+
{
18+
public function __construct(
19+
private Session $session,
20+
) {}
21+
22+
public function __invoke(Request $request, HttpMiddlewareCallable $next): Response
23+
{
24+
if ($request->method === Method::GET) {
25+
$this->session->setPreviousUrl($request->uri);
26+
}
27+
28+
return $next($request);
29+
}
30+
}

src/Tempest/Router/src/Session/Session.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ final class Session
1616

1717
public const string ORIGINAL_VALUES = 'original_values';
1818

19+
public const string PREVIOUS_URL = '_previous_url';
20+
1921
private array $expiredKeys = [];
2022

2123
public function __construct(
@@ -47,6 +49,16 @@ public function get(string $key, mixed $default = null): mixed
4749
return $value;
4850
}
4951

52+
public function getPreviousUrl(): string
53+
{
54+
return $this->get(self::PREVIOUS_URL, '');
55+
}
56+
57+
public function setPreviousUrl(string $url): void
58+
{
59+
$this->set(self::PREVIOUS_URL, $url);
60+
}
61+
5062
public function consume(string $key, mixed $default = null): mixed
5163
{
5264
$value = $this->get($key, $default);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Tests\Tempest\Fixtures\Controllers;
4+
5+
use Tempest\Router\Get;
6+
use Tempest\Router\Request;
7+
use Tempest\Router\Response;
8+
use Tempest\Router\Responses\Back;
9+
10+
final class RedirectBackTestController
11+
{
12+
#[Get('/test-redirect-back-url')]
13+
public function formAction(Request $request): Response
14+
{
15+
return new Back();
16+
}
17+
}

tests/Integration/Http/FileSessionTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@ public function test_destroy(): void
9494
$this->assertFileDoesNotExist($path);
9595
}
9696

97+
public function test_set_previous_url(): void
98+
{
99+
$session = $this->container->get(Session::class);
100+
$session->setPreviousUrl('http://localhost/previous');
101+
102+
$this->assertEquals('http://localhost/previous', $session->getPreviousUrl());
103+
}
104+
97105
public function test_is_valid(): void
98106
{
99107
$clock = $this->clock('2023-01-01 00:00:00');
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Tempest\Integration\Http\Responses;
6+
7+
use Tempest\Http\Method;
8+
use Tempest\Http\Status;
9+
use Tempest\Router\GenericRequest;
10+
use Tempest\Router\Header;
11+
use Tempest\Router\Request;
12+
use Tempest\Router\Responses\Back;
13+
use Tempest\Router\Session\Session;
14+
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
15+
16+
/**
17+
* @internal
18+
*/
19+
final class BackResponseTest extends FrameworkIntegrationTestCase
20+
{
21+
public function test_back_response(): void
22+
{
23+
$this->bindRequest();
24+
$response = new Back();
25+
26+
$this->assertSame(Status::FOUND, $response->status);
27+
$this->assertEquals(new Header('Location', ['/']), $response->headers['Location']);
28+
$this->assertNotSame(Status::OK, $response->status);
29+
}
30+
31+
public function test_back_response_with_referer(): void
32+
{
33+
$this->bindRequest(referer: $referer = '/referer-test');
34+
35+
$response = new Back();
36+
37+
$this->assertEquals(new Header('Location', [$referer]), $response->headers['Location']);
38+
}
39+
40+
public function test_back_response_with_fallback(): void
41+
{
42+
$this->bindRequest();
43+
44+
$referer = '/test';
45+
$response = new Back($referer);
46+
47+
$this->assertEquals(new Header('Location', [$referer]), $response->headers['Location']);
48+
}
49+
50+
public function test_back_response_for_get_request(): void
51+
{
52+
$this->http
53+
->get('/test-redirect-back-url')
54+
->assertRedirect('/test-redirect-back-url');
55+
}
56+
57+
public function bindRequest(?string $uri = '/', ?string $referer = null): void
58+
{
59+
$headers = $referer ? ['referer' => $referer] : [];
60+
61+
$this->container->singleton(Request::class, new GenericRequest(
62+
method: Method::GET,
63+
uri: $uri,
64+
headers: $headers,
65+
));
66+
}
67+
}

0 commit comments

Comments
 (0)