Skip to content

Commit

Permalink
Presenter::storeRequest() & restoreRequest() are separated into Reque…
Browse files Browse the repository at this point in the history
…stStorage service; restoreRequest() redirects to original URL

Conflicts:
	src/Application/UI/Presenter.php
	tests/Application/Presenter.storeRequest().phpt
  • Loading branch information
MartinMajor authored and dg committed May 25, 2015
1 parent 2f4f606 commit 20e7595
Show file tree
Hide file tree
Showing 7 changed files with 312 additions and 24 deletions.
8 changes: 6 additions & 2 deletions src/Application/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,17 @@ class Application extends Nette\Object
/** @var IRouter */
private $router;

/** @var IRequestStorage */
private $requestStorage;

public function __construct(IPresenterFactory $presenterFactory, IRouter $router, Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse)

public function __construct(IPresenterFactory $presenterFactory, IRouter $router, Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse, IRequestStorage $requestStorage)
{
$this->httpRequest = $httpRequest;
$this->httpResponse = $httpResponse;
$this->presenterFactory = $presenterFactory;
$this->router = $router;
$this->requestStorage = $requestStorage;
}


Expand Down Expand Up @@ -111,7 +115,7 @@ public function run()
*/
public function createInitialRequest()
{
$request = $this->router->match($this->httpRequest);
$request = $this->requestStorage->restore() ?: $this->router->match($this->httpRequest);

if (!$request instanceof Request) {
throw new BadRequestException('No route for HTTP request.');
Expand Down
40 changes: 40 additions & 0 deletions src/Application/IRequestStorage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

/**
* This file is part of the Nette Framework (http://nette.org)
* Copyright (c) 2004 David Grudl (http://davidgrudl.com)
*/

namespace Nette\Application;

use Nette;


/**
* Interface for storing and restoring requests.
*
* @author Martin Major
*/
interface IRequestStorage
{

/**
* Stores request and returns key.
* @return string key
*/
function store(Request $request, Nette\Http\Url $url);

/**
* Restores original URL.
* @param string key
* @return string|NULL
*/
function getUrl($key);

/**
* Returns stored request.
* @return Request|NULL
*/
function restore();

}
83 changes: 83 additions & 0 deletions src/Application/RequestStorage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

/**
* This file is part of the Nette Framework (http://nette.org)
* Copyright (c) 2004 David Grudl (http://davidgrudl.com)
*/

namespace Nette\Application;

use Nette,
Nette\Http;


/**
* Service for storing and restoring requests from session.
*
* @author Martin Major
*/
class RequestStorage extends Nette\Object implements IRequestStorage
{
/** @var Http\Session */
private $session;

/** @var Nette\Security\User */
private $user;


public function __construct(Http\Session $session, Nette\Security\User $user)
{
$this->session = $session;
$this->user = $user;
}


/**
* Stores request and returns key.
* @return string key
*/
public function store(Request $request, Http\Url $url, $expiration = '10 minutes')
{
$session = $this->session->getSection(__CLASS__);
do {
$key = Nette\Utils\Random::generate(5);
} while (isset($session[$key]));

$session[$key] = [clone $request, clone $url, $this->user->getId()];
$session->setExpiration($expiration, $key);
return $key;
}


/**
* Restores original URL.
* @param string key
* @return string|NULL
*/
public function getUrl($key)
{
list($request, $url, $user) = $this->session->getSection(__CLASS__)->$key;
if (!$request || !$url || ($user !== NULL && $user !== $this->user->getId())) {
return;
}

$request->setFlag($request::RESTORED, TRUE);
$this->session->getFlashSection(__CLASS__)->request = $request;

$url->setQueryParameter(Http\Session::FLASH_KEY, $this->session->getFlashId());
return (string) $url;
}


/**
* Returns stored request.
* @return Request|NULL
*/
public function restore()
{
return $this->session->getFlashId()
? $this->session->getFlashSection(__CLASS__)->request
: NULL;
}

}
33 changes: 14 additions & 19 deletions src/Application/UI/Presenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ abstract class Presenter extends Control implements Application\IPresenter
/** @var ITemplateFactory */
private $templateFactory;

/** @var Application\IRequestStorage */
private $requestStorage;


public function __construct()
{
Expand Down Expand Up @@ -1077,14 +1080,10 @@ protected function handleInvalidLink(InvalidLinkException $e)
*/
public function storeRequest($expiration = '+ 10 minutes')
{
$session = $this->getSession('Nette.Application/requests');
do {
$key = Nette\Utils\Random::generate(5);
} while (isset($session[$key]));

$session[$key] = [$this->getUser()->getId(), $this->request];
$session->setExpiration($expiration, $key);
return $key;
if (!$this->requestStorage) {
throw new Nette\InvalidStateException('Service IRequestStorage has not been set.');
}
return $this->requestStorage->store($this->request, $this->httpRequest->getUrl(), $expiration);
}


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


Expand Down Expand Up @@ -1303,7 +1296,8 @@ public function getFlashSession()


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


Expand Down
10 changes: 7 additions & 3 deletions tests/Application/Presenter.storeRequest().phpt
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,12 @@ $presenter->injectPrimary(
NULL,
NULL,
new Application\Routers\SimpleRouter,
new Http\Request(new Http\UrlScript),
new Http\Request($url = new Http\UrlScript),
new Http\Response,
$session = new MockSession,
$user = new MockUser
$user = new MockUser,
NULL,
new Application\RequestStorage($session, $user)
);

$section = $session->testSection = new MockSessionSection($session);
Expand All @@ -105,4 +107,6 @@ Assert::same($expiration, $section->testExpiration);
Assert::same($key, $section->testExpirationVariables);
Assert::same($key, $section->testedKeyExistence);
Assert::same($key, $section->storedKey);
Assert::same([$user->getId(), $applicationRequest], $section->storedValue);
Assert::equal($applicationRequest, $section->storedValue[0]);
Assert::equal($url, $section->storedValue[1]);
Assert::same($user->getId(), $section->storedValue[2]);
50 changes: 50 additions & 0 deletions tests/Application/RequestStorage.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

/**
* Test: Nette\Application\RequestStorage
*
* @author Martin Major
*/

use Nette\Http,
Nette\Application,
Nette\Security\Identity,
Tester\Assert;


require __DIR__ . '/../bootstrap.php';
require __DIR__ . '/mocks.php';


$url = 'https://www.example.com/my/address?with=parameter';

$httpRequest = new Http\Request(new Http\UrlScript($url));

$session = new MockSession($httpRequest, new Http\Response);
$session->mockSection = new MockSessionSection;
$session->mockFlashSection = new MockSessionSection;

$user = new MockUser;
$user->mockIdentity = new Identity(42);

$requestStorage = new Application\RequestStorage($session, $user);

$applicationRequest = new Application\Request('Presenter', 'action', ['param' => 'value']);

$key = $requestStorage->store($applicationRequest, $httpRequest->getUrl());


// restore key
Assert::null($requestStorage->getUrl('bad_key'));

$redirect = $requestStorage->getUrl($key);
Assert::same($url . '&_fid=x', $redirect);


// redirect to original URL
$httpRequest = new Http\Request(new Http\UrlScript($redirect));

$application = new Application\Application(new MockPresenterFactory, new MockRouter, $httpRequest, new MockResponse, $requestStorage);

$applicationRequest->setFlag(Application\Request::RESTORED);
Assert::equal($applicationRequest, $application->createInitialRequest());
Loading

0 comments on commit 20e7595

Please sign in to comment.