From 795a0631cb907f29fd385d150ee5b40192bf2a14 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 7 Apr 2020 15:08:49 +0200 Subject: [PATCH] Added application base url: Redirector now uses URLs instead of relative paths --- config/config.default.php | 3 + config/routes.php | 6 +- includes/pages/schedule/ImportSchedule.php | 6 +- includes/sys_menu.php | 2 +- resources/views/admin/schedule/index.twig | 2 +- resources/views/admin/schedule/load.twig | 2 +- src/Controllers/AuthController.php | 24 +++---- src/Http/Redirector.php | 15 ++-- src/Http/UrlGenerator.php | 47 +++++++++++-- src/Http/UrlGeneratorInterface.php | 2 +- src/Renderer/Twig/Extensions/Assets.php | 8 +-- src/Renderer/Twig/Extensions/Url.php | 8 +-- .../Controllers/Admin/NewsControllerTest.php | 15 ++-- tests/Unit/Controllers/AuthControllerTest.php | 36 +++++----- tests/Unit/Controllers/NewsControllerTest.php | 7 ++ tests/Unit/Http/RedirectorTest.php | 36 +++++++++- tests/Unit/Http/UrlGeneratorTest.php | 70 ++++++++++++++++--- tests/Unit/Middleware/ErrorHandlerTest.php | 26 +++---- 18 files changed, 229 insertions(+), 86 deletions(-) diff --git a/config/config.default.php b/config/config.default.php index 980c9e1d..3a03941e 100644 --- a/config/config.default.php +++ b/config/config.default.php @@ -23,6 +23,9 @@ return [ // Set to development to enable debugging messages 'environment' => env('ENVIRONMENT', 'production'), + // Application URL and base path to use instead of the auto detected one + 'url' => env('APP_URL', null), + // Header links // Available link placeholders: %lang% 'header_items' => [ diff --git a/config/routes.php b/config/routes.php index a524a196..f4c6c183 100644 --- a/config/routes.php +++ b/config/routes.php @@ -38,11 +38,11 @@ $route->addGroup( function (RouteCollector $route) { // Schedule $route->addGroup( - '-schedule', + '/schedule', function (RouteCollector $route) { $route->get('', 'Admin\\Schedule\\ImportSchedule@index'); - $route->post('-load', 'Admin\\Schedule\\ImportSchedule@loadSchedule'); - $route->post('-import', 'Admin\\Schedule\\ImportSchedule@importSchedule'); + $route->post('/load', 'Admin\\Schedule\\ImportSchedule@loadSchedule'); + $route->post('/import', 'Admin\\Schedule\\ImportSchedule@importSchedule'); } ); $route->addGroup( diff --git a/includes/pages/schedule/ImportSchedule.php b/includes/pages/schedule/ImportSchedule.php index 7b60beff..fa7b1b1e 100644 --- a/includes/pages/schedule/ImportSchedule.php +++ b/includes/pages/schedule/ImportSchedule.php @@ -48,7 +48,7 @@ class ImportSchedule extends BaseController protected $session; /** @var string */ - protected $url = 'admin-schedule'; + protected $url = '/admin/schedule'; /** @var GuzzleClient */ protected $guzzle; @@ -520,7 +520,7 @@ class ImportSchedule extends BaseController /** * @param ScheduleUrl $scheduleUrl * @param string[] $events - * @return QueryBuilder[]|DatabaseCollection|ScheduleShift[] + * @return QueryBuilder[]|DatabaseCollection|Collection|ScheduleShift[] */ protected function getScheduleShiftsByGuid(ScheduleUrl $scheduleUrl, array $events) { @@ -533,7 +533,7 @@ class ImportSchedule extends BaseController /** * @param ScheduleUrl $scheduleUrl * @param string[] $events - * @return QueryBuilder[]|DatabaseCollection|ScheduleShift[] + * @return QueryBuilder[]|DatabaseCollection|Collection|ScheduleShift[] */ protected function getScheduleShiftsWhereNotGuid(ScheduleUrl $scheduleUrl, array $events) { diff --git a/includes/sys_menu.php b/includes/sys_menu.php index 7c422890..75b8df4b 100644 --- a/includes/sys_menu.php +++ b/includes/sys_menu.php @@ -117,7 +117,7 @@ function make_navigation() 'admin_shifts' => 'Create shifts', 'admin_rooms' => 'Rooms', 'admin_groups' => 'Grouprights', - 'admin-schedule' => ['schedule.import', 'schedule.import'], + 'admin/schedule' => ['schedule.import', 'schedule.import'], 'admin_log' => 'Log', 'admin_event_config' => 'Event config', ]; diff --git a/resources/views/admin/schedule/index.twig b/resources/views/admin/schedule/index.twig index 69bb13c7..08a9cb2b 100644 --- a/resources/views/admin/schedule/index.twig +++ b/resources/views/admin/schedule/index.twig @@ -17,7 +17,7 @@
{% block row_content %} -
+ {{ csrf() }}
diff --git a/resources/views/admin/schedule/load.twig b/resources/views/admin/schedule/load.twig index dffc3017..8c936bec 100644 --- a/resources/views/admin/schedule/load.twig +++ b/resources/views/admin/schedule/load.twig @@ -4,7 +4,7 @@ {% block title %}{{ __('schedule.import.load.title') }}{% endblock %} {% block row_content %} - + {{ csrf() }} {{ f.hidden('schedule-url', schedule_url) }} {{ f.hidden('shift-type', shift_type) }} diff --git a/src/Controllers/AuthController.php b/src/Controllers/AuthController.php index dc4d1594..acf1c36e 100644 --- a/src/Controllers/AuthController.php +++ b/src/Controllers/AuthController.php @@ -5,9 +5,9 @@ namespace Engelsystem\Controllers; use Carbon\Carbon; use Engelsystem\Config\Config; use Engelsystem\Helpers\Authenticator; +use Engelsystem\Http\Redirector; use Engelsystem\Http\Request; use Engelsystem\Http\Response; -use Engelsystem\Http\UrlGeneratorInterface; use Engelsystem\Models\User\User; use Symfony\Component\HttpFoundation\Session\SessionInterface; @@ -21,8 +21,8 @@ class AuthController extends BaseController /** @var SessionInterface */ protected $session; - /** @var UrlGeneratorInterface */ - protected $url; + /** @var Redirector */ + protected $redirect; /** @var Config */ protected $config; @@ -37,22 +37,22 @@ class AuthController extends BaseController ]; /** - * @param Response $response - * @param SessionInterface $session - * @param UrlGeneratorInterface $url - * @param Config $config - * @param Authenticator $auth + * @param Response $response + * @param SessionInterface $session + * @param Redirector $redirect + * @param Config $config + * @param Authenticator $auth */ public function __construct( Response $response, SessionInterface $session, - UrlGeneratorInterface $url, + Redirector $redirect, Config $config, Authenticator $auth ) { $this->response = $response; $this->session = $session; - $this->url = $url; + $this->redirect = $redirect; $this->config = $config; $this->auth = $auth; } @@ -104,7 +104,7 @@ class AuthController extends BaseController $user->last_login_at = new Carbon(); $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(); - return $this->response->redirectTo($this->url->to('/')); + return $this->redirect->to('/'); } } diff --git a/src/Http/Redirector.php b/src/Http/Redirector.php index 4149a8ec..fdae3650 100644 --- a/src/Http/Redirector.php +++ b/src/Http/Redirector.php @@ -10,17 +10,24 @@ class Redirector /** @var Response */ protected $response; + /** @var UrlGeneratorInterface */ + protected $url; + /** - * @param Request $request - * @param Response $response + * @param Request $request + * @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->response = $response; + $this->url = $url; } /** + * Redirects to a path, generating a full URL + * * @param string $path * @param int $status * @param array $headers @@ -28,7 +35,7 @@ class Redirector */ 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); } /** diff --git a/src/Http/UrlGenerator.php b/src/Http/UrlGenerator.php index d84a02b5..ee800da4 100644 --- a/src/Http/UrlGenerator.php +++ b/src/Http/UrlGenerator.php @@ -3,22 +3,26 @@ namespace Engelsystem\Http; /** - * Provides urls when rewriting on the webserver is enabled. (default) + * Provides URLs * * The urls have the form /? */ class UrlGenerator implements UrlGeneratorInterface { /** + * Create a URL for the given path, using the applications base url if configured + * * @param string $path * @param array $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, '/'); - $request = app('request'); - $uri = $request->getUriForPath($path); + $uri = $path; + + if (!$this->isValidUrl($uri)) { + $uri = $this->generateUrl($path); + } if (!empty($parameters) && is_array($parameters)) { $parameters = http_build_query($parameters); @@ -27,4 +31,37 @@ class UrlGenerator implements UrlGeneratorInterface 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; + } } diff --git a/src/Http/UrlGeneratorInterface.php b/src/Http/UrlGeneratorInterface.php index b3b6b12d..40c5d462 100644 --- a/src/Http/UrlGeneratorInterface.php +++ b/src/Http/UrlGeneratorInterface.php @@ -12,5 +12,5 @@ interface UrlGeneratorInterface * @param array $parameters * @return string */ - public function to($path, $parameters = []); + public function to(string $path, array $parameters = []): string; } diff --git a/src/Renderer/Twig/Extensions/Assets.php b/src/Renderer/Twig/Extensions/Assets.php index 04d6c9c8..9a65eb1a 100644 --- a/src/Renderer/Twig/Extensions/Assets.php +++ b/src/Renderer/Twig/Extensions/Assets.php @@ -2,19 +2,19 @@ namespace Engelsystem\Renderer\Twig\Extensions; -use Engelsystem\Http\UrlGenerator; +use Engelsystem\Http\UrlGeneratorInterface; use Twig\Extension\AbstractExtension as TwigExtension; use Twig\TwigFunction; class Assets extends TwigExtension { - /** @var UrlGenerator */ + /** @var UrlGeneratorInterface */ protected $urlGenerator; /** - * @param UrlGenerator $urlGenerator + * @param UrlGeneratorInterface $urlGenerator */ - public function __construct(UrlGenerator $urlGenerator) + public function __construct(UrlGeneratorInterface $urlGenerator) { $this->urlGenerator = $urlGenerator; } diff --git a/src/Renderer/Twig/Extensions/Url.php b/src/Renderer/Twig/Extensions/Url.php index 17fd6ff0..6c841b74 100644 --- a/src/Renderer/Twig/Extensions/Url.php +++ b/src/Renderer/Twig/Extensions/Url.php @@ -2,19 +2,19 @@ namespace Engelsystem\Renderer\Twig\Extensions; -use Engelsystem\Http\UrlGenerator; +use Engelsystem\Http\UrlGeneratorInterface; use Twig\Extension\AbstractExtension as TwigExtension; use Twig\TwigFunction; class Url extends TwigExtension { - /** @var UrlGenerator */ + /** @var UrlGeneratorInterface */ protected $urlGenerator; /** - * @param UrlGenerator $urlGenerator + * @param UrlGeneratorInterface $urlGenerator */ - public function __construct(UrlGenerator $urlGenerator) + public function __construct(UrlGeneratorInterface $urlGenerator) { $this->urlGenerator = $urlGenerator; } diff --git a/tests/Unit/Controllers/Admin/NewsControllerTest.php b/tests/Unit/Controllers/Admin/NewsControllerTest.php index 3a8f0d30..d33b6742 100644 --- a/tests/Unit/Controllers/Admin/NewsControllerTest.php +++ b/tests/Unit/Controllers/Admin/NewsControllerTest.php @@ -2,17 +2,19 @@ namespace Engelsystem\Test\Unit\Controllers\Admin; +use Engelsystem\Config\Config; use Engelsystem\Controllers\Admin\NewsController; use Engelsystem\Helpers\Authenticator; use Engelsystem\Http\Exceptions\ValidationException; use Engelsystem\Http\Request; use Engelsystem\Http\Response; +use Engelsystem\Http\UrlGenerator; +use Engelsystem\Http\UrlGeneratorInterface; use Engelsystem\Http\Validation\Validator; use Engelsystem\Models\News; use Engelsystem\Models\User\User; use Engelsystem\Test\Unit\HasDatabase; use Engelsystem\Test\Unit\TestCase; -use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Collection; use PHPUnit\Framework\MockObject\MockObject; use Psr\Http\Message\ServerRequestInterface; @@ -161,7 +163,7 @@ class NewsControllerTest extends TestCase ->willReturn($canEditHtml); $this->response->expects($this->once()) ->method('redirectTo') - ->with('/news/' . $id) + ->with('http://localhost/news/' . $id) ->willReturn($this->response); /** @var NewsController $controller */ @@ -195,7 +197,7 @@ class NewsControllerTest extends TestCase ]); $this->response->expects($this->once()) ->method('redirectTo') - ->with('/news') + ->with('http://localhost/news') ->willReturn($this->response); /** @var NewsController $controller */ @@ -220,7 +222,8 @@ class NewsControllerTest extends TestCase parent::setUp(); $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(ServerRequestInterface::class, $this->request); @@ -235,6 +238,10 @@ class NewsControllerTest extends TestCase $this->auth = $this->createMock(Authenticator::class); $this->app->instance(Authenticator::class, $this->auth); + $this->app->bind(UrlGeneratorInterface::class, UrlGenerator::class); + + $this->app->instance('config', new Config()); + (new News([ 'title' => 'Foo', 'text' => 'foo', diff --git a/tests/Unit/Controllers/AuthControllerTest.php b/tests/Unit/Controllers/AuthControllerTest.php index 8dfb0a64..d71409ec 100644 --- a/tests/Unit/Controllers/AuthControllerTest.php +++ b/tests/Unit/Controllers/AuthControllerTest.php @@ -7,9 +7,9 @@ use Engelsystem\Config\Config; use Engelsystem\Controllers\AuthController; use Engelsystem\Helpers\Authenticator; use Engelsystem\Http\Exceptions\ValidationException; +use Engelsystem\Http\Redirector; use Engelsystem\Http\Request; use Engelsystem\Http\Response; -use Engelsystem\Http\UrlGeneratorInterface; use Engelsystem\Http\Validation\Validator; use Engelsystem\Models\User\Settings; use Engelsystem\Models\User\User; @@ -35,10 +35,10 @@ class AuthControllerTest extends TestCase /** @var Response|MockObject $response */ $response = $this->createMock(Response::class); /** @var SessionInterface|MockObject $session */ - /** @var UrlGeneratorInterface|MockObject $url */ + /** @var Redirector|MockObject $redirect */ /** @var Config $config */ /** @var Authenticator|MockObject $auth */ - list(, $session, $url, $config, $auth) = $this->getMocks(); + list(, $session, $redirect, $config, $auth) = $this->getMocks(); $session->expects($this->atLeastOnce()) ->method('get') @@ -50,7 +50,7 @@ class AuthControllerTest extends TestCase ->with('pages/login') ->willReturn($response); - $controller = new AuthController($response, $session, $url, $config, $auth); + $controller = new AuthController($response, $session, $redirect, $config, $auth); $controller->login(); } @@ -64,10 +64,10 @@ class AuthControllerTest extends TestCase $request = new Request(); /** @var Response|MockObject $response */ $response = $this->createMock(Response::class); - /** @var UrlGeneratorInterface|MockObject $url */ + /** @var Redirector|MockObject $redirect */ /** @var Config $config */ /** @var Authenticator|MockObject $auth */ - list(, , $url, $config, $auth) = $this->getMocks(); + list(, , $redirect, $config, $auth) = $this->getMocks(); $session = new Session(new MockArraySessionStorage()); /** @var Validator|MockObject $validator */ $validator = new Validator(); @@ -101,13 +101,13 @@ class AuthControllerTest extends TestCase $this->assertArraySubset(['errors' => collect(['some.bar.error', 'auth.not-found'])], $data); return $response; }); - $response->expects($this->once()) - ->method('redirectTo') + $redirect->expects($this->once()) + ->method('to') ->with('news') ->willReturn($response); // No credentials - $controller = new AuthController($response, $session, $url, $config, $auth); + $controller = new AuthController($response, $session, $redirect, $config, $auth); $controller->setValidator($validator); try { $controller->postLogin($request); @@ -142,23 +142,23 @@ class AuthControllerTest extends TestCase { /** @var Response $response */ /** @var SessionInterface|MockObject $session */ - /** @var UrlGeneratorInterface|MockObject $url */ + /** @var Redirector|MockObject $redirect */ /** @var Config $config */ /** @var Authenticator|MockObject $auth */ - list($response, $session, $url, $config, $auth) = $this->getMocks(); + list($response, $session, $redirect, $config, $auth) = $this->getMocks(); $session->expects($this->once()) ->method('invalidate'); - $url->expects($this->once()) + $redirect->expects($this->once()) ->method('to') ->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(); - $this->assertEquals(['https://foo.bar/'], $return->getHeader('location')); + $this->assertEquals($response, $return); } /** @@ -169,14 +169,14 @@ class AuthControllerTest extends TestCase $response = new Response(); /** @var SessionInterface|MockObject $session */ $session = $this->getMockForAbstractClass(SessionInterface::class); - /** @var UrlGeneratorInterface|MockObject $url */ - $url = $this->getMockForAbstractClass(UrlGeneratorInterface::class); + /** @var Redirector|MockObject $redirect */ + $redirect = $this->createMock(Redirector::class); $config = new Config(['home_site' => 'news']); /** @var Authenticator|MockObject $auth */ $auth = $this->createMock(Authenticator::class); $this->app->instance('session', $session); - return [$response, $session, $url, $config, $auth]; + return [$response, $session, $redirect, $config, $auth]; } } diff --git a/tests/Unit/Controllers/NewsControllerTest.php b/tests/Unit/Controllers/NewsControllerTest.php index 3301042b..822d398b 100644 --- a/tests/Unit/Controllers/NewsControllerTest.php +++ b/tests/Unit/Controllers/NewsControllerTest.php @@ -8,6 +8,8 @@ use Engelsystem\Helpers\Authenticator; use Engelsystem\Http\Exceptions\ValidationException; use Engelsystem\Http\Request; use Engelsystem\Http\Response; +use Engelsystem\Http\UrlGenerator; +use Engelsystem\Http\UrlGeneratorInterface; use Engelsystem\Http\Validation\Validator; use Engelsystem\Models\News; use Engelsystem\Models\NewsComment; @@ -231,6 +233,7 @@ class NewsControllerTest extends TestCase $this->initDatabase(); $this->request = new Request(); + $this->app->instance('request', $this->request); $this->app->instance(Request::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->app->instance(Authenticator::class, $this->auth); + $this->app->bind(UrlGeneratorInterface::class, UrlGenerator::class); + + $this->app->instance('config', new Config()); + foreach ($this->data as $news) { (new News($news))->save(); } diff --git a/tests/Unit/Http/RedirectorTest.php b/tests/Unit/Http/RedirectorTest.php index 300b0180..12c2215a 100644 --- a/tests/Unit/Http/RedirectorTest.php +++ b/tests/Unit/Http/RedirectorTest.php @@ -5,6 +5,8 @@ namespace Engelsystem\Test\Unit\Http; use Engelsystem\Http\Redirector; use Engelsystem\Http\Request; use Engelsystem\Http\Response; +use Engelsystem\Http\UrlGeneratorInterface; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class RedirectorTest extends TestCase @@ -17,7 +19,9 @@ class RedirectorTest extends TestCase { $request = new Request(); $response = new Response(); - $redirector = new Redirector($request, $response); + $url = $this->getUrlGenerator(); + + $redirector = new Redirector($request, $response, $url); $return = $redirector->to('/test'); $this->assertEquals(['/test'], $return->getHeader('location')); @@ -37,17 +41,43 @@ class RedirectorTest extends TestCase { $request = new Request(); $response = new Response(); - $redirector = new Redirector($request, $response); + $url = $this->getUrlGenerator(); + $redirector = new Redirector($request, $response, $url); $return = $redirector->back(); $this->assertEquals(['/'], $return->getHeader('location')); $this->assertEquals(302, $return->getStatusCode()); $request = $request->withHeader('referer', '/old-page'); - $redirector = new Redirector($request, $response); + $redirector = new Redirector($request, $response, $url); $return = $redirector->back(303, ['foo' => 'bar']); $this->assertEquals(303, $return->getStatusCode()); $this->assertEquals(['/old-page'], $return->getHeader('location')); $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; + } } diff --git a/tests/Unit/Http/UrlGeneratorTest.php b/tests/Unit/Http/UrlGeneratorTest.php index fa2ec36e..34293f56 100644 --- a/tests/Unit/Http/UrlGeneratorTest.php +++ b/tests/Unit/Http/UrlGeneratorTest.php @@ -2,15 +2,17 @@ namespace Engelsystem\Test\Unit\Http; -use Engelsystem\Application; -use Engelsystem\Container\Container; +use Engelsystem\Config\Config; use Engelsystem\Http\Request; use Engelsystem\Http\UrlGenerator; -use PHPUnit\Framework\TestCase; +use Engelsystem\Test\Unit\TestCase; class UrlGeneratorTest extends TestCase { - public function provideLinksTo() + /** + * @return array + */ + public function provideLinksTo(): array { return [ ['/foo/path', '/foo/path', 'http://foo.bar/foo/path', [], 'http://foo.bar/foo/path'], @@ -22,6 +24,7 @@ class UrlGeneratorTest extends TestCase /** * @dataProvider provideLinksTo * @covers \Engelsystem\Http\UrlGenerator::to + * @covers \Engelsystem\Http\UrlGenerator::generateUrl * * @param string $path * @param string $willReturn @@ -31,21 +34,68 @@ class UrlGeneratorTest extends TestCase */ public function testTo($urlToPath, $path, $willReturn, $arguments, $expectedUrl) { - $app = new Container(); - $urlGenerator = new UrlGenerator(); - Application::setInstance($app); - $request = $this->getMockBuilder(Request::class) ->getMock(); - $request->expects($this->once()) ->method('getUriForPath') ->with($path) ->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); $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')); + } } diff --git a/tests/Unit/Middleware/ErrorHandlerTest.php b/tests/Unit/Middleware/ErrorHandlerTest.php index cd7f8536..e18028f7 100644 --- a/tests/Unit/Middleware/ErrorHandlerTest.php +++ b/tests/Unit/Middleware/ErrorHandlerTest.php @@ -2,7 +2,7 @@ namespace Engelsystem\Test\Unit\Middleware; -use Engelsystem\Application; +use Engelsystem\Config\Config; use Engelsystem\Http\Exceptions\HttpException; use Engelsystem\Http\Exceptions\ValidationException; use Engelsystem\Http\Psr7ServiceProvider; @@ -10,12 +10,13 @@ use Engelsystem\Http\RedirectServiceProvider; use Engelsystem\Http\Request; use Engelsystem\Http\Response; use Engelsystem\Http\ResponseServiceProvider; +use Engelsystem\Http\UrlGeneratorServiceProvider; use Engelsystem\Http\Validation\Validator; use Engelsystem\Middleware\ErrorHandler; use Engelsystem\Test\Unit\Middleware\Stub\ReturnResponseMiddlewareHandler; +use Engelsystem\Test\Unit\TestCase; use Illuminate\Database\Eloquent\ModelNotFoundException; use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; @@ -186,19 +187,20 @@ class ErrorHandlerTest extends TestCase ); $request->setSession($session); - /** @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(); + $this->app->instance(Session::class, $session); + $this->app->bind(SessionInterface::class, Session::class); + $this->app->instance('request', $request); + $this->app->instance('config', new Config()); + (new ResponseServiceProvider($this->app))->register(); + (new Psr7ServiceProvider($this->app))->register(); + (new RedirectServiceProvider($this->app))->register(); + (new UrlGeneratorServiceProvider($this->app))->register(); $errorHandler = new ErrorHandler($twigLoader); $return = $errorHandler->process($request, $handler); $this->assertEquals(302, $return->getStatusCode()); - $this->assertEquals('/', $return->getHeaderLine('location')); + $this->assertEquals('http://localhost/', $return->getHeaderLine('location')); $this->assertEquals([ 'errors' => [ 'validation' => [ @@ -214,10 +216,10 @@ class ErrorHandlerTest extends TestCase ], $session->all()); $request = $request->withAddedHeader('referer', '/foo/batz'); - $app->instance(Request::class, $request); + $this->app->instance(Request::class, $request); $return = $errorHandler->process($request, $handler); - $this->assertEquals('/foo/batz', $return->getHeaderLine('location')); + $this->assertEquals('http://localhost/foo/batz', $return->getHeaderLine('location')); } /**