Skip to content
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
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
],
"require": {
"php": ">=8.1.0",
"psr/http-message": "^2.0",
"psr/simple-cache": "^2.0 || ^3.0"
},
"require-dev": {
"lcobucci/coding-standard": "^11.1",
"nyholm/psr7": "^1.8",
"phpbench/phpbench": "^1.2",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.10",
Expand Down
188 changes: 187 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutCoverageMetadata="true"
beStrictAboutTodoAnnotatedTests="true"
beStrictAboutChangesToGlobalState="true"
beStrictAboutOutputDuringTests="true"
displayDetailsOnTestsThatTriggerDeprecations="true"
Expand Down
3 changes: 2 additions & 1 deletion src/GenerateUri.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace FastRoute;

use FastRoute\GenerateUri\GeneratedUri;
use FastRoute\GenerateUri\UriCouldNotBeGenerated;

/**
Expand All @@ -17,5 +18,5 @@ interface GenerateUri
*
* @throws UriCouldNotBeGenerated
*/
public function forRoute(string $name, array $substitutions = []): string;
public function forRoute(string $name, array $substitutions = []): GeneratedUri;
}
9 changes: 6 additions & 3 deletions src/GenerateUri/FromProcessedConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function __construct(private readonly array $processedConfiguration)
}

/** @inheritDoc */
public function forRoute(string $name, array $substitutions = []): string
public function forRoute(string $name, array $substitutions = []): GeneratedUri
{
if (! array_key_exists($name, $this->processedConfiguration)) {
throw UriCouldNotBeGenerated::routeIsUndefined($name);
Expand Down Expand Up @@ -79,7 +79,7 @@ private function missingParameters(array $parts, array $substitutions): array
* @param ParsedRoute $parsedRoute
* @param UriSubstitutions $substitutions
*/
private function generatePath(string $route, array $parsedRoute, array $substitutions): string
private function generatePath(string $route, array $parsedRoute, array $substitutions): GeneratedUri
{
$path = '';

Expand All @@ -97,8 +97,11 @@ private function generatePath(string $route, array $parsedRoute, array $substitu
}

$path .= $substitutions[$parameterName];
unset($substitutions[$parameterName]);
}

return $path;
assert($path !== '');

return new GeneratedUri($path, $substitutions);
}
}
36 changes: 36 additions & 0 deletions src/GenerateUri/GeneratedUri.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);

namespace FastRoute\GenerateUri;

use FastRoute\GenerateUri;
use Psr\Http\Message\UriInterface;
use Stringable;

use function http_build_query;

/** @phpstan-import-type UriSubstitutions from GenerateUri */
final class GeneratedUri implements Stringable
{
/**
* @param non-empty-string $path
* @param UriSubstitutions $unmatchedSubstitutions
*/
public function __construct(
public readonly string $path,
public readonly array $unmatchedSubstitutions,
) {
}

public function asUri(UriInterface $baseUri): UriInterface
{
return $baseUri
->withPath($this->path)
->withQuery(http_build_query($this->unmatchedSubstitutions));
}

public function __toString(): string
{
return $this->path;
}
}
16 changes: 9 additions & 7 deletions test/FastRouteTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use FastRoute\Dispatcher;
use FastRoute\FastRoute;
use FastRoute\GenerateUri;
use Nyholm\Psr7\Uri;
use PHPUnit\Framework\Attributes as PHPUnit;
use PHPUnit\Framework\TestCase;
use RuntimeException;
Expand Down Expand Up @@ -115,9 +116,9 @@ public function uriGeneratorCanBeOverridden(): void
{
$generator = new class () implements GenerateUri {
/** @inheritDoc */
public function forRoute(string $name, array $substitutions = []): string
public function forRoute(string $name, array $substitutions = []): GenerateUri\GeneratedUri
{
return '';
return new GenerateUri\GeneratedUri('/', $substitutions);
}
};

Expand Down Expand Up @@ -159,10 +160,11 @@ public function processedDataShouldOnlyBeBuiltOnce(): void
self::assertInstanceOf(Dispatcher\Result\Matched::class, $dispatcher->dispatch('POST', '/users/lcobucci'));
self::assertInstanceOf(Dispatcher\Result\Matched::class, $dispatcher->dispatch('GET', '/posts/1234'));

self::assertSame('/users/lcobucci', $uriGenerator->forRoute('users', ['name' => 'lcobucci']));
self::assertSame('/posts/1234', $uriGenerator->forRoute('posts.fetch', ['id' => '1234']));
self::assertSame('/articles/2024', $uriGenerator->forRoute('articles.fetch', ['year' => '2024']));
self::assertSame('/articles/2024/02', $uriGenerator->forRoute('articles.fetch', ['year' => '2024', 'month' => '02']));
self::assertSame('/articles/2024/02/15', $uriGenerator->forRoute('articles.fetch', ['year' => '2024', 'month' => '02', 'day' => '15']));
self::assertEquals('/users/lcobucci', $uriGenerator->forRoute('users', ['name' => 'lcobucci']));
self::assertEquals('/posts/1234', $uriGenerator->forRoute('posts.fetch', ['id' => '1234']));
self::assertEquals('/articles/2024', $uriGenerator->forRoute('articles.fetch', ['year' => '2024']));
self::assertEquals('/articles/2024/02', $uriGenerator->forRoute('articles.fetch', ['year' => '2024', 'month' => '02']));
self::assertEquals('/articles/2024/02/15', $uriGenerator->forRoute('articles.fetch', ['year' => '2024', 'month' => '02', 'day' => '15']));
self::assertSame('/articles/2024/02/15?extra=value', (string) $uriGenerator->forRoute('articles.fetch', ['year' => '2024', 'month' => '02', 'day' => '15', 'extra' => 'value'])->asUri(new Uri()));
}
}
Loading
Loading