Skip to content

Commit

Permalink
Move DI functionality to Settings object
Browse files Browse the repository at this point in the history
This is actually a Service Locator, but the term 'settings' fits better with pre-existing FastRoute language.
  • Loading branch information
pmjones committed Mar 29, 2024
1 parent fcc6278 commit 924ae7d
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 153 deletions.
2 changes: 2 additions & 0 deletions src/Dispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
use FastRoute\Dispatcher\Result\MethodNotAllowed;
use FastRoute\Dispatcher\Result\NotMatched;

/** @phpstan-import-type ParsedRoutes from RouteParser */
interface Dispatcher
{
public const NOT_FOUND = 0;
public const FOUND = 1;
public const METHOD_NOT_ALLOWED = 2;

/** @param ParsedRoutes $processedData */
public function with(array $processedData): self;

/**
Expand Down
1 change: 1 addition & 0 deletions src/Dispatcher/RegexBasedAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public function with(array $data): self
$clone = clone $this;
$clone->staticRouteMap = $data[0];
$clone->variableRouteData = $data[1];

return $clone;
}

Expand Down
130 changes: 13 additions & 117 deletions src/FastRoute.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
namespace FastRoute;

use Closure;
use FastRoute\Cache\FileCache;

use function assert;
use function is_string;
Expand All @@ -16,123 +15,16 @@ final class FastRoute
private ?array $processedConfiguration = null;

/**
* @param Closure(ConfigureRoutes):void $routeDefinitionCallback
* @param class-string<DataGenerator> $dataGenerator
* @param class-string<Dispatcher> $dispatcher
* @param class-string<ConfigureRoutes> $routesConfiguration
* @param class-string<GenerateUri> $uriGenerator
* @param Cache|class-string<Cache>|null $cacheDriver
* @param non-empty-string|null $cacheKey
* @param Closure(ConfigureRoutes):void $routeDefinitionCallback
* @param non-empty-string|null $cacheKey
*/
public function __construct(
private Closure $routeDefinitionCallback,
private DataGenerator $dataGenerator,
private Dispatcher $dispatcher,
private ConfigureRoutes $routesConfiguration,
private GenerateUri $uriGenerator,
private ?Cache $cacheDriver,
private ?string $cacheKey,
private Settings $settings = new FastSettings(),
) {
}

/**
* @param Closure(ConfigureRoutes):void $routeDefinitionCallback
* @param non-empty-string $cacheKey
*/
public static function recommendedSettings(Closure $routeDefinitionCallback, string $cacheKey): self
{
return new self(
$routeDefinitionCallback,
new DataGenerator\MarkBased(),
new Dispatcher\MarkBased(),
new RouteCollector(new RouteParser\Std()),
new GenerateUri\FromProcessedConfiguration,
new FileCache(),
$cacheKey,
);
}

public function disableCache(): self
{
return new self(
$this->routeDefinitionCallback,
$this->dataGenerator,
$this->dispatcher,
$this->routesConfiguration,
$this->uriGenerator,
null,
null,
);
}

/**
* @param Cache|class-string<Cache> $driver
* @param non-empty-string $cacheKey
*/
public function withCache(Cache $driver, string $cacheKey): self
{
return new self(
$this->routeDefinitionCallback,
$this->dataGenerator,
$this->dispatcher,
$this->routesConfiguration,
$this->uriGenerator,
$driver,
$cacheKey,
);
}

public function useCharCountDispatcher(): self
{
return $this->useCustomDispatcher(new DataGenerator\CharCountBased(), new Dispatcher\CharCountBased());
}

public function useGroupCountDispatcher(): self
{
return $this->useCustomDispatcher(new DataGenerator\GroupCountBased(), new Dispatcher\GroupCountBased());
}

public function useGroupPosDispatcher(): self
{
return $this->useCustomDispatcher(new DataGenerator\GroupPosBased(), new Dispatcher\GroupPosBased());
}

public function useMarkDispatcher(): self
{
return $this->useCustomDispatcher(new DataGenerator\MarkBased(), new Dispatcher\MarkBased());
}

/**
* @param class-string<DataGenerator> $dataGenerator
* @param class-string<Dispatcher> $dispatcher
*/
public function useCustomDispatcher(DataGenerator $dataGenerator, Dispatcher $dispatcher): self
{
return new self(
$this->routeDefinitionCallback,
$dataGenerator,
$dispatcher,
$this->routesConfiguration,
$this->uriGenerator,
$this->cacheDriver,
$this->cacheKey,
);
}

/** @param class-string<GenerateUri> $uriGenerator */
public function withUriGenerator(GenerateUri $uriGenerator): self
{
return new self(
$this->routeDefinitionCallback,
$this->dataGenerator,
$this->dispatcher,
$this->routesConfiguration,
$uriGenerator,
$this->cacheDriver,
$this->cacheKey,
);
}

/** @return ProcessedData */
private function buildConfiguration(): array
{
Expand All @@ -141,26 +33,30 @@ private function buildConfiguration(): array
}

$loader = function (): array {
($this->routeDefinitionCallback)($this->routesConfiguration);
return $this->routesConfiguration->processedRoutes($this->dataGenerator);
$routesConfiguration = $this->settings->getRoutesConfiguration();
($this->routeDefinitionCallback)($routesConfiguration);

return $routesConfiguration->processedRoutes($this->settings->getDataGenerator());
};

if ($this->cacheDriver === null) {
$cacheDriver = $this->settings->getCacheDriver();

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

assert(is_string($this->cacheKey));

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

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

public function uriGenerator(): GenerateUri
{
return $this->uriGenerator->with($this->buildConfiguration()[2]);
return $this->settings->getUriGenerator()->with($this->buildConfiguration()[2]);
}
}
173 changes: 173 additions & 0 deletions src/FastSettings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<?php
declare(strict_types=1);

namespace FastRoute;

use FastRoute\Cache\FileCache;

use function is_string;

/** @phpstan-import-type ProcessedData from ConfigureRoutes */
final class FastSettings implements Settings
{
/** @var array <string, object> */
protected array $instances = [];

/**
* @param RouteParser|class-string<RouteParser> $routeParser
* @param DataGenerator|class-string<DataGenerator> $dataGenerator
* @param Dispatcher|class-string<Dispatcher> $dispatcher
* @param ConfigureRoutes|class-string<ConfigureRoutes> $routesConfiguration
* @param GenerateUri|class-string<GenerateUri> $uriGenerator
* @param Cache|class-string<Cache>|null $cacheDriver
*/
public function __construct(
private readonly RouterParser|string $routeParser = RouteParser\Std::class,
private readonly DataGenerator|string $dataGenerator = DataGenerator\MarkBased::class,
private readonly Dispatcher|string $dispatcher = Dispatcher\MarkBased::class,
private readonly RoutesConfiguration|string $routesConfiguration = RouteCollector::class,
private readonly GenerateUri|string $uriGenerator = GenerateUri\FromProcessedConfiguration::class,
private readonly Cache|string|null $cacheDriver = FileCache::class,
) {
}

public function getRouteParser(): RouteParser
{
return $this->instances['routeParser'] ??= is_string($this->routeParser)
? new $this->routeParser()
: $this->routeParser;
}

public function getDataGenerator(): DataGenerator
{
return $this->instances['dataGenerator'] ??= is_string($this->dataGenerator)
? new $this->dataGenerator()
: $this->dataGenerator;
}

public function getDispatcher(): Dispatcher
{
return $this->instances['dispatcher'] ??= is_string($this->dispatcher)
? new $this->dispatcher()
: $this->dispatcher;
}

public function getRoutesConfiguration(): ConfigureRoutes
{
return $this->instances['routesConfiguration'] ??= is_string($this->routesConfiguration)
? new $this->routesConfiguration($this->getRouteParser())
: $this->routesConfiguration;
}

public function getUriGenerator(): GenerateUri
{
return $this->instances['uriGenerator'] ??= is_string($this->uriGenerator)
? new $this->uriGenerator()
: $this->uriGenerator;
}

public function getCacheDriver(): ?Cache
{
return $this->instances['cacheDriver'] ??= is_string($this->cacheDriver)
? new $this->cacheDriver()
: $this->cacheDriver;
}

public static function recommended(): self
{
return new self(
RouteParser\Std::class,
DataGenerator\MarkBased::class,
Dispatcher\MarkBased::class,
RouteCollector::class,
GenerateUri\FromProcessedConfiguration::class,
FileCache::class,
);
}

public function disableCache(): self
{
return new self(
$this->routeParser,
$this->dataGenerator,
$this->dispatcher,
$this->routesConfiguration,
$this->uriGenerator,
null,
);
}

/** @param Cache|class-string<Cache> $driver */
public function withCache(Cache|string $driver): self
{
return new self(
$this->routeParser,
$this->dataGenerator,
$this->dispatcher,
$this->routesConfiguration,
$this->uriGenerator,
$driver,
);
}

public function useCharCountDispatcher(): self
{
return $this->useCustomDispatcher(
DataGenerator\CharCountBased::class,
Dispatcher\CharCountBased::class,
);
}

public function useGroupCountDispatcher(): self
{
return $this->useCustomDispatcher(
DataGenerator\GroupCountBased::class,
Dispatcher\GroupCountBased::class,
);
}

public function useGroupPosDispatcher(): self
{
return $this->useCustomDispatcher(
DataGenerator\GroupPosBased::class,
Dispatcher\GroupPosBased::class,
);
}

public function useMarkDispatcher(): self
{
return $this->useCustomDispatcher(
DataGenerator\MarkBased::class,
Dispatcher\MarkBased::class,
);
}

/**
* @param DataGenerator|class-string<DataGenerator> $dataGenerator
* @param Dispatcher|class-string<Dispatcher> $dispatcher
*/
public function useCustomDispatcher(DataGenerator|string $dataGenerator, Dispatcher|string $dispatcher): self
{
return new self(
$this->routeParser,
$dataGenerator,
$dispatcher,
$this->routesConfiguration,
$this->uriGenerator,
$this->cacheDriver,
);
}

/** @param GenerateUri|class-string<GenerateUri> $uriGenerator */
public function withUriGenerator(GenerateUri|string $uriGenerator): self
{
return new self(
$this->routeParser,
$this->dataGenerator,
$this->dispatcher,
$this->routesConfiguration,
$uriGenerator,
$this->cacheDriver,
);
}
}
1 change: 1 addition & 0 deletions src/GenerateUri.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
interface GenerateUri
{
/** @param ParsedRoutes $processedConfiguration */
public function with(array $processedConfiguration): self;

/**
Expand Down
4 changes: 3 additions & 1 deletion src/GenerateUri/FromProcessedConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
*/
final class FromProcessedConfiguration implements GenerateUri
{
/** @param RoutesForUriGeneration $processedConfiguration */
/** @var RoutesForUriGeneration $processedConfiguration */
private array $processedConfiguration = [];

/** @param RoutesForUriGeneration $processedConfiguration */
public function with(array $processedConfiguration): self
{
$clone = clone $this;
$clone->processedConfiguration = $processedConfiguration;

return $clone;
}

Expand Down
Loading

0 comments on commit 924ae7d

Please sign in to comment.