Skip to content

Commit 20e7595

Browse files
MartinMajordg
authored andcommitted
Presenter::storeRequest() & restoreRequest() are separated into RequestStorage service; restoreRequest() redirects to original URL
Conflicts: src/Application/UI/Presenter.php tests/Application/Presenter.storeRequest().phpt
1 parent 2f4f606 commit 20e7595

File tree

7 files changed

+312
-24
lines changed

7 files changed

+312
-24
lines changed

src/Application/Application.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,17 @@ class Application extends Nette\Object
6767
/** @var IRouter */
6868
private $router;
6969

70+
/** @var IRequestStorage */
71+
private $requestStorage;
7072

71-
public function __construct(IPresenterFactory $presenterFactory, IRouter $router, Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse)
73+
74+
public function __construct(IPresenterFactory $presenterFactory, IRouter $router, Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse, IRequestStorage $requestStorage)
7275
{
7376
$this->httpRequest = $httpRequest;
7477
$this->httpResponse = $httpResponse;
7578
$this->presenterFactory = $presenterFactory;
7679
$this->router = $router;
80+
$this->requestStorage = $requestStorage;
7781
}
7882

7983

@@ -111,7 +115,7 @@ public function run()
111115
*/
112116
public function createInitialRequest()
113117
{
114-
$request = $this->router->match($this->httpRequest);
118+
$request = $this->requestStorage->restore() ?: $this->router->match($this->httpRequest);
115119

116120
if (!$request instanceof Request) {
117121
throw new BadRequestException('No route for HTTP request.');
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Nette Framework (http://nette.org)
5+
* Copyright (c) 2004 David Grudl (http://davidgrudl.com)
6+
*/
7+
8+
namespace Nette\Application;
9+
10+
use Nette;
11+
12+
13+
/**
14+
* Interface for storing and restoring requests.
15+
*
16+
* @author Martin Major
17+
*/
18+
interface IRequestStorage
19+
{
20+
21+
/**
22+
* Stores request and returns key.
23+
* @return string key
24+
*/
25+
function store(Request $request, Nette\Http\Url $url);
26+
27+
/**
28+
* Restores original URL.
29+
* @param string key
30+
* @return string|NULL
31+
*/
32+
function getUrl($key);
33+
34+
/**
35+
* Returns stored request.
36+
* @return Request|NULL
37+
*/
38+
function restore();
39+
40+
}

src/Application/RequestStorage.php

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Nette Framework (http://nette.org)
5+
* Copyright (c) 2004 David Grudl (http://davidgrudl.com)
6+
*/
7+
8+
namespace Nette\Application;
9+
10+
use Nette,
11+
Nette\Http;
12+
13+
14+
/**
15+
* Service for storing and restoring requests from session.
16+
*
17+
* @author Martin Major
18+
*/
19+
class RequestStorage extends Nette\Object implements IRequestStorage
20+
{
21+
/** @var Http\Session */
22+
private $session;
23+
24+
/** @var Nette\Security\User */
25+
private $user;
26+
27+
28+
public function __construct(Http\Session $session, Nette\Security\User $user)
29+
{
30+
$this->session = $session;
31+
$this->user = $user;
32+
}
33+
34+
35+
/**
36+
* Stores request and returns key.
37+
* @return string key
38+
*/
39+
public function store(Request $request, Http\Url $url, $expiration = '10 minutes')
40+
{
41+
$session = $this->session->getSection(__CLASS__);
42+
do {
43+
$key = Nette\Utils\Random::generate(5);
44+
} while (isset($session[$key]));
45+
46+
$session[$key] = [clone $request, clone $url, $this->user->getId()];
47+
$session->setExpiration($expiration, $key);
48+
return $key;
49+
}
50+
51+
52+
/**
53+
* Restores original URL.
54+
* @param string key
55+
* @return string|NULL
56+
*/
57+
public function getUrl($key)
58+
{
59+
list($request, $url, $user) = $this->session->getSection(__CLASS__)->$key;
60+
if (!$request || !$url || ($user !== NULL && $user !== $this->user->getId())) {
61+
return;
62+
}
63+
64+
$request->setFlag($request::RESTORED, TRUE);
65+
$this->session->getFlashSection(__CLASS__)->request = $request;
66+
67+
$url->setQueryParameter(Http\Session::FLASH_KEY, $this->session->getFlashId());
68+
return (string) $url;
69+
}
70+
71+
72+
/**
73+
* Returns stored request.
74+
* @return Request|NULL
75+
*/
76+
public function restore()
77+
{
78+
return $this->session->getFlashId()
79+
? $this->session->getFlashSection(__CLASS__)->request
80+
: NULL;
81+
}
82+
83+
}

src/Application/UI/Presenter.php

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ abstract class Presenter extends Control implements Application\IPresenter
126126
/** @var ITemplateFactory */
127127
private $templateFactory;
128128

129+
/** @var Application\IRequestStorage */
130+
private $requestStorage;
131+
129132

130133
public function __construct()
131134
{
@@ -1077,14 +1080,10 @@ protected function handleInvalidLink(InvalidLinkException $e)
10771080
*/
10781081
public function storeRequest($expiration = '+ 10 minutes')
10791082
{
1080-
$session = $this->getSession('Nette.Application/requests');
1081-
do {
1082-
$key = Nette\Utils\Random::generate(5);
1083-
} while (isset($session[$key]));
1084-
1085-
$session[$key] = [$this->getUser()->getId(), $this->request];
1086-
$session->setExpiration($expiration, $key);
1087-
return $key;
1083+
if (!$this->requestStorage) {
1084+
throw new Nette\InvalidStateException('Service IRequestStorage has not been set.');
1085+
}
1086+
return $this->requestStorage->store($this->request, $this->httpRequest->getUrl(), $expiration);
10881087
}
10891088

10901089

@@ -1095,17 +1094,11 @@ public function storeRequest($expiration = '+ 10 minutes')
10951094
*/
10961095
public function restoreRequest($key)
10971096
{
1098-
$session = $this->getSession('Nette.Application/requests');
1099-
if (!isset($session[$key]) || ($session[$key][0] !== NULL && $session[$key][0] !== $this->getUser()->getId())) {
1100-
return;
1097+
if (!$this->requestStorage) {
1098+
throw new Nette\InvalidStateException('Service IRequestStorage has not been set.');
1099+
} elseif ($url = $this->requestStorage->getUrl($key)) {
1100+
$this->redirectUrl($url);
11011101
}
1102-
$request = clone $session[$key][1];
1103-
unset($session[$key]);
1104-
$request->setFlag(Application\Request::RESTORED, TRUE);
1105-
$params = $request->getParameters();
1106-
$params[Http\Session::FLASH_KEY] = $this->getSession()->getFlashId();
1107-
$request->setParameters($params);
1108-
$this->sendResponse(new Responses\ForwardResponse($request));
11091102
}
11101103

11111104

@@ -1303,7 +1296,8 @@ public function getFlashSession()
13031296

13041297

13051298
public function injectPrimary(Nette\DI\Container $context = NULL, Application\IPresenterFactory $presenterFactory = NULL, Application\IRouter $router = NULL,
1306-
Http\IRequest $httpRequest, Http\IResponse $httpResponse, Http\Session $session = NULL, Nette\Security\User $user = NULL, ITemplateFactory $templateFactory = NULL)
1299+
Http\IRequest $httpRequest, Http\IResponse $httpResponse, Http\Session $session = NULL, Nette\Security\User $user = NULL, ITemplateFactory $templateFactory = NULL,
1300+
Application\IRequestStorage $requestStorage = NULL)
13071301
{
13081302
if ($this->presenterFactory !== NULL) {
13091303
throw new Nette\InvalidStateException("Method " . __METHOD__ . " is intended for initialization and should not be called more than once.");
@@ -1317,6 +1311,7 @@ public function injectPrimary(Nette\DI\Container $context = NULL, Application\IP
13171311
$this->session = $session;
13181312
$this->user = $user;
13191313
$this->templateFactory = $templateFactory;
1314+
$this->requestStorage = $requestStorage;
13201315
}
13211316

13221317

tests/Application/Presenter.storeRequest().phpt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,12 @@ $presenter->injectPrimary(
8787
NULL,
8888
NULL,
8989
new Application\Routers\SimpleRouter,
90-
new Http\Request(new Http\UrlScript),
90+
new Http\Request($url = new Http\UrlScript),
9191
new Http\Response,
9292
$session = new MockSession,
93-
$user = new MockUser
93+
$user = new MockUser,
94+
NULL,
95+
new Application\RequestStorage($session, $user)
9496
);
9597

9698
$section = $session->testSection = new MockSessionSection($session);
@@ -105,4 +107,6 @@ Assert::same($expiration, $section->testExpiration);
105107
Assert::same($key, $section->testExpirationVariables);
106108
Assert::same($key, $section->testedKeyExistence);
107109
Assert::same($key, $section->storedKey);
108-
Assert::same([$user->getId(), $applicationRequest], $section->storedValue);
110+
Assert::equal($applicationRequest, $section->storedValue[0]);
111+
Assert::equal($url, $section->storedValue[1]);
112+
Assert::same($user->getId(), $section->storedValue[2]);
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
/**
4+
* Test: Nette\Application\RequestStorage
5+
*
6+
* @author Martin Major
7+
*/
8+
9+
use Nette\Http,
10+
Nette\Application,
11+
Nette\Security\Identity,
12+
Tester\Assert;
13+
14+
15+
require __DIR__ . '/../bootstrap.php';
16+
require __DIR__ . '/mocks.php';
17+
18+
19+
$url = 'https://www.example.com/my/address?with=parameter';
20+
21+
$httpRequest = new Http\Request(new Http\UrlScript($url));
22+
23+
$session = new MockSession($httpRequest, new Http\Response);
24+
$session->mockSection = new MockSessionSection;
25+
$session->mockFlashSection = new MockSessionSection;
26+
27+
$user = new MockUser;
28+
$user->mockIdentity = new Identity(42);
29+
30+
$requestStorage = new Application\RequestStorage($session, $user);
31+
32+
$applicationRequest = new Application\Request('Presenter', 'action', ['param' => 'value']);
33+
34+
$key = $requestStorage->store($applicationRequest, $httpRequest->getUrl());
35+
36+
37+
// restore key
38+
Assert::null($requestStorage->getUrl('bad_key'));
39+
40+
$redirect = $requestStorage->getUrl($key);
41+
Assert::same($url . '&_fid=x', $redirect);
42+
43+
44+
// redirect to original URL
45+
$httpRequest = new Http\Request(new Http\UrlScript($redirect));
46+
47+
$application = new Application\Application(new MockPresenterFactory, new MockRouter, $httpRequest, new MockResponse, $requestStorage);
48+
49+
$applicationRequest->setFlag(Application\Request::RESTORED);
50+
Assert::equal($applicationRequest, $application->createInitialRequest());

0 commit comments

Comments
 (0)