Response: Added with and withInput methods and back/redirect functions
This commit is contained in:
parent
be39c63f46
commit
89742ecd55
|
@ -26,6 +26,7 @@ return [
|
|||
\Engelsystem\Middleware\RequestHandlerServiceProvider::class,
|
||||
\Engelsystem\Middleware\SessionHandlerServiceProvider::class,
|
||||
\Engelsystem\Http\Validation\ValidationServiceProvider::class,
|
||||
\Engelsystem\Http\RedirectServiceProvider::class,
|
||||
|
||||
// Additional services
|
||||
\Engelsystem\Helpers\VersionServiceProvider::class,
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Engelsystem\Http;
|
||||
|
||||
use Engelsystem\Container\ServiceProvider;
|
||||
|
||||
class RedirectServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register()
|
||||
{
|
||||
$this->app->bind('redirect', Redirector::class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace Engelsystem\Http;
|
||||
|
||||
class Redirector
|
||||
{
|
||||
/** @var Request */
|
||||
protected $request;
|
||||
|
||||
/** @var Response */
|
||||
protected $response;
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
*/
|
||||
public function __construct(Request $request, Response $response)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param int $status
|
||||
* @param array $headers
|
||||
* @return Response
|
||||
*/
|
||||
public function to(string $path, int $status = 302, array $headers = []): Response
|
||||
{
|
||||
return $this->response->redirectTo($path, $status, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $status
|
||||
* @param array $headers
|
||||
* @return Response
|
||||
*/
|
||||
public function back(int $status = 302, array $headers = []): Response
|
||||
{
|
||||
return $this->to($this->getPreviousUrl(), $status, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getPreviousUrl(): string
|
||||
{
|
||||
if ($header = $this->request->getHeader('referer')) {
|
||||
return array_pop($header);
|
||||
}
|
||||
|
||||
return '/';
|
||||
}
|
||||
}
|
|
@ -6,11 +6,17 @@ use Engelsystem\Renderer\Renderer;
|
|||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
|
||||
class Response extends SymfonyResponse implements ResponseInterface
|
||||
{
|
||||
use MessageTrait;
|
||||
|
||||
/**
|
||||
* @var SessionInterface
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/** @var Renderer */
|
||||
protected $renderer;
|
||||
|
||||
|
@ -19,14 +25,18 @@ class Response extends SymfonyResponse implements ResponseInterface
|
|||
* @param int $status
|
||||
* @param array $headers
|
||||
* @param Renderer $renderer
|
||||
* @param SessionInterface $session
|
||||
*/
|
||||
public function __construct(
|
||||
$content = '',
|
||||
int $status = 200,
|
||||
array $headers = [],
|
||||
Renderer $renderer = null
|
||||
Renderer $renderer = null,
|
||||
SessionInterface $session = null
|
||||
) {
|
||||
$this->renderer = $renderer;
|
||||
$this->session = $session;
|
||||
|
||||
parent::__construct($content, $status, $headers);
|
||||
}
|
||||
|
||||
|
@ -155,4 +165,44 @@ class Response extends SymfonyResponse implements ResponseInterface
|
|||
{
|
||||
$this->renderer = $renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a session attribute (which is mutable)
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed|mixed[] $value
|
||||
* @return Response
|
||||
*/
|
||||
public function with(string $key, $value)
|
||||
{
|
||||
if (!$this->session instanceof SessionInterface) {
|
||||
throw new InvalidArgumentException('Session not defined');
|
||||
}
|
||||
|
||||
$data = $this->session->get($key);
|
||||
if (is_array($data) && is_array($value)) {
|
||||
$value = array_merge_recursive($data, $value);
|
||||
}
|
||||
|
||||
$this->session->set($key, $value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets form data to the mutable session
|
||||
*
|
||||
* @param array $input
|
||||
* @return Response
|
||||
*/
|
||||
public function withInput(array $input)
|
||||
{
|
||||
if (!$this->session instanceof SessionInterface) {
|
||||
throw new InvalidArgumentException('Session not defined');
|
||||
}
|
||||
|
||||
$this->session->set('form-data', $input);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,17 +63,11 @@ class ErrorHandler implements MiddlewareInterface
|
|||
} catch (HttpException $e) {
|
||||
$response = $this->createResponse($e->getMessage(), $e->getStatusCode(), $e->getHeaders());
|
||||
} catch (ValidationException $e) {
|
||||
$response = $this->createResponse('', 302, ['Location' => $this->getPreviousUrl($request)]);
|
||||
$response = $this->redirectBack();
|
||||
$response->with('errors', ['validation' => $e->getValidator()->getErrors()]);
|
||||
|
||||
if ($request instanceof Request) {
|
||||
$session = $request->getSession();
|
||||
$errors = array_merge_recursive(
|
||||
$session->get('errors', []),
|
||||
['validation' => $e->getValidator()->getErrors()]
|
||||
);
|
||||
$session->set('errors', $errors);
|
||||
|
||||
$session->set('form-data', Arr::except($request->request->all(), $this->formIgnore));
|
||||
$response->withInput(Arr::except($request->request->all(), $this->formIgnore));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,15 +134,12 @@ class ErrorHandler implements MiddlewareInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @return string
|
||||
* Create a redirect back response
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
protected function getPreviousUrl(ServerRequestInterface $request)
|
||||
protected function redirectBack()
|
||||
{
|
||||
if ($header = $request->getHeader('referer')) {
|
||||
return array_pop($header);
|
||||
}
|
||||
|
||||
return '/';
|
||||
return back();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ use Engelsystem\Application;
|
|||
use Engelsystem\Config\Config;
|
||||
use Engelsystem\Helpers\Authenticator;
|
||||
use Engelsystem\Helpers\Translation\Translator;
|
||||
use Engelsystem\Http\Redirector;
|
||||
use Engelsystem\Http\Request;
|
||||
use Engelsystem\Http\Response;
|
||||
use Engelsystem\Http\UrlGeneratorInterface;
|
||||
|
@ -28,7 +29,7 @@ function app($id = null)
|
|||
/**
|
||||
* @return Authenticator
|
||||
*/
|
||||
function auth()
|
||||
function auth(): Authenticator
|
||||
{
|
||||
return app('authenticator');
|
||||
}
|
||||
|
@ -37,11 +38,24 @@ function auth()
|
|||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function base_path($path = '')
|
||||
function base_path($path = ''): string
|
||||
{
|
||||
return app('path') . (empty($path) ? '' : DIRECTORY_SEPARATOR . $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $status
|
||||
* @param array $headers
|
||||
* @return Response
|
||||
*/
|
||||
function back($status = 302, $headers = []): Response
|
||||
{
|
||||
/** @var Redirector $redirect */
|
||||
$redirect = app('redirect');
|
||||
|
||||
return $redirect->back($status, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set config values
|
||||
*
|
||||
|
@ -70,11 +84,25 @@ function config($key = null, $default = null)
|
|||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function config_path($path = '')
|
||||
function config_path($path = ''): string
|
||||
{
|
||||
return app('path.config') . (empty($path) ? '' : DIRECTORY_SEPARATOR . $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param int $status
|
||||
* @param array $headers
|
||||
* @return Response
|
||||
*/
|
||||
function redirect(string $path, $status = 302, $headers = []): Response
|
||||
{
|
||||
/** @var Redirector $redirect */
|
||||
$redirect = app('redirect');
|
||||
|
||||
return $redirect->to($path, $status, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
|
@ -97,7 +125,7 @@ function request($key = null, $default = null)
|
|||
* @param array $headers
|
||||
* @return Response
|
||||
*/
|
||||
function response($content = '', $status = 200, $headers = [])
|
||||
function response($content = '', $status = 200, $headers = []): Response
|
||||
{
|
||||
/** @var Response $response */
|
||||
$response = app('psr7.response');
|
||||
|
@ -155,7 +183,7 @@ function trans($key = null, $replace = [])
|
|||
* @param array $replace
|
||||
* @return string
|
||||
*/
|
||||
function __($key, $replace = [])
|
||||
function __($key, $replace = []): string
|
||||
{
|
||||
/** @var Translator $translator */
|
||||
$translator = app('translator');
|
||||
|
@ -172,7 +200,7 @@ function __($key, $replace = [])
|
|||
* @param array $replace
|
||||
* @return string
|
||||
*/
|
||||
function _e($key, $keyPlural, $number, $replace = [])
|
||||
function _e($key, $keyPlural, $number, $replace = []): string
|
||||
{
|
||||
/** @var Translator $translator */
|
||||
$translator = app('translator');
|
||||
|
|
|
@ -7,6 +7,7 @@ use Engelsystem\Config\Config;
|
|||
use Engelsystem\Container\Container;
|
||||
use Engelsystem\Helpers\Authenticator;
|
||||
use Engelsystem\Helpers\Translation\Translator;
|
||||
use Engelsystem\Http\Redirector;
|
||||
use Engelsystem\Http\Request;
|
||||
use Engelsystem\Http\Response;
|
||||
use Engelsystem\Http\UrlGeneratorInterface;
|
||||
|
@ -98,6 +99,29 @@ class HelpersTest extends TestCase
|
|||
$this->assertEquals(['user' => 'FooBar'], config('mail'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \back
|
||||
*/
|
||||
public function testBack()
|
||||
{
|
||||
$response = new Response();
|
||||
/** @var Redirector|MockObject $redirect */
|
||||
$redirect = $this->createMock(Redirector::class);
|
||||
$redirect->expects($this->exactly(2))
|
||||
->method('back')
|
||||
->withConsecutive([302, []], [303, ['test' => 'ing']])
|
||||
->willReturn($response);
|
||||
|
||||
$app = new Application();
|
||||
$app->instance('redirect', $redirect);
|
||||
|
||||
$return = back();
|
||||
$this->assertEquals($response, $return);
|
||||
|
||||
$return = back(303, ['test' => 'ing']);
|
||||
$this->assertEquals($response, $return);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \config_path
|
||||
*/
|
||||
|
@ -117,6 +141,29 @@ class HelpersTest extends TestCase
|
|||
$this->assertEquals('/foo/conf/bar.php', config_path('bar.php'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \redirect
|
||||
*/
|
||||
public function testRedirect()
|
||||
{
|
||||
$response = new Response();
|
||||
/** @var Redirector|MockObject $redirect */
|
||||
$redirect = $this->createMock(Redirector::class);
|
||||
$redirect->expects($this->exactly(2))
|
||||
->method('to')
|
||||
->withConsecutive(['/lorem', 302, []], ['/ipsum', 303, ['test' => 'er']])
|
||||
->willReturn($response);
|
||||
|
||||
$app = new Application();
|
||||
$app->instance('redirect', $redirect);
|
||||
|
||||
$return = redirect('/lorem');
|
||||
$this->assertEquals($response, $return);
|
||||
|
||||
$return = redirect('/ipsum', 303, ['test' => 'er']);
|
||||
$this->assertEquals($response, $return);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \request
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Http;
|
||||
|
||||
use Engelsystem\Application;
|
||||
use Engelsystem\Http\RedirectServiceProvider;
|
||||
use Engelsystem\Test\Unit\ServiceProviderTest;
|
||||
|
||||
class RedirectServiceProviderTest extends ServiceProviderTest
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Http\RedirectServiceProvider::register
|
||||
*/
|
||||
public function testRegister()
|
||||
{
|
||||
$app = new Application();
|
||||
|
||||
$serviceProvider = new RedirectServiceProvider($app);
|
||||
$serviceProvider->register();
|
||||
|
||||
$this->assertTrue($app->has('redirect'));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Http;
|
||||
|
||||
use Engelsystem\Http\Redirector;
|
||||
use Engelsystem\Http\Request;
|
||||
use Engelsystem\Http\Response;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class RedirectorTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Http\Redirector::__construct
|
||||
* @covers \Engelsystem\Http\Redirector::to
|
||||
*/
|
||||
public function testTo()
|
||||
{
|
||||
$request = new Request();
|
||||
$response = new Response();
|
||||
$redirector = new Redirector($request, $response);
|
||||
|
||||
$return = $redirector->to('/test');
|
||||
$this->assertEquals(['/test'], $return->getHeader('location'));
|
||||
$this->assertEquals(302, $return->getStatusCode());
|
||||
|
||||
$return = $redirector->to('/foo', 303, ['test' => 'data']);
|
||||
$this->assertEquals(['/foo'], $return->getHeader('location'));
|
||||
$this->assertEquals(303, $return->getStatusCode());
|
||||
$this->assertEquals(['data'], $return->getHeader('test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Http\Redirector::back
|
||||
* @covers \Engelsystem\Http\Redirector::getPreviousUrl
|
||||
*/
|
||||
public function testBack()
|
||||
{
|
||||
$request = new Request();
|
||||
$response = new Response();
|
||||
$redirector = new Redirector($request, $response);
|
||||
|
||||
$return = $redirector->back();
|
||||
$this->assertEquals(['/'], $return->getHeader('location'));
|
||||
$this->assertEquals(302, $return->getStatusCode());
|
||||
|
||||
$request = $request->withHeader('referer', '/old-page');
|
||||
$redirector = new Redirector($request, $response);
|
||||
$return = $redirector->back(303, ['foo' => 'bar']);
|
||||
$this->assertEquals(303, $return->getStatusCode());
|
||||
$this->assertEquals(['/old-page'], $return->getHeader('location'));
|
||||
$this->assertEquals(['bar'], $return->getHeader('foo'));
|
||||
}
|
||||
}
|
|
@ -10,6 +10,8 @@ use PHPUnit\Framework\MockObject\MockObject;
|
|||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||
|
||||
class ResponseTest extends TestCase
|
||||
{
|
||||
|
@ -116,4 +118,59 @@ class ResponseTest extends TestCase
|
|||
$newResponse->getHeaders()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Http\Response::with
|
||||
*/
|
||||
public function testWith()
|
||||
{
|
||||
$session = new Session(new MockArraySessionStorage());
|
||||
$response = new Response('', 200, [], null, $session);
|
||||
|
||||
$response->with('foo', 'bar');
|
||||
$this->assertEquals('bar', $session->get('foo'));
|
||||
|
||||
$response->with('lorem', ['ipsum', 'dolor' => ['foo' => 'bar']]);
|
||||
$this->assertEquals(['ipsum', 'dolor' => ['foo' => 'bar']], $session->get('lorem'));
|
||||
|
||||
$response->with('lorem', ['dolor' => ['test' => 'er']]);
|
||||
$this->assertEquals(['ipsum', 'dolor' => ['foo' => 'bar', 'test' => 'er']], $session->get('lorem'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Http\Response::with
|
||||
*/
|
||||
public function testWithNoSession()
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
|
||||
$response = new Response();
|
||||
$response->with('foo', 'bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Http\Response::withInput
|
||||
*/
|
||||
public function testWithInput()
|
||||
{
|
||||
$session = new Session(new MockArraySessionStorage());
|
||||
$response = new Response('', 200, [], null, $session);
|
||||
|
||||
$response->withInput(['some' => 'value']);
|
||||
$this->assertEquals(['some' => 'value'], $session->get('form-data'));
|
||||
|
||||
$response->withInput(['lorem' => 'ipsum']);
|
||||
$this->assertEquals(['lorem' => 'ipsum'], $session->get('form-data'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Http\Response::withInput
|
||||
*/
|
||||
public function testWithInputNoSession()
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
|
||||
$response = new Response();
|
||||
$response->withInput(['some' => 'value']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use Engelsystem\Application;
|
|||
use Engelsystem\Http\Exceptions\HttpException;
|
||||
use Engelsystem\Http\Exceptions\ValidationException;
|
||||
use Engelsystem\Http\Psr7ServiceProvider;
|
||||
use Engelsystem\Http\RedirectServiceProvider;
|
||||
use Engelsystem\Http\Request;
|
||||
use Engelsystem\Http\Response;
|
||||
use Engelsystem\Http\ResponseServiceProvider;
|
||||
|
@ -18,6 +19,7 @@ use Psr\Http\Message\ResponseInterface;
|
|||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||
use Twig\Loader\LoaderInterface as TwigLoader;
|
||||
|
||||
|
@ -155,7 +157,7 @@ class ErrorHandlerTest extends TestCase
|
|||
|
||||
/**
|
||||
* @covers \Engelsystem\Middleware\ErrorHandler::process
|
||||
* @covers \Engelsystem\Middleware\ErrorHandler::getPreviousUrl
|
||||
* @covers \Engelsystem\Middleware\ErrorHandler::redirectBack
|
||||
*/
|
||||
public function testProcessValidationException()
|
||||
{
|
||||
|
@ -185,11 +187,13 @@ class ErrorHandlerTest extends TestCase
|
|||
|
||||
/** @var Application $app */
|
||||
$app = app();
|
||||
$app->instance(Session::class, $session);
|
||||
$app->bind(SessionInterface::class, Session::class);
|
||||
(new ResponseServiceProvider($app))->register();
|
||||
(new Psr7ServiceProvider($app))->register();
|
||||
(new RedirectServiceProvider($app))->register();
|
||||
|
||||
$errorHandler = new ErrorHandler($twigLoader);
|
||||
|
||||
$return = $errorHandler->process($request, $handler);
|
||||
|
||||
$this->assertEquals(302, $return->getStatusCode());
|
||||
|
@ -209,6 +213,7 @@ class ErrorHandlerTest extends TestCase
|
|||
], $session->all());
|
||||
|
||||
$request = $request->withAddedHeader('referer', '/foo/batz');
|
||||
$app->instance(Request::class, $request);
|
||||
$return = $errorHandler->process($request, $handler);
|
||||
|
||||
$this->assertEquals('/foo/batz', $return->getHeaderLine('location'));
|
||||
|
|
Loading…
Reference in New Issue