diff --git a/composer.json b/composer.json index 14970c7..711023f 100644 --- a/composer.json +++ b/composer.json @@ -35,12 +35,12 @@ "require": { "php": ">=8.1", "ext-json": "*", - "spiral/core": "^3.14.10", - "spiral/hmvc": "^3.14.10", - "spiral/http": "^3.14.10", - "spiral/interceptors": "^3.14.10", + "spiral/core": "^3.15", + "spiral/hmvc": "^3.15", + "spiral/http": "^3.15", + "spiral/interceptors": "^3.15", "cocur/slugify": "^3.2 || ^4.0", - "spiral/telemetry": "^3.14.10", + "spiral/telemetry": "^3.15", "doctrine/inflector": "^1.4|^2.0", "psr/event-dispatcher": "^1.0" }, diff --git a/src/AbstractRoute.php b/src/AbstractRoute.php index 14a5c21..4405481 100644 --- a/src/AbstractRoute.php +++ b/src/AbstractRoute.php @@ -30,7 +30,7 @@ abstract class AbstractRoute implements RouteInterface public function __construct( protected string $pattern, - array $defaults = [] + array $defaults = [], ) { $this->defaults = $defaults; } @@ -80,7 +80,7 @@ public function uri(iterable $parameters = []): UriInterface { return $this->uriHandler->uri( $parameters, - \array_merge($this->defaults, $this->matches ?? []) + \array_merge($this->defaults, $this->matches ?? []), ); } } diff --git a/src/Autofill.php b/src/Autofill.php index e5b37f4..6ae2a32 100644 --- a/src/Autofill.php +++ b/src/Autofill.php @@ -7,9 +7,8 @@ final class Autofill implements \Stringable { public function __construct( - private readonly string $value - ) { - } + private readonly string $value, + ) {} public function __toString(): string { diff --git a/src/CoreHandler.php b/src/CoreHandler.php index 1624ee7..42e9947 100644 --- a/src/CoreHandler.php +++ b/src/CoreHandler.php @@ -6,6 +6,7 @@ use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Server\RequestHandlerInterface; use Spiral\Core\CoreInterface; @@ -35,10 +36,13 @@ final class CoreHandler implements RequestHandlerInterface /** @readonly */ private ?string $controller = null; + /** @readonly */ private ?string $action = null; + /** @readonly */ private ?bool $verbActions = null; + /** @readonly */ private ?array $parameters = null; @@ -48,7 +52,7 @@ public function __construct( private readonly HandlerInterface|CoreInterface $core, private readonly ScopeInterface $scope, private readonly ResponseFactoryInterface $responseFactory, - ?TracerInterface $tracer = null + ?TracerInterface $tracer = null, ) { $this->tracer = $tracer ?? new NullTracer($scope); $this->isLegacyPipeline = !$core instanceof HandlerInterface; @@ -112,26 +116,29 @@ public function handle(Request $request): Response name: 'http-request', bindings: [Request::class => $request, Response::class => $response, $controller => $controller], ), - fn (): mixed => $this->tracer->trace( + fn(): mixed => $this->tracer->trace( name: 'Controller [' . $controller . ':' . $action . ']', callback: $this->isLegacyPipeline - ? fn (): mixed => $this->core->callAction( + ? fn(): mixed => $this->core->callAction( controller: $controller, action: $action, parameters: $parameters, ) - : fn (): mixed => $this->core->handle( + : fn(): mixed => $this->core->handle( new CallContext( Target::fromPair($controller, $action), $parameters, + [ + ServerRequestInterface::class => $request, + ], ), ), attributes: [ 'route.controller' => $this->controller, 'route.action' => $action, 'route.parameters' => \array_keys($parameters), - ] - ) + ], + ), ); } catch (TargetCallException $e) { \ob_get_clean(); @@ -176,7 +183,7 @@ private function wrapResponse(Response $response, mixed $result = null, string $ if (\is_array($result) || $result instanceof \JsonSerializable) { $response = $this->writeJson($response, $result); } else { - $response->getBody()->write((string)$result); + $response->getBody()->write((string) $result); } //Always glue buffered output diff --git a/src/Event/RouteMatched.php b/src/Event/RouteMatched.php index d4f01c4..a4fe559 100644 --- a/src/Event/RouteMatched.php +++ b/src/Event/RouteMatched.php @@ -12,6 +12,5 @@ final class RouteMatched public function __construct( public readonly ServerRequestInterface $request, public readonly RouteInterface $route, - ) { - } + ) {} } diff --git a/src/Event/RouteNotFound.php b/src/Event/RouteNotFound.php index c25bae2..df34248 100644 --- a/src/Event/RouteNotFound.php +++ b/src/Event/RouteNotFound.php @@ -9,7 +9,6 @@ final class RouteNotFound { public function __construct( - public readonly ServerRequestInterface $request - ) { - } + public readonly ServerRequestInterface $request, + ) {} } diff --git a/src/Event/Routing.php b/src/Event/Routing.php index a4a00ec..0a10d42 100644 --- a/src/Event/Routing.php +++ b/src/Event/Routing.php @@ -9,7 +9,6 @@ final class Routing { public function __construct( - public readonly ServerRequestInterface $request - ) { - } + public readonly ServerRequestInterface $request, + ) {} } diff --git a/src/Exception/ConstrainException.php b/src/Exception/ConstrainException.php index 7e12084..eb55fa0 100644 --- a/src/Exception/ConstrainException.php +++ b/src/Exception/ConstrainException.php @@ -4,6 +4,4 @@ namespace Spiral\Router\Exception; -class ConstrainException extends RouteException -{ -} +class ConstrainException extends RouteException {} diff --git a/src/Exception/HandlerException.php b/src/Exception/HandlerException.php index e257210..1a2b723 100644 --- a/src/Exception/HandlerException.php +++ b/src/Exception/HandlerException.php @@ -4,6 +4,4 @@ namespace Spiral\Router\Exception; -class HandlerException extends \RuntimeException -{ -} +class HandlerException extends \RuntimeException {} diff --git a/src/Exception/LoaderLoadException.php b/src/Exception/LoaderLoadException.php index ebf8de5..c8bb362 100644 --- a/src/Exception/LoaderLoadException.php +++ b/src/Exception/LoaderLoadException.php @@ -4,6 +4,4 @@ namespace Spiral\Router\Exception; -class LoaderLoadException extends \RuntimeException -{ -} +class LoaderLoadException extends \RuntimeException {} diff --git a/src/Exception/RouteException.php b/src/Exception/RouteException.php index 9763f5f..0f7556f 100644 --- a/src/Exception/RouteException.php +++ b/src/Exception/RouteException.php @@ -4,6 +4,4 @@ namespace Spiral\Router\Exception; -class RouteException extends RouterException -{ -} +class RouteException extends RouterException {} diff --git a/src/Exception/RouteNotFoundException.php b/src/Exception/RouteNotFoundException.php index ff2094a..647eb98 100644 --- a/src/Exception/RouteNotFoundException.php +++ b/src/Exception/RouteNotFoundException.php @@ -11,7 +11,7 @@ class RouteNotFoundException extends UndefinedRouteException public function __construct( private readonly UriInterface $uri, int $code = 0, - ?\Throwable $previous = null + ?\Throwable $previous = null, ) { parent::__construct(\sprintf('Unable to route `%s`.', (string) $uri), $code, $previous); } diff --git a/src/Exception/RouterException.php b/src/Exception/RouterException.php index 2fc84bd..2df3454 100644 --- a/src/Exception/RouterException.php +++ b/src/Exception/RouterException.php @@ -4,6 +4,4 @@ namespace Spiral\Router\Exception; -class RouterException extends \RuntimeException -{ -} +class RouterException extends \RuntimeException {} diff --git a/src/Exception/TargetException.php b/src/Exception/TargetException.php index 4346a51..3cdaa37 100644 --- a/src/Exception/TargetException.php +++ b/src/Exception/TargetException.php @@ -4,6 +4,4 @@ namespace Spiral\Router\Exception; -class TargetException extends \RuntimeException -{ -} +class TargetException extends \RuntimeException {} diff --git a/src/Exception/UndefinedRouteException.php b/src/Exception/UndefinedRouteException.php index 772a4b6..6205c91 100644 --- a/src/Exception/UndefinedRouteException.php +++ b/src/Exception/UndefinedRouteException.php @@ -4,6 +4,4 @@ namespace Spiral\Router\Exception; -class UndefinedRouteException extends RouterException -{ -} +class UndefinedRouteException extends RouterException {} diff --git a/src/Exception/UriHandlerException.php b/src/Exception/UriHandlerException.php index 3d184ca..b3ce021 100644 --- a/src/Exception/UriHandlerException.php +++ b/src/Exception/UriHandlerException.php @@ -4,6 +4,4 @@ namespace Spiral\Router\Exception; -class UriHandlerException extends \RuntimeException -{ -} +class UriHandlerException extends \RuntimeException {} diff --git a/src/GroupRegistry.php b/src/GroupRegistry.php index 71dcf9f..6744d90 100644 --- a/src/GroupRegistry.php +++ b/src/GroupRegistry.php @@ -20,9 +20,8 @@ final class GroupRegistry implements \IteratorAggregate private array $groups = []; public function __construct( - private readonly FactoryInterface $factory - ) { - } + private readonly FactoryInterface $factory, + ) {} /** * @param non-empty-string $name diff --git a/src/Loader/Configurator/ImportConfigurator.php b/src/Loader/Configurator/ImportConfigurator.php index 8f06263..b6a1d98 100644 --- a/src/Loader/Configurator/ImportConfigurator.php +++ b/src/Loader/Configurator/ImportConfigurator.php @@ -13,24 +13,8 @@ final class ImportConfigurator { public function __construct( private readonly RouteCollection $parent, - private readonly RouteCollection $routes - ) { - } - - public function __destruct() - { - $this->parent->addCollection($this->routes); - } - - public function __sleep(): array - { - throw new \BadMethodCallException('Cannot unserialize ' . self::class); - } - - public function __wakeup() - { - throw new \BadMethodCallException('Cannot unserialize ' . self::class); - } + private readonly RouteCollection $routes, + ) {} public function defaults(array $defaults): self { @@ -95,4 +79,19 @@ public function middleware(MiddlewareInterface|string|array $middleware): self return $this; } + + public function __sleep(): array + { + throw new \BadMethodCallException('Cannot unserialize ' . self::class); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize ' . self::class); + } + + public function __destruct() + { + $this->parent->addCollection($this->routes); + } } diff --git a/src/Loader/Configurator/RouteConfigurator.php b/src/Loader/Configurator/RouteConfigurator.php index b6ed22a..6e3ee48 100644 --- a/src/Loader/Configurator/RouteConfigurator.php +++ b/src/Loader/Configurator/RouteConfigurator.php @@ -35,41 +35,8 @@ final class RouteConfigurator public function __construct( private readonly string $name, private readonly string $pattern, - private readonly RouteCollection $collection - ) { - } - - public function __destruct() - { - if ($this->target === null) { - throw new TargetException( - \sprintf('The [%s] route has no defined target. Call one of: `controller`, `action`, - `namespaced`, `groupControllers`, `callable`, `handler` methods.', $this->name) - ); - } - - $this->collection->add($this->name, $this); - } - - /** - * @internal - * - * Don't use this method. For internal use only. - */ - public function __get(string $name): mixed - { - return match ($name) { - 'core' => $this->core, - 'target' => $this->target, - 'defaults' => $this->defaults, - 'group' => $this->group, - 'middleware' => $this->middleware, - 'methods' => $this->methods, - 'pattern' => $this->pattern, - 'prefix' => \trim($this->prefix, '/'), - default => throw new \BadMethodCallException(\sprintf('Unable to access %s.', $name)) - }; - } + private readonly RouteCollection $collection, + ) {} public function controller(string $controller, int $options = 0, string $defaultAction = 'index'): self { @@ -158,4 +125,36 @@ public function methods(string|array $methods): self return $this; } + + /** + * @internal + * + * Don't use this method. For internal use only. + */ + public function __get(string $name): mixed + { + return match ($name) { + 'core' => $this->core, + 'target' => $this->target, + 'defaults' => $this->defaults, + 'group' => $this->group, + 'middleware' => $this->middleware, + 'methods' => $this->methods, + 'pattern' => $this->pattern, + 'prefix' => \trim($this->prefix, '/'), + default => throw new \BadMethodCallException(\sprintf('Unable to access %s.', $name)), + }; + } + + public function __destruct() + { + if ($this->target === null) { + throw new TargetException( + \sprintf('The [%s] route has no defined target. Call one of: `controller`, `action`, + `namespaced`, `groupControllers`, `callable`, `handler` methods.', $this->name), + ); + } + + $this->collection->add($this->name, $this); + } } diff --git a/src/Loader/Configurator/RoutingConfigurator.php b/src/Loader/Configurator/RoutingConfigurator.php index dcbec44..9deaa67 100644 --- a/src/Loader/Configurator/RoutingConfigurator.php +++ b/src/Loader/Configurator/RoutingConfigurator.php @@ -13,9 +13,8 @@ final class RoutingConfigurator public function __construct( private readonly RouteCollection $collection, - private readonly LoaderInterface $loader - ) { - } + private readonly LoaderInterface $loader, + ) {} public function import(string|array $resource, ?string $type = null): ImportConfigurator { diff --git a/src/Loader/DelegatingLoader.php b/src/Loader/DelegatingLoader.php index 8a782ed..d76da66 100644 --- a/src/Loader/DelegatingLoader.php +++ b/src/Loader/DelegatingLoader.php @@ -9,9 +9,8 @@ final class DelegatingLoader implements LoaderInterface { public function __construct( - private readonly LoaderRegistryInterface $registry - ) { - } + private readonly LoaderRegistryInterface $registry, + ) {} public function load(mixed $resource, ?string $type = null): mixed { diff --git a/src/Loader/PhpFileLoader.php b/src/Loader/PhpFileLoader.php index bae5f2d..c6c33ea 100644 --- a/src/Loader/PhpFileLoader.php +++ b/src/Loader/PhpFileLoader.php @@ -4,7 +4,6 @@ namespace Spiral\Router\Loader; -use Spiral\Core\Container; use Spiral\Core\FactoryInterface; use Spiral\Core\ResolverInterface; use Spiral\Router\Exception\LoaderLoadException; @@ -16,8 +15,7 @@ final class PhpFileLoader implements LoaderInterface public function __construct( private readonly FactoryInterface $factory, private readonly ResolverInterface $resolver, - ) { - } + ) {} /** * Loads a PHP file. @@ -28,7 +26,7 @@ public function load(mixed $resource, ?string $type = null): RouteCollection throw new LoaderLoadException(\sprintf('File [%s] does not exist.', $resource)); } - $load = static fn (string $path) => include $path; + $load = static fn(string $path) => include $path; $callback = $load($resource); diff --git a/src/PipelineFactory.php b/src/PipelineFactory.php index 3365e47..baafa8f 100644 --- a/src/PipelineFactory.php +++ b/src/PipelineFactory.php @@ -16,9 +16,8 @@ final class PipelineFactory { public function __construct( private readonly ContainerInterface $container, - private readonly FactoryInterface $factory - ) { - } + private readonly FactoryInterface $factory, + ) {} /** * @throws RouteException diff --git a/src/Route.php b/src/Route.php index 270c79f..fec0d4c 100644 --- a/src/Route.php +++ b/src/Route.php @@ -41,6 +41,7 @@ final class Route extends AbstractRoute implements ContainerizedInterface /** @var string|callable|RequestHandlerInterface|TargetInterface */ private mixed $target; + private ?RequestHandlerInterface $requestHandler = null; /** @@ -51,13 +52,13 @@ final class Route extends AbstractRoute implements ContainerizedInterface public function __construct( string $pattern, string|callable|RequestHandlerInterface|TargetInterface $target, - array $defaults = [] + array $defaults = [], ) { parent::__construct( $pattern, $target instanceof TargetInterface ? \array_merge($target->getDefaults(), $defaults) - : $defaults + : $defaults, ); $this->target = $target; @@ -90,7 +91,7 @@ public function withContainer(ContainerInterface $container): ContainerizedInter $route->target = clone $route->target; } - $route->pipeline = $route->makePipeline(); + $route->pipeline = $route->makeLazyPipeline(); return $route; } @@ -120,7 +121,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface \assert($this->pipeline !== null); return $this->pipeline->process( $request->withAttribute(self::ROUTE_ATTRIBUTE, $this), - $this->requestHandler + $this->requestHandler, ); } @@ -129,9 +130,9 @@ public function handle(ServerRequestInterface $request): ResponseInterface */ protected function requestHandler(): RequestHandlerInterface { - if (!$this->hasContainer()) { - throw new RouteException('Unable to configure route pipeline without associated container'); - } + $this->hasContainer() or throw new RouteException( + 'Unable to configure route pipeline without associated container.', + ); if ($this->target instanceof TargetInterface) { try { @@ -157,7 +158,7 @@ protected function requestHandler(): RequestHandlerInterface return new CallableHandler( $target, - $this->container->get(ResponseFactoryInterface::class) + $this->container->get(ResponseFactoryInterface::class), ); } catch (ContainerExceptionInterface $e) { throw new RouteException($e->getMessage(), $e->getCode(), $e); diff --git a/src/RouteCollection.php b/src/RouteCollection.php index e752a4d..b8e3306 100644 --- a/src/RouteCollection.php +++ b/src/RouteCollection.php @@ -14,13 +14,6 @@ class RouteCollection implements \IteratorAggregate, \Countable /** @var array */ private array $routes = []; - public function __clone() - { - foreach ($this->routes as $name => $route) { - $this->routes[$name] = clone $route; - } - } - /** * Gets the current RouteCollection as an Iterator that includes all routes. * @@ -124,4 +117,11 @@ public function group(string $group) $route->group($group); } } + + public function __clone() + { + foreach ($this->routes as $name => $route) { + $this->routes[$name] = clone $route; + } + } } diff --git a/src/RouteGroup.php b/src/RouteGroup.php index 0ef0384..4b436e9 100644 --- a/src/RouteGroup.php +++ b/src/RouteGroup.php @@ -36,9 +36,8 @@ public function __construct( /** @deprecated since v3.3.0 */ private readonly ?RouterInterface $router = null, /** @deprecated since v3.3.0 */ - private readonly ?UriHandler $handler = null - ) { - } + private readonly ?UriHandler $handler = null, + ) {} /** * Check if group has a route with given name @@ -114,7 +113,7 @@ public function register(RouterInterface $router, FactoryInterface $factory): vo $name, $route ->withUriHandler($uriHandler->withPrefix($this->prefix)) - ->withMiddleware(...$this->middleware) + ->withMiddleware(...$this->middleware), ); } } diff --git a/src/Router.php b/src/Router.php index cf8dbb4..92db18d 100644 --- a/src/Router.php +++ b/src/Router.php @@ -67,7 +67,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface return $this->tracer->trace( name: 'Routing', - callback: function (SpanInterface $span) use ($request) { + callback: function (SpanInterface $span) use ($request): ResponseInterface { try { $route = $this->matchRoute($request, $routeName); } catch (RouteException $e) { @@ -80,7 +80,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface } $span - ->setAttribute('request.uri', (string)$request->getUri()) + ->setAttribute('request.uri', (string) $request->getUri()) ->setAttribute('route.name', $routeName) ->setAttribute('route.matches', $route->getMatches() ?? []); @@ -92,7 +92,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface $this->eventDispatcher?->dispatch(new RouteMatched($request, $route)); return $route->handle($request); - } + }, ); } @@ -228,11 +228,11 @@ protected function castRoute(string $route): RouteInterface !\preg_match( '/^(?:(?P[^\/]+)\/)?(?:(?P[^:]+):+)?(?P[a-z_\-]+)$/i', $route, - $matches + $matches, ) ) { throw new UndefinedRouteException( - "Unable to locate route or use default route with 'name/controller:action' pattern" + "Unable to locate route or use default route with 'name/controller:action' pattern", ); } @@ -251,7 +251,7 @@ protected function castRoute(string $route): RouteInterface [ 'controller' => $matches['controller'], 'action' => $matches['action'], - ] + ], ); } } diff --git a/src/Target/AbstractTarget.php b/src/Target/AbstractTarget.php index 7e18d81..5fd0380 100644 --- a/src/Target/AbstractTarget.php +++ b/src/Target/AbstractTarget.php @@ -35,7 +35,7 @@ public function __construct( private array $defaults, private array $constrains, int $options = 0, - private string $defaultAction = 'index' + private string $defaultAction = 'index', ) { $this->verbActions = ($options & self::RESTFUL) === self::RESTFUL; } @@ -80,7 +80,7 @@ public function getHandler(ContainerInterface $container, array $matches): Handl return $this->coreHandler($container)->withContext( $this->resolveController($matches), $this->resolveAction($matches) ?? $this->defaultAction, - $matches + $matches, )->withVerbActions($this->verbActions); } @@ -102,7 +102,7 @@ protected function coreHandler(ContainerInterface $container): CoreHandler }, $scope, $container->get(ResponseFactoryInterface::class), - $container->get(TracerInterface::class) + $container->get(TracerInterface::class), ); return $this->handler; diff --git a/src/Target/Action.php b/src/Target/Action.php index 0d003ec..e5482c8 100644 --- a/src/Target/Action.php +++ b/src/Target/Action.php @@ -24,19 +24,19 @@ final class Action extends AbstractTarget public function __construct( private readonly string $controller, private readonly string|array $action, - int $options = 0 + int $options = 0, ) { if (\is_string($action)) { parent::__construct( ['action' => $action], ['action' => new Autofill($action)], - $options + $options, ); } else { parent::__construct( ['action' => null], ['action' => $action], - $options + $options, ); } } diff --git a/src/Target/Controller.php b/src/Target/Controller.php index 4174c14..4bc0425 100644 --- a/src/Target/Controller.php +++ b/src/Target/Controller.php @@ -14,13 +14,13 @@ final class Controller extends AbstractTarget public function __construct( private readonly string $controller, int $options = 0, - string $defaultAction = 'index' + string $defaultAction = 'index', ) { parent::__construct( ['action' => null], ['action' => null], $options, - $defaultAction + $defaultAction, ); } diff --git a/src/Target/Group.php b/src/Target/Group.php index 23a2a35..49c2bbc 100644 --- a/src/Target/Group.php +++ b/src/Target/Group.php @@ -18,13 +18,13 @@ final class Group extends AbstractTarget public function __construct( private readonly array $controllers, int $options = 0, - string $defaultAction = 'index' + string $defaultAction = 'index', ) { parent::__construct( ['controller' => null, 'action' => null], ['controller' => \array_keys($controllers), 'action' => null], $options, - $defaultAction + $defaultAction, ); } diff --git a/src/Target/Namespaced.php b/src/Target/Namespaced.php index c51a6e2..b2e74c0 100644 --- a/src/Target/Namespaced.php +++ b/src/Target/Namespaced.php @@ -25,7 +25,7 @@ final class Namespaced extends AbstractTarget public function __construct( string $namespace, string $postfix = 'Controller', - int $options = 0 + int $options = 0, ) { $this->namespace = \rtrim($namespace, '\\'); $this->postfix = \ucfirst($postfix); @@ -33,7 +33,7 @@ public function __construct( parent::__construct( ['controller' => null, 'action' => null], ['controller' => null, 'action' => null], - $options + $options, ); $this->inflector = (new InflectorFactory())->build(); @@ -52,7 +52,7 @@ protected function resolveController(array $matches): string '%s\\%s%s', $this->namespace, $this->inflector->classify($matches['controller']), - $this->postfix + $this->postfix, ); } diff --git a/src/Traits/PipelineTrait.php b/src/Traits/PipelineTrait.php index dd43f80..32c5ad7 100644 --- a/src/Traits/PipelineTrait.php +++ b/src/Traits/PipelineTrait.php @@ -7,6 +7,7 @@ use Psr\Container\ContainerExceptionInterface; use Psr\Http\Server\MiddlewareInterface; use Spiral\Core\Container\Autowire; +use Spiral\Http\LazyPipeline; use Spiral\Http\Pipeline; use Spiral\Router\Exception\RouteException; use Spiral\Router\PipelineFactory; @@ -19,7 +20,7 @@ trait PipelineTrait { use ContainerTrait; - protected ?Pipeline $pipeline = null; + protected Pipeline|LazyPipeline|null $pipeline = null; /** @psalm-var array */ protected array $middleware = []; @@ -53,7 +54,7 @@ public function withMiddleware(...$middleware): RouteInterface } if ($route->pipeline !== null) { - $route->pipeline = $route->makePipeline(); + $route->pipeline = $route->makeLazyPipeline(); } return $route; @@ -73,6 +74,8 @@ public function withPipeline(Pipeline $pipeline): static * Get associated route pipeline. * * @throws RouteException + * + * @deprecated Will be removed in Spiral v4.0. Use {@see makeLazyPipeline()} instead. */ protected function makePipeline(): Pipeline { @@ -85,4 +88,21 @@ protected function makePipeline(): Pipeline throw new RouteException($e->getMessage(), $e->getCode(), $e); } } + + /** + * Get associated route pipeline. + * + * @throws RouteException + */ + protected function makeLazyPipeline(): LazyPipeline + { + \assert($this->container !== null); + try { + /** @var LazyPipeline $pipeline */ + $pipeline = $this->container->get(LazyPipeline::class); + return $pipeline->withMiddleware(...$this->middleware); + } catch (ContainerExceptionInterface $e) { + throw new RouteException($e->getMessage(), $e->getCode(), $e); + } + } } diff --git a/src/UriHandler.php b/src/UriHandler.php index e8961a2..3d071de 100644 --- a/src/UriHandler.php +++ b/src/UriHandler.php @@ -29,24 +29,28 @@ final class UriHandler '[/]' => '', '[' => '', ']' => '', - '://' => '://', '//' => '/', + // todo: probably should be removed. There are no examples of usage or cases where it is needed. + '://' => '://', ]; private ?string $pattern = null; - private readonly RoutePatternRegistryInterface $patternRegistry; private array $constrains = []; private array $defaults = []; private bool $matchHost = false; + /** @readonly */ private string $prefix = ''; + /** @readonly */ private string $basePath = '/'; + private ?string $compiled = null; private ?string $template = null; private array $options = []; - + private array $requiredOptions = []; + private bool $strict = false; private \Closure $pathSegmentEncoder; /** @@ -61,7 +65,12 @@ public function __construct( $this->patternRegistry = $patternRegistry ?? new DefaultPatternRegistry(); $slugify ??= new Slugify(); - $this->pathSegmentEncoder = static fn (string $segment): string => $slugify->slugify($segment); + $this->pathSegmentEncoder = static fn(string $segment): string => $slugify->slugify($segment); + } + + public function setStrict(bool $strict): void + { + $this->strict = $strict; } /** @@ -182,8 +191,8 @@ public function match(UriInterface $uri, array $defaults): ?array } $matches = \array_intersect_key( - \array_filter($matches, static fn (string $value) => $value !== ''), - $this->options + \array_filter($matches, static fn(string $value): bool => $value !== ''), + $this->options, ); return \array_merge($this->options, $defaults, $matches); @@ -201,15 +210,33 @@ public function uri(iterable $parameters = [], array $defaults = []): UriInterfa $parameters = \array_merge( $this->options, $defaults, - $this->fetchOptions($parameters, $query) + $this->fetchOptions($parameters, $query), ); - foreach ($this->constrains as $key => $_) { + $required = \array_keys($this->constrains); + if ($this->strict) { + $required = \array_unique([...$this->requiredOptions, ...$required]); + } + + $missingParameters = []; + + foreach ($required as $key) { if (empty($parameters[$key])) { - throw new UriHandlerException(\sprintf('Unable to generate Uri, parameter `%s` is missing', $key)); + $missingParameters[] = $key; } } + if ($missingParameters !== []) { + throw new UriHandlerException( + \sprintf( + \count($missingParameters) === 1 + ? 'Unable to generate Uri, parameter `%s` is missing' + : 'Unable to generate Uri, parameters `%s` are missing', + \implode('`, `', $missingParameters), + ), + ); + } + //Uri without empty blocks (pretty stupid implementation) $path = $this->interpolate($this->template, $parameters); @@ -245,7 +272,7 @@ private function fetchOptions(iterable $parameters, ?array &$query): array continue; } - $result[$key] = (string)$parameter; + $result[$key] = (string) $parameter; } return $result; @@ -262,14 +289,9 @@ private function fetchTarget(UriInterface $uri): string $path = '/' . $path; } - if ($this->matchHost) { - $uriString = $uri->getHost() . $path; - } else { - $uriString = \substr($path, \strlen($this->basePath)); - if ($uriString === false) { - $uriString = ''; - } - } + $uriString = $this->matchHost + ? $uri->getHost() . $path + : \substr($path, \strlen($this->basePath)); return \trim($uriString, '/'); } @@ -289,6 +311,7 @@ private function compile(): void $options = []; $replaces = []; + // 1) Build full pattern $prefix = \rtrim($this->getPrefix(), '/ '); $pattern = \ltrim($this->pattern, '/ '); $pattern = $prefix . '/' . $pattern; @@ -299,6 +322,7 @@ private function compile(): void $pattern = '[' . \substr($pattern, 2); } + // 2) Extract variables from the pattern if (\preg_match_all('/<(\w+):?(.*?)?>/', $pattern, $matches)) { $variables = \array_combine($matches[1], $matches[2]); @@ -309,29 +333,97 @@ private function compile(): void } } + // Simplify template $template = \preg_replace('/<(\w+):?.*?>/', '<\1>', $pattern); $options = \array_fill_keys($options, null); + // 3) Validate constraints foreach ($this->constrains as $key => $value) { if ($value instanceof Autofill) { // only forces value replacement, not required to be presented as parameter continue; } + // If a constraint references a param that doesn't appear in the pattern or defaults if (!\array_key_exists($key, $options) && !isset($this->defaults[$key])) { throw new ConstrainException( \sprintf( 'Route `%s` does not define routing parameter `<%s>`.', $this->pattern, - $key - ) + $key, + ), ); } } + // 4) Compile your final regex pattern $this->compiled = '/^' . \strtr($template, $replaces + self::PATTERN_REPLACES) . '$/iu'; $this->template = \stripslashes(\str_replace('?', '', $template)); $this->options = $options; + + // 5) Mark which parameters are required vs. optional + if ($this->strict) { + $this->requiredOptions = $this->findRequiredOptions($pattern, \array_keys($options)); + } + } + + /** + * Find which parameters are required based on bracket notation and defaults. + * + * @param string $pattern The full pattern (with optional segments in [ ]) + * @param array $paramNames All the parameter names found (e.g. ['id','controller','action']) + * @return array List of required parameter names + */ + private function findRequiredOptions(string $pattern, array $paramNames): array + { + // This array will collect optional vars, either because they're in [ ] or have defaults + $optionalVars = []; + + // 1) Identify any variables that appear in optional bracket segments + $optLevel = 0; + $pos = 0; + $length = \strlen($pattern); + + while ($pos < $length) { + $char = $pattern[$pos]; + + if ($char === '[') { + // We enter an optional segment + ++$optLevel; + } elseif ($char === ']') { + // We exit an optional segment + $optLevel = \max(0, $optLevel - 1); + } elseif ($char === '<') { + // We see a parameter like or + + // Find the closing '>' + $endPos = \strpos($pattern, '>', $pos); + if ($endPos === false) { + break; + } + + // The inside is something like 'id:\d+' or just 'id' + $varPart = \substr($pattern, $pos + 1, $endPos - $pos - 1); + + // The first chunk is the variable name (before any :) + $varName = \explode(':', $varPart)[0]; + + // If we are inside a bracket, that var is optional + $optLevel > 0 and $optionalVars[] = $varName; + + // Move past this variable + $pos = $endPos; + } + + $pos++; + } + + // 2) Also mark anything that has a default value as optional + // so we merge them into $optionalVars + $optionalVars = \array_unique($optionalVars); + + // 3) Required = everything in $paramNames that is not in optionalVars + return \array_diff($paramNames, $optionalVars); } /** @@ -342,12 +434,16 @@ private function interpolate(string $string, array $values): string $replaces = []; foreach ($values as $key => $value) { $replaces[\sprintf('<%s>', $key)] = match (true) { - $value instanceof \Stringable || \is_scalar($value) => (string)$value, + $value instanceof \Stringable || \is_scalar($value) => (string) $value, default => '', }; } - return \strtr($string, $replaces + self::URI_FIXERS); + // Replace all variables + $path = \strtr($string, $replaces + self::URI_FIXERS); + + // Remove all empty segments + return \preg_replace('/\/{2,}/', '/', $path); } /** @@ -360,9 +456,9 @@ private function prepareSegment(string $name, string $segment): string !isset($this->constrains[$name]) => self::DEFAULT_SEGMENT, \is_array($this->constrains[$name]) => \implode( '|', - \array_map(fn (string $segment): string => $this->filterSegment($segment), $this->constrains[$name]) + \array_map(fn(string $segment): string => $this->filterSegment($segment), $this->constrains[$name]), ), - default => $this->filterSegment((string)$this->constrains[$name]) + default => $this->filterSegment((string) $this->constrains[$name]), }; } diff --git a/tests/BaseTestCase.php b/tests/BaseTestCase.php index 02083e3..895e304 100644 --- a/tests/BaseTestCase.php +++ b/tests/BaseTestCase.php @@ -37,23 +37,35 @@ abstract class BaseTestCase extends TestCase protected Container $container; protected Router $router; + public static function middlewaresDataProvider(): \Traversable + { + yield [TestMiddleware::class]; + yield [new TestMiddleware()]; + yield [new Autowire(TestMiddleware::class)]; + } + protected function setUp(): void { $this->initContainer(); $this->initRouter(); } + protected function getContainer(): Container + { + return $this->container; + } + protected function makeRouter(string $basePath = '', ?EventDispatcherInterface $dispatcher = null): RouterInterface { return new Router( $basePath, new UriHandler( new UriFactory(), - new Slugify() + new Slugify(), ), $this->container, $dispatcher, - new NullTracer($this->container) + new NullTracer($this->container), ); } @@ -67,13 +79,6 @@ protected function getProperty(object $object, string $property): mixed return $r->getProperty($property)->getValue($object); } - public static function middlewaresDataProvider(): \Traversable - { - yield [TestMiddleware::class]; - yield [new TestMiddleware()]; - yield [new Autowire(TestMiddleware::class)]; - } - private function initContainer(): void { $options = new Options(); @@ -88,8 +93,8 @@ private function initContainer(): void new LoaderRegistry([ new PhpFileLoader($this->container, $this->container), new TestLoader(), - ]) - ) + ]), + ), ); $this->container->bind(HandlerInterface::class, Core::class); diff --git a/tests/BaseTestingCase.php b/tests/BaseTestingCase.php new file mode 100644 index 0000000..3eb4e58 --- /dev/null +++ b/tests/BaseTestingCase.php @@ -0,0 +1,40 @@ +router = $this->getContainer()->get(RouterInterface::class); + } + + /** + * @throws \ReflectionException + */ + protected function getProperty(object $object, string $property): mixed + { + $r = new \ReflectionObject($object); + + return $r->getProperty($property)->getValue($object); + } +} diff --git a/tests/CallableTest.php b/tests/CallableTest.php index d283c53..c74a51c 100644 --- a/tests/CallableTest.php +++ b/tests/CallableTest.php @@ -16,12 +16,12 @@ public function testFunctionRoute(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/something', fn() => 'hello world') + new Route('/something', static fn(): string => 'hello world'), ); $response = $router->handle(new ServerRequest('GET', new Uri('/something'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); } public function testObjectRoute(): void @@ -29,12 +29,12 @@ public function testObjectRoute(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/something', new Call()) + new Route('/something', new Call()), ); $response = $router->handle(new ServerRequest('GET', new Uri('/something'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('invoked', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('invoked', (string) $response->getBody()); } public function testObjectViaContainerRoute(): void @@ -42,12 +42,12 @@ public function testObjectViaContainerRoute(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/something', Call::class) + new Route('/something', Call::class), ); $response = $router->handle(new ServerRequest('GET', new Uri('/something'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('invoked', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('invoked', (string) $response->getBody()); } public function testHandlerRoute(): void @@ -55,12 +55,12 @@ public function testHandlerRoute(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/something', new Handler()) + new Route('/something', new Handler()), ); $response = $router->handle(new ServerRequest('GET', new Uri('/something'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('handler', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('handler', (string) $response->getBody()); } public function testHandlerViaContainerRoute(): void @@ -68,12 +68,12 @@ public function testHandlerViaContainerRoute(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/something', Handler::class) + new Route('/something', Handler::class), ); $response = $router->handle(new ServerRequest('GET', new Uri('/something'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('handler', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('handler', (string) $response->getBody()); } public function testInvalidTarget(): void @@ -83,11 +83,11 @@ public function testInvalidTarget(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/something', 'something') + new Route('/something', 'something'), ); $response = $router->handle(new ServerRequest('GET', new Uri('/something'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('handler', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('handler', (string) $response->getBody()); } } diff --git a/tests/ContainerScopeTest.php b/tests/ContainerScopeTest.php index c74cd66..b2bf9c7 100644 --- a/tests/ContainerScopeTest.php +++ b/tests/ContainerScopeTest.php @@ -15,7 +15,7 @@ use Spiral\Tests\Router\Fixtures\UserContextController; use Spiral\Tests\Router\Stub\IdentityScopedMiddleware; -class ContainerScopeTest extends \Spiral\Testing\TestCase +class ContainerScopeTest extends BaseTestingCase { public function defineBootloaders(): array { diff --git a/tests/ControllerTest.php b/tests/ControllerTest.php index 4005708..9cff180 100644 --- a/tests/ControllerTest.php +++ b/tests/ControllerTest.php @@ -4,7 +4,6 @@ namespace Spiral\Tests\Router; -use Spiral\Core\Container; use Spiral\Core\CoreInterface; use Spiral\Http\Exception\ClientException\NotFoundException; use Spiral\Interceptors\Handler\AutowireHandler; @@ -27,7 +26,7 @@ public function testRouteException(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('//', new Controller(TestController::class)) + new Route('//', new Controller(TestController::class)), ); $router->handle(new ServerRequest('GET', '')); @@ -38,20 +37,20 @@ public function testRoute(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/[/]', new Controller(TestController::class)) + new Route('/[/]', new Controller(TestController::class)), ); $response = $router->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); $response = $router->handle(new ServerRequest('GET', new Uri('/echo'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('echoed', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('echoed', (string) $response->getBody()); $response = $router->handle(new ServerRequest('GET', new Uri('/id/888'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('888', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('888', (string) $response->getBody()); } public function testOptionalParam(): void @@ -59,26 +58,26 @@ public function testOptionalParam(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/default[/]', new Action(TestController::class, 'default')) + new Route('/default[/]', new Action(TestController::class, 'default')), ); $response = $router->handle(new ServerRequest('GET', new Uri('/default'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('default', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('default', (string) $response->getBody()); $response = $router->handle(new ServerRequest('GET', new Uri('/default/123'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('123', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('123', (string) $response->getBody()); } public function testFallbackHandler(): void { $target = new Action(TestController::class, 'default'); - $this->container->removeBinding(HandlerInterface::class); - $this->container->removeBinding(CoreInterface::class); + $this->getContainer()->removeBinding(HandlerInterface::class); + $this->getContainer()->removeBinding(CoreInterface::class); - $core = $target->getHandler($this->container, []); - $handler = (fn(CoreHandler $core) => $core->core)->call($core, $core); + $core = $target->getHandler($this->getContainer(), []); + $handler = (fn(CoreHandler $core): HandlerInterface|CoreInterface => $core->core)->call($core, $core); self::assertInstanceOf(AutowireHandler::class, $handler); } @@ -88,16 +87,16 @@ public function testOptionalParamWithDefaultInt(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/defaultInt[/]', new Action(TestController::class, 'defaultInt')) + new Route('/defaultInt[/]', new Action(TestController::class, 'defaultInt')), ); $response = $router->handle(new ServerRequest('GET', new Uri('/defaultInt'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('int: 1', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('int: 1', (string) $response->getBody()); $response = $router->handle(new ServerRequest('GET', new Uri('/defaultInt/123'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('string: 123', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('string: 123', (string) $response->getBody()); } public function testUriGeneration(): void @@ -105,14 +104,14 @@ public function testUriGeneration(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('//', new Controller(TestController::class)) + new Route('//', new Controller(TestController::class)), ); $uri = $router->uri('action/test'); - $this->assertSame('/test', $uri->getPath()); + self::assertSame('/test', $uri->getPath()); $uri = $router->uri('action/id', ['id' => 100]); - $this->assertSame('/id/100', $uri->getPath()); + self::assertSame('/id/100', $uri->getPath()); } public function testClientException(): void @@ -122,7 +121,7 @@ public function testClientException(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/[/]', new Controller(TestController::class)) + new Route('/[/]', new Controller(TestController::class)), ); $router->handle(new ServerRequest('GET', new Uri('/other'))); diff --git a/tests/Core.php b/tests/Core.php index 49e9993..e5f9aad 100644 --- a/tests/Core.php +++ b/tests/Core.php @@ -6,6 +6,4 @@ use Spiral\Core\AbstractCore; -class Core extends AbstractCore -{ -} +class Core extends AbstractCore {} diff --git a/tests/CoreTest.php b/tests/CoreTest.php index 7622a4d..6400ee6 100644 --- a/tests/CoreTest.php +++ b/tests/CoreTest.php @@ -43,7 +43,7 @@ public function testAutoCore(): void $action = new Action(TestController::class, 'test'); $handler = $action->getHandler($this->getContainer(), []); - $this->assertInstanceOf(CoreHandler::class, $handler); + self::assertInstanceOf(CoreHandler::class, $handler); } public function testWithAutoCore(): void @@ -53,11 +53,11 @@ public function testWithAutoCore(): void $action = $action->withCore(new TestCore($this->getContainer()->get(CoreInterface::class))); $handler = $action->getHandler($this->getContainer(), []); - $this->assertInstanceOf(CoreHandler::class, $handler); + self::assertInstanceOf(CoreHandler::class, $handler); $result = $handler->handle(new ServerRequest('GET', '')); - $this->assertSame('@wrapped.hello world', (string)$result->getBody()); + self::assertSame('@wrapped.hello world', (string) $result->getBody()); } public function testErrAction(): void @@ -70,7 +70,7 @@ public function testErrAction(): void $action = $action->withCore(new TestCore($this->getContainer()->get(CoreInterface::class))); $handler = $action->getHandler($this->getContainer(), []); - $this->assertInstanceOf(CoreHandler::class, $handler); + self::assertInstanceOf(CoreHandler::class, $handler); $handler->handle(new ServerRequest('GET', '')); } @@ -80,11 +80,11 @@ public function testRSP(): void $action = new Action(TestController::class, 'rsp'); $handler = $action->getHandler($this->getContainer(), []); - $this->assertInstanceOf(CoreHandler::class, $handler); + self::assertInstanceOf(CoreHandler::class, $handler); $result = $handler->handle(new ServerRequest('GET', '')); - $this->assertSame('rspbuf', (string)$result->getBody()); + self::assertSame('rspbuf', (string) $result->getBody()); } public function testJson(): void @@ -92,12 +92,12 @@ public function testJson(): void $action = new Action(TestController::class, 'json'); $handler = $action->getHandler($this->getContainer(), []); - $this->assertInstanceOf(CoreHandler::class, $handler); + self::assertInstanceOf(CoreHandler::class, $handler); $result = $handler->handle(new ServerRequest('GET', '')); - $this->assertSame(301, $result->getStatusCode()); - $this->assertSame('{"status":301,"msg":"redirect"}', (string)$result->getBody()); + self::assertSame(301, $result->getStatusCode()); + self::assertSame('{"status":301,"msg":"redirect"}', (string) $result->getBody()); } public function testForbidden(): void @@ -138,10 +138,10 @@ public function testRESTFul(): void $action = new Action(TestController::class, 'Target', Action::RESTFUL); $r = $action->getHandler($this->getContainer(), [])->handle(new ServerRequest('POST', '')); - $this->assertSame('POST', (string)$r->getBody()); + self::assertSame('POST', (string) $r->getBody()); $r = $action->getHandler($this->getContainer(), [])->handle(new ServerRequest('DELETE', '')); - $this->assertSame('DELETE', (string)$r->getBody()); + self::assertSame('DELETE', (string) $r->getBody()); } } diff --git a/tests/DefaultPatternRegistryTest.php b/tests/DefaultPatternRegistryTest.php index 8f986e5..59c75db 100644 --- a/tests/DefaultPatternRegistryTest.php +++ b/tests/DefaultPatternRegistryTest.php @@ -20,12 +20,9 @@ public function testAll(): void $registry->register('foo', '\d+'); $registry->register('bar', '\d+'); - $this->assertSame( - self::DEFAULT_PATTERNS + [ - 'foo' => '\d+', - 'bar' => '\d+' - ], - $registry->all() - ); + self::assertSame(self::DEFAULT_PATTERNS + [ + 'foo' => '\d+', + 'bar' => '\d+', + ], $registry->all()); } } diff --git a/tests/Diactoros/ResponseFactory.php b/tests/Diactoros/ResponseFactory.php index 98cb8d0..a51f79c 100644 --- a/tests/Diactoros/ResponseFactory.php +++ b/tests/Diactoros/ResponseFactory.php @@ -11,9 +11,7 @@ final class ResponseFactory implements ResponseFactoryInterface { - public function __construct(protected HttpConfig $config) - { - } + public function __construct(protected HttpConfig $config) {} public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface { diff --git a/tests/Diactoros/StreamFactory.php b/tests/Diactoros/StreamFactory.php index b79669a..24ee542 100644 --- a/tests/Diactoros/StreamFactory.php +++ b/tests/Diactoros/StreamFactory.php @@ -10,9 +10,6 @@ final class StreamFactory implements StreamFactoryInterface { - /** - * @inheritdoc - */ public function createStream(string $content = ''): StreamInterface { $resource = fopen('php://temp', 'r+'); @@ -21,18 +18,12 @@ public function createStream(string $content = ''): StreamInterface return $this->createStreamFromResource($resource); } - /** - * @inheritdoc - */ public function createStreamFromFile(string $file, string $mode = 'r'): StreamInterface { $resource = fopen($file, $mode); return $this->createStreamFromResource($resource); } - /** - * @inheritdoc - */ public function createStreamFromResource($resource): StreamInterface { return Stream::create($resource); diff --git a/tests/Diactoros/UploadedFileFactory.php b/tests/Diactoros/UploadedFileFactory.php index 2a91bee..0134d66 100644 --- a/tests/Diactoros/UploadedFileFactory.php +++ b/tests/Diactoros/UploadedFileFactory.php @@ -11,15 +11,12 @@ final class UploadedFileFactory implements UploadedFileFactoryInterface { - /** - * @inheritdoc - */ public function createUploadedFile( StreamInterface $stream, ?int $size = null, int $error = \UPLOAD_ERR_OK, ?string $clientFilename = null, - ?string $clientMediaType = null + ?string $clientMediaType = null, ): UploadedFileInterface { if ($size === null) { $size = $stream->getSize(); diff --git a/tests/Fixtures/TestController.php b/tests/Fixtures/TestController.php index efe6ef0..f6e7d5b 100644 --- a/tests/Fixtures/TestController.php +++ b/tests/Fixtures/TestController.php @@ -62,7 +62,7 @@ public function json(): array { return [ 'status' => 301, - 'msg' => 'redirect' + 'msg' => 'redirect', ]; } diff --git a/tests/Fixtures/TestRouterBootloader.php b/tests/Fixtures/TestRouterBootloader.php new file mode 100644 index 0000000..4411260 --- /dev/null +++ b/tests/Fixtures/TestRouterBootloader.php @@ -0,0 +1,33 @@ + fn(Container $container) => new LoaderRegistry([ + new PhpFileLoader($container, $container), + new TestLoader(), + ]), + ]; + } +} diff --git a/tests/Fixtures/file.php b/tests/Fixtures/file.php index 734816c..1f631bc 100644 --- a/tests/Fixtures/file.php +++ b/tests/Fixtures/file.php @@ -3,7 +3,7 @@ use Spiral\Router\Loader\Configurator\RoutingConfigurator; return function (RoutingConfigurator $routes) { - $routes->add('index', '/')->callable(static fn () => null); - $routes->add('posts', '/posts')->callable(static fn () => null); - $routes->add('post', '/post/')->callable(static fn () => null); + $routes->add('index', '/')->callable(static fn() => null); + $routes->add('posts', '/posts')->callable(static fn() => null); + $routes->add('post', '/post/')->callable(static fn() => null); }; diff --git a/tests/GroupTest.php b/tests/GroupTest.php index 562a146..b36a7a5 100644 --- a/tests/GroupTest.php +++ b/tests/GroupTest.php @@ -24,7 +24,7 @@ public function testRouteException(): void 'group', new Route('//', new Group([ 'test' => TestController::class, - ])) + ])), ); $router->handle(new ServerRequest('GET', '')); @@ -37,16 +37,16 @@ public function testRoute(): void 'group', new Route('/[/[/]]', new Group([ 'test' => TestController::class, - ])) + ])), ); $response = $router->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); $response = $router->handle(new ServerRequest('GET', new Uri('/test/id/900'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('900', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('900', (string) $response->getBody()); } public function testRouteOther(): void @@ -58,7 +58,7 @@ public function testRouteOther(): void 'group', new Route('/[/[/]]', new Group([ 'test' => TestController::class, - ])) + ])), ); $router->handle(new ServerRequest('GET', new Uri('/other'))); @@ -73,7 +73,7 @@ public function testUriInvalid(): void 'group', new Route('/[/[/]]', new Group([ 'test' => TestController::class, - ])) + ])), ); $router->uri('group/test'); @@ -88,7 +88,7 @@ public function testUriInvalidNoAction(): void 'group', new Route('/[/[/]]', new Group([ 'test' => TestController::class, - ])) + ])), ); $router->getRoute('group')->uri(['controller' => 'test']); @@ -103,7 +103,7 @@ public function testClientException(): void 'group', new Route('/[/[/]]', new Group([ 'test' => TestController::class, - ])) + ])), ); $router->handle(new ServerRequest('GET', new Uri('/test/other'))); diff --git a/tests/HostsTest.php b/tests/HostsTest.php index bbdc302..13c6977 100644 --- a/tests/HostsTest.php +++ b/tests/HostsTest.php @@ -19,7 +19,7 @@ public function testRouteException(): void $router = $this->makeRouter(); $router->setDefault(new Route( '://.com/', - new Action(TestController::class, 'test') + new Action(TestController::class, 'test'), )); $router->handle(new ServerRequest('GET', '')); @@ -30,21 +30,17 @@ public function testRoute(): void $router = $this->makeRouter(); $router->setDefault(new Route( '//.com/', - new Action(TestController::class, 'test') + new Action(TestController::class, 'test'), )); - $this->assertNotNull( - $r = $router->handle(new ServerRequest('GET', 'http://domain.com/')) - ); + self::assertNotNull($r = $router->handle(new ServerRequest('GET', 'http://domain.com/'))); - $this->assertSame(200, $r->getStatusCode()); - $this->assertSame('hello world', (string)$r->getBody()); + self::assertSame(200, $r->getStatusCode()); + self::assertSame('hello world', (string) $r->getBody()); - $this->assertNotNull( - $r = $router->handle(new ServerRequest('GET', 'https://domain.com/')) - ); + self::assertNotNull($r = $router->handle(new ServerRequest('GET', 'https://domain.com/'))); - $this->assertSame(200, $r->getStatusCode()); - $this->assertSame('hello world', (string)$r->getBody()); + self::assertSame(200, $r->getStatusCode()); + self::assertSame('hello world', (string) $r->getBody()); } } diff --git a/tests/Loader/Configurator/RouteConfiguratorTest.php b/tests/Loader/Configurator/RouteConfiguratorTest.php index 58b46c6..2766149 100644 --- a/tests/Loader/Configurator/RouteConfiguratorTest.php +++ b/tests/Loader/Configurator/RouteConfiguratorTest.php @@ -27,7 +27,7 @@ public function testDestructException(): void $routes = new RouteCollection(); $configurator = new RouteConfigurator('test', '/', $routes); - $this->assertCount(0, $routes); + self::assertCount(0, $routes); $this->expectException(TargetException::class); unset($configurator); @@ -38,13 +38,13 @@ public function testDestruct(): void $routes = new RouteCollection(); $configurator = new RouteConfigurator('test', '/', $routes); - $this->assertCount(0, $routes); + self::assertCount(0, $routes); $configurator->controller('Controller'); unset($configurator); - $this->assertCount(1, $routes); + self::assertCount(1, $routes); } public function testController(): void @@ -52,7 +52,7 @@ public function testController(): void $configurator = new RouteConfigurator('test', '/', new RouteCollection()); $configurator->controller('SomeController'); - $this->assertInstanceOf(Controller::class, $configurator->target); + self::assertInstanceOf(Controller::class, $configurator->target); } public function testNamespaced(): void @@ -60,7 +60,7 @@ public function testNamespaced(): void $configurator = new RouteConfigurator('test', '/', new RouteCollection()); $configurator->namespaced('App\\Controller'); - $this->assertInstanceOf(Namespaced::class, $configurator->target); + self::assertInstanceOf(Namespaced::class, $configurator->target); } public function testGroupControllers(): void @@ -68,7 +68,7 @@ public function testGroupControllers(): void $configurator = new RouteConfigurator('test', '/', new RouteCollection()); $configurator->groupControllers(['Controller']); - $this->assertInstanceOf(Group::class, $configurator->target); + self::assertInstanceOf(Group::class, $configurator->target); } public function testAction(): void @@ -76,22 +76,21 @@ public function testAction(): void $configurator = new RouteConfigurator('test', '/', new RouteCollection()); $configurator->action('Controller', 'action'); - $this->assertInstanceOf(Action::class, $configurator->target); + self::assertInstanceOf(Action::class, $configurator->target); } public function testCallable(): void { $configurator = new RouteConfigurator('test', '/', new RouteCollection()); - $configurator->callable(fn () => null); + $configurator->callable(fn() => null); - $this->assertInstanceOf(\Closure::class, $configurator->target); + self::assertInstanceOf(\Closure::class, $configurator->target); } public function testHandler(): void { $configurator = new RouteConfigurator('test', '/', new RouteCollection()); - $configurator->handler(new class ([], []) extends AbstractTarget - { + $configurator->handler(new class([], []) extends AbstractTarget { protected function resolveController(array $matches): string { return ''; @@ -103,7 +102,7 @@ protected function resolveAction(array $matches): ?string } }); - $this->assertInstanceOf(AbstractTarget::class, $configurator->target); + self::assertInstanceOf(AbstractTarget::class, $configurator->target); } public function testDefaults(): void @@ -111,7 +110,7 @@ public function testDefaults(): void $configurator = new RouteConfigurator('test', '/', new RouteCollection()); $configurator->controller('Controller')->defaults(['some', 'array']); - $this->assertSame(['some', 'array'], $configurator->defaults); + self::assertSame(['some', 'array'], $configurator->defaults); } public function testGroup(): void @@ -119,7 +118,7 @@ public function testGroup(): void $configurator = new RouteConfigurator('test', '/', new RouteCollection()); $configurator->controller('Controller')->group('api'); - $this->assertSame('api', $configurator->group); + self::assertSame('api', $configurator->group); } public function testPrefix(): void @@ -127,7 +126,7 @@ public function testPrefix(): void $configurator = new RouteConfigurator('test', '/', new RouteCollection()); $configurator->controller('Controller')->prefix('admin'); - $this->assertSame('admin', $configurator->prefix); + self::assertSame('admin', $configurator->prefix); } public function testCore(): void @@ -135,38 +134,35 @@ public function testCore(): void $configurator = new RouteConfigurator('test', '/', new RouteCollection()); $configurator->controller('Controller')->core(new Core(new Container())); - $this->assertInstanceOf(Core::class, $configurator->core); + self::assertInstanceOf(Core::class, $configurator->core); } public function testMiddleware(): void { $configurator = new RouteConfigurator('test', '/', new RouteCollection()); $configurator->controller('Controller')->middleware('class-string'); - $this->assertSame(['class-string'], $configurator->middleware); + self::assertSame(['class-string'], $configurator->middleware); $configurator = new RouteConfigurator('test', '/', new RouteCollection()); $configurator->controller('Controller')->middleware(['class-string', 'other-class-string']); - $this->assertSame(['class-string', 'other-class-string'], $configurator->middleware); + self::assertSame(['class-string', 'other-class-string'], $configurator->middleware); $configurator = new RouteConfigurator('test', '/', new RouteCollection()); - $testMiddleware = new class () implements MiddlewareInterface - { - public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface - { - } + $testMiddleware = new class implements MiddlewareInterface { + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {} }; $configurator->controller('Controller')->middleware($testMiddleware); - $this->assertSame([$testMiddleware], $configurator->middleware); + self::assertSame([$testMiddleware], $configurator->middleware); } public function testMethods(): void { $configurator = new RouteConfigurator('test', '/', new RouteCollection()); $configurator->controller('Controller')->methods('GET'); - $this->assertSame(['GET'], $configurator->methods); + self::assertSame(['GET'], $configurator->methods); $configurator = new RouteConfigurator('test', '/', new RouteCollection()); $configurator->controller('Controller')->methods(['GET', 'POST']); - $this->assertSame(['GET', 'POST'], $configurator->methods); + self::assertSame(['GET', 'POST'], $configurator->methods); } } diff --git a/tests/Loader/Configurator/RoutingConfiguratorTest.php b/tests/Loader/Configurator/RoutingConfiguratorTest.php index 3dc094f..54877d5 100644 --- a/tests/Loader/Configurator/RoutingConfiguratorTest.php +++ b/tests/Loader/Configurator/RoutingConfiguratorTest.php @@ -13,65 +13,65 @@ final class RoutingConfiguratorTest extends BaseTestCase { public function testImportWithoutConcreteLoader(): void { - $routes = $this->container->get(RoutingConfigurator::class); + $routes = $this->getContainer()->get(RoutingConfigurator::class); - $this->assertCount(0, $routes->getCollection()); + self::assertCount(0, $routes->getCollection()); $routes->import(\dirname(__DIR__, 2) . '/Fixtures/file.php'); - $this->assertCount(3, $routes->getCollection()); + self::assertCount(3, $routes->getCollection()); } public function testImportWithLoader(): void { - $routes = $this->container->get(RoutingConfigurator::class); + $routes = $this->getContainer()->get(RoutingConfigurator::class); - $this->assertCount(0, $routes->getCollection()); + self::assertCount(0, $routes->getCollection()); $routes->import(\dirname(__DIR__, 2) . '/Fixtures/file.php', 'php'); - $this->assertCount(3, $routes->getCollection()); + self::assertCount(3, $routes->getCollection()); } public function testImportWithWrongLoader(): void { - $routes = $this->container->get(RoutingConfigurator::class); + $routes = $this->getContainer()->get(RoutingConfigurator::class); - $this->assertCount(0, $routes->getCollection()); + self::assertCount(0, $routes->getCollection()); $routes->import(\dirname(__DIR__, 2) . '/Fixtures/file.php', 'yaml'); - $this->assertCount(0, $routes->getCollection()); + self::assertCount(0, $routes->getCollection()); } public function testGetCollection(): void { - $routes = $this->container->get(RoutingConfigurator::class); + $routes = $this->getContainer()->get(RoutingConfigurator::class); - $this->assertInstanceOf(RouteCollection::class, $routes->getCollection()); + self::assertInstanceOf(RouteCollection::class, $routes->getCollection()); } public function testDefault(): void { - $routes = $this->container->get(RoutingConfigurator::class); + $routes = $this->getContainer()->get(RoutingConfigurator::class); - $this->assertNull($routes->getDefault()); + self::assertNull($routes->getDefault()); - $routes->default('/')->callable(static fn () => null); + $routes->default('/')->callable(static fn() => null); - $this->assertInstanceOf(RouteConfigurator::class, $routes->getDefault()); + self::assertInstanceOf(RouteConfigurator::class, $routes->getDefault()); } public function testAdd(): void { - $routes = $this->container->get(RoutingConfigurator::class); + $routes = $this->getContainer()->get(RoutingConfigurator::class); - $this->assertCount(0, $routes->getCollection()); - $route = $routes->add('test', '/')->callable(static fn () => null); - $this->assertInstanceOf(RouteConfigurator::class, $route); + self::assertCount(0, $routes->getCollection()); + $route = $routes->add('test', '/')->callable(static fn() => null); + self::assertInstanceOf(RouteConfigurator::class, $route); // important. For destruct unset($route); - $this->assertCount(1, $routes->getCollection()); + self::assertCount(1, $routes->getCollection()); } } diff --git a/tests/Loader/DelegatingLoaderTest.php b/tests/Loader/DelegatingLoaderTest.php index 13c954d..dd0944f 100644 --- a/tests/Loader/DelegatingLoaderTest.php +++ b/tests/Loader/DelegatingLoaderTest.php @@ -17,36 +17,36 @@ final class DelegatingLoaderTest extends TestCase public function testLoad(): void { $loader = new DelegatingLoader(new LoaderRegistry([ - new TestLoader() + new TestLoader(), ])); - $this->assertInstanceOf(RouteCollection::class, $loader->load('file.yaml', 'yaml')); + self::assertInstanceOf(RouteCollection::class, $loader->load('file.yaml', 'yaml')); } public function testSupports(): void { $loader = new DelegatingLoader(new LoaderRegistry()); - $this->assertFalse($loader->supports('file.php')); - $this->assertFalse($loader->supports('file.php', 'php')); + self::assertFalse($loader->supports('file.php')); + self::assertFalse($loader->supports('file.php', 'php')); $container = new Container(); $loader = new DelegatingLoader(new LoaderRegistry([new PhpFileLoader($container, $container)])); - $this->assertTrue($loader->supports('file.php')); - $this->assertTrue($loader->supports('file.php', 'php')); - $this->assertFalse($loader->supports('file.php', 'yaml')); - $this->assertFalse($loader->supports('file.yaml')); - $this->assertFalse($loader->supports('file.yaml', 'yaml')); + self::assertTrue($loader->supports('file.php')); + self::assertTrue($loader->supports('file.php', 'php')); + self::assertFalse($loader->supports('file.php', 'yaml')); + self::assertFalse($loader->supports('file.yaml')); + self::assertFalse($loader->supports('file.yaml', 'yaml')); $loader = new DelegatingLoader(new LoaderRegistry([ new PhpFileLoader($container, $container), - new TestLoader() + new TestLoader(), ])); - $this->assertTrue($loader->supports('file.php')); - $this->assertTrue($loader->supports('file.php', 'php')); - $this->assertFalse($loader->supports('file.yaml')); - $this->assertTrue($loader->supports('file.yaml', 'yaml')); - $this->assertFalse($loader->supports('file.yaml', 'php')); + self::assertTrue($loader->supports('file.php')); + self::assertTrue($loader->supports('file.php', 'php')); + self::assertFalse($loader->supports('file.yaml')); + self::assertTrue($loader->supports('file.yaml', 'yaml')); + self::assertFalse($loader->supports('file.yaml', 'php')); } } diff --git a/tests/Loader/LoaderRegistryTest.php b/tests/Loader/LoaderRegistryTest.php index ea0b786..8481e7c 100644 --- a/tests/Loader/LoaderRegistryTest.php +++ b/tests/Loader/LoaderRegistryTest.php @@ -17,15 +17,15 @@ public function testResolve(): void $container = new Container(); $registry = new LoaderRegistry([ new PhpFileLoader($container, $container), - new TestLoader() + new TestLoader(), ]); - $this->assertInstanceOf(PhpFileLoader::class, $registry->resolve('test/file.php')); - $this->assertInstanceOf(PhpFileLoader::class, $registry->resolve('test/file.php', 'php')); - $this->assertFalse($registry->resolve('test/file.php', 'txt')); + self::assertInstanceOf(PhpFileLoader::class, $registry->resolve('test/file.php')); + self::assertInstanceOf(PhpFileLoader::class, $registry->resolve('test/file.php', 'php')); + self::assertFalse($registry->resolve('test/file.php', 'txt')); - $this->assertInstanceOf(TestLoader::class, $registry->resolve('test/file.yaml', 'yaml')); - $this->assertFalse($registry->resolve('test/file.yaml', 'php')); + self::assertInstanceOf(TestLoader::class, $registry->resolve('test/file.yaml', 'yaml')); + self::assertFalse($registry->resolve('test/file.yaml', 'php')); } public function testAddAndGetLoaders(): void @@ -35,12 +35,12 @@ public function testAddAndGetLoaders(): void $php = new PhpFileLoader($container, $container); $yaml = new TestLoader(); - $this->assertSame([], $registry->getLoaders()); + self::assertSame([], $registry->getLoaders()); $registry->addLoader($php); - $this->assertSame([$php], $registry->getLoaders()); + self::assertSame([$php], $registry->getLoaders()); $registry->addLoader($yaml); - $this->assertSame([$php, $yaml], $registry->getLoaders()); + self::assertSame([$php, $yaml], $registry->getLoaders()); } } diff --git a/tests/Loader/PhpFileLoaderTest.php b/tests/Loader/PhpFileLoaderTest.php index 2f65ea4..9e2a994 100644 --- a/tests/Loader/PhpFileLoaderTest.php +++ b/tests/Loader/PhpFileLoaderTest.php @@ -17,21 +17,13 @@ final class PhpFileLoaderTest extends TestCase { private Container $container; - protected function setUp(): void - { - $this->container = new Container(); - $this->container->bind(LoaderInterface::class, $this->createMock(LoaderInterface::class)); - $this->container->bind(RouterInterface::class, $this->createMock(RouterInterface::class)); - $this->container->bind(UriFactoryInterface::class, $this->createMock(UriFactoryInterface::class)); - } - public function testLoad(): void { $loader = new PhpFileLoader($this->container, $this->container); $routes = $loader->load(\dirname(__DIR__) . '/Fixtures/file.php'); - $this->assertInstanceOf(RouteCollection::class, $routes); - $this->assertCount(3, $routes); + self::assertInstanceOf(RouteCollection::class, $routes); + self::assertCount(3, $routes); $this->expectException(LoaderLoadException::class); $loader->load(\dirname(__DIR__) . '/Fixtures/unknown.php'); @@ -41,11 +33,19 @@ public function testSupports(): void { $loader = new PhpFileLoader($this->container, $this->container); - $this->assertTrue($loader->supports('file.php')); - $this->assertTrue($loader->supports('file.php', 'php')); + self::assertTrue($loader->supports('file.php')); + self::assertTrue($loader->supports('file.php', 'php')); - $this->assertFalse($loader->supports('file.php', 'txt')); - $this->assertFalse($loader->supports('file.txt')); - $this->assertFalse($loader->supports('file.txt', 'txt')); + self::assertFalse($loader->supports('file.php', 'txt')); + self::assertFalse($loader->supports('file.txt')); + self::assertFalse($loader->supports('file.txt', 'txt')); + } + + protected function setUp(): void + { + $this->container = new Container(); + $this->container->bind(LoaderInterface::class, $this->createMock(LoaderInterface::class)); + $this->container->bind(RouterInterface::class, $this->createMock(RouterInterface::class)); + $this->container->bind(UriFactoryInterface::class, $this->createMock(UriFactoryInterface::class)); } } diff --git a/tests/MiddlewareTest.php b/tests/MiddlewareTest.php index aa114d2..cb01772 100644 --- a/tests/MiddlewareTest.php +++ b/tests/MiddlewareTest.php @@ -6,6 +6,7 @@ use Nyholm\Psr7\ServerRequest; use Nyholm\Psr7\Uri; +use Psr\Container\NotFoundExceptionInterface; use Spiral\Router\Exception\RouteException; use Spiral\Router\Route; use Spiral\Router\Target\Group; @@ -14,8 +15,10 @@ use Spiral\Tests\Router\Fixtures\TestController; use Spiral\Tests\Router\Stub\HeaderMiddleware; -class MiddlewareTest extends BaseTestCase +class MiddlewareTest extends BaseTestingCase { + use RouterFactoryTrait; + public function testRoute(): void { $router = $this->makeRouter(); @@ -24,21 +27,21 @@ public function testRoute(): void 'group', (new Route('/[/[/]]', new Group([ 'test' => TestController::class, - ])))->withMiddleware(HeaderMiddleware::class) + ])))->withMiddleware(HeaderMiddleware::class), ); $response = $router->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); - $this->assertSame('Value*', $response->getHeaderLine('Header')); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); + self::assertSame('Value*', $response->getHeaderLine('Header')); $r = $router->getRoute('group')->withMiddleware(HeaderMiddleware::class); $r = $r->match(new ServerRequest('GET', new Uri('/test'))); $response = $r->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); - $this->assertSame('Value*, Value*', $response->getHeaderLine('Header')); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); + self::assertSame('Value*, Value*', $response->getHeaderLine('Header')); } public function testRouteRuntime(): void @@ -49,13 +52,13 @@ public function testRouteRuntime(): void 'group', (new Route('/[/[/]]', new Group([ 'test' => TestController::class, - ])))->withMiddleware(new HeaderMiddleware()) + ])))->withMiddleware(new HeaderMiddleware()), ); $response = $router->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); - $this->assertSame('Value*', $response->getHeaderLine('Header')); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); + self::assertSame('Value*', $response->getHeaderLine('Header')); } public function testRouteArray(): void @@ -66,56 +69,44 @@ public function testRouteArray(): void 'group', (new Route('/[/[/]]', new Group([ 'test' => TestController::class, - ])))->withMiddleware([new HeaderMiddleware(), HeaderMiddleware::class]) + ])))->withMiddleware([new HeaderMiddleware(), HeaderMiddleware::class]), ); $response = $router->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); - $this->assertSame('Value*, Value*', $response->getHeaderLine('Header')); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); + self::assertSame('Value*, Value*', $response->getHeaderLine('Header')); $response = $router->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); - $this->assertSame('Value*, Value*', $response->getHeaderLine('Header')); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); + self::assertSame('Value*, Value*', $response->getHeaderLine('Header')); } public function testInvalid(): void { - $this->expectException(RouteException::class); - $router = $this->makeRouter(); + $this->expectException(\Throwable::class); $router->setRoute( 'group', (new Route('/[/[/]]', new Group([ 'test' => TestController::class, - ])))->withMiddleware($this) + ])))->withMiddleware($this), ); - - $response = $router->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); - $this->assertSame('Value*, Value*', $response->getHeaderLine('Header')); } public function testInvalid2(): void { - $this->expectException(RouteException::class); - $router = $this->makeRouter(); + $this->expectException(\Throwable::class); $router->setRoute( 'group', (new Route('/[/[/]]', new Group([ 'test' => TestController::class, - ])))->withMiddleware([[]]) + ])))->withMiddleware([[]]), ); - - $response = $router->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); - $this->assertSame('Value*, Value*', $response->getHeaderLine('Header')); } public function testPipelineException(): void @@ -129,23 +120,23 @@ public function testPipelineException(): void $r = $r->match(new ServerRequest('GET', new Uri('/test'))); $response = $r->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); - $this->assertSame('Value*, Value*', $response->getHeaderLine('Header')); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); + self::assertSame('Value*, Value*', $response->getHeaderLine('Header')); } - public function testPipelineExceptionMiddleware(): void + public function testUndefinedMiddleware(): void { - $this->expectException(RouteException::class); - $r = (new Route('/[/[/]]', new Group([ 'test' => TestController::class, ])))->withMiddleware([new HeaderMiddleware(), 'other']); $r = $r->withUriHandler(new UriHandler(new UriFactory())); - $r = $r->withContainer($this->container); + $r = $r->withContainer($this->getContainer()); $r = $r->match(new ServerRequest('GET', new Uri('/test'))); + + $this->expectException(NotFoundExceptionInterface::class); $r->handle(new ServerRequest('GET', new Uri('/test'))); } } diff --git a/tests/MultipleActionsTest.php b/tests/MultipleActionsTest.php index cc3f324..12a81a3 100644 --- a/tests/MultipleActionsTest.php +++ b/tests/MultipleActionsTest.php @@ -20,7 +20,7 @@ public function testRouteException(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('//', new Action(TestController::class, ['test', 'id'])) + new Route('//', new Action(TestController::class, ['test', 'id'])), ); $router->handle(new ServerRequest('GET', '')); @@ -31,16 +31,16 @@ public function testRoute(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/[/]', new Action(TestController::class, ['test', 'id'])) + new Route('/[/]', new Action(TestController::class, ['test', 'id'])), ); $response = $router->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); $response = $router->handle(new ServerRequest('GET', new Uri('/id/900'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('900', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('900', (string) $response->getBody()); } public function testUriGeneration(): void @@ -48,13 +48,13 @@ public function testUriGeneration(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/[/]', new Action(TestController::class, ['test', 'id'])) + new Route('/[/]', new Action(TestController::class, ['test', 'id'])), ); $uri = $router->uri('action/test'); - $this->assertSame('/test', $uri->getPath()); + self::assertSame('/test', $uri->getPath()); $uri = $router->uri('action/id', ['id' => 100]); - $this->assertSame('/id/100', $uri->getPath()); + self::assertSame('/id/100', $uri->getPath()); } } diff --git a/tests/NamespacedTest.php b/tests/NamespacedTest.php index 9583891..9f8af93 100644 --- a/tests/NamespacedTest.php +++ b/tests/NamespacedTest.php @@ -22,8 +22,8 @@ public function testRouteException(): void 'group', new Route( '//', - new Namespaced('Spiral\Tests\Router\Fixtures') - ) + new Namespaced('Spiral\Tests\Router\Fixtures'), + ), ); $router->handle(new ServerRequest('GET', '')); @@ -36,21 +36,21 @@ public function testRoute(): void 'group', new Route( '/[/[/]]', - new Namespaced('Spiral\Tests\Router\Fixtures') - ) + new Namespaced('Spiral\Tests\Router\Fixtures'), + ), ); $response = $router->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); $response = $router->handle(new ServerRequest('GET', new Uri('/test/id/900'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('900', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('900', (string) $response->getBody()); $response = $router->handle(new ServerRequest('GET', new Uri('/other/action'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('action!', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('action!', (string) $response->getBody()); } public function testBypass(): void @@ -59,7 +59,7 @@ public function testBypass(): void $n = new Namespaced('Spiral\Tests\Router\Fixtures'); - $n->getHandler($this->container, [ + $n->getHandler($this->getContainer(), [ 'controller' => 'secret/controller', 'action' => null, ]); diff --git a/tests/PatternsTests.php b/tests/PatternsTests.php index 33cdb2f..5e829bd 100644 --- a/tests/PatternsTests.php +++ b/tests/PatternsTests.php @@ -21,14 +21,14 @@ public function testDigitWithZeroValue(): void { $route = new Route( '/statistics/set///', - 'test' + 'test', ); $route = $route->withUriHandler(new UriHandler(new UriFactory())); $match = $route->match(new ServerRequest('GET', new Uri('http://site.com/statistics/set/10/285/0'))); - $this->assertSame([ + self::assertSame([ 'moduleType' => '10', 'moduleId' => '285', 'type' => '0', @@ -39,16 +39,16 @@ public function testIntPatternWithValidValue(): void { $route = new Route( '/users/', - 'test' + 'test', ); $route = $route->withUriHandler(new UriHandler(new UriFactory())); $match = $route->match( - new ServerRequest('GET', new Uri('http://site.com/users/1')) + new ServerRequest('GET', new Uri('http://site.com/users/1')), ); - $this->assertSame([ + self::assertSame([ 'int' => '1', ], $match->getMatches()); } @@ -57,32 +57,32 @@ public function testIntPatternWithInvalidValue(): void { $route = new Route( '/users/', - 'test' + 'test', ); $route = $route->withUriHandler(new UriHandler(new UriFactory())); $match = $route->match( - new ServerRequest('GET', new Uri('http://site.com/users/1b')) + new ServerRequest('GET', new Uri('http://site.com/users/1b')), ); - $this->assertNull($match); + self::assertNull($match); } public function testIntegerPatternWithValidValue(): void { $route = new Route( '/users/', - 'test' + 'test', ); $route = $route->withUriHandler(new UriHandler(new UriFactory())); $match = $route->match( - new ServerRequest('GET', new Uri('http://site.com/users/1')) + new ServerRequest('GET', new Uri('http://site.com/users/1')), ); - $this->assertSame([ + self::assertSame([ 'integer' => '1', ], $match->getMatches()); } @@ -91,32 +91,32 @@ public function testIntegerPatternWithInvalidValue(): void { $route = new Route( '/users/', - 'test' + 'test', ); $route = $route->withUriHandler(new UriHandler(new UriFactory())); $match = $route->match( - new ServerRequest('GET', new Uri('http://site.com/users/1b')) + new ServerRequest('GET', new Uri('http://site.com/users/1b')), ); - $this->assertNull($match); + self::assertNull($match); } public function testUuidPatternWithValidValue(): void { $route = new Route( '/users/', - 'test' + 'test', ); $route = $route->withUriHandler(new UriHandler(new UriFactory())); $match = $route->match( - new ServerRequest('GET', new Uri('http://site.com/users/34f7b660-7ad0-11ed-a1eb-0242ac120002')) + new ServerRequest('GET', new Uri('http://site.com/users/34f7b660-7ad0-11ed-a1eb-0242ac120002')), ); - $this->assertSame([ + self::assertSame([ 'uuid' => '34f7b660-7ad0-11ed-a1eb-0242ac120002', ], $match->getMatches()); } @@ -125,23 +125,23 @@ public function testUuidPatternWithInvalidValue(): void { $route = new Route( '/users/', - 'test' + 'test', ); $route = $route->withUriHandler(new UriHandler(new UriFactory())); $match = $route->match( - new ServerRequest('GET', new Uri('http://site.com/users/34f7b660-7ad0')) + new ServerRequest('GET', new Uri('http://site.com/users/34f7b660-7ad0')), ); - $this->assertNull($match); + self::assertNull($match); } public function testCustomPattern(): void { $route = new Route( '/users/', - 'test' + 'test', ); $registry = m::mock(RoutePatternRegistryInterface::class); @@ -154,15 +154,15 @@ public function testCustomPattern(): void $route = $route->withUriHandler( new UriHandler( new UriFactory(), - patternRegistry: $registry - ) + patternRegistry: $registry, + ), ); $match = $route->match( - new ServerRequest('GET', new Uri('http://site.com/users/34f7b660-7ad0-11ed-a1eb-0242ac222222')) + new ServerRequest('GET', new Uri('http://site.com/users/34f7b660-7ad0-11ed-a1eb-0242ac222222')), ); - $this->assertSame([ + self::assertSame([ 'uuid' => '34f7b660-7ad0-11ed-a1eb-0242ac222222', ], $match->getMatches()); } @@ -171,43 +171,43 @@ public function testCustomStringablePattern(): void { $route = new Route( '/users/', - 'test' + 'test', ); $registry = new DefaultPatternRegistry(); $registry->register( 'in_array', - new InArrayPattern(['foo', 'bar']) + new InArrayPattern(['foo', 'bar']), ); $registry->register( 'foo', - '[0-9]+' + '[0-9]+', ); $route = $route->withUriHandler( new UriHandler( new UriFactory(), - patternRegistry: $registry - ) + patternRegistry: $registry, + ), ); $match = $route->match( - new ServerRequest('GET', new Uri('http://site.com/users/foo')) + new ServerRequest('GET', new Uri('http://site.com/users/foo')), ); $match1 = $route->match( - new ServerRequest('GET', new Uri('http://site.com/users/bar')) + new ServerRequest('GET', new Uri('http://site.com/users/bar')), ); $match2 = $route->match( - new ServerRequest('GET', new Uri('http://site.com/users/baz')) + new ServerRequest('GET', new Uri('http://site.com/users/baz')), ); - $this->assertSame([ + self::assertSame([ 'name' => 'foo', ], $match->getMatches()); - $this->assertSame([ + self::assertSame([ 'name' => 'bar', ], $match1->getMatches()); - $this->assertNull($match2); + self::assertNull($match2); } } diff --git a/tests/PipelineFactoryTest.php b/tests/PipelineFactoryTest.php index 1725da5..21d4804 100644 --- a/tests/PipelineFactoryTest.php +++ b/tests/PipelineFactoryTest.php @@ -27,14 +27,14 @@ final class PipelineFactoryTest extends \PHPUnit\Framework\TestCase private FactoryInterface $factory; private PipelineFactory $pipeline; - protected function setUp(): void + public static function invalidTypeDataProvider(): \Generator { - parent::setUp(); - - $this->container = $this->createMock(ContainerInterface::class); - $this->factory = m::mock(FactoryInterface::class); - - $this->pipeline = new PipelineFactory($this->container, $this->factory); + yield 'true' => [true, 'bool']; + yield 'false' => [false, 'bool']; + yield 'array' => [[], 'array']; + yield 'int' => [1, 'int']; + yield 'float' => [1.0, 'float']; + yield 'object' => [new \stdClass(), 'stdClass']; } public function testCreatesFromArrayWithPipeline(): void @@ -43,10 +43,7 @@ public function testCreatesFromArrayWithPipeline(): void scope: $this->createMock(ScopeInterface::class), ); - $this->assertSame( - $newPipeline, - $this->pipeline->createWithMiddleware([$newPipeline]) - ); + self::assertSame($newPipeline, $this->pipeline->createWithMiddleware([$newPipeline])); } public function testCreates(): void @@ -60,7 +57,7 @@ public function testCreates(): void ->with(Pipeline::class) ->andReturn($p = new Pipeline( $this->createMock(ScopeInterface::class), - tracer: new NullTracer($container) + tracer: new NullTracer($container), )); $this->factory @@ -75,14 +72,14 @@ public function testCreates(): void ->with('foo') ->willReturn($middleware4 = $this->createMock(MiddlewareInterface::class)); - $this->assertSame($p, $this->pipeline->createWithMiddleware([ + self::assertSame($p, $this->pipeline->createWithMiddleware([ 'foo', $middleware1 = $this->createMock(MiddlewareInterface::class), $middleware2 = $this->createMock(MiddlewareInterface::class), new Autowire('bar'), ])); - $handle = fn(ServerRequestInterface $request, RequestHandlerInterface $handler) => $handler->handle($request); + $handle = fn(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface => $handler->handle($request); $middleware1->expects($this->once())->method('process')->willReturnCallback($handle); $middleware2->expects($this->once())->method('process')->willReturnCallback($handle); @@ -119,13 +116,13 @@ public function testInvalidTypeShouldThrowAnException(mixed $value, string $type $this->pipeline->createWithMiddleware([$value]); } - public static function invalidTypeDataProvider(): \Generator + protected function setUp(): void { - yield 'true' => [true, 'bool']; - yield 'false' => [false, 'bool']; - yield 'array' => [[], 'array']; - yield 'int' => [1, 'int']; - yield 'float' => [1.0, 'float']; - yield 'object' => [new \stdClass(), 'stdClass']; + parent::setUp(); + + $this->container = $this->createMock(ContainerInterface::class); + $this->factory = m::mock(FactoryInterface::class); + + $this->pipeline = new PipelineFactory($this->container, $this->factory); } } diff --git a/tests/RegistryTest.php b/tests/RegistryTest.php index e6ebb81..62352f7 100644 --- a/tests/RegistryTest.php +++ b/tests/RegistryTest.php @@ -14,11 +14,11 @@ final class RegistryTest extends BaseTestCase { public function testSameGroup(): void { - $registry = new GroupRegistry($this->container); - $router = new Router('/', new UriHandler(new Psr17Factory()), $this->container); - $this->container->bind(RouterInterface::class, $router); + $registry = new GroupRegistry($this->getContainer()); + $router = new Router('/', new UriHandler(new Psr17Factory()), $this->getContainer()); + $this->getContainer()->bind(RouterInterface::class, $router); $group = $registry->getGroup('default'); - $this->assertSame($group, $registry->getGroup('default')); + self::assertSame($group, $registry->getGroup('default')); } } diff --git a/tests/RouteGroupTest.php b/tests/RouteGroupTest.php index c4bb000..3f3d498 100644 --- a/tests/RouteGroupTest.php +++ b/tests/RouteGroupTest.php @@ -20,14 +20,17 @@ final class RouteGroupTest extends BaseTestCase { - - protected function setUp(): void + public static function routePrefixDataProvider(): iterable { - parent::setUp(); - - $this->container = new Container(); - $this->container->bind(LoaderInterface::class, $this->createMock(LoaderInterface::class)); - $this->container->bind(UriFactoryInterface::class, Psr17Factory::class); + yield ['/api/', '/blog']; + yield ['/api', '/blog']; + yield ['/api', 'blog']; + yield ['api/', '/blog']; + yield ['api', '/blog']; + yield ['api', 'blog']; + yield ['api/', '/blog/']; + yield ['api', '/blog/']; + yield ['api', 'blog/']; } public function testCoreString(): void @@ -40,12 +43,12 @@ public function testCoreString(): void $t = $this->getProperty($this->router->getRoute('name'), 'target'); - $this->assertInstanceOf(Action::class, $t); + self::assertInstanceOf(Action::class, $t); - $this->assertSame('controller', $this->getProperty($t, 'controller')); - $this->assertSame('method', $this->getProperty($t, 'action')); + self::assertSame('controller', $this->getProperty($t, 'controller')); + self::assertSame('method', $this->getProperty($t, 'action')); - $this->assertInstanceOf(RoutesTestCore::class, $this->getActionProperty($t, 'pipeline')); + self::assertInstanceOf(RoutesTestCore::class, $this->getActionProperty($t, 'pipeline')); } public function testCoreObject(): void @@ -58,12 +61,12 @@ public function testCoreObject(): void $t = $this->getProperty($this->router->getRoute('name'), 'target'); - $this->assertInstanceOf(Action::class, $t); + self::assertInstanceOf(Action::class, $t); - $this->assertSame('controller', $this->getProperty($t, 'controller')); - $this->assertSame('method', $this->getProperty($t, 'action')); + self::assertSame('controller', $this->getProperty($t, 'controller')); + self::assertSame('method', $this->getProperty($t, 'action')); - $this->assertInstanceOf(RoutesTestCore::class, $this->getActionProperty($t, 'pipeline')); + self::assertInstanceOf(RoutesTestCore::class, $this->getActionProperty($t, 'pipeline')); } public function testGroupHasRoute(): void @@ -73,8 +76,8 @@ public function testGroupHasRoute(): void $group->addRoute('foo', new Route('/', new Action('controller', 'method'))); $group->register($this->router, $this->container); - $this->assertTrue($group->hasRoute('foo')); - $this->assertFalse($group->hasRoute('bar')); + self::assertTrue($group->hasRoute('foo')); + self::assertFalse($group->hasRoute('bar')); } #[DataProvider('middlewaresDataProvider')] @@ -92,8 +95,9 @@ public function testMiddleware(mixed $middleware): void $p = $this->getProperty($r, 'pipeline'); $m = $this->getProperty($p, 'middleware'); - $this->assertCount(1, $m); - $this->assertInstanceOf(TestMiddleware::class, $m[0]); + self::assertCount(1, $m); + // Because of the pipeline is lazy + self::assertSame($middleware, $m[0]); } public function testRouteWithMiddlewareAddGroupMiddleware(): void @@ -110,10 +114,11 @@ public function testRouteWithMiddlewareAddGroupMiddleware(): void $p = $this->getProperty($r, 'pipeline'); $m = $this->getProperty($p, 'middleware'); - $this->assertCount(2, $m); + self::assertCount(2, $m); - $this->assertInstanceOf(TestMiddleware::class, $m[1]); - $this->assertInstanceOf(AnotherMiddleware::class, $m[0]); + // Because of the pipeline is lazy + self::assertSame(TestMiddleware::class, $m[1]); + self::assertSame(AnotherMiddleware::class, $m[0]); } public function testWithoutNamePrefix(): void @@ -122,7 +127,7 @@ public function testWithoutNamePrefix(): void $group->addRoute('name', new Route('/', new Action('controller', 'method'))); $group->register($this->router, $this->container); - $this->assertTrue($group->hasRoute('name')); + self::assertTrue($group->hasRoute('name')); } public function testWithNamePrefix(): void @@ -132,8 +137,8 @@ public function testWithNamePrefix(): void $group->addRoute('name', new Route('/', new Action('controller', 'method'))); $group->register($this->router, $this->container); - $this->assertTrue($group->hasRoute('admin.name')); - $this->assertFalse($group->hasRoute('name')); + self::assertTrue($group->hasRoute('admin.name')); + self::assertFalse($group->hasRoute('name')); } #[DataProvider('routePrefixDataProvider')] @@ -146,24 +151,18 @@ public function testWithPrefix(string $prefix, string $pattern): void $group->register($this->router, $this->container); $route = $this->router->getRoute('name'); - $this->assertNotNull( - $route->match(new ServerRequest('GET', '/api/blog')) - ); + self::assertNotNull($route->match(new ServerRequest('GET', '/api/blog'))); - $this->assertSame('/api/blog', (string) $route->uri()); + self::assertSame('/api/blog', (string) $route->uri()); } - public static function routePrefixDataProvider(): iterable + protected function setUp(): void { - yield ['/api/', '/blog']; - yield ['/api', '/blog']; - yield ['/api', 'blog']; - yield ['api/', '/blog']; - yield ['api', '/blog']; - yield ['api', 'blog']; - yield ['api/', '/blog/']; - yield ['api', '/blog/']; - yield ['api', 'blog/']; + parent::setUp(); + + $this->container = new Container(); + $this->container->bind(LoaderInterface::class, $this->createMock(LoaderInterface::class)); + $this->container->bind(UriFactoryInterface::class, Psr17Factory::class); } /** diff --git a/tests/RouteTest.php b/tests/RouteTest.php index fe8e8eb..508d67c 100644 --- a/tests/RouteTest.php +++ b/tests/RouteTest.php @@ -10,16 +10,25 @@ use Spiral\Tests\Router\Diactoros\UriFactory; use Spiral\Router\UriHandler; use Nyholm\Psr7\ServerRequest; -use Spiral\Tests\Router\Stub\TestMiddleware; class RouteTest extends BaseTestCase { + public static function prefixesDataProvider(): \Traversable + { + yield ['something', 'something']; + yield ['/something/', 'something']; + yield ['//something/', 'something']; + yield ['something//', 'something']; + yield ['something/other', 'something/other']; + yield ['/something/other/', 'something/other']; + } + public function testEmptyPrefix(): void { $route = new Route('/action', Call::class); $route = $route->withUriHandler(new UriHandler(new UriFactory())); - $this->assertSame('', $route->getUriHandler()->getPrefix()); + self::assertSame('', $route->getUriHandler()->getPrefix()); } #[DataProvider('prefixesDataProvider')] @@ -28,7 +37,7 @@ public function testPrefix(string $prefix, string $expected): void $route = new Route('/action', Call::class); $route = $route->withUriHandler((new UriHandler(new UriFactory()))->withPrefix($prefix)); - $this->assertSame($expected, $route->getUriHandler()->getPrefix()); + self::assertSame($expected, $route->getUriHandler()->getPrefix()); } public function testContainerException(): void @@ -50,17 +59,8 @@ public function testWithMiddleware(mixed $middleware): void $p = $this->getProperty($route, 'pipeline'); $m = $this->getProperty($p, 'middleware'); - $this->assertCount(1, $m); - $this->assertInstanceOf(TestMiddleware::class, $m[0]); - } - - public static function prefixesDataProvider(): \Traversable - { - yield ['something', 'something']; - yield ['/something/', 'something']; - yield ['//something/', 'something']; - yield ['something//', 'something']; - yield ['something/other', 'something/other']; - yield ['/something/other/', 'something/other']; + self::assertCount(1, $m); + // Because of the pipeline is lazy + self::assertSame($middleware, $m[0]); } } diff --git a/tests/RouterFactoryTrait.php b/tests/RouterFactoryTrait.php new file mode 100644 index 0000000..01f2991 --- /dev/null +++ b/tests/RouterFactoryTrait.php @@ -0,0 +1,34 @@ +getContainer(); + return new Router( + $basePath, + new UriHandler( + new UriFactory(), + new Slugify(), + ), + $container, + $dispatcher, + new NullTracer($container), + ); + } +} diff --git a/tests/RouterTest.php b/tests/RouterTest.php index 01ac370..903f970 100644 --- a/tests/RouterTest.php +++ b/tests/RouterTest.php @@ -24,7 +24,7 @@ public function testGetRoutes(): void $router = $this->makeRouter(); $router->setRoute('name', new Route('/', Call::class)); - $this->assertCount(1, $router->getRoutes()); + self::assertCount(1, $router->getRoutes()); } public function testDefault(): void @@ -34,7 +34,7 @@ public function testDefault(): void $router->setRoute('name', new Route('/', Call::class)); $router->setDefault(new Route('/', Call::class)); - $this->assertCount(2, $router->getRoutes()); + self::assertCount(2, $router->getRoutes()); } public function testCastError(): void @@ -48,13 +48,13 @@ public function testCastError(): void public function testEventsShouldBeDispatched(): void { $request = new ServerRequest('GET', '/foo'); - $route = (new Route('/foo', Call::class))->withContainer($this->container); + $route = (new Route('/foo', Call::class))->withContainer($this->getContainer()); $dispatcher = $this->createMock(EventDispatcherInterface::class); $dispatcher ->expects(self::exactly(2)) ->method('dispatch') - ->with($this->callback(static fn (Routing|RouteMatched $event): bool => $event->request instanceof ServerRequest)); + ->with($this->callback(static fn(Routing|RouteMatched $event): bool => $event->request instanceof ServerRequest)); $router = $this->makeRouter('', $dispatcher); $router->setDefault($route); @@ -71,7 +71,7 @@ public function testRouteNotFoundEventShouldBeDispatched(): void ->method('dispatch') ->with($this->logicalOr( new Routing($request), - new RouteNotFound($request) + new RouteNotFound($request), )); $router = $this->makeRouter('', $dispatcher); @@ -85,13 +85,13 @@ public function testImportWithHost(): void $router = $this->makeRouter('https://host.com', $this->createMock(EventDispatcherInterface::class)); $configurator = new RoutingConfigurator(new RouteCollection(), $this->createMock(LoaderInterface::class)); - $configurator->add('foo', '///register')->callable(fn () => null); + $configurator->add('foo', '///register')->callable(fn() => null); $router->import($configurator); - $this->container->get(GroupRegistry::class)->registerRoutes($router); + $this->getContainer()->get(GroupRegistry::class)->registerRoutes($router); $uri = (string) $router->uri('foo', ['host' => 'some']); - $this->assertSame('some/register', $uri); - $this->assertFalse(\str_contains('https://host.com', $uri)); + self::assertSame('some/register', $uri); + self::assertFalse(\str_contains('https://host.com', $uri)); } } diff --git a/tests/SingleActionTest.php b/tests/SingleActionTest.php index 278919c..886fa13 100644 --- a/tests/SingleActionTest.php +++ b/tests/SingleActionTest.php @@ -21,7 +21,7 @@ public function testRouteException(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/test', new Action(TestController::class, 'test')) + new Route('/test', new Action(TestController::class, 'test')), ); $router->handle(new ServerRequest('GET', '')); @@ -32,16 +32,16 @@ public function testRoute(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/test', new Action(TestController::class, 'test')) + new Route('/test', new Action(TestController::class, 'test')), ); $response = $router->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); $response = $router->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); } public function testVerbRoute(): void @@ -51,7 +51,7 @@ public function testVerbRoute(): void $router = $this->makeRouter(); $router->setRoute( 'action', - (new Route('/test', new Action(TestController::class, 'test')))->withVerbs('POST') + (new Route('/test', new Action(TestController::class, 'test')))->withVerbs('POST'), ); $router->handle(new ServerRequest('GET', new Uri('/test'))); @@ -62,12 +62,12 @@ public function testVerbRouteValid(): void $router = $this->makeRouter(); $router->setRoute( 'action', - (new Route('/test', new Action(TestController::class, 'test')))->withVerbs('POST') + (new Route('/test', new Action(TestController::class, 'test')))->withVerbs('POST'), ); $response = $router->handle(new ServerRequest('POST', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('hello world', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('hello world', (string) $response->getBody()); } public function testEchoed(): void @@ -75,12 +75,12 @@ public function testEchoed(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/test', new Action(TestController::class, 'echo')) + new Route('/test', new Action(TestController::class, 'echo')), ); $response = $router->handle(new ServerRequest('GET', new Uri('/test'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('echoed', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('echoed', (string) $response->getBody()); } public function testAutoFill(): void @@ -88,12 +88,12 @@ public function testAutoFill(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/', new Action(TestController::class, 'echo')) + new Route('/', new Action(TestController::class, 'echo')), ); $response = $router->handle(new ServerRequest('GET', new Uri('/echo'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('echoed', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('echoed', (string) $response->getBody()); $e = null; try { @@ -101,7 +101,7 @@ public function testAutoFill(): void } catch (UndefinedRouteException $e) { } - $this->assertNotNull($e, 'Autofill not fired'); + self::assertNotNull($e, 'Autofill not fired'); } public function testVerbException(): void @@ -111,7 +111,7 @@ public function testVerbException(): void $router = $this->makeRouter(); $router->setRoute( 'action', - (new Route('/test', new Action(TestController::class, 'test')))->withVerbs('other') + (new Route('/test', new Action(TestController::class, 'test')))->withVerbs('other'), ); } @@ -120,12 +120,12 @@ public function testParametrizedActionRoute(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/test/', new Action(TestController::class, 'id')) + new Route('/test/', new Action(TestController::class, 'id')), ); $response = $router->handle(new ServerRequest('GET', new Uri('/test/100'))); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('100', (string)$response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('100', (string) $response->getBody()); } public function testParametrizedActionRouteNotFound(): void @@ -135,7 +135,7 @@ public function testParametrizedActionRouteNotFound(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/test/', new Action(TestController::class, 'id')) + new Route('/test/', new Action(TestController::class, 'id')), ); $router->handle(new ServerRequest('GET', new Uri('/test/abc'))); @@ -146,14 +146,14 @@ public function testUriGeneration(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/test/', new Action(TestController::class, 'id')) + new Route('/test/', new Action(TestController::class, 'id')), ); $uri = $router->uri('action'); - $this->assertSame('/test', $uri->getPath()); + self::assertSame('/test', $uri->getPath()); $uri = $router->uri('action', ['id' => 100]); - $this->assertSame('/test/100', $uri->getPath()); + self::assertSame('/test/100', $uri->getPath()); } public function testWrongActionRoute(): void @@ -163,7 +163,7 @@ public function testWrongActionRoute(): void $router = $this->makeRouter(); $router->setRoute( 'action', - new Route('/test', new Action(TestController::class, 'test')) + new Route('/test', new Action(TestController::class, 'test')), ); $router->handle(new ServerRequest('GET', new Uri('/other'))); diff --git a/tests/Stub/HeaderMiddleware.php b/tests/Stub/HeaderMiddleware.php index e298674..d9d6921 100644 --- a/tests/Stub/HeaderMiddleware.php +++ b/tests/Stub/HeaderMiddleware.php @@ -13,7 +13,7 @@ class HeaderMiddleware implements MiddlewareInterface { public function process( ServerRequestInterface $request, - RequestHandlerInterface $handler + RequestHandlerInterface $handler, ): ResponseInterface { return $handler->handle($request)->withAddedHeader('Header', 'Value*'); } diff --git a/tests/Stub/IdentityScopedMiddleware.php b/tests/Stub/IdentityScopedMiddleware.php index e968747..59ab534 100644 --- a/tests/Stub/IdentityScopedMiddleware.php +++ b/tests/Stub/IdentityScopedMiddleware.php @@ -20,7 +20,7 @@ public function __construct( public function process( ServerRequestInterface $request, - RequestHandlerInterface $handler + RequestHandlerInterface $handler, ): ResponseInterface { return $this->scope->runScope( new Scope(name: 'idenity', bindings: ['identity' => 'test-identity']), diff --git a/tests/Stub/InArrayPattern.php b/tests/Stub/InArrayPattern.php index c24bb74..6165f44 100644 --- a/tests/Stub/InArrayPattern.php +++ b/tests/Stub/InArrayPattern.php @@ -5,9 +5,8 @@ class InArrayPattern implements \Stringable { public function __construct( - private readonly array $values - ) { - } + private readonly array $values, + ) {} public function __toString() { diff --git a/tests/Stub/RoutesTestCore.php b/tests/Stub/RoutesTestCore.php index 293be00..15135cd 100644 --- a/tests/Stub/RoutesTestCore.php +++ b/tests/Stub/RoutesTestCore.php @@ -6,6 +6,4 @@ use Spiral\Core\AbstractCore; -class RoutesTestCore extends AbstractCore -{ -} +class RoutesTestCore extends AbstractCore {} diff --git a/tests/SubdomainTest.php b/tests/SubdomainTest.php index 637aee6..615cd64 100644 --- a/tests/SubdomainTest.php +++ b/tests/SubdomainTest.php @@ -18,16 +18,16 @@ public function testSubDomainWithoutAction(): void $route = new Route( '//[.]site.com/foo', 'test', - ['sub' => 'subdomain'] + ['sub' => 'subdomain'], ); $route = $route->withUriHandler(new UriHandler(new UriFactory())); $match = $route->match(new ServerRequest('GET', new Uri('http://site.com/foo'))); - $this->assertSame(['sub' => 'subdomain'], $match->getMatches()); + self::assertSame(['sub' => 'subdomain'], $match->getMatches()); $match = $route->match(new ServerRequest('GET', new Uri('http://bar.site.com/foo'))); - $this->assertSame(['sub' => 'bar'], $match->getMatches()); + self::assertSame(['sub' => 'bar'], $match->getMatches()); } public function testSubDomainWithAction(): void @@ -35,21 +35,21 @@ public function testSubDomainWithAction(): void $route = new Route( '//[.]site.com/foo[/]', 'test', - ['sub' => 'subdomain'] + ['sub' => 'subdomain'], ); $route = $route->withUriHandler(new UriHandler(new UriFactory())); $match = $route->match(new ServerRequest('GET', new Uri('http://site.com/foo/bar'))); - $this->assertSame(['sub' => 'subdomain', 'action' => 'bar'], $match->getMatches()); + self::assertSame(['sub' => 'subdomain', 'action' => 'bar'], $match->getMatches()); $match = $route->match(new ServerRequest('GET', new Uri('http://site.com/foo'))); - $this->assertSame(['sub' => 'subdomain', 'action' => null], $match->getMatches()); + self::assertSame(['sub' => 'subdomain', 'action' => null], $match->getMatches()); $match = $route->match(new ServerRequest('GET', new Uri('http://bar.site.com/foo'))); - $this->assertSame(['sub' => 'bar', 'action' => null], $match->getMatches()); + self::assertSame(['sub' => 'bar', 'action' => null], $match->getMatches()); $match = $route->match(new ServerRequest('GET', new Uri('http://bar.site.com/foo/bar'))); - $this->assertSame(['sub' => 'bar', 'action' => 'bar'], $match->getMatches()); + self::assertSame(['sub' => 'bar', 'action' => 'bar'], $match->getMatches()); } } diff --git a/tests/Targets/ActionTargetTest.php b/tests/Targets/ActionTargetTest.php index ece4c7f..0d2a209 100644 --- a/tests/Targets/ActionTargetTest.php +++ b/tests/Targets/ActionTargetTest.php @@ -22,7 +22,7 @@ public function testDefaultAction(): void $route = new Route('/home', new Action(TestController::class, 'test')); $route = $route->withUriHandler(new UriHandler(new UriFactory())); - $this->assertSame(['action' => 'test'], $route->getDefaults()); + self::assertSame(['action' => 'test'], $route->getDefaults()); } public function testConstrains(): void @@ -30,12 +30,12 @@ public function testConstrains(): void $route = new Route('/home', new Action(TestController::class, 'test')); $route = $route->withUriHandler(new UriHandler(new UriFactory())); - $this->assertEquals(['action' => new Autofill('test')], $route->getUriHandler()->getConstrains()); + self::assertEquals(['action' => new Autofill('test')], $route->getUriHandler()->getConstrains()); $route = new Route('/', new Action(TestController::class, ['test', 'other'])); $route = $route->withUriHandler(new UriHandler(new UriFactory())); - $this->assertSame(['action' => ['test', 'other']], $route->getUriHandler()->getConstrains()); + self::assertSame(['action' => ['test', 'other']], $route->getUriHandler()->getConstrains()); } public function testConstrainedAction(): void @@ -52,41 +52,31 @@ public function testMatch(): void { $route = new Route( '/test[/]', - new Action(TestController::class, ['test', 'other']) + new Action(TestController::class, ['test', 'other']), ); $route = $route->withUriHandler(new UriHandler(new UriFactory())); $route = $route->withDefaults(['action' => 'test']); - $this->assertNull($route->match(new ServerRequest('GET', ''))); - $this->assertNull($route->match(new ServerRequest('GET', new Uri('/test/something')))); - $this->assertNull($route->match(new ServerRequest('GET', new Uri('/test/tester')))); + self::assertNull($route->match(new ServerRequest('GET', ''))); + self::assertNull($route->match(new ServerRequest('GET', new Uri('/test/something')))); + self::assertNull($route->match(new ServerRequest('GET', new Uri('/test/tester')))); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test'))) - ); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test')))); - $this->assertSame(['action' => 'test'], $match->getMatches()); + self::assertSame(['action' => 'test'], $match->getMatches()); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test/'))) - ); - $this->assertSame(['action' => 'test'], $match->getMatches()); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test/')))); + self::assertSame(['action' => 'test'], $match->getMatches()); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test/test'))) - ); - $this->assertSame(['action' => 'test'], $match->getMatches()); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test/test')))); + self::assertSame(['action' => 'test'], $match->getMatches()); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test/test/'))) - ); - $this->assertSame(['action' => 'test'], $match->getMatches()); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test/test/')))); + self::assertSame(['action' => 'test'], $match->getMatches()); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test/other'))) - ); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test/other')))); - $this->assertSame(['action' => 'other'], $match->getMatches()); + self::assertSame(['action' => 'other'], $match->getMatches()); } } diff --git a/tests/Targets/ControllerTargetTest.php b/tests/Targets/ControllerTargetTest.php index fefcd7b..735dc59 100644 --- a/tests/Targets/ControllerTargetTest.php +++ b/tests/Targets/ControllerTargetTest.php @@ -20,46 +20,36 @@ public function testDefaultAction(): void $route = new Route('/home[/]', new Controller(TestController::class)); $route = $route->withUriHandler(new UriHandler(new UriFactory())); - $this->assertSame(['action' => null], $route->getDefaults()); + self::assertSame(['action' => null], $route->getDefaults()); } public function testMatch(): void { $route = new Route( '/test[/]', - new Controller(TestController::class) + new Controller(TestController::class), ); $route = $route->withUriHandler(new UriHandler(new UriFactory())); - $this->assertNull($route->match(new ServerRequest('GET', ''))); - $this->assertNotNull($route->match(new ServerRequest('GET', new Uri('/test/something')))); - $this->assertNotNull($route->match(new ServerRequest('GET', new Uri('/test/tester')))); + self::assertNull($route->match(new ServerRequest('GET', ''))); + self::assertNotNull($route->match(new ServerRequest('GET', new Uri('/test/something')))); + self::assertNotNull($route->match(new ServerRequest('GET', new Uri('/test/tester')))); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test'))) - ); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test')))); - $this->assertSame(['action' => null], $match->getMatches()); + self::assertSame(['action' => null], $match->getMatches()); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test/'))) - ); - $this->assertSame(['action' => null], $match->getMatches()); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test/')))); + self::assertSame(['action' => null], $match->getMatches()); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test/test'))) - ); - $this->assertSame(['action' => 'test'], $match->getMatches()); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test/test')))); + self::assertSame(['action' => 'test'], $match->getMatches()); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test/test/'))) - ); - $this->assertSame(['action' => 'test'], $match->getMatches()); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test/test/')))); + self::assertSame(['action' => 'test'], $match->getMatches()); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test/other'))) - ); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test/other')))); - $this->assertSame(['action' => 'other'], $match->getMatches()); + self::assertSame(['action' => 'other'], $match->getMatches()); } } diff --git a/tests/Targets/GroupTargetTest.php b/tests/Targets/GroupTargetTest.php index a4f8291..a34c6e1 100644 --- a/tests/Targets/GroupTargetTest.php +++ b/tests/Targets/GroupTargetTest.php @@ -21,7 +21,7 @@ public function testDefaultAction(): void $route = new Route('//', new Group(['test' => TestController::class])); $route = $route->withUriHandler(new UriHandler(new UriFactory())); - $this->assertSame(['controller' => null, 'action' => null], $route->getDefaults()); + self::assertSame(['controller' => null, 'action' => null], $route->getDefaults()); } public function testConstrainedController(): void @@ -47,33 +47,25 @@ public function testMatch(): void { $route = new Route( '/[/]', - new Group(['test' => TestController::class]) + new Group(['test' => TestController::class]), ); $route = $route->withUriHandler(new UriHandler(new UriFactory())); $route = $route->withDefaults(['controller' => 'test']); - $this->assertNull($route->match(new ServerRequest('GET', ''))); + self::assertNull($route->match(new ServerRequest('GET', ''))); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test'))) - ); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test')))); - $this->assertSame(['controller' => 'test', 'action' => null], $match->getMatches()); + self::assertSame(['controller' => 'test', 'action' => null], $match->getMatches()); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test/action/'))) - ); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test/action/')))); - $this->assertSame(['controller' => 'test', 'action' => 'action'], $match->getMatches()); + self::assertSame(['controller' => 'test', 'action' => 'action'], $match->getMatches()); - $this->assertNull( - $match = $route->match(new ServerRequest('GET', new Uri('/other/action/'))) - ); + self::assertNull($match = $route->match(new ServerRequest('GET', new Uri('/other/action/')))); - $this->assertNull( - $match = $route->match(new ServerRequest('GET', new Uri('/other'))) - ); + self::assertNull($match = $route->match(new ServerRequest('GET', new Uri('/other')))); } } diff --git a/tests/Targets/NamespacedTargetTest.php b/tests/Targets/NamespacedTargetTest.php index f5bed2b..e5a2e78 100644 --- a/tests/Targets/NamespacedTargetTest.php +++ b/tests/Targets/NamespacedTargetTest.php @@ -16,12 +16,30 @@ class NamespacedTargetTest extends TestCase { + public static function defaultProvider(): \Traversable + { + yield ['[/]', '/home', ['controller' => 'home', 'action' => 'test']]; + yield ['[/]', '/home/test', ['controller' => 'home', 'action' => 'test']]; + yield ['/[/]', '/home', ['controller' => 'home', 'action' => 'test']]; + yield ['/[/]', '/home/test', ['controller' => 'home', 'action' => 'test']]; + + yield ['[[/]]', '/home', ['controller' => 'home', 'action' => 'test']]; + yield ['[[/]]', '/home/test', ['controller' => 'home', 'action' => 'test']]; + yield ['[[/]]', '/', ['controller' => 'home', 'action' => 'test']]; + yield ['[[/]]', '', ['controller' => 'home', 'action' => 'test']]; + + yield ['[/[/]]', '/home', ['controller' => 'home', 'action' => 'test']]; + yield ['[/[/]]', '/home/test', ['controller' => 'home', 'action' => 'test']]; + yield ['[/[/]]', '/', ['controller' => 'home', 'action' => 'test']]; + yield ['[/[/]]', '', ['controller' => 'home', 'action' => 'test']]; + } + public function testDefaultAction(): void { $route = new Route('//', new Namespaced('Spiral\Router\Fixtures')); $route = $route->withUriHandler(new UriHandler(new UriFactory())); - $this->assertSame(['controller' => null, 'action' => null], $route->getDefaults()); + self::assertSame(['controller' => null, 'action' => null], $route->getDefaults()); } public function testConstrainedController(): void @@ -48,31 +66,25 @@ public function testMatch(): void { $route = new Route( '/[/]', - new Namespaced('Spiral\Router\Fixtures') + new Namespaced('Spiral\Router\Fixtures'), ); $route = $route->withUriHandler(new UriHandler(new UriFactory())); $route = $route->withDefaults(['controller' => 'test']); - $this->assertNull($route->match(new ServerRequest('GET', ''))); + self::assertNull($route->match(new ServerRequest('GET', ''))); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test'))) - ); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test')))); - $this->assertSame(['controller' => 'test', 'action' => null], $match->getMatches()); + self::assertSame(['controller' => 'test', 'action' => null], $match->getMatches()); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/test/action/'))) - ); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/test/action/')))); - $this->assertSame(['controller' => 'test', 'action' => 'action'], $match->getMatches()); + self::assertSame(['controller' => 'test', 'action' => 'action'], $match->getMatches()); - $this->assertNotNull( - $match = $route->match(new ServerRequest('GET', new Uri('/other/action/'))) - ); + self::assertNotNull($match = $route->match(new ServerRequest('GET', new Uri('/other/action/')))); - $this->assertSame(['controller' => 'other', 'action' => 'action'], $match->getMatches()); + self::assertSame(['controller' => 'other', 'action' => 'action'], $match->getMatches()); } #[DataProvider('defaultProvider')] @@ -84,28 +96,10 @@ public function testDefaults(string $pattern, string $uri, array $defaults): voi $request = new ServerRequest('GET', new Uri($uri)); $match = $route->match($request); - $this->assertNotNull($match); + self::assertNotNull($match); $values = $match->getMatches(); - $this->assertNotNull($values['controller']); - $this->assertNotNull($values['action']); - } - - public static function defaultProvider(): \Traversable - { - yield ['[/]', '/home', ['controller' => 'home', 'action' => 'test']]; - yield ['[/]', '/home/test', ['controller' => 'home', 'action' => 'test']]; - yield ['/[/]', '/home', ['controller' => 'home', 'action' => 'test']]; - yield ['/[/]', '/home/test', ['controller' => 'home', 'action' => 'test']]; - - yield ['[[/]]', '/home', ['controller' => 'home', 'action' => 'test']]; - yield ['[[/]]', '/home/test', ['controller' => 'home', 'action' => 'test']]; - yield ['[[/]]', '/', ['controller' => 'home', 'action' => 'test']]; - yield ['[[/]]', '', ['controller' => 'home', 'action' => 'test']]; - - yield ['[/[/]]', '/home', ['controller' => 'home', 'action' => 'test']]; - yield ['[/[/]]', '/home/test', ['controller' => 'home', 'action' => 'test']]; - yield ['[/[/]]', '/', ['controller' => 'home', 'action' => 'test']]; - yield ['[/[/]]', '', ['controller' => 'home', 'action' => 'test']]; + self::assertNotNull($values['controller']); + self::assertNotNull($values['action']); } } diff --git a/tests/TestCore.php b/tests/TestCore.php index 6432443..09d5ff7 100644 --- a/tests/TestCore.php +++ b/tests/TestCore.php @@ -8,9 +8,7 @@ class TestCore implements CoreInterface { - public function __construct(private readonly CoreInterface $core) - { - } + public function __construct(private readonly CoreInterface $core) {} public function callAction(string $controller, ?string $action = null, array $parameters = []): string { diff --git a/tests/UriTest.php b/tests/UriTest.php index 2e3ded5..63a140a 100644 --- a/tests/UriTest.php +++ b/tests/UriTest.php @@ -6,12 +6,38 @@ use PHPUnit\Framework\Attributes\DataProvider; use Spiral\Router\Exception\UndefinedRouteException; +use Spiral\Router\Exception\UriHandlerException; use Spiral\Router\Route; +use Spiral\Router\Target\Action; use Spiral\Router\Target\Group; use Spiral\Tests\Router\Fixtures\TestController; class UriTest extends BaseTestCase { + public static function providePatternsWithRequiredSegments(): iterable + { + yield ['[/
[/]]/test/', ['controller' => 'test', 'id' => 1], '/test/test/1']; + yield ['/articles/[/
]', ['id' => 1], '/articles/1']; + yield ['/articles/', ['id' => 1], '/articles/1']; + yield ['/articles//edit', ['id' => 1], '/articles/1/edit']; + yield ['/articles//edit/
', ['id' => 1, 'section' => 'test'], '/articles/1/edit/test']; + yield ['/articles//edit/[
/]', ['id' => 1, 'path' => 'test'], '/articles/1/edit/test']; + yield ['/articles/', ['id' => 1], '/articles/1']; + yield ['/articles/', ['id' => 1], '/articles/1']; + yield ['/', ['path' => 'test'], '/test']; + yield ['/do/', ['method' => 'login'], '/do/login']; + yield ['//.domain.com/[
]', ['sub' => 'test'], 'test.domain.com']; + yield ['//.domain.com/', ['sub' => 'test'], 'test.domain.com']; + } + + public static function provideSegmentInDifferentLanguages(): iterable + { + yield 'English' => ['test', '/test/test']; + yield 'Russian' => ['тест', '/test/%D1%82%D0%B5%D1%81%D1%82']; + yield 'Japanese' => ['テスト', '/test/%E3%83%86%E3%82%B9%E3%83%88']; + yield 'Chinese' => ['测试', '/test/%E6%B5%8B%E8%AF%95']; + } + public function testCastRoute(): void { $router = $this->makeRouter(); @@ -23,7 +49,7 @@ public function testCastRoute(): void ); $uri = $router->uri('group/test:test'); - $this->assertSame('/test/test', $uri->getPath()); + self::assertSame('/test/test', $uri->getPath()); } public function testQuery(): void @@ -37,8 +63,8 @@ public function testQuery(): void ); $uri = $router->uri('group/test:id', ['id' => 100, 'data' => 'hello']); - $this->assertSame('/test/id/100', $uri->getPath()); - $this->assertSame('data=hello', $uri->getQuery()); + self::assertSame('/test/id/100', $uri->getPath()); + self::assertSame('data=hello', $uri->getQuery()); } public function testDirect(): void @@ -52,7 +78,7 @@ public function testDirect(): void ); $uri = $router->getRoute('group')->uri(['test', 'id', 100]); - $this->assertSame('/test/id/100', $uri->getPath()); + self::assertSame('/test/id/100', $uri->getPath()); } public function testSlug(): void @@ -66,7 +92,7 @@ public function testSlug(): void ); $uri = $router->getRoute('group')->uri(['test', 'id', 100, 'Hello World']); - $this->assertSame('/test/id/100-hello-world', $uri->getPath()); + self::assertSame('/test/id/100-hello-world', $uri->getPath()); } public function testSlugDefault(): void @@ -79,7 +105,7 @@ public function testSlugDefault(): void ); $uri = $router->uri('test:id', ['id' => 100, 'title' => 'Hello World']); - $this->assertSame('/test/id/100-hello-world', $uri->getPath()); + self::assertSame('/test/id/100-hello-world', $uri->getPath()); } public function testSlugNoDefault(): void @@ -89,7 +115,7 @@ public function testSlugNoDefault(): void $router = $this->makeRouter(); $uri = $router->uri('test:id', ['id' => 100, 'title' => 'Hello World']); - $this->assertSame('/test/id/100-hello-world', $uri->getPath()); + self::assertSame('/test/id/100-hello-world', $uri->getPath()); } public function testObject(): void @@ -111,7 +137,86 @@ public function __toString() }, ]); - $this->assertSame('/test/id/100-hello-world', $uri->getPath()); + self::assertSame('/test/id/100-hello-world', $uri->getPath()); + } + + #[DataProvider('providePatternsWithRequiredSegments')] + public function testRouteRequiredSegmentsNoStrict(string $pattern): void + { + $router = $this->makeRouter(); + $router->setRoute( + 'article', + new Route( + pattern: $pattern, + target: new Action( + controller: TestController::class, + action: 'id', + ), + ), + ); + + $route = $router->getRoute('article'); + + $uriHandler = $route->getUriHandler()->withPathSegmentEncoder( + fn(string $segment): string => \rawurlencode($segment), + ); + $route = $route->withUriHandler($uriHandler); + + self::assertNotNull($route->uri()); + } + + #[DataProvider('providePatternsWithRequiredSegments')] + public function testRouteRequiredSegments(string $pattern): void + { + $this->expectException(UriHandlerException::class); + + $router = $this->makeRouter(); + $router->setRoute( + 'article', + new Route( + pattern: $pattern, + target: new Action( + controller: TestController::class, + action: 'id', + ), + ), + ); + + $route = $router->getRoute('article'); + + $uriHandler = $route->getUriHandler()->withPathSegmentEncoder( + fn(string $segment): string => \rawurlencode($segment), + ); + $uriHandler->setStrict(true); + $route = $route->withUriHandler($uriHandler); + + $route->uri(); + } + + #[DataProvider('providePatternsWithRequiredSegments')] + public function testRouteOptionalSegments(string $pattern, array $params, string $expected): void + { + $router = $this->makeRouter(); + $router->setRoute( + 'article', + new Route( + pattern: $pattern, + target: new Action( + controller: TestController::class, + action: 'id', + ), + ), + ); + + $route = $router->getRoute('article'); + + $uriHandler = $route->getUriHandler()->withPathSegmentEncoder( + fn(string $segment): string => \rawurlencode($segment), + ); + $uriHandler->setStrict(true); + $route = $route->withUriHandler($uriHandler); + + self::assertSame($expected, (string) $route->uri($params)); } #[DataProvider('provideSegmentInDifferentLanguages')] @@ -126,18 +231,12 @@ public function testCustomPathSegmentEncoder(string $segment, string $expected): ); $route = $router->getRoute('group'); - $uriHandler = $route->getUriHandler()->withPathSegmentEncoder(fn(string $segment) => \rawurlencode($segment)); + $uriHandler = $route + ->getUriHandler() + ->withPathSegmentEncoder(static fn(string $segment): string => \rawurlencode($segment)); $route = $route->withUriHandler($uriHandler); $uri = $route->uri(['controller' => 'test', 'action' => $segment]); - $this->assertSame($expected, $uri->getPath()); - } - - public static function provideSegmentInDifferentLanguages(): iterable - { - yield 'English' => ['test', '/test/test']; - yield 'Russian' => ['тест', '/test/%D1%82%D0%B5%D1%81%D1%82']; - yield 'Japanese' => ['テスト', '/test/%E3%83%86%E3%82%B9%E3%83%88']; - yield 'Chinese' => ['测试', '/test/%E6%B5%8B%E8%AF%95']; + self::assertSame($expected, $uri->getPath()); } }