Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional default host and scheme to UrlGenerator #144

Merged
merged 4 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 3.0.2 under development

- New #144: Add optional default host and scheme to `UrlGenerator` (@vjik)
- Enh #139: Add support for `psr/http-message` version `^2.0` (@vjik)

## 3.0.1 December 24, 2023
Expand Down
30 changes: 21 additions & 9 deletions src/UrlGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
public function __construct(
private RouteCollectionInterface $routeCollection,
private ?CurrentRoute $currentRoute = null,
RouteParser $parser = null
?RouteParser $parser = null,
private ?string $scheme = null,
private ?string $host = null,
) {
$this->routeParser = $parser ?? new RouteParser\Std();
}
Expand Down Expand Up @@ -88,24 +90,31 @@
string $name,
array $arguments = [],
array $queryParameters = [],
string $scheme = null,
string $host = null
?string $scheme = null,
?string $host = null
): string {
$url = $this->generate($name, $arguments, $queryParameters);
$route = $this->routeCollection->getRoute($name);
$uri = $this->currentRoute && $this->currentRoute->getUri() !== null ? $this->currentRoute->getUri() : null;
$lastRequestScheme = $uri?->getScheme();

if ($host !== null || ($host = $route->getData('host')) !== null) {
if ($scheme === null && !$this->isRelative($host)) {
$host ??= $route->getData('host') ?? $this->host ?? null;
if ($host !== null) {
$isRelativeHost = $this->isRelative($host);

$scheme ??= $isRelativeHost
? $this->scheme ?? $lastRequestScheme
: null;

if ($scheme === null && !$isRelativeHost) {
return rtrim($host, '/') . $url;
}

if ((empty($scheme) || $lastRequestScheme === null) && $host !== '' && $this->isRelative($host)) {
if ($host !== '' && $isRelativeHost) {
$host = '//' . $host;
}

return $this->ensureScheme(rtrim($host, '/') . $url, $scheme ?? $lastRequestScheme);
return $this->ensureScheme(rtrim($host, '/') . $url, $scheme);

Check warning on line 117 in src/UrlGenerator.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "UnwrapRtrim": --- Original +++ New @@ @@ if ($host !== '' && $isRelativeHost) { $host = '//' . $host; } - return $this->ensureScheme(rtrim($host, '/') . $url, $scheme); + return $this->ensureScheme($host . $url, $scheme); } return $uri === null ? $url : $this->generateAbsoluteFromLastMatchedRequest($url, $uri, $scheme); }
}

return $uri === null ? $url : $this->generateAbsoluteFromLastMatchedRequest($url, $uri, $scheme);
Expand All @@ -114,8 +123,11 @@
/**
* {@inheritdoc}
*/
public function generateFromCurrent(array $replacedArguments, array $queryParameters = [], string $fallbackRouteName = null): string
{
public function generateFromCurrent(
array $replacedArguments,
array $queryParameters = [],
?string $fallbackRouteName = null,
): string {
if ($this->currentRoute === null || $this->currentRoute->getName() === null) {
if ($fallbackRouteName !== null) {
return $this->generate($fallbackRouteName, $replacedArguments);
Expand Down Expand Up @@ -157,7 +169,7 @@
{
$port = '';
$uriPort = $uri->getPort();
if ($uriPort !== 80 && $uriPort !== null) {

Check warning on line 172 in src/UrlGenerator.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "DecrementInteger": --- Original +++ New @@ @@ { $port = ''; $uriPort = $uri->getPort(); - if ($uriPort !== 80 && $uriPort !== null) { + if ($uriPort !== 79 && $uriPort !== null) { $port = ':' . $uriPort; } return $this->ensureScheme('://' . $uri->getHost() . $port . $url, $scheme ?? $uri->getScheme());

Check warning on line 172 in src/UrlGenerator.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "IncrementInteger": --- Original +++ New @@ @@ { $port = ''; $uriPort = $uri->getPort(); - if ($uriPort !== 80 && $uriPort !== null) { + if ($uriPort !== 81 && $uriPort !== null) { $port = ':' . $uriPort; } return $this->ensureScheme('://' . $uri->getHost() . $port . $url, $scheme ?? $uri->getScheme());
$port = ':' . $uriPort;
}

Expand Down Expand Up @@ -207,7 +219,7 @@
*/
private function isRelative(string $url): bool
{
return strncmp($url, '//', 2) && !str_contains($url, '://');

Check warning on line 222 in src/UrlGenerator.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "DecrementInteger": --- Original +++ New @@ @@ */ private function isRelative(string $url) : bool { - return strncmp($url, '//', 2) && !str_contains($url, '://'); + return strncmp($url, '//', 1) && !str_contains($url, '://'); } public function getUriPrefix() : string {
}

public function getUriPrefix(): string
Expand Down Expand Up @@ -293,7 +305,7 @@
}
}

$path = str_replace('//', '/', $path);

Check warning on line 308 in src/UrlGenerator.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "UnwrapStrReplace": --- Original +++ New @@ @@ $path .= $this->encodeRaw ? rawurlencode($arguments[$part[0]]) : urlencode($arguments[$part[0]]); } } - $path = str_replace('//', '/', $path); + $path = $path; $queryString = ''; if (!empty($queryParameters)) { $queryString = http_build_query($queryParameters);

$queryString = '';
if (!empty($queryParameters)) {
Expand Down
125 changes: 93 additions & 32 deletions tests/UrlGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public function testQueryParametersAddedAsQueryString(): void
{
$routes = [
Route::get('/test/{name}')
->name('test'),
->name('test'),
];

$url = $this
Expand All @@ -200,7 +200,7 @@ public function testQueryParametersAddedAsQueryStringWithEmptyValues(): void
{
$routes = [
Route::get('/test/{name}')
->name('test'),
->name('test'),
];

$url = $this
Expand All @@ -213,7 +213,7 @@ public function testQueryParametersOverrideExtraArguments(): void
{
$routes = [
Route::get('/test/{name}')
->name('test'),
->name('test'),
];

$url = $this
Expand All @@ -226,7 +226,7 @@ public function testNotSubstitutedArgumentsRemove(): void
{
$routes = [
Route::get('/test/{name}')
->name('test'),
->name('test'),
];

$url = $this
Expand All @@ -239,8 +239,8 @@ public function testDefaultNotUsedForOptionalArgument(): void
{
$routes = [
Route::get('/[{name}]')
->name('defaults')
->defaults(['name' => 'default']),
->name('defaults')
->defaults(['name' => 'default']),
];

$url = $this
Expand All @@ -253,8 +253,8 @@ public function testValueUsedForOptionalArgument(): void
{
$routes = [
Route::get('/[{name}]')
->name('defaults')
->defaults(['name' => 'default']),
->name('defaults')
->defaults(['name' => 'default']),
];

$url = $this
Expand All @@ -267,8 +267,8 @@ public function testDefaultNotUsedForRequiredParameter(): void
{
$routes = [
Route::get('/{name}')
->name('defaults')
->defaults(['name' => 'default']),
->name('defaults')
->defaults(['name' => 'default']),
];

$this->expectExceptionMessage('Route `defaults` expects at least argument values for [name], but received []');
Expand All @@ -284,8 +284,8 @@ public function testAbsoluteUrlHostOverride(): void
{
$routes = [
Route::get('/home/index')
->name('index')
->host('http://test.com'),
->name('index')
->host('http://test.com'),
];
$url = $this
->createUrlGenerator($routes)
Expand All @@ -301,8 +301,8 @@ public function testAbsoluteUrlHostOverrideWithTrailingSlash(): void
{
$routes = [
Route::get('/home/index')
->name('index')
->host('http://test.com'),
->name('index')
->host('http://test.com'),
];
$url = $this
->createUrlGenerator($routes)
Expand All @@ -318,8 +318,8 @@ public function testAbsoluteUrlSchemeOverrideHostInRouteScheme(): void
{
$routes = [
Route::get('/home/index')
->name('index')
->host('http://test.com'),
->name('index')
->host('http://test.com'),
];
$url = $this
->createUrlGenerator($routes)
Expand Down Expand Up @@ -368,8 +368,8 @@ public function testAbsoluteUrlWithHostInRoute(): void
{
$routes = [
Route::get('/home/index')
->name('index')
->host('http://test.com'),
->name('index')
->host('http://test.com'),
];
$url = $this
->createUrlGenerator($routes)
Expand All @@ -385,8 +385,8 @@ public function testAbsoluteUrlWithTrailingSlashHostInRoute(): void
{
$routes = [
Route::get('/home/index')
->name('index')
->host('http://test.com/'),
->name('index')
->host('http://test.com/'),
];
$url = $this
->createUrlGenerator($routes)
Expand Down Expand Up @@ -443,8 +443,8 @@ public function testHostInRouteWithProtocolRelativeSchemeAbsoluteUrl(): void
$request = new ServerRequest('GET', 'http://test.com/home/index');
$routes = [
Route::get('/home/index')
->name('index')
->host('//test.com'),
->name('index')
->host('//test.com'),
];

$currentRoute = new CurrentRoute();
Expand All @@ -465,8 +465,8 @@ public function testHostInMethodWithProtocolRelativeSchemeAbsoluteUrl(): void
$request = new ServerRequest('GET', 'http://test.com/home/index');
$routes = [
Route::get('/home/index')
->name('index')
->host('//mysite.com'),
->name('index')
->host('//mysite.com'),
];

$currentRoute = new CurrentRoute();
Expand All @@ -483,11 +483,11 @@ public function testHostInRouteProtocolRelativeSchemeAbsoluteUrl(): void
$request = new ServerRequest('GET', 'http://test.com/home/index');
$routes = [
Route::get('/home/index')
->name('index')
->host('http://test.com'),
->name('index')
->host('http://test.com'),
Route::get('/home/view')
->name('view')
->host('test.com'),
->name('view')
->host('test.com'),
];

$currentRoute = new CurrentRoute();
Expand All @@ -508,8 +508,8 @@ public function testHostInMethodProtocolRelativeSchemeAbsoluteUrl(): void
$request = new ServerRequest('GET', 'http://test.com/home/index');
$routes = [
Route::get('/home/index')
->name('index')
->host('//mysite.com'),
->name('index')
->host('//mysite.com'),
];

$currentRoute = new CurrentRoute();
Expand Down Expand Up @@ -560,8 +560,8 @@ public function testHostInRouteWithoutSchemeAbsoluteUrl(): void
$request = new ServerRequest('GET', 'http://example.com/home/index');
$routes = [
Route::get('/home/index')
->name('index')
->host('example.com'),
->name('index')
->host('example.com'),
];

$currentRoute = new CurrentRoute();
Expand Down Expand Up @@ -853,6 +853,67 @@ public function testNotFoundRoutes(): void
$urlGenerator->generate('index');
}

public function testDefaultHostAndScheme(): void
{
$urlGenerator = new UrlGenerator(
$this->createRouteCollection([Route::get('/home/index')->name('index')]),
scheme: 'https',
host: 'example.com',
);

$url = $urlGenerator->generateAbsolute('index');

$this->assertSame('https://example.com/home/index', $url);
}

public function testOverrideDefaultHostAndSchemeFromMethodArguments(): void
{
$urlGenerator = new UrlGenerator(
$this->createRouteCollection([Route::get('/home/index')->name('index')]),
scheme: 'https',
host: 'example.com',
);

$url = $urlGenerator->generateAbsolute('index', scheme: 'http', host: 'example.yii');

$this->assertSame('http://example.yii/home/index', $url);
}

public function testOverrideDefaultHostAndSchemeFromRoute(): void
{
$urlGenerator = new UrlGenerator(
$this->createRouteCollection([
Route::get('/home/index')
->host('//test.yii')
->name('index'),
]),
scheme: 'https',
host: 'example.com',
);

$url = $urlGenerator->generateAbsolute('index');

$this->assertSame('//test.yii/home/index', $url);
}

public function testDefaultHostAndSchemeWithUri(): void
{
$request = new ServerRequest('GET', 'http://test.com/home/index');
$currentRoute = new CurrentRoute();
$currentRoute->setUri($request->getUri());

$urlGenerator = new UrlGenerator(
$this->createRouteCollection([Route::get('/home/index')->name('index')]),
$currentRoute,
scheme: 'https',
host: 'example.com',
);

$url = $urlGenerator->generateAbsolute('index');

$this->assertSame('https://example.com/home/index', $url);
}

private function createUrlGenerator(
array $routes,
CurrentRoute $currentRoute = null,
Expand Down
Loading