diff --git a/Slim/App.php b/Slim/App.php index ebcc751f6..68b900023 100644 --- a/Slim/App.php +++ b/Slim/App.php @@ -31,6 +31,11 @@ use function strtoupper; +/** + * @api + * @template TContainerInterface of (ContainerInterface|null) + * @template-extends RouteCollectorProxy + */ class App extends RouteCollectorProxy implements RequestHandlerInterface { /** @@ -44,6 +49,9 @@ class App extends RouteCollectorProxy implements RequestHandlerInterface protected MiddlewareDispatcherInterface $middlewareDispatcher; + /** + * @param TContainerInterface $container + */ public function __construct( ResponseFactoryInterface $responseFactory, ?ContainerInterface $container = null, @@ -89,6 +97,7 @@ public function getMiddlewareDispatcher(): MiddlewareDispatcherInterface /** * @param MiddlewareInterface|string|callable $middleware + * @return App */ public function add($middleware): self { @@ -98,6 +107,7 @@ public function add($middleware): self /** * @param MiddlewareInterface $middleware + * @return App */ public function addMiddleware(MiddlewareInterface $middleware): self { diff --git a/Slim/CallableResolver.php b/Slim/CallableResolver.php index 66f225de8..dab46c460 100644 --- a/Slim/CallableResolver.php +++ b/Slim/CallableResolver.php @@ -26,12 +26,19 @@ use function preg_match; use function sprintf; +/** + * @template TContainerInterface of (ContainerInterface|null) + */ final class CallableResolver implements AdvancedCallableResolverInterface { public static string $callablePattern = '!^([^\:]+)\:([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)$!'; + /** @var TContainerInterface $container */ private ?ContainerInterface $container; + /** + * @param TContainerInterface $container + */ public function __construct(?ContainerInterface $container = null) { $this->container = $container; @@ -120,11 +127,10 @@ private function isMiddleware($toResolve): bool */ private function resolveSlimNotation(string $toResolve): array { + /** @psalm-suppress ArgumentTypeCoercion */ preg_match(CallableResolver::$callablePattern, $toResolve, $matches); [$class, $method] = $matches ? [$matches[1], $matches[2]] : [$toResolve, null]; - /** @var string $class */ - /** @var string|null $method */ if ($this->container && $this->container->has($class)) { $instance = $this->container->get($class); if (!is_object($instance)) { diff --git a/Slim/Error/Renderers/HtmlErrorRenderer.php b/Slim/Error/Renderers/HtmlErrorRenderer.php index e030522aa..8fd838bcb 100644 --- a/Slim/Error/Renderers/HtmlErrorRenderer.php +++ b/Slim/Error/Renderers/HtmlErrorRenderer.php @@ -39,7 +39,6 @@ private function renderExceptionFragment(Throwable $exception): string { $html = sprintf('
Type: %s
', get_class($exception)); - /** @var int|string $code */ $code = $exception->getCode(); $html .= sprintf('
Code: %s
', $code); diff --git a/Slim/Error/Renderers/JsonErrorRenderer.php b/Slim/Error/Renderers/JsonErrorRenderer.php index 63d905b3c..06085d2e5 100644 --- a/Slim/Error/Renderers/JsonErrorRenderer.php +++ b/Slim/Error/Renderers/JsonErrorRenderer.php @@ -43,7 +43,6 @@ public function __invoke(Throwable $exception, bool $displayErrorDetails): strin */ private function formatExceptionFragment(Throwable $exception): array { - /** @var int|string $code */ $code = $exception->getCode(); return [ 'type' => get_class($exception), diff --git a/Slim/Error/Renderers/PlainTextErrorRenderer.php b/Slim/Error/Renderers/PlainTextErrorRenderer.php index 9788568d5..fcb6e8a15 100644 --- a/Slim/Error/Renderers/PlainTextErrorRenderer.php +++ b/Slim/Error/Renderers/PlainTextErrorRenderer.php @@ -43,7 +43,7 @@ private function formatExceptionFragment(Throwable $exception): string $text = sprintf("Type: %s\n", get_class($exception)); $code = $exception->getCode(); - /** @var int|string $code */ + $text .= sprintf("Code: %s\n", $code); $text .= sprintf("Message: %s\n", $exception->getMessage()); diff --git a/Slim/Exception/HttpBadRequestException.php b/Slim/Exception/HttpBadRequestException.php index 9be551cf9..000c2480a 100644 --- a/Slim/Exception/HttpBadRequestException.php +++ b/Slim/Exception/HttpBadRequestException.php @@ -10,6 +10,7 @@ namespace Slim\Exception; +/** @api */ class HttpBadRequestException extends HttpSpecializedException { /** diff --git a/Slim/Exception/HttpException.php b/Slim/Exception/HttpException.php index d9dbd6cbe..c714dbbe5 100644 --- a/Slim/Exception/HttpException.php +++ b/Slim/Exception/HttpException.php @@ -15,6 +15,7 @@ use Throwable; /** + * @api * @method int getCode() */ class HttpException extends RuntimeException diff --git a/Slim/Exception/HttpForbiddenException.php b/Slim/Exception/HttpForbiddenException.php index dd3bb230a..d262a63f6 100644 --- a/Slim/Exception/HttpForbiddenException.php +++ b/Slim/Exception/HttpForbiddenException.php @@ -10,6 +10,7 @@ namespace Slim\Exception; +/** @api */ class HttpForbiddenException extends HttpSpecializedException { /** diff --git a/Slim/Exception/HttpGoneException.php b/Slim/Exception/HttpGoneException.php index 42899e1e6..b1005d83e 100644 --- a/Slim/Exception/HttpGoneException.php +++ b/Slim/Exception/HttpGoneException.php @@ -10,6 +10,7 @@ namespace Slim\Exception; +/** @api */ class HttpGoneException extends HttpSpecializedException { /** diff --git a/Slim/Exception/HttpInternalServerErrorException.php b/Slim/Exception/HttpInternalServerErrorException.php index b43226190..f9cb60f7b 100644 --- a/Slim/Exception/HttpInternalServerErrorException.php +++ b/Slim/Exception/HttpInternalServerErrorException.php @@ -10,6 +10,7 @@ namespace Slim\Exception; +/** @api */ class HttpInternalServerErrorException extends HttpSpecializedException { /** diff --git a/Slim/Exception/HttpNotImplementedException.php b/Slim/Exception/HttpNotImplementedException.php index 607a6f49a..af4fe253d 100644 --- a/Slim/Exception/HttpNotImplementedException.php +++ b/Slim/Exception/HttpNotImplementedException.php @@ -10,6 +10,7 @@ namespace Slim\Exception; +/** @api */ class HttpNotImplementedException extends HttpSpecializedException { /** diff --git a/Slim/Exception/HttpTooManyRequestsException.php b/Slim/Exception/HttpTooManyRequestsException.php index be4b29bb3..af438bad4 100644 --- a/Slim/Exception/HttpTooManyRequestsException.php +++ b/Slim/Exception/HttpTooManyRequestsException.php @@ -10,6 +10,7 @@ namespace Slim\Exception; +/** @api */ class HttpTooManyRequestsException extends HttpSpecializedException { /** diff --git a/Slim/Exception/HttpUnauthorizedException.php b/Slim/Exception/HttpUnauthorizedException.php index 07bd70d01..afb0e5407 100644 --- a/Slim/Exception/HttpUnauthorizedException.php +++ b/Slim/Exception/HttpUnauthorizedException.php @@ -10,6 +10,7 @@ namespace Slim\Exception; +/** @api */ class HttpUnauthorizedException extends HttpSpecializedException { /** diff --git a/Slim/Factory/AppFactory.php b/Slim/Factory/AppFactory.php index 6fc5f86ea..be91e88e9 100644 --- a/Slim/Factory/AppFactory.php +++ b/Slim/Factory/AppFactory.php @@ -24,6 +24,7 @@ use Slim\Interfaces\RouteCollectorInterface; use Slim\Interfaces\RouteResolverInterface; +/** @api */ class AppFactory { protected static ?Psr17FactoryProviderInterface $psr17FactoryProvider = null; @@ -44,6 +45,11 @@ class AppFactory protected static bool $slimHttpDecoratorsAutomaticDetectionEnabled = true; + /** + * @template TContainerInterface of (ContainerInterface|null) + * @param TContainerInterface $container + * @return (TContainerInterface is ContainerInterface ? App : App) + */ public static function create( ?ResponseFactoryInterface $responseFactory = null, ?ContainerInterface $container = null, @@ -63,6 +69,11 @@ public static function create( ); } + /** + * @template TContainerInterface of (ContainerInterface) + * @param TContainerInterface $container + * @return App + */ public static function createFromContainer(ContainerInterface $container): App { $responseFactory = $container->has(ResponseFactoryInterface::class) diff --git a/Slim/Factory/ServerRequestCreatorFactory.php b/Slim/Factory/ServerRequestCreatorFactory.php index 94f639d2a..2bd95d77c 100644 --- a/Slim/Factory/ServerRequestCreatorFactory.php +++ b/Slim/Factory/ServerRequestCreatorFactory.php @@ -17,6 +17,7 @@ use Slim\Interfaces\Psr17FactoryProviderInterface; use Slim\Interfaces\ServerRequestCreatorInterface; +/** @api */ class ServerRequestCreatorFactory { protected static ?Psr17FactoryProviderInterface $psr17FactoryProvider = null; diff --git a/Slim/Handlers/ErrorHandler.php b/Slim/Handlers/ErrorHandler.php index f9606e364..689b4630b 100644 --- a/Slim/Handlers/ErrorHandler.php +++ b/Slim/Handlers/ErrorHandler.php @@ -43,6 +43,7 @@ * * It outputs the error message and diagnostic information in one of the following formats: * JSON, XML, Plain Text or HTML based on the Accept header. + * @api */ class ErrorHandler implements ErrorHandlerInterface { @@ -259,7 +260,7 @@ protected function writeToErrorLog(): void { $renderer = $this->callableResolver->resolve($this->logErrorRenderer); $error = $renderer($this->exception, $this->logErrorDetails); - if (!$this->displayErrorDetails) { + if ($this->logErrorRenderer === PlainTextErrorRenderer::class && !$this->displayErrorDetails) { $error .= "\nTips: To display error details in HTTP response "; $error .= 'set "displayErrorDetails" to true in the ErrorHandler constructor.'; } diff --git a/Slim/Handlers/Strategies/RequestResponseArgs.php b/Slim/Handlers/Strategies/RequestResponseArgs.php index c4ab16df5..6eab63a25 100644 --- a/Slim/Handlers/Strategies/RequestResponseArgs.php +++ b/Slim/Handlers/Strategies/RequestResponseArgs.php @@ -18,6 +18,7 @@ /** * Route callback strategy with route parameters as individual arguments. + * @api */ class RequestResponseArgs implements InvocationStrategyInterface { diff --git a/Slim/Handlers/Strategies/RequestResponseNamedArgs.php b/Slim/Handlers/Strategies/RequestResponseNamedArgs.php index 651111dde..f36059646 100644 --- a/Slim/Handlers/Strategies/RequestResponseNamedArgs.php +++ b/Slim/Handlers/Strategies/RequestResponseNamedArgs.php @@ -17,6 +17,7 @@ /** * Route callback strategy with route parameters as individual arguments. + * @api */ class RequestResponseNamedArgs implements InvocationStrategyInterface { diff --git a/Slim/Interfaces/MiddlewareDispatcherInterface.php b/Slim/Interfaces/MiddlewareDispatcherInterface.php index aa7a26ad2..9fa34a6ad 100644 --- a/Slim/Interfaces/MiddlewareDispatcherInterface.php +++ b/Slim/Interfaces/MiddlewareDispatcherInterface.php @@ -13,6 +13,7 @@ use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; +/** @api */ interface MiddlewareDispatcherInterface extends RequestHandlerInterface { /** diff --git a/Slim/Interfaces/Psr17FactoryProviderInterface.php b/Slim/Interfaces/Psr17FactoryProviderInterface.php index c7b87aa78..24590fe0f 100644 --- a/Slim/Interfaces/Psr17FactoryProviderInterface.php +++ b/Slim/Interfaces/Psr17FactoryProviderInterface.php @@ -10,6 +10,7 @@ namespace Slim\Interfaces; +/** @api */ interface Psr17FactoryProviderInterface { /** diff --git a/Slim/Interfaces/RouteCollectorInterface.php b/Slim/Interfaces/RouteCollectorInterface.php index 921a2365f..aa83883f6 100644 --- a/Slim/Interfaces/RouteCollectorInterface.php +++ b/Slim/Interfaces/RouteCollectorInterface.php @@ -13,6 +13,7 @@ use InvalidArgumentException; use RuntimeException; +/** @api */ interface RouteCollectorInterface { /** diff --git a/Slim/Interfaces/RouteCollectorProxyInterface.php b/Slim/Interfaces/RouteCollectorProxyInterface.php index fcbed92b6..0220af030 100644 --- a/Slim/Interfaces/RouteCollectorProxyInterface.php +++ b/Slim/Interfaces/RouteCollectorProxyInterface.php @@ -14,12 +14,19 @@ use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\UriInterface; +/** + * @api + * @template TContainerInterface of (ContainerInterface|null) + */ interface RouteCollectorProxyInterface { public function getResponseFactory(): ResponseFactoryInterface; public function getCallableResolver(): CallableResolverInterface; + /** + * @return TContainerInterface + */ public function getContainer(): ?ContainerInterface; public function getRouteCollector(): RouteCollectorInterface; @@ -31,6 +38,7 @@ public function getBasePath(): string; /** * Set the RouteCollectorProxy's base path + * @return RouteCollectorProxyInterface */ public function setBasePath(string $basePath): RouteCollectorProxyInterface; diff --git a/Slim/Interfaces/RouteGroupInterface.php b/Slim/Interfaces/RouteGroupInterface.php index 0411ce944..efc1c5a3b 100644 --- a/Slim/Interfaces/RouteGroupInterface.php +++ b/Slim/Interfaces/RouteGroupInterface.php @@ -13,6 +13,7 @@ use Psr\Http\Server\MiddlewareInterface; use Slim\MiddlewareDispatcher; +/** @api */ interface RouteGroupInterface { public function collectRoutes(): RouteGroupInterface; @@ -31,6 +32,7 @@ public function addMiddleware(MiddlewareInterface $middleware): RouteGroupInterf /** * Append the group's middleware to the MiddlewareDispatcher + * @param MiddlewareDispatcher<\Psr\Container\ContainerInterface|null> $dispatcher */ public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher): RouteGroupInterface; diff --git a/Slim/Interfaces/RouteInterface.php b/Slim/Interfaces/RouteInterface.php index c15333123..8ed817ef4 100644 --- a/Slim/Interfaces/RouteInterface.php +++ b/Slim/Interfaces/RouteInterface.php @@ -14,6 +14,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; +/** @api */ interface RouteInterface { /** diff --git a/Slim/Interfaces/RouteParserInterface.php b/Slim/Interfaces/RouteParserInterface.php index 03d932665..8ccea3bc3 100644 --- a/Slim/Interfaces/RouteParserInterface.php +++ b/Slim/Interfaces/RouteParserInterface.php @@ -14,6 +14,7 @@ use Psr\Http\Message\UriInterface; use RuntimeException; +/** @api */ interface RouteParserInterface { /** diff --git a/Slim/Middleware/BodyParsingMiddleware.php b/Slim/Middleware/BodyParsingMiddleware.php index 9a90f30c4..94bba3713 100644 --- a/Slim/Middleware/BodyParsingMiddleware.php +++ b/Slim/Middleware/BodyParsingMiddleware.php @@ -33,6 +33,7 @@ use const LIBXML_VERSION; +/** @api */ class BodyParsingMiddleware implements MiddlewareInterface { /** diff --git a/Slim/Middleware/ContentLengthMiddleware.php b/Slim/Middleware/ContentLengthMiddleware.php index 8fa13bcf7..e289fa365 100644 --- a/Slim/Middleware/ContentLengthMiddleware.php +++ b/Slim/Middleware/ContentLengthMiddleware.php @@ -15,6 +15,7 @@ use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; +/** @api */ class ContentLengthMiddleware implements MiddlewareInterface { public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface diff --git a/Slim/Middleware/ErrorMiddleware.php b/Slim/Middleware/ErrorMiddleware.php index 2eb5cc96f..39b1e585d 100644 --- a/Slim/Middleware/ErrorMiddleware.php +++ b/Slim/Middleware/ErrorMiddleware.php @@ -25,6 +25,7 @@ use function get_class; use function is_subclass_of; +/** @api */ class ErrorMiddleware implements MiddlewareInterface { protected CallableResolverInterface $callableResolver; diff --git a/Slim/Middleware/MethodOverrideMiddleware.php b/Slim/Middleware/MethodOverrideMiddleware.php index 079a1f189..553463e2d 100644 --- a/Slim/Middleware/MethodOverrideMiddleware.php +++ b/Slim/Middleware/MethodOverrideMiddleware.php @@ -18,6 +18,7 @@ use function is_array; use function strtoupper; +/** @api */ class MethodOverrideMiddleware implements MiddlewareInterface { public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface diff --git a/Slim/Middleware/OutputBufferingMiddleware.php b/Slim/Middleware/OutputBufferingMiddleware.php index 69ee1f6f1..8bfbbf64e 100644 --- a/Slim/Middleware/OutputBufferingMiddleware.php +++ b/Slim/Middleware/OutputBufferingMiddleware.php @@ -23,6 +23,7 @@ use function ob_get_clean; use function ob_start; +/** @api */ class OutputBufferingMiddleware implements MiddlewareInterface { public const APPEND = 'append'; diff --git a/Slim/MiddlewareDispatcher.php b/Slim/MiddlewareDispatcher.php index 7e0564414..1d4c668ff 100644 --- a/Slim/MiddlewareDispatcher.php +++ b/Slim/MiddlewareDispatcher.php @@ -28,6 +28,10 @@ use function preg_match; use function sprintf; +/** + * @api + * @template TContainerInterface of (ContainerInterface|null) + */ class MiddlewareDispatcher implements MiddlewareDispatcherInterface { /** @@ -37,8 +41,12 @@ class MiddlewareDispatcher implements MiddlewareDispatcherInterface protected ?CallableResolverInterface $callableResolver; + /** @var TContainerInterface $container */ protected ?ContainerInterface $container; + /** + * @param TContainerInterface $container + */ public function __construct( RequestHandlerInterface $kernel, ?CallableResolverInterface $callableResolver = null, @@ -131,6 +139,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface * Middleware are organized as a stack. That means middleware * that have been added before will be executed after the newly * added one (last in, first out). + * @return MiddlewareDispatcher */ public function addDeferred(string $middleware): self { @@ -183,6 +192,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface $instance = null; $method = null; + /** @psalm-suppress ArgumentTypeCoercion */ // Check for Slim callable as `class:method` if (preg_match(CallableResolver::$callablePattern, $resolved, $matches)) { $resolved = $matches[1]; @@ -237,6 +247,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface * Middleware are organized as a stack. That means middleware * that have been added before will be executed after the newly * added one (last in, first out). + * @return MiddlewareDispatcher */ public function addCallable(callable $middleware): self { diff --git a/Slim/Routing/Route.php b/Slim/Routing/Route.php index 2cd9fa567..a2d9d04a2 100644 --- a/Slim/Routing/Route.php +++ b/Slim/Routing/Route.php @@ -33,6 +33,10 @@ use function in_array; use function is_array; +/** + * @api + * @template TContainerInterface of (ContainerInterface|null) + */ class Route implements RouteInterface, RequestHandlerInterface { /** @@ -77,9 +81,11 @@ class Route implements RouteInterface, RequestHandlerInterface /** * Container + * @var TContainerInterface $container */ protected ?ContainerInterface $container = null; + /** @var MiddlewareDispatcher $middlewareDispatcher */ protected MiddlewareDispatcher $middlewareDispatcher; /** @@ -106,7 +112,7 @@ class Route implements RouteInterface, RequestHandlerInterface * @param callable|string $callable The route callable * @param ResponseFactoryInterface $responseFactory * @param CallableResolverInterface $callableResolver - * @param ContainerInterface|null $container + * @param TContainerInterface $container * @param InvocationStrategyInterface|null $invocationStrategy * @param RouteGroupInterface[] $groups The parent route groups * @param int $identifier The route identifier @@ -323,7 +329,6 @@ protected function appendGroupMiddlewareToRoute(): void $inner = $this->middlewareDispatcher; $this->middlewareDispatcher = new MiddlewareDispatcher($inner, $this->callableResolver, $this->container); - /** @var RouteGroupInterface $group */ foreach (array_reverse($this->groups) as $group) { $group->appendMiddlewareToDispatcher($this->middlewareDispatcher); } diff --git a/Slim/Routing/RouteCollector.php b/Slim/Routing/RouteCollector.php index 61b450300..6f9f0f66b 100644 --- a/Slim/Routing/RouteCollector.php +++ b/Slim/Routing/RouteCollector.php @@ -32,6 +32,7 @@ /** * RouteCollector is used to collect routes and route groups * as well as generate paths and URLs relative to its environment + * @template TContainerInterface of (ContainerInterface|null) */ class RouteCollector implements RouteCollectorInterface { @@ -81,6 +82,9 @@ class RouteCollector implements RouteCollectorInterface protected ResponseFactoryInterface $responseFactory; + /** + * @param TContainerInterface $container + */ public function __construct( ResponseFactoryInterface $responseFactory, CallableResolverInterface $callableResolver, @@ -181,6 +185,7 @@ public function removeNamedRoute(string $name): RouteCollectorInterface { $route = $this->getNamedRoute($name); + /** @psalm-suppress PossiblyNullArrayOffset */ unset($this->routesByName[$route->getName()], $this->routes[$route->getIdentifier()]); return $this; } @@ -243,8 +248,12 @@ protected function createGroup(string $pattern, $callable): RouteGroupInterface return new RouteGroup($pattern, $callable, $this->callableResolver, $routeCollectorProxy); } + /** + * @return RouteCollectorProxyInterface + */ protected function createProxy(string $pattern): RouteCollectorProxyInterface { + /** @var RouteCollectorProxyInterface */ return new RouteCollectorProxy( $this->responseFactory, $this->callableResolver, diff --git a/Slim/Routing/RouteCollectorProxy.php b/Slim/Routing/RouteCollectorProxy.php index f8bc232bc..a946d148f 100644 --- a/Slim/Routing/RouteCollectorProxy.php +++ b/Slim/Routing/RouteCollectorProxy.php @@ -18,18 +18,26 @@ use Slim\Interfaces\RouteGroupInterface; use Slim\Interfaces\RouteInterface; +/** + * @template TContainerInterface of (ContainerInterface|null) + * @template-implements RouteCollectorProxyInterface + */ class RouteCollectorProxy implements RouteCollectorProxyInterface { protected ResponseFactoryInterface $responseFactory; protected CallableResolverInterface $callableResolver; + /** @var TContainerInterface */ protected ?ContainerInterface $container = null; protected RouteCollectorInterface $routeCollector; protected string $groupPattern; + /** + * @param TContainerInterface $container + */ public function __construct( ResponseFactoryInterface $responseFactory, CallableResolverInterface $callableResolver, @@ -62,6 +70,7 @@ public function getCallableResolver(): CallableResolverInterface /** * {@inheritdoc} + * @return TContainerInterface */ public function getContainer(): ?ContainerInterface { diff --git a/Slim/Routing/RouteContext.php b/Slim/Routing/RouteContext.php index 3ba5e23a6..853b0df3e 100644 --- a/Slim/Routing/RouteContext.php +++ b/Slim/Routing/RouteContext.php @@ -15,6 +15,7 @@ use Slim\Interfaces\RouteInterface; use Slim\Interfaces\RouteParserInterface; +/** @api */ final class RouteContext { public const ROUTE = '__route__'; diff --git a/Slim/Routing/RouteGroup.php b/Slim/Routing/RouteGroup.php index cd2f4e79a..60d3df3d8 100644 --- a/Slim/Routing/RouteGroup.php +++ b/Slim/Routing/RouteGroup.php @@ -26,6 +26,9 @@ class RouteGroup implements RouteGroupInterface protected CallableResolverInterface $callableResolver; + /** + * @var RouteCollectorProxyInterface<\Psr\Container\ContainerInterface|null> + */ protected RouteCollectorProxyInterface $routeCollectorProxy; /** @@ -37,6 +40,7 @@ class RouteGroup implements RouteGroupInterface /** * @param callable|string $callable + * @param RouteCollectorProxyInterface<\Psr\Container\ContainerInterface|null> $routeCollectorProxy */ public function __construct( string $pattern, @@ -84,6 +88,7 @@ public function addMiddleware(MiddlewareInterface $middleware): RouteGroupInterf /** * {@inheritdoc} + * @param MiddlewareDispatcher<\Psr\Container\ContainerInterface|null> $dispatcher */ public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher): RouteGroupInterface { diff --git a/Slim/Routing/RouteRunner.php b/Slim/Routing/RouteRunner.php index 40946af56..3fb541352 100644 --- a/Slim/Routing/RouteRunner.php +++ b/Slim/Routing/RouteRunner.php @@ -26,8 +26,14 @@ class RouteRunner implements RequestHandlerInterface private RouteParserInterface $routeParser; + /** + * @var RouteCollectorProxyInterface<\Psr\Container\ContainerInterface|null> + */ private ?RouteCollectorProxyInterface $routeCollectorProxy; + /** + * @param RouteCollectorProxyInterface<\Psr\Container\ContainerInterface|null> $routeCollectorProxy + */ public function __construct( RouteResolverInterface $routeResolver, RouteParserInterface $routeParser, @@ -63,7 +69,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface ); } - /** @var Route $route */ + /** @var Route<\Psr\Container\ContainerInterface|null> $route */ $route = $request->getAttribute(RouteContext::ROUTE); return $route->run($request); } diff --git a/Slim/Routing/RoutingResults.php b/Slim/Routing/RoutingResults.php index ac2fa64f9..4fd8973f8 100644 --- a/Slim/Routing/RoutingResults.php +++ b/Slim/Routing/RoutingResults.php @@ -14,6 +14,7 @@ use function rawurldecode; +/** @api */ class RoutingResults { public const NOT_FOUND = 0; diff --git a/composer.json b/composer.json index 8fa37b8e0..10cf49cf1 100644 --- a/composer.json +++ b/composer.json @@ -68,7 +68,8 @@ "phpunit/phpunit": "^9.6", "slim/http": "^1.3", "slim/psr7": "^1.6", - "squizlabs/php_codesniffer": "^3.9" + "squizlabs/php_codesniffer": "^3.10", + "vimeo/psalm": "^5.24" }, "autoload": { "psr-4": { @@ -84,11 +85,13 @@ "test": [ "@phpunit", "@phpcs", - "@phpstan" + "@phpstan", + "@psalm" ], "phpunit": "phpunit", "phpcs": "phpcs", - "phpstan": "phpstan --memory-limit=-1" + "phpstan": "phpstan --memory-limit=-1", + "psalm": "psalm --no-cache" }, "suggest": { "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 000000000..af258ff89 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/tests/Handlers/ErrorHandlerTest.php b/tests/Handlers/ErrorHandlerTest.php index 9346f1c7e..b50dff4b3 100644 --- a/tests/Handlers/ErrorHandlerTest.php +++ b/tests/Handlers/ErrorHandlerTest.php @@ -353,6 +353,35 @@ public function testWriteToErrorLogShowTip() $handler->__invoke($request, $exception, false, true, true); } + public function testWriteToErrorLogDoesNotShowTipIfErrorLogRendererIsNotPlainText() + { + $request = $this + ->createServerRequest('/', 'GET') + ->withHeader('Accept', 'application/json'); + + $logger = $this->getMockLogger(); + + $handler = new ErrorHandler( + $this->getCallableResolver(), + $this->getResponseFactory(), + $logger + ); + + $handler->setLogErrorRenderer(HtmlErrorRenderer::class); + + $logger->expects(self::once()) + ->method('error') + ->willReturnCallback(static function (string $error) { + self::assertStringNotContainsString( + 'set "displayErrorDetails" to true in the ErrorHandler constructor', + $error + ); + }); + + $exception = new HttpNotFoundException($request); + $handler->__invoke($request, $exception, false, true, true); + } + public function testDefaultErrorRenderer() { $request = $this