Added application base url: Redirector now uses URLs instead of relative paths

This commit is contained in:
Igor Scheller 2020-04-07 15:08:49 +02:00 committed by msquare
parent 6b1c22a743
commit 795a0631cb
18 changed files with 229 additions and 86 deletions

View File

@ -23,6 +23,9 @@ return [
// Set to development to enable debugging messages // Set to development to enable debugging messages
'environment' => env('ENVIRONMENT', 'production'), 'environment' => env('ENVIRONMENT', 'production'),
// Application URL and base path to use instead of the auto detected one
'url' => env('APP_URL', null),
// Header links // Header links
// Available link placeholders: %lang% // Available link placeholders: %lang%
'header_items' => [ 'header_items' => [

View File

@ -38,11 +38,11 @@ $route->addGroup(
function (RouteCollector $route) { function (RouteCollector $route) {
// Schedule // Schedule
$route->addGroup( $route->addGroup(
'-schedule', '/schedule',
function (RouteCollector $route) { function (RouteCollector $route) {
$route->get('', 'Admin\\Schedule\\ImportSchedule@index'); $route->get('', 'Admin\\Schedule\\ImportSchedule@index');
$route->post('-load', 'Admin\\Schedule\\ImportSchedule@loadSchedule'); $route->post('/load', 'Admin\\Schedule\\ImportSchedule@loadSchedule');
$route->post('-import', 'Admin\\Schedule\\ImportSchedule@importSchedule'); $route->post('/import', 'Admin\\Schedule\\ImportSchedule@importSchedule');
} }
); );
$route->addGroup( $route->addGroup(

View File

@ -48,7 +48,7 @@ class ImportSchedule extends BaseController
protected $session; protected $session;
/** @var string */ /** @var string */
protected $url = 'admin-schedule'; protected $url = '/admin/schedule';
/** @var GuzzleClient */ /** @var GuzzleClient */
protected $guzzle; protected $guzzle;
@ -520,7 +520,7 @@ class ImportSchedule extends BaseController
/** /**
* @param ScheduleUrl $scheduleUrl * @param ScheduleUrl $scheduleUrl
* @param string[] $events * @param string[] $events
* @return QueryBuilder[]|DatabaseCollection|ScheduleShift[] * @return QueryBuilder[]|DatabaseCollection|Collection|ScheduleShift[]
*/ */
protected function getScheduleShiftsByGuid(ScheduleUrl $scheduleUrl, array $events) protected function getScheduleShiftsByGuid(ScheduleUrl $scheduleUrl, array $events)
{ {
@ -533,7 +533,7 @@ class ImportSchedule extends BaseController
/** /**
* @param ScheduleUrl $scheduleUrl * @param ScheduleUrl $scheduleUrl
* @param string[] $events * @param string[] $events
* @return QueryBuilder[]|DatabaseCollection|ScheduleShift[] * @return QueryBuilder[]|DatabaseCollection|Collection|ScheduleShift[]
*/ */
protected function getScheduleShiftsWhereNotGuid(ScheduleUrl $scheduleUrl, array $events) protected function getScheduleShiftsWhereNotGuid(ScheduleUrl $scheduleUrl, array $events)
{ {

View File

@ -117,7 +117,7 @@ function make_navigation()
'admin_shifts' => 'Create shifts', 'admin_shifts' => 'Create shifts',
'admin_rooms' => 'Rooms', 'admin_rooms' => 'Rooms',
'admin_groups' => 'Grouprights', 'admin_groups' => 'Grouprights',
'admin-schedule' => ['schedule.import', 'schedule.import'], 'admin/schedule' => ['schedule.import', 'schedule.import'],
'admin_log' => 'Log', 'admin_log' => 'Log',
'admin_event_config' => 'Event config', 'admin_event_config' => 'Event config',
]; ];

View File

@ -17,7 +17,7 @@
<div class="row"> <div class="row">
{% block row_content %} {% block row_content %}
<form method="POST" action="{{ url('/admin-schedule-load') }}"> <form method="POST" action="{{ url('/admin/schedule/load') }}">
{{ csrf() }} {{ csrf() }}
<div class="col-md-12"> <div class="col-md-12">

View File

@ -4,7 +4,7 @@
{% block title %}{{ __('schedule.import.load.title') }}{% endblock %} {% block title %}{{ __('schedule.import.load.title') }}{% endblock %}
{% block row_content %} {% block row_content %}
<form method="POST" action="{{ url('/admin-schedule-import') }}"> <form method="POST" action="{{ url('/admin/schedule/import') }}">
{{ csrf() }} {{ csrf() }}
{{ f.hidden('schedule-url', schedule_url) }} {{ f.hidden('schedule-url', schedule_url) }}
{{ f.hidden('shift-type', shift_type) }} {{ f.hidden('shift-type', shift_type) }}

View File

@ -5,9 +5,9 @@ namespace Engelsystem\Controllers;
use Carbon\Carbon; use Carbon\Carbon;
use Engelsystem\Config\Config; use Engelsystem\Config\Config;
use Engelsystem\Helpers\Authenticator; use Engelsystem\Helpers\Authenticator;
use Engelsystem\Http\Redirector;
use Engelsystem\Http\Request; use Engelsystem\Http\Request;
use Engelsystem\Http\Response; use Engelsystem\Http\Response;
use Engelsystem\Http\UrlGeneratorInterface;
use Engelsystem\Models\User\User; use Engelsystem\Models\User\User;
use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface;
@ -21,8 +21,8 @@ class AuthController extends BaseController
/** @var SessionInterface */ /** @var SessionInterface */
protected $session; protected $session;
/** @var UrlGeneratorInterface */ /** @var Redirector */
protected $url; protected $redirect;
/** @var Config */ /** @var Config */
protected $config; protected $config;
@ -39,20 +39,20 @@ class AuthController extends BaseController
/** /**
* @param Response $response * @param Response $response
* @param SessionInterface $session * @param SessionInterface $session
* @param UrlGeneratorInterface $url * @param Redirector $redirect
* @param Config $config * @param Config $config
* @param Authenticator $auth * @param Authenticator $auth
*/ */
public function __construct( public function __construct(
Response $response, Response $response,
SessionInterface $session, SessionInterface $session,
UrlGeneratorInterface $url, Redirector $redirect,
Config $config, Config $config,
Authenticator $auth Authenticator $auth
) { ) {
$this->response = $response; $this->response = $response;
$this->session = $session; $this->session = $session;
$this->url = $url; $this->redirect = $redirect;
$this->config = $config; $this->config = $config;
$this->auth = $auth; $this->auth = $auth;
} }
@ -104,7 +104,7 @@ class AuthController extends BaseController
$user->last_login_at = new Carbon(); $user->last_login_at = new Carbon();
$user->save(['touch' => false]); $user->save(['touch' => false]);
return $this->response->redirectTo($this->config->get('home_site')); return $this->redirect->to($this->config->get('home_site'));
} }
/** /**
@ -114,6 +114,6 @@ class AuthController extends BaseController
{ {
$this->session->invalidate(); $this->session->invalidate();
return $this->response->redirectTo($this->url->to('/')); return $this->redirect->to('/');
} }
} }

View File

@ -10,17 +10,24 @@ class Redirector
/** @var Response */ /** @var Response */
protected $response; protected $response;
/** @var UrlGeneratorInterface */
protected $url;
/** /**
* @param Request $request * @param Request $request
* @param Response $response * @param Response $response
* @param UrlGeneratorInterface $url
*/ */
public function __construct(Request $request, Response $response) public function __construct(Request $request, Response $response, UrlGeneratorInterface $url)
{ {
$this->request = $request; $this->request = $request;
$this->response = $response; $this->response = $response;
$this->url = $url;
} }
/** /**
* Redirects to a path, generating a full URL
*
* @param string $path * @param string $path
* @param int $status * @param int $status
* @param array $headers * @param array $headers
@ -28,7 +35,7 @@ class Redirector
*/ */
public function to(string $path, int $status = 302, array $headers = []): Response public function to(string $path, int $status = 302, array $headers = []): Response
{ {
return $this->response->redirectTo($path, $status, $headers); return $this->response->redirectTo($this->url->to($path), $status, $headers);
} }
/** /**

View File

@ -3,22 +3,26 @@
namespace Engelsystem\Http; namespace Engelsystem\Http;
/** /**
* Provides urls when rewriting on the webserver is enabled. (default) * Provides URLs
* *
* The urls have the form <app url>/<path>?<parameters> * The urls have the form <app url>/<path>?<parameters>
*/ */
class UrlGenerator implements UrlGeneratorInterface class UrlGenerator implements UrlGeneratorInterface
{ {
/** /**
* Create a URL for the given path, using the applications base url if configured
*
* @param string $path * @param string $path
* @param array $parameters * @param array $parameters
* @return string url in the form [app url]/[path]?[parameters] * @return string url in the form [app url]/[path]?[parameters]
*/ */
public function to($path, $parameters = []) public function to(string $path, array $parameters = []): string
{ {
$path = '/' . ltrim($path, '/'); $uri = $path;
$request = app('request');
$uri = $request->getUriForPath($path); if (!$this->isValidUrl($uri)) {
$uri = $this->generateUrl($path);
}
if (!empty($parameters) && is_array($parameters)) { if (!empty($parameters) && is_array($parameters)) {
$parameters = http_build_query($parameters); $parameters = http_build_query($parameters);
@ -27,4 +31,37 @@ class UrlGenerator implements UrlGeneratorInterface
return $uri; return $uri;
} }
/**
* Check if the URL is valid
*
* @param string $path
* @return bool
*/
public function isValidUrl(string $path): bool
{
return preg_match('~^(?:\w+:(//)?|#)~', $path) || filter_var($path, FILTER_VALIDATE_URL) !== false;
}
/**
* Prepend the auto detected or configured app base path and domain
*
* @param $path
* @return string
*/
protected function generateUrl(string $path): string
{
$path = '/' . ltrim($path, '/');
$baseUrl = config('url');
if ($baseUrl) {
$uri = rtrim($baseUrl, '/') . $path;
} else {
/** @var Request $request */
$request = app('request');
$uri = $request->getUriForPath($path);
}
return $uri;
}
} }

View File

@ -12,5 +12,5 @@ interface UrlGeneratorInterface
* @param array $parameters * @param array $parameters
* @return string * @return string
*/ */
public function to($path, $parameters = []); public function to(string $path, array $parameters = []): string;
} }

View File

@ -2,19 +2,19 @@
namespace Engelsystem\Renderer\Twig\Extensions; namespace Engelsystem\Renderer\Twig\Extensions;
use Engelsystem\Http\UrlGenerator; use Engelsystem\Http\UrlGeneratorInterface;
use Twig\Extension\AbstractExtension as TwigExtension; use Twig\Extension\AbstractExtension as TwigExtension;
use Twig\TwigFunction; use Twig\TwigFunction;
class Assets extends TwigExtension class Assets extends TwigExtension
{ {
/** @var UrlGenerator */ /** @var UrlGeneratorInterface */
protected $urlGenerator; protected $urlGenerator;
/** /**
* @param UrlGenerator $urlGenerator * @param UrlGeneratorInterface $urlGenerator
*/ */
public function __construct(UrlGenerator $urlGenerator) public function __construct(UrlGeneratorInterface $urlGenerator)
{ {
$this->urlGenerator = $urlGenerator; $this->urlGenerator = $urlGenerator;
} }

View File

@ -2,19 +2,19 @@
namespace Engelsystem\Renderer\Twig\Extensions; namespace Engelsystem\Renderer\Twig\Extensions;
use Engelsystem\Http\UrlGenerator; use Engelsystem\Http\UrlGeneratorInterface;
use Twig\Extension\AbstractExtension as TwigExtension; use Twig\Extension\AbstractExtension as TwigExtension;
use Twig\TwigFunction; use Twig\TwigFunction;
class Url extends TwigExtension class Url extends TwigExtension
{ {
/** @var UrlGenerator */ /** @var UrlGeneratorInterface */
protected $urlGenerator; protected $urlGenerator;
/** /**
* @param UrlGenerator $urlGenerator * @param UrlGeneratorInterface $urlGenerator
*/ */
public function __construct(UrlGenerator $urlGenerator) public function __construct(UrlGeneratorInterface $urlGenerator)
{ {
$this->urlGenerator = $urlGenerator; $this->urlGenerator = $urlGenerator;
} }

View File

@ -2,17 +2,19 @@
namespace Engelsystem\Test\Unit\Controllers\Admin; namespace Engelsystem\Test\Unit\Controllers\Admin;
use Engelsystem\Config\Config;
use Engelsystem\Controllers\Admin\NewsController; use Engelsystem\Controllers\Admin\NewsController;
use Engelsystem\Helpers\Authenticator; use Engelsystem\Helpers\Authenticator;
use Engelsystem\Http\Exceptions\ValidationException; use Engelsystem\Http\Exceptions\ValidationException;
use Engelsystem\Http\Request; use Engelsystem\Http\Request;
use Engelsystem\Http\Response; use Engelsystem\Http\Response;
use Engelsystem\Http\UrlGenerator;
use Engelsystem\Http\UrlGeneratorInterface;
use Engelsystem\Http\Validation\Validator; use Engelsystem\Http\Validation\Validator;
use Engelsystem\Models\News; use Engelsystem\Models\News;
use Engelsystem\Models\User\User; use Engelsystem\Models\User\User;
use Engelsystem\Test\Unit\HasDatabase; use Engelsystem\Test\Unit\HasDatabase;
use Engelsystem\Test\Unit\TestCase; use Engelsystem\Test\Unit\TestCase;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
@ -161,7 +163,7 @@ class NewsControllerTest extends TestCase
->willReturn($canEditHtml); ->willReturn($canEditHtml);
$this->response->expects($this->once()) $this->response->expects($this->once())
->method('redirectTo') ->method('redirectTo')
->with('/news/' . $id) ->with('http://localhost/news/' . $id)
->willReturn($this->response); ->willReturn($this->response);
/** @var NewsController $controller */ /** @var NewsController $controller */
@ -195,7 +197,7 @@ class NewsControllerTest extends TestCase
]); ]);
$this->response->expects($this->once()) $this->response->expects($this->once())
->method('redirectTo') ->method('redirectTo')
->with('/news') ->with('http://localhost/news')
->willReturn($this->response); ->willReturn($this->response);
/** @var NewsController $controller */ /** @var NewsController $controller */
@ -220,7 +222,8 @@ class NewsControllerTest extends TestCase
parent::setUp(); parent::setUp();
$this->initDatabase(); $this->initDatabase();
$this->request = new Request(); $this->request = Request::create('http://localhost');
$this->app->instance('request', $this->request);
$this->app->instance(Request::class, $this->request); $this->app->instance(Request::class, $this->request);
$this->app->instance(ServerRequestInterface::class, $this->request); $this->app->instance(ServerRequestInterface::class, $this->request);
@ -235,6 +238,10 @@ class NewsControllerTest extends TestCase
$this->auth = $this->createMock(Authenticator::class); $this->auth = $this->createMock(Authenticator::class);
$this->app->instance(Authenticator::class, $this->auth); $this->app->instance(Authenticator::class, $this->auth);
$this->app->bind(UrlGeneratorInterface::class, UrlGenerator::class);
$this->app->instance('config', new Config());
(new News([ (new News([
'title' => 'Foo', 'title' => 'Foo',
'text' => '<b>foo</b>', 'text' => '<b>foo</b>',

View File

@ -7,9 +7,9 @@ use Engelsystem\Config\Config;
use Engelsystem\Controllers\AuthController; use Engelsystem\Controllers\AuthController;
use Engelsystem\Helpers\Authenticator; use Engelsystem\Helpers\Authenticator;
use Engelsystem\Http\Exceptions\ValidationException; use Engelsystem\Http\Exceptions\ValidationException;
use Engelsystem\Http\Redirector;
use Engelsystem\Http\Request; use Engelsystem\Http\Request;
use Engelsystem\Http\Response; use Engelsystem\Http\Response;
use Engelsystem\Http\UrlGeneratorInterface;
use Engelsystem\Http\Validation\Validator; use Engelsystem\Http\Validation\Validator;
use Engelsystem\Models\User\Settings; use Engelsystem\Models\User\Settings;
use Engelsystem\Models\User\User; use Engelsystem\Models\User\User;
@ -35,10 +35,10 @@ class AuthControllerTest extends TestCase
/** @var Response|MockObject $response */ /** @var Response|MockObject $response */
$response = $this->createMock(Response::class); $response = $this->createMock(Response::class);
/** @var SessionInterface|MockObject $session */ /** @var SessionInterface|MockObject $session */
/** @var UrlGeneratorInterface|MockObject $url */ /** @var Redirector|MockObject $redirect */
/** @var Config $config */ /** @var Config $config */
/** @var Authenticator|MockObject $auth */ /** @var Authenticator|MockObject $auth */
list(, $session, $url, $config, $auth) = $this->getMocks(); list(, $session, $redirect, $config, $auth) = $this->getMocks();
$session->expects($this->atLeastOnce()) $session->expects($this->atLeastOnce())
->method('get') ->method('get')
@ -50,7 +50,7 @@ class AuthControllerTest extends TestCase
->with('pages/login') ->with('pages/login')
->willReturn($response); ->willReturn($response);
$controller = new AuthController($response, $session, $url, $config, $auth); $controller = new AuthController($response, $session, $redirect, $config, $auth);
$controller->login(); $controller->login();
} }
@ -64,10 +64,10 @@ class AuthControllerTest extends TestCase
$request = new Request(); $request = new Request();
/** @var Response|MockObject $response */ /** @var Response|MockObject $response */
$response = $this->createMock(Response::class); $response = $this->createMock(Response::class);
/** @var UrlGeneratorInterface|MockObject $url */ /** @var Redirector|MockObject $redirect */
/** @var Config $config */ /** @var Config $config */
/** @var Authenticator|MockObject $auth */ /** @var Authenticator|MockObject $auth */
list(, , $url, $config, $auth) = $this->getMocks(); list(, , $redirect, $config, $auth) = $this->getMocks();
$session = new Session(new MockArraySessionStorage()); $session = new Session(new MockArraySessionStorage());
/** @var Validator|MockObject $validator */ /** @var Validator|MockObject $validator */
$validator = new Validator(); $validator = new Validator();
@ -101,13 +101,13 @@ class AuthControllerTest extends TestCase
$this->assertArraySubset(['errors' => collect(['some.bar.error', 'auth.not-found'])], $data); $this->assertArraySubset(['errors' => collect(['some.bar.error', 'auth.not-found'])], $data);
return $response; return $response;
}); });
$response->expects($this->once()) $redirect->expects($this->once())
->method('redirectTo') ->method('to')
->with('news') ->with('news')
->willReturn($response); ->willReturn($response);
// No credentials // No credentials
$controller = new AuthController($response, $session, $url, $config, $auth); $controller = new AuthController($response, $session, $redirect, $config, $auth);
$controller->setValidator($validator); $controller->setValidator($validator);
try { try {
$controller->postLogin($request); $controller->postLogin($request);
@ -142,23 +142,23 @@ class AuthControllerTest extends TestCase
{ {
/** @var Response $response */ /** @var Response $response */
/** @var SessionInterface|MockObject $session */ /** @var SessionInterface|MockObject $session */
/** @var UrlGeneratorInterface|MockObject $url */ /** @var Redirector|MockObject $redirect */
/** @var Config $config */ /** @var Config $config */
/** @var Authenticator|MockObject $auth */ /** @var Authenticator|MockObject $auth */
list($response, $session, $url, $config, $auth) = $this->getMocks(); list($response, $session, $redirect, $config, $auth) = $this->getMocks();
$session->expects($this->once()) $session->expects($this->once())
->method('invalidate'); ->method('invalidate');
$url->expects($this->once()) $redirect->expects($this->once())
->method('to') ->method('to')
->with('/') ->with('/')
->willReturn('https://foo.bar/'); ->willReturn($response);
$controller = new AuthController($response, $session, $url, $config, $auth); $controller = new AuthController($response, $session, $redirect, $config, $auth);
$return = $controller->logout(); $return = $controller->logout();
$this->assertEquals(['https://foo.bar/'], $return->getHeader('location')); $this->assertEquals($response, $return);
} }
/** /**
@ -169,14 +169,14 @@ class AuthControllerTest extends TestCase
$response = new Response(); $response = new Response();
/** @var SessionInterface|MockObject $session */ /** @var SessionInterface|MockObject $session */
$session = $this->getMockForAbstractClass(SessionInterface::class); $session = $this->getMockForAbstractClass(SessionInterface::class);
/** @var UrlGeneratorInterface|MockObject $url */ /** @var Redirector|MockObject $redirect */
$url = $this->getMockForAbstractClass(UrlGeneratorInterface::class); $redirect = $this->createMock(Redirector::class);
$config = new Config(['home_site' => 'news']); $config = new Config(['home_site' => 'news']);
/** @var Authenticator|MockObject $auth */ /** @var Authenticator|MockObject $auth */
$auth = $this->createMock(Authenticator::class); $auth = $this->createMock(Authenticator::class);
$this->app->instance('session', $session); $this->app->instance('session', $session);
return [$response, $session, $url, $config, $auth]; return [$response, $session, $redirect, $config, $auth];
} }
} }

View File

@ -8,6 +8,8 @@ use Engelsystem\Helpers\Authenticator;
use Engelsystem\Http\Exceptions\ValidationException; use Engelsystem\Http\Exceptions\ValidationException;
use Engelsystem\Http\Request; use Engelsystem\Http\Request;
use Engelsystem\Http\Response; use Engelsystem\Http\Response;
use Engelsystem\Http\UrlGenerator;
use Engelsystem\Http\UrlGeneratorInterface;
use Engelsystem\Http\Validation\Validator; use Engelsystem\Http\Validation\Validator;
use Engelsystem\Models\News; use Engelsystem\Models\News;
use Engelsystem\Models\NewsComment; use Engelsystem\Models\NewsComment;
@ -231,6 +233,7 @@ class NewsControllerTest extends TestCase
$this->initDatabase(); $this->initDatabase();
$this->request = new Request(); $this->request = new Request();
$this->app->instance('request', $this->request);
$this->app->instance(Request::class, $this->request); $this->app->instance(Request::class, $this->request);
$this->app->instance(ServerRequestInterface::class, $this->request); $this->app->instance(ServerRequestInterface::class, $this->request);
@ -247,6 +250,10 @@ class NewsControllerTest extends TestCase
$this->auth = $this->createMock(Authenticator::class); $this->auth = $this->createMock(Authenticator::class);
$this->app->instance(Authenticator::class, $this->auth); $this->app->instance(Authenticator::class, $this->auth);
$this->app->bind(UrlGeneratorInterface::class, UrlGenerator::class);
$this->app->instance('config', new Config());
foreach ($this->data as $news) { foreach ($this->data as $news) {
(new News($news))->save(); (new News($news))->save();
} }

View File

@ -5,6 +5,8 @@ namespace Engelsystem\Test\Unit\Http;
use Engelsystem\Http\Redirector; use Engelsystem\Http\Redirector;
use Engelsystem\Http\Request; use Engelsystem\Http\Request;
use Engelsystem\Http\Response; use Engelsystem\Http\Response;
use Engelsystem\Http\UrlGeneratorInterface;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
class RedirectorTest extends TestCase class RedirectorTest extends TestCase
@ -17,7 +19,9 @@ class RedirectorTest extends TestCase
{ {
$request = new Request(); $request = new Request();
$response = new Response(); $response = new Response();
$redirector = new Redirector($request, $response); $url = $this->getUrlGenerator();
$redirector = new Redirector($request, $response, $url);
$return = $redirector->to('/test'); $return = $redirector->to('/test');
$this->assertEquals(['/test'], $return->getHeader('location')); $this->assertEquals(['/test'], $return->getHeader('location'));
@ -37,17 +41,43 @@ class RedirectorTest extends TestCase
{ {
$request = new Request(); $request = new Request();
$response = new Response(); $response = new Response();
$redirector = new Redirector($request, $response); $url = $this->getUrlGenerator();
$redirector = new Redirector($request, $response, $url);
$return = $redirector->back(); $return = $redirector->back();
$this->assertEquals(['/'], $return->getHeader('location')); $this->assertEquals(['/'], $return->getHeader('location'));
$this->assertEquals(302, $return->getStatusCode()); $this->assertEquals(302, $return->getStatusCode());
$request = $request->withHeader('referer', '/old-page'); $request = $request->withHeader('referer', '/old-page');
$redirector = new Redirector($request, $response); $redirector = new Redirector($request, $response, $url);
$return = $redirector->back(303, ['foo' => 'bar']); $return = $redirector->back(303, ['foo' => 'bar']);
$this->assertEquals(303, $return->getStatusCode()); $this->assertEquals(303, $return->getStatusCode());
$this->assertEquals(['/old-page'], $return->getHeader('location')); $this->assertEquals(['/old-page'], $return->getHeader('location'));
$this->assertEquals(['bar'], $return->getHeader('foo')); $this->assertEquals(['bar'], $return->getHeader('foo'));
} }
/**
* @return UrlGeneratorInterface|MockObject
*/
protected function getUrlGenerator()
{
/** @var UrlGeneratorInterface|MockObject $url */
$url = $this->getMockForAbstractClass(UrlGeneratorInterface::class);
$url->expects($this->atLeastOnce())
->method('to')
->willReturnCallback([$this, 'returnPath']);
return $url;
}
/**
* Returns the provided path
*
* @param string $path
* @return string
*/
public function returnPath(string $path)
{
return $path;
}
} }

View File

@ -2,15 +2,17 @@
namespace Engelsystem\Test\Unit\Http; namespace Engelsystem\Test\Unit\Http;
use Engelsystem\Application; use Engelsystem\Config\Config;
use Engelsystem\Container\Container;
use Engelsystem\Http\Request; use Engelsystem\Http\Request;
use Engelsystem\Http\UrlGenerator; use Engelsystem\Http\UrlGenerator;
use PHPUnit\Framework\TestCase; use Engelsystem\Test\Unit\TestCase;
class UrlGeneratorTest extends TestCase class UrlGeneratorTest extends TestCase
{ {
public function provideLinksTo() /**
* @return array
*/
public function provideLinksTo(): array
{ {
return [ return [
['/foo/path', '/foo/path', 'http://foo.bar/foo/path', [], 'http://foo.bar/foo/path'], ['/foo/path', '/foo/path', 'http://foo.bar/foo/path', [], 'http://foo.bar/foo/path'],
@ -22,6 +24,7 @@ class UrlGeneratorTest extends TestCase
/** /**
* @dataProvider provideLinksTo * @dataProvider provideLinksTo
* @covers \Engelsystem\Http\UrlGenerator::to * @covers \Engelsystem\Http\UrlGenerator::to
* @covers \Engelsystem\Http\UrlGenerator::generateUrl
* *
* @param string $path * @param string $path
* @param string $willReturn * @param string $willReturn
@ -31,21 +34,68 @@ class UrlGeneratorTest extends TestCase
*/ */
public function testTo($urlToPath, $path, $willReturn, $arguments, $expectedUrl) public function testTo($urlToPath, $path, $willReturn, $arguments, $expectedUrl)
{ {
$app = new Container();
$urlGenerator = new UrlGenerator();
Application::setInstance($app);
$request = $this->getMockBuilder(Request::class) $request = $this->getMockBuilder(Request::class)
->getMock(); ->getMock();
$request->expects($this->once()) $request->expects($this->once())
->method('getUriForPath') ->method('getUriForPath')
->with($path) ->with($path)
->willReturn($willReturn); ->willReturn($willReturn);
$this->app->instance('request', $request);
$this->app->instance('config', new Config());
$app->instance('request', $request); $urlGenerator = new UrlGenerator();
$url = $urlGenerator->to($urlToPath, $arguments); $url = $urlGenerator->to($urlToPath, $arguments);
$this->assertEquals($expectedUrl, $url); $this->assertEquals($expectedUrl, $url);
} }
/**
* @covers \Engelsystem\Http\UrlGenerator::to
*/
public function testToWithValidUrl()
{
$url = new UrlGenerator();
$this->app->instance('config', new Config());
$this->assertEquals('https://foo.bar/batz', $url->to('https://foo.bar/batz'));
$this->assertEquals('https://some.url?lorem=ipsum', $url->to('https://some.url', ['lorem' => 'ipsum']));
$this->assertEquals('mailto:foo@bar.batz', $url->to('mailto:foo@bar.batz'));
$this->assertEquals('#some-anchor', $url->to('#some-anchor'));
}
/**
* @covers \Engelsystem\Http\UrlGenerator::to
* @covers \Engelsystem\Http\UrlGenerator::generateUrl
*/
public function testToWithApplicationURL()
{
$this->app->instance('config', new Config(['url' => 'https://foo.bar/base/']));
$url = new UrlGenerator();
$this->assertEquals('https://foo.bar/base/test', $url->to('test'));
$this->assertEquals('https://foo.bar/base/test', $url->to('/test'));
$this->assertEquals('https://foo.bar/base/lorem?ipsum=dolor', $url->to('/lorem', ['ipsum' => 'dolor']));
$this->app->instance('config', new Config(['url' => 'https://foo.bar/base']));
$this->assertEquals('https://foo.bar/base/test', $url->to('test'));
$this->assertEquals('https://foo.bar/base/test', $url->to('/test'));
}
/**
* @covers \Engelsystem\Http\UrlGenerator::isValidUrl
*/
public function testIsValidUrl()
{
$url = new UrlGenerator();
$this->assertTrue($url->isValidUrl('https://foo.bar'));
$this->assertTrue($url->isValidUrl('#foo-bar'));
$this->assertTrue($url->isValidUrl('tel:+123456'));
$this->assertTrue($url->isValidUrl('ftp://foo@bar.batz'));
$this->assertFalse($url->isValidUrl('foo/bar'));
$this->assertFalse($url->isValidUrl('foo/uff://bar'));
$this->assertFalse($url->isValidUrl('lorem/ipsum#dolor'));
}
} }

View File

@ -2,7 +2,7 @@
namespace Engelsystem\Test\Unit\Middleware; namespace Engelsystem\Test\Unit\Middleware;
use Engelsystem\Application; use Engelsystem\Config\Config;
use Engelsystem\Http\Exceptions\HttpException; use Engelsystem\Http\Exceptions\HttpException;
use Engelsystem\Http\Exceptions\ValidationException; use Engelsystem\Http\Exceptions\ValidationException;
use Engelsystem\Http\Psr7ServiceProvider; use Engelsystem\Http\Psr7ServiceProvider;
@ -10,12 +10,13 @@ use Engelsystem\Http\RedirectServiceProvider;
use Engelsystem\Http\Request; use Engelsystem\Http\Request;
use Engelsystem\Http\Response; use Engelsystem\Http\Response;
use Engelsystem\Http\ResponseServiceProvider; use Engelsystem\Http\ResponseServiceProvider;
use Engelsystem\Http\UrlGeneratorServiceProvider;
use Engelsystem\Http\Validation\Validator; use Engelsystem\Http\Validation\Validator;
use Engelsystem\Middleware\ErrorHandler; use Engelsystem\Middleware\ErrorHandler;
use Engelsystem\Test\Unit\Middleware\Stub\ReturnResponseMiddlewareHandler; use Engelsystem\Test\Unit\Middleware\Stub\ReturnResponseMiddlewareHandler;
use Engelsystem\Test\Unit\TestCase;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Server\RequestHandlerInterface;
@ -186,19 +187,20 @@ class ErrorHandlerTest extends TestCase
); );
$request->setSession($session); $request->setSession($session);
/** @var Application $app */ $this->app->instance(Session::class, $session);
$app = app(); $this->app->bind(SessionInterface::class, Session::class);
$app->instance(Session::class, $session); $this->app->instance('request', $request);
$app->bind(SessionInterface::class, Session::class); $this->app->instance('config', new Config());
(new ResponseServiceProvider($app))->register(); (new ResponseServiceProvider($this->app))->register();
(new Psr7ServiceProvider($app))->register(); (new Psr7ServiceProvider($this->app))->register();
(new RedirectServiceProvider($app))->register(); (new RedirectServiceProvider($this->app))->register();
(new UrlGeneratorServiceProvider($this->app))->register();
$errorHandler = new ErrorHandler($twigLoader); $errorHandler = new ErrorHandler($twigLoader);
$return = $errorHandler->process($request, $handler); $return = $errorHandler->process($request, $handler);
$this->assertEquals(302, $return->getStatusCode()); $this->assertEquals(302, $return->getStatusCode());
$this->assertEquals('/', $return->getHeaderLine('location')); $this->assertEquals('http://localhost/', $return->getHeaderLine('location'));
$this->assertEquals([ $this->assertEquals([
'errors' => [ 'errors' => [
'validation' => [ 'validation' => [
@ -214,10 +216,10 @@ class ErrorHandlerTest extends TestCase
], $session->all()); ], $session->all());
$request = $request->withAddedHeader('referer', '/foo/batz'); $request = $request->withAddedHeader('referer', '/foo/batz');
$app->instance(Request::class, $request); $this->app->instance(Request::class, $request);
$return = $errorHandler->process($request, $handler); $return = $errorHandler->process($request, $handler);
$this->assertEquals('/foo/batz', $return->getHeaderLine('location')); $this->assertEquals('http://localhost/foo/batz', $return->getHeaderLine('location'));
} }
/** /**