Skip to content

Commit fb748b6

Browse files
MartinMajordg
authored andcommitted
Presenter::storeRequest() & restoreRequest() are separated into RequestStorage service; restoreRequest() redirects to original URL
1 parent c9e457c commit fb748b6

File tree

7 files changed

+312
-29
lines changed

7 files changed

+312
-29
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.');

src/Application/IRequestStorage.php

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] = array(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
{
@@ -1073,14 +1076,10 @@ protected function handleInvalidLink(InvalidLinkException $e)
10731076
*/
10741077
public function storeRequest($expiration = '+ 10 minutes')
10751078
{
1076-
$session = $this->getSession('Nette.Application/requests');
1077-
do {
1078-
$key = Nette\Utils\Random::generate(5);
1079-
} while (isset($session[$key]));
1080-
1081-
$session[$key] = array($this->getUser()->getId(), $this->request);
1082-
$session->setExpiration($expiration, $key);
1083-
return $key;
1079+
if (!$this->requestStorage) {
1080+
throw new Nette\InvalidStateException('Service IRequestStorage has not been set.');
1081+
}
1082+
return $this->requestStorage->store($this->request, $this->httpRequest->getUrl(), $expiration);
10841083
}
10851084

10861085

@@ -1091,17 +1090,11 @@ public function storeRequest($expiration = '+ 10 minutes')
10911090
*/
10921091
public function restoreRequest($key)
10931092
{
1094-
$session = $this->getSession('Nette.Application/requests');
1095-
if (!isset($session[$key]) || ($session[$key][0] !== NULL && $session[$key][0] !== $this->getUser()->getId())) {
1096-
return;
1093+
if (!$this->requestStorage) {
1094+
throw new Nette\InvalidStateException('Service IRequestStorage has not been set.');
1095+
} elseif ($url = $this->requestStorage->getUrl($key)) {
1096+
$this->redirectUrl($url);
10971097
}
1098-
$request = clone $session[$key][1];
1099-
unset($session[$key]);
1100-
$request->setFlag(Application\Request::RESTORED, TRUE);
1101-
$params = $request->getParameters();
1102-
$params[Http\Session::FLASH_KEY] = $this->getSession()->getFlashId();
1103-
$request->setParameters($params);
1104-
$this->sendResponse(new Responses\ForwardResponse($request));
11051098
}
11061099

11071100

@@ -1298,7 +1291,8 @@ public function getFlashSession()
12981291

12991292

13001293
public function injectPrimary(Nette\DI\Container $context = NULL, Nette\Application\IPresenterFactory $presenterFactory = NULL, Nette\Application\IRouter $router = NULL,
1301-
Http\IRequest $httpRequest, Http\IResponse $httpResponse, Http\Session $session = NULL, Nette\Security\User $user = NULL, ITemplateFactory $templateFactory = NULL)
1294+
Http\IRequest $httpRequest, Http\IResponse $httpResponse, Http\Session $session = NULL, Nette\Security\User $user = NULL, ITemplateFactory $templateFactory = NULL,
1295+
Application\IRequestStorage $requestStorage = NULL)
13021296
{
13031297
if ($this->presenterFactory !== NULL) {
13041298
throw new Nette\InvalidStateException("Method " . __METHOD__ . " is intended for initialization and should not be called more than once.");
@@ -1312,6 +1306,7 @@ public function injectPrimary(Nette\DI\Container $context = NULL, Nette\Applicat
13121306
$this->session = $session;
13131307
$this->user = $user;
13141308
$this->templateFactory = $templateFactory;
1309+
$this->requestStorage = $requestStorage;
13151310
}
13161311

13171312

tests/Application/Presenter.storeRequest().phpt

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,21 +81,18 @@ class MockUser extends Security\User
8181
}
8282
}
8383

84-
class MockHttpRequest extends Http\Request
85-
{
86-
public function __construct() {}
87-
}
88-
8984

9085
$presenter = new TestPresenter();
9186
$presenter->injectPrimary(
9287
NULL,
9388
NULL,
9489
NULL,
95-
new MockHttpRequest,
90+
new Http\Request($url = new Http\UrlScript),
9691
new Http\Response,
9792
$session = new MockSession,
98-
$user = new MockUser
93+
$user = new MockUser,
94+
NULL,
95+
new Application\RequestStorage($session, $user)
9996
);
10097

10198
$section = $session->testSection = new MockSessionSection($session);
@@ -110,4 +107,6 @@ Assert::same($expiration, $section->testExpiration);
110107
Assert::same($key, $section->testExpirationVariables);
111108
Assert::same($key, $section->testedKeyExistence);
112109
Assert::same($key, $section->storedKey);
113-
Assert::same(array($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]);

tests/Application/RequestStorage.phpt

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', array('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)