Skip to content

Commit

Permalink
Populate URI generation data on DataGenerator
Browse files Browse the repository at this point in the history
Signed-off-by: Luís Cobucci <[email protected]>
  • Loading branch information
lcobucci committed Feb 6, 2024
1 parent cc1e8ff commit 4b60e45
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/DataGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* @phpstan-type DynamicRouteChunks list<DynamicRouteChunk>
* @phpstan-type DynamicRoutes array<string, DynamicRouteChunks>
* @phpstan-type RoutesForUriGeneration array<non-empty-string, ParsedRoutes>
* @phpstan-type RouteData array{StaticRoutes, DynamicRoutes}
* @phpstan-type RouteData array{StaticRoutes, DynamicRoutes, RoutesForUriGeneration}
*/
interface DataGenerator
{
Expand Down
51 changes: 49 additions & 2 deletions src/DataGenerator/RegexBasedAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@
use FastRoute\DataGenerator;
use FastRoute\Route;
use FastRoute\RouteParser;
use RuntimeException;

use function array_chunk;
use function array_key_exists;
use function array_map;
use function assert;
use function ceil;
use function count;
use function is_string;
use function max;
use function round;
use function usort;

/**
* @internal
Expand All @@ -25,6 +28,7 @@
* @phpstan-import-type DynamicRoutes from DataGenerator
* @phpstan-import-type RouteData from DataGenerator
* @phpstan-import-type ExtraParameters from DataGenerator
* @phpstan-import-type RoutesForUriGeneration from DataGenerator
* @phpstan-import-type ParsedRoute from RouteParser
*/
abstract class RegexBasedAbstract implements DataGenerator
Expand All @@ -35,6 +39,9 @@ abstract class RegexBasedAbstract implements DataGenerator
/** @var array<string, array<string, Route>> */
protected array $methodToRegexToRoutesMap = [];

/** @var RoutesForUriGeneration */
private array $uriGenerationData = [];

abstract protected function getApproxChunkSize(): int;

/**
Expand All @@ -52,16 +59,40 @@ public function addRoute(string $httpMethod, array $routeData, mixed $handler, a
} else {
$this->addVariableRoute($httpMethod, $routeData, $handler, $extraParameters);
}

$this->registerNamedRoute($routeData, $extraParameters);
}

/**
* @param ParsedRoute $routeData
* @param ExtraParameters $extraParameters
*/
private function registerNamedRoute(array $routeData, array $extraParameters): void
{
if (! array_key_exists('_name', $extraParameters)) {
return;
}

$routeName = $extraParameters['_name'];

if (! is_string($routeName) || $routeName === '') {
throw new RuntimeException('broken!');
}

$this->uriGenerationData[$routeName] ??= [];
$this->uriGenerationData[$routeName][] = $routeData;
}

/** @inheritDoc */
public function getData(): array
{
$routesForUriGeneration = $this->routesForUriGeneration();

if ($this->methodToRegexToRoutesMap === []) {
return [$this->staticRoutes, []];
return [$this->staticRoutes, [], $routesForUriGeneration];
}

return [$this->staticRoutes, $this->generateVariableRouteData()];
return [$this->staticRoutes, $this->generateVariableRouteData(), $routesForUriGeneration];
}

/** @return DynamicRoutes */
Expand Down Expand Up @@ -132,4 +163,20 @@ private function addVariableRoute(string $httpMethod, array $routeData, mixed $h

$this->methodToRegexToRoutesMap[$httpMethod][$regex] = $route;
}

/** @return RoutesForUriGeneration */
private function routesForUriGeneration(): array
{
return array_map(
static function (array $routes): array {
usort(
$routes,
static fn (array $routeA, array $routeB) => count($routeB) <=> count($routeA),
);

return $routes;
},
$this->uriGenerationData,
);
}
}
18 changes: 16 additions & 2 deletions src/FastRoute.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@
use Closure;
use FastRoute\Cache\FileCache;

use function assert;
use function is_string;

/** @phpstan-import-type RouteData from DataGenerator */
final class FastRoute
{
/** @var RouteData|null */
private ?array $processedConfiguration = null;

/**
* @param Closure(ConfigureRoutes):void $routeDefinitionCallback
* @param class-string<RouteParser> $routeParser
Expand Down Expand Up @@ -110,6 +115,10 @@ public function useCustomDispatcher(string $dataGenerator, string $dispatcher):
/** @return RouteData */
private function buildConfiguration(): array
{
if ($this->processedConfiguration !== null) {
return $this->processedConfiguration;
}

$loader = function (): array {
$configuredRoutes = new $this->routesConfiguration(
new $this->routeParser(),
Expand All @@ -122,7 +131,7 @@ private function buildConfiguration(): array
};

if ($this->cacheDriver === null) {
return loader();
return $this->processedConfiguration = $loader();
}

assert(is_string($this->cacheKey));
Expand All @@ -131,11 +140,16 @@ private function buildConfiguration(): array
? new $this->cacheDriver()
: $this->cacheDriver;

return $cache->get($this->cacheKey, $loader);
return $this->processedConfiguration = $cache->get($this->cacheKey, $loader);
}

public function dispatcher(): Dispatcher
{
return new $this->dispatcher($this->buildConfiguration());
}

public function uriGenerator(): GenerateUri
{
return new GenerateUri\FromProcessedConfiguration($this->buildConfiguration()[2]);
}
}
4 changes: 2 additions & 2 deletions test/Cache/Psr16CacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public function cacheShouldOnlyBeSetOnMiss(): void
{
$data = [];

$generatedData = [['GET' => ['/' => ['test', []]]], []];
$generatedData = [['GET' => ['/' => ['test', []]]], [], []];

$adapter = new Psr16Cache($this->createDummyCache($data));
$result = $adapter->get('test', static fn () => $generatedData);
Expand All @@ -24,7 +24,7 @@ public function cacheShouldOnlyBeSetOnMiss(): void
self::assertSame($generatedData, $data['test']);

// Try again, now with a different callback
$result = $adapter->get('test', static fn () => [['POST' => ['/' => ['test', []]]], []]);
$result = $adapter->get('test', static fn () => [['POST' => ['/' => ['test', []]]], [], []]);

self::assertSame($generatedData, $result);
}
Expand Down
2 changes: 1 addition & 1 deletion test/RouteCollectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ private static function dummyDataGenerator(): DataGenerator
/** @inheritDoc */
public function getData(): array
{
return [[], []];
return [[], [], []];
}

/** @inheritDoc */
Expand Down

0 comments on commit 4b60e45

Please sign in to comment.