MDL-86456 libraries: Upgrade Slim Framework to 4.15.1

This commit is contained in:
Muhammad Arnaldo
2026-03-12 16:33:18 +07:00
parent 6ebf41a6c2
commit 6b7f82e3da
48 changed files with 340 additions and 118 deletions
+119 -5
View File
@@ -1,6 +1,117 @@
# Changelog
# 4.11.0 - 2022-11-06
## [Unreleased]
### Fixed
### Added
### Changed
### Removed
## 4.15.1 - 2025-11-21
## Fixed
- Allow PHPUnit 10, 11 and 12 when testing Slim itself (#3411)
### Added
- Add support for PHP 8.5 (#3415)
**Full Changelog**: https://github.com/slimphp/Slim/compare/4.15.0...4.15.1
## 4.15.0 - 2025-08-24
### Fixed
- Fix DocBlocks for callable route handlers (#3389)
- Change class keyword to lowercase (#3346)
- Fix tests for PHP 8.3
- Fixes the build status badge in Readme (#3331)
- Fix text and eol attributes for * selector in .gitattributes (#3391)
- Deprecate setArgument/s (#3383)
### Added
- Add support for PHP 8.4
- Add phpstan v2
### Changed
- Update http urls in composer.json (#3399)
**Full Changelog**: https://github.com/slimphp/Slim/compare/4.14.0...4.15.0
## 4.14.0 - 2024-06-13
### Changed
- Do not HTML entity encode in PlainTextErrorRenderer by @akrabat in https://github.com/slimphp/Slim/pull/3319
- Only render tip to error log if plain text renderer is used by @akrabat in https://github.com/slimphp/Slim/pull/3321
- Add template generics for PSR-11 implementations in PHPStan and Psalm by @limarkxx in https://github.com/slimphp/Slim/pull/3322
- Update squizlabs/php_codesniffer requirement from ^3.9 to ^3.10 by @dependabot in https://github.com/slimphp/Slim/pull/3324
- Update phpstan/phpstan requirement from ^1.10 to ^1.11 by @dependabot in https://github.com/slimphp/Slim/pull/3325
- Update psr/http-factory requirement from ^1.0 to ^1.1 by @dependabot in https://github.com/slimphp/Slim/pull/3326
#### Type hinting with template generics
With the introduction of template generics, if you type-hint `Slim\App` instance variable using `/** @var \Slim\App $app */`, then you will need to change it to either:
* `/** @var \Slim\App<null> $app */` if you are not using a DI container, or
* `/** @var \Slim\App<\Psr\Container\ContainerInterface> $app */` if you are
You can also type-hint to the concrete instance of the container you are using too. For example, if you are using [PHP-DI](https://php-di.org), then you can use: `/** @var \Slim\App<DI\Container> $app */`.
### New Contributors
* @limarkxx made their first contribution in https://github.com/slimphp/Slim/pull/3322
**Full Changelog**: https://github.com/slimphp/Slim/compare/4.13.0...4.14.0
# 4.13.0 - 2024-03-03
- [3277: Create HttpTooManyRequestsException.php](https://github.com/slimphp/Slim/pull/3277) thanks to @flavioheleno
- [3278: Remove HttpGoneException executable flag](https://github.com/slimphp/Slim/pull/3278) thanks to @flavioheleno
- [3285: Update guzzlehttp/psr7 requirement from ^2.5 to ^2.6](https://github.com/slimphp/Slim/pull/3285) thanks to @dependabot[bot]
- [3290: Bump actions/checkout from 3 to 4](https://github.com/slimphp/Slim/pull/3290) thanks to @dependabot[bot]
- [3291: Fix line length](https://github.com/slimphp/Slim/pull/3291) thanks to @l0gicgate
- [3296: PSR 7 http-message version requirement](https://github.com/slimphp/Slim/issues/3296) thanks to @rotexdegba
- [3297: Allow Diactoros 3](https://github.com/slimphp/Slim/pull/3297) thanks to @derrabus
- [3299: Update tests and add PHP 8.3 to the CI matrix](https://github.com/slimphp/Slim/pull/3299) thanks to @akrabat
- [3301: Update nyholm/psr7-server requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/3301) thanks to @dependabot[bot]
- [3302: Add support for psr/http-message ^2.0](https://github.com/slimphp/Slim/pull/3302) thanks to @rotexdegba
- [3305: Update phpspec/prophecy-phpunit requirement from ^2.0 to ^2.1](https://github.com/slimphp/Slim/pull/3305) thanks to @dependabot[bot]
- [3306: Update phpspec/prophecy requirement from ^1.17 to ^1.18](https://github.com/slimphp/Slim/pull/3306) thanks to @dependabot[bot]
- [3308: Update squizlabs/php&#95;codesniffer requirement from ^3.7 to ^3.8](https://github.com/slimphp/Slim/pull/3308) thanks to @dependabot[bot]
- [3313: Bump ramsey/composer-install from 2 to 3](https://github.com/slimphp/Slim/pull/3313) thanks to @dependabot[bot]
- [3314: Update phpspec/prophecy requirement from ^1.18 to ^1.19](https://github.com/slimphp/Slim/pull/3314) thanks to @dependabot[bot]
- [3315: Update squizlabs/php&#95;codesniffer requirement from ^3.8 to ^3.9](https://github.com/slimphp/Slim/pull/3315) thanks to @dependabot[bot]
# 4.12.0 - 2023-07-23
- [3220: Refactor](https://github.com/slimphp/Slim/pull/3220) thanks to @amirkhodabande
- [3237: Update phpstan/phpstan requirement from ^1.8 to ^1.9](https://github.com/slimphp/Slim/pull/3237) thanks to @dependabot[bot]
- [3238: Update slim/http requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/3238) thanks to @dependabot[bot]
- [3239: Update slim/psr7 requirement from ^1.5 to ^1.6](https://github.com/slimphp/Slim/pull/3239) thanks to @dependabot[bot]
- [3240: Update phpspec/prophecy requirement from ^1.15 to ^1.16](https://github.com/slimphp/Slim/pull/3240) thanks to @dependabot[bot]
- [3241: Update adriansuter/php-autoload-override requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3241) thanks to @dependabot[bot]
- [3245: New ability to override RouteGroupInterface in the Route class](https://github.com/slimphp/Slim/pull/3245) thanks to @githubjeka
- [3253: Fix HttpBadRequestException description](https://github.com/slimphp/Slim/pull/3253) thanks to @jsanahuja
- [3254: Update phpunit/phpunit requirement from ^9.5 to ^9.6](https://github.com/slimphp/Slim/pull/3254) thanks to @dependabot[bot]
- [3255: Update phpstan/phpstan requirement from ^1.9 to ^1.10](https://github.com/slimphp/Slim/pull/3255) thanks to @dependabot[bot]
- [3256: Update phpspec/prophecy requirement from ^1.16 to ^1.17](https://github.com/slimphp/Slim/pull/3256) thanks to @dependabot[bot]
- [3264: Update psr/http-message requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/3264) thanks to @dependabot[bot]
- [3265: Update nyholm/psr7 requirement from ^1.5 to ^1.7](https://github.com/slimphp/Slim/pull/3265) thanks to @dependabot[bot]
- [3266: Update guzzlehttp/psr7 requirement from ^2.4 to ^2.5](https://github.com/slimphp/Slim/pull/3266) thanks to @dependabot[bot]
- [3267: Update nyholm/psr7 requirement from ^1.7 to ^1.8](https://github.com/slimphp/Slim/pull/3267) thanks to @dependabot[bot]
- [3269: Update httpsoft/http-server-request requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/3269) thanks to @dependabot[bot]
- [3270: Update httpsoft/http-message requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/3270) thanks to @dependabot[bot]
- [3271: prevent multiple entries of same methode in FastRouteDispatcher](https://github.com/slimphp/Slim/pull/3271) thanks to @papparazzo
## 4.11.0 - 2022-11-06
- [3180: Declare types](https://github.com/slimphp/Slim/pull/3180) thanks to @nbayramberdiyev
- [3181: Update laminas/laminas-diactoros requirement from ^2.8 to ^2.9](https://github.com/slimphp/Slim/pull/3181) thanks to @dependabot[bot]
- [3182: Update guzzlehttp/psr7 requirement from ^2.1 to ^2.2](https://github.com/slimphp/Slim/pull/3182) thanks to @dependabot[bot]
@@ -29,7 +140,8 @@
- [3229: Update laminas/laminas-diactoros requirement from ^2.14 to ^2.17](https://github.com/slimphp/Slim/pull/3229) thanks to @dependabot[bot]
- [3235: Persist routes indexed by name in RouteCollector for improved performance.](https://github.com/slimphp/Slim/pull/3235) thanks to @BusterNeece
# 4.10.0 - 2022-03-14
## 4.10.0 - 2022-03-14
- [3120: Add a new PSR-17 factory to Psr17FactoryProvider](https://github.com/slimphp/Slim/pull/3120) thanks to @solventt
- [3123: Replace deprecated setMethods() in tests](https://github.com/slimphp/Slim/pull/3123) thanks to @solventt
- [3126: Update guzzlehttp/psr7 requirement from ^2.0 to ^2.1](https://github.com/slimphp/Slim/pull/3126) thanks to @dependabot[bot]
@@ -48,7 +160,8 @@
- [3148: Upgrade to HTML5](https://github.com/slimphp/Slim/pull/3148) thanks to @nbayramberdiyev
- [3172: Update nyholm/psr7 requirement from ^1.4 to ^1.5](https://github.com/slimphp/Slim/pull/3172) thanks to @dependabot[bot]
# 4.9.0 - 2021-10-05
## 4.9.0 - 2021-10-05
- [3058: Implement exception class for Gone Http error](https://github.com/slimphp/Slim/pull/3058) thanks to @TheKernelPanic
- [3086: Update slim/psr7 requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3086) thanks to @dependabot[bot]
- [3087: Update nyholm/psr7-server requirement from ^1.0.1 to ^1.0.2](https://github.com/slimphp/Slim/pull/3087) thanks to @dependabot[bot]
@@ -62,7 +175,8 @@
- [3115: Update phpstan/phpstan requirement from ^0.12.96 to ^0.12.99](https://github.com/slimphp/Slim/pull/3115) thanks to @dependabot[bot]
- [3116: Remove Zend Diactoros references](https://github.com/slimphp/Slim/pull/3116) thanks to @l0gicgate
# 4.8.0 - 2021-05-19
## 4.8.0 - 2021-05-19
- [3034: Fix phpunit dependency version](https://github.com/slimphp/Slim/pull/3034) thanks to @l0gicgate
- [3037: Replace Travis by GitHub Actions](https://github.com/slimphp/Slim/pull/3037) thanks to @t0mmy742
- [3043: Cover App creation from AppFactory with empty Container](https://github.com/slimphp/Slim/pull/3043) thanks to @t0mmy742
@@ -79,7 +193,7 @@
- [3080: Update guzzlehttp/psr7 requirement from ^1.7 to ^1.8](https://github.com/slimphp/Slim/pull/3080) thanks to @dependabot[bot]
- [3082: Update phpstan/phpstan requirement from ^0.12.80 to ^0.12.85](https://github.com/slimphp/Slim/pull/3082) thanks to @dependabot[bot]
# 4.7.0 - 2020-11-30
## 4.7.0 - 2020-11-30
### Fixed
- [3027: Fix: FastRoute dispatcher and data generator should match](https://github.com/slimphp/Slim/pull/3027) thanks to @edudobay
-17
View File
@@ -1,17 +0,0 @@
# Maintainers
There aren't many rules for maintainers of Slim to remember; what we have is listed here.
## We don't merge our own PRs
Our code is better if more than one set of eyes looks at it. Therefore we do not merge our own pull requests unless there is an exceptional circumstance. This helps to spot errors in the patch and also enables us to share information about the project around the maintainer team.
## PRs tagged `WIP` are not ready to be merged
Sometimes it's helpful to collaborate on a patch before it's ready to be merged. We use the text `WIP` (for _Work in Progress_) in the title to mark these PRs.
If a PR has `WIP` in its title, then it is not to be merged. The person who raised the PR will remove the `WIP` text when they are ready for a full review and merge.
## Assign a merged PR to a milestone
By ensuring that all merged PRs are assigned to a milestone, we can easily find which PRs were in which release.
+11 -1
View File
@@ -31,6 +31,11 @@ use Slim\Routing\RouteRunner;
use function strtoupper;
/**
* @api
* @template TContainerInterface of (ContainerInterface|null)
* @template-extends RouteCollectorProxy<TContainerInterface>
*/
class App extends RouteCollectorProxy implements RequestHandlerInterface
{
/**
@@ -38,12 +43,15 @@ class App extends RouteCollectorProxy implements RequestHandlerInterface
*
* @var string
*/
public const VERSION = '4.12.0';
public const VERSION = '4.15.1';
protected RouteResolverInterface $routeResolver;
protected MiddlewareDispatcherInterface $middlewareDispatcher;
/**
* @param TContainerInterface $container
*/
public function __construct(
ResponseFactoryInterface $responseFactory,
?ContainerInterface $container = null,
@@ -89,6 +97,7 @@ class App extends RouteCollectorProxy implements RequestHandlerInterface
/**
* @param MiddlewareInterface|string|callable $middleware
* @return App<TContainerInterface>
*/
public function add($middleware): self
{
@@ -98,6 +107,7 @@ class App extends RouteCollectorProxy implements RequestHandlerInterface
/**
* @param MiddlewareInterface $middleware
* @return App<TContainerInterface>
*/
public function addMiddleware(MiddlewareInterface $middleware): self
{
+12 -5
View File
@@ -26,12 +26,19 @@ use function json_encode;
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;
@@ -72,7 +79,7 @@ final class CallableResolver implements AdvancedCallableResolverInterface
}
/**
* @param string|callable $toResolve
* @param callable|array{class-string, string}|string $toResolve
*
* @throws RuntimeException
*/
@@ -120,11 +127,10 @@ final class CallableResolver implements AdvancedCallableResolverInterface
*/
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)) {
@@ -174,8 +180,9 @@ final class CallableResolver implements AdvancedCallableResolverInterface
}
/**
* @param string|callable $toResolve
* @return string|callable
* @param callable|string|array{class-string, string}|mixed $toResolve
*
* @return callable|string|array{class-string, string}|mixed
*/
private function prepareToResolve($toResolve)
{
@@ -39,7 +39,6 @@ class HtmlErrorRenderer extends AbstractErrorRenderer
{
$html = sprintf('<div><strong>Type:</strong> %s</div>', get_class($exception));
/** @var int|string $code */
$code = $exception->getCode();
$html .= sprintf('<div><strong>Code:</strong> %s</div>', $code);
@@ -43,7 +43,6 @@ class JsonErrorRenderer extends AbstractErrorRenderer
*/
private function formatExceptionFragment(Throwable $exception): array
{
/** @var int|string $code */
$code = $exception->getCode();
return [
'type' => get_class($exception),
@@ -43,10 +43,10 @@ class PlainTextErrorRenderer extends AbstractErrorRenderer
$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", htmlentities($exception->getMessage()));
$text .= sprintf("Message: %s\n", $exception->getMessage());
$text .= sprintf("File: %s\n", $exception->getFile());
@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpBadRequestException extends HttpSpecializedException
{
/**
@@ -15,6 +15,7 @@ use RuntimeException;
use Throwable;
/**
* @api
* @method int getCode()
*/
class HttpException extends RuntimeException
@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpForbiddenException extends HttpSpecializedException
{
/**
@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpGoneException extends HttpSpecializedException
{
/**
@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpInternalServerErrorException extends HttpSpecializedException
{
/**
@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpNotImplementedException extends HttpSpecializedException
{
/**
@@ -17,8 +17,8 @@ abstract class HttpSpecializedException extends HttpException
{
/**
* @param ServerRequestInterface $request
* @param string|null $message
* @param Throwable|null $previous
* @param string|null $message
* @param Throwable|null $previous
*/
public function __construct(ServerRequestInterface $request, ?string $message = null, ?Throwable $previous = null)
{
@@ -26,6 +26,7 @@ abstract class HttpSpecializedException extends HttpException
$this->message = $message;
}
// @phpstan-ignore-next-line
parent::__construct($request, $this->message, $this->code, $previous);
}
}
@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpTooManyRequestsException extends HttpSpecializedException
{
/**
@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpUnauthorizedException extends HttpSpecializedException
{
/**
@@ -24,6 +24,7 @@ use Slim\Interfaces\Psr17FactoryProviderInterface;
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<TContainerInterface> : App<ContainerInterface|null>)
*/
public static function create(
?ResponseFactoryInterface $responseFactory = null,
?ContainerInterface $container = null,
@@ -63,6 +69,11 @@ class AppFactory
);
}
/**
* @template TContainerInterface of (ContainerInterface)
* @param TContainerInterface $container
* @return App<TContainerInterface>
*/
public static function createFromContainer(ContainerInterface $container): App
{
$responseFactory = $container->has(ResponseFactoryInterface::class)
@@ -39,6 +39,8 @@ class ServerRequestCreator implements ServerRequestCreatorInterface
{
/** @var callable $callable */
$callable = [$this->serverRequestCreator, $this->serverRequestCreatorMethod];
/** @var ServerRequestInterface */
return (Closure::fromCallable($callable))();
}
}
@@ -17,6 +17,7 @@ use Slim\Factory\Psr17\SlimHttpServerRequestCreator;
use Slim\Interfaces\Psr17FactoryProviderInterface;
use Slim\Interfaces\ServerRequestCreatorInterface;
/** @api */
class ServerRequestCreatorFactory
{
protected static ?Psr17FactoryProviderInterface $psr17FactoryProvider = null;
@@ -43,6 +43,7 @@ use function preg_match;
*
* 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
{
@@ -188,6 +189,7 @@ class ErrorHandler implements ErrorHandlerInterface
}
}
// @phpstan-ignore-next-line
if (is_string($current)) {
return $current;
}
@@ -258,11 +260,15 @@ class ErrorHandler implements ErrorHandlerInterface
protected function writeToErrorLog(): void
{
$renderer = $this->callableResolver->resolve($this->logErrorRenderer);
/** @var string $error */
$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.';
}
$this->logError($error);
}
@@ -43,6 +43,7 @@ class RequestHandler implements RequestHandlerInvocationStrategyInterface
}
}
/** @var ResponseInterface */
return $callable($request);
}
}
@@ -35,6 +35,7 @@ class RequestResponse implements InvocationStrategyInterface
$request = $request->withAttribute($k, $v);
}
/** @var ResponseInterface */
return $callable($request, $response, $routeArguments);
}
}
@@ -18,6 +18,7 @@ use function array_values;
/**
* Route callback strategy with route parameters as individual arguments.
* @api
*/
class RequestResponseArgs implements InvocationStrategyInterface
{
@@ -33,6 +34,7 @@ class RequestResponseArgs implements InvocationStrategyInterface
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
/** @var ResponseInterface */
return $callable($request, $response, ...array_values($routeArguments));
}
}
@@ -17,16 +17,10 @@ use RuntimeException;
/**
* Route callback strategy with route parameters as individual arguments.
* @api
*/
class RequestResponseNamedArgs implements InvocationStrategyInterface
{
public function __construct()
{
if (PHP_VERSION_ID < 80000) {
throw new RuntimeException('Named arguments are only available for PHP >= 8.0.0');
}
}
/**
* Invoke a route callable with request, response and all route parameters
* as individual arguments.
@@ -39,6 +33,7 @@ class RequestResponseNamedArgs implements InvocationStrategyInterface
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
/** @var ResponseInterface */
return $callable($request, $response, ...$routeArguments);
}
}
@@ -15,14 +15,14 @@ interface AdvancedCallableResolverInterface extends CallableResolverInterface
/**
* Resolve $toResolve into a callable
*
* @param string|callable $toResolve
* @param callable|array{class-string, string}|string $toResolve
*/
public function resolveRoute($toResolve): callable;
/**
* Resolve $toResolve into a callable
*
* @param string|callable $toResolve
* @param callable|array{class-string, string}|string $toResolve
*/
public function resolveMiddleware($toResolve): callable;
}
@@ -15,7 +15,7 @@ interface CallableResolverInterface
/**
* Resolve $toResolve into a callable
*
* @param string|callable $toResolve
* @param callable|array{class-string, string}|string $toResolve
*/
public function resolve($toResolve): callable;
}
@@ -13,6 +13,7 @@ namespace Slim\Interfaces;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
/** @api */
interface MiddlewareDispatcherInterface extends RequestHandlerInterface
{
/**
@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Slim\Interfaces;
/** @api */
interface Psr17FactoryProviderInterface
{
/**
@@ -13,6 +13,7 @@ namespace Slim\Interfaces;
use InvalidArgumentException;
use RuntimeException;
/** @api */
interface RouteCollectorInterface
{
/**
@@ -94,9 +95,9 @@ interface RouteCollectorInterface
/**
* Add route
*
* @param string[] $methods Array of HTTP methods
* @param string $pattern The route pattern
* @param callable|string $handler The route callable
* @param string[] $methods Array of HTTP methods
* @param string $pattern The route pattern
* @param callable|array{class-string, string}|string $handler The route callable
*/
public function map(array $methods, string $pattern, $handler): RouteInterface;
}
@@ -14,12 +14,19 @@ use Psr\Container\ContainerInterface;
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,71 +38,72 @@ interface RouteCollectorProxyInterface
/**
* Set the RouteCollectorProxy's base path
* @return RouteCollectorProxyInterface<TContainerInterface>
*/
public function setBasePath(string $basePath): RouteCollectorProxyInterface;
/**
* Add GET route
*
* @param string $pattern The route URI pattern
* @param callable|string $callable The route callback routine
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function get(string $pattern, $callable): RouteInterface;
/**
* Add POST route
*
* @param string $pattern The route URI pattern
* @param callable|string $callable The route callback routine
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function post(string $pattern, $callable): RouteInterface;
/**
* Add PUT route
*
* @param string $pattern The route URI pattern
* @param callable|string $callable The route callback routine
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function put(string $pattern, $callable): RouteInterface;
/**
* Add PATCH route
*
* @param string $pattern The route URI pattern
* @param callable|string $callable The route callback routine
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function patch(string $pattern, $callable): RouteInterface;
/**
* Add DELETE route
*
* @param string $pattern The route URI pattern
* @param callable|string $callable The route callback routine
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function delete(string $pattern, $callable): RouteInterface;
/**
* Add OPTIONS route
*
* @param string $pattern The route URI pattern
* @param callable|string $callable The route callback routine
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function options(string $pattern, $callable): RouteInterface;
/**
* Add route for any HTTP method
*
* @param string $pattern The route URI pattern
* @param callable|string $callable The route callback routine
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function any(string $pattern, $callable): RouteInterface;
/**
* Add route with multiple methods
*
* @param string[] $methods Numeric array of HTTP method names
* @param string $pattern The route URI pattern
* @param callable|string $callable The route callback routine
* @param string[] $methods Numeric array of HTTP method names
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function map(array $methods, string $pattern, $callable): RouteInterface;
@@ -13,6 +13,7 @@ namespace Slim\Interfaces;
use Psr\Http\Server\MiddlewareInterface;
use Slim\MiddlewareDispatcher;
/** @api */
interface RouteGroupInterface
{
public function collectRoutes(): RouteGroupInterface;
@@ -31,6 +32,7 @@ interface RouteGroupInterface
/**
* Append the group's middleware to the MiddlewareDispatcher
* @param MiddlewareDispatcher<\Psr\Container\ContainerInterface|null> $dispatcher
*/
public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher): RouteGroupInterface;
@@ -14,6 +14,7 @@ use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
/** @api */
interface RouteInterface
{
/**
@@ -46,14 +47,14 @@ interface RouteInterface
/**
* Get route callable
*
* @return callable|string
* @return callable|array{class-string, string}|string
*/
public function getCallable();
/**
* Set route callable
*
* @param callable|string $callable
* @param callable|array{class-string, string}|string $callable
*/
public function setCallable($callable): RouteInterface;
@@ -88,6 +89,8 @@ interface RouteInterface
/**
* Set a route argument
*
* @deprecated 4.14.1 Use a middleware for custom route arguments now.
*/
public function setArgument(string $name, string $value): RouteInterface;
@@ -95,6 +98,8 @@ interface RouteInterface
* Replace route arguments
*
* @param array<string, string> $arguments
*
* @deprecated 4.14.1 Use a middleware for custom route arguments now.
*/
public function setArguments(array $arguments): self;
@@ -14,14 +14,15 @@ use InvalidArgumentException;
use Psr\Http\Message\UriInterface;
use RuntimeException;
/** @api */
interface RouteParserInterface
{
/**
* Build the path for a named route excluding the base path
*
* @param string $routeName Route name
* @param array<string, string> $data Named argument replacement data
* @param array<string, string> $queryParams Optional query string parameters
* @param string $routeName Route name
* @param array<string, string> $data Named argument replacement data
* @param array<string, string | array<array-key, string>> $queryParams Optional query string parameters
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
@@ -31,9 +32,9 @@ interface RouteParserInterface
/**
* Build the path for a named route including the base path
*
* @param string $routeName Route name
* @param array<string, string> $data Named argument replacement data
* @param array<string, string> $queryParams Optional query string parameters
* @param string $routeName Route name
* @param array<string, string> $data Named argument replacement data
* @param array<string, string | array<array-key, string>> $queryParams Optional query string parameters
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
@@ -43,10 +44,10 @@ interface RouteParserInterface
/**
* Get fully qualified URL for named route
*
* @param UriInterface $uri
* @param string $routeName Route name
* @param array<string, string> $data Named argument replacement data
* @param array<string, string> $queryParams Optional query string parameters
* @param UriInterface $uri
* @param string $routeName Route name
* @param array<string, string> $data Named argument replacement data
* @param array<string, string | array<array-key, string>> $queryParams Optional query string parameters
*/
public function fullUrlFor(UriInterface $uri, string $routeName, array $data = [], array $queryParams = []): string;
}
@@ -19,7 +19,6 @@ use RuntimeException;
use function count;
use function explode;
use function is_array;
use function is_null;
use function is_object;
use function is_string;
use function json_decode;
@@ -33,6 +32,7 @@ use function trim;
use const LIBXML_VERSION;
/** @api */
class BodyParsingMiddleware implements MiddlewareInterface
{
/**
@@ -65,8 +65,8 @@ class BodyParsingMiddleware implements MiddlewareInterface
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
* @param callable $callable A callable that returns parsed contents for media type.
* @param string $mediaType A HTTP media type (excluding content-type params).
* @param callable $callable A callable that returns parsed contents for media type.
*/
public function registerBodyParser(string $mediaType, callable $callable): self
{
@@ -75,7 +75,7 @@ class BodyParsingMiddleware implements MiddlewareInterface
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
* @param string $mediaType A HTTP media type (excluding content-type params).
*/
public function hasBodyParser(string $mediaType): bool
{
@@ -83,7 +83,7 @@ class BodyParsingMiddleware implements MiddlewareInterface
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
* @param string $mediaType A HTTP media type (excluding content-type params).
* @throws RuntimeException
*/
public function getBodyParser(string $mediaType): callable
@@ -97,6 +97,7 @@ class BodyParsingMiddleware implements MiddlewareInterface
protected function registerDefaultBodyParsers(): void
{
$this->registerBodyParser('application/json', static function ($input) {
/** @var string $input */
$result = json_decode($input, true);
if (!is_array($result)) {
@@ -107,11 +108,15 @@ class BodyParsingMiddleware implements MiddlewareInterface
});
$this->registerBodyParser('application/x-www-form-urlencoded', static function ($input) {
/** @var string $input */
parse_str($input, $data);
return $data;
});
$xmlCallable = static function ($input) {
/** @var string $input */
$backup = self::disableXmlEntityLoader(true);
$backup_errors = libxml_use_internal_errors(true);
$result = simplexml_load_string($input);
@@ -15,6 +15,7 @@ use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
/** @api */
class ContentLengthMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
@@ -25,6 +25,7 @@ use Throwable;
use function get_class;
use function is_subclass_of;
/** @api */
class ErrorMiddleware implements MiddlewareInterface
{
protected CallableResolverInterface $callableResolver;
@@ -88,6 +89,7 @@ class ErrorMiddleware implements MiddlewareInterface
$exceptionType = get_class($exception);
$handler = $this->getErrorHandler($exceptionType);
/** @var ResponseInterface */
return $handler($request, $exception, $this->displayErrorDetails, $this->logErrors, $this->logErrorDetails);
}
@@ -140,7 +142,8 @@ class ErrorMiddleware implements MiddlewareInterface
*
* The callable signature MUST match the ErrorHandlerInterface
*
* @see \Slim\Interfaces\ErrorHandlerInterface
* @param string|callable|ErrorHandler $handler
* @see ErrorHandlerInterface
*
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
* 2. Instance of \Throwable
@@ -151,7 +154,6 @@ class ErrorMiddleware implements MiddlewareInterface
* The callable MUST return an instance of
* \Psr\Http\Message\ResponseInterface.
*
* @param string|callable|ErrorHandler $handler
*/
public function setDefaultErrorHandler($handler): self
{
@@ -168,7 +170,12 @@ class ErrorMiddleware implements MiddlewareInterface
* Pass true to $handleSubclasses to make the handler handle all subclasses of
* the type as well. Pass an array of classes to make the same function handle multiple exceptions.
*
* @see \Slim\Interfaces\ErrorHandlerInterface
* @param string|string[] $typeOrTypes Exception/Throwable name.
* ie: RuntimeException::class or an array of classes
* ie: [HttpNotFoundException::class, HttpMethodNotAllowedException::class]
* @param string|callable|ErrorHandlerInterface $handler
*
* @see ErrorHandlerInterface
*
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
* 2. Instance of \Throwable
@@ -179,10 +186,6 @@ class ErrorMiddleware implements MiddlewareInterface
* The callable MUST return an instance of
* \Psr\Http\Message\ResponseInterface.
*
* @param string|string[] $typeOrTypes Exception/Throwable name.
* ie: RuntimeException::class or an array of classes
* ie: [HttpNotFoundException::class, HttpMethodNotAllowedException::class]
* @param string|callable|ErrorHandlerInterface $handler
*/
public function setErrorHandler($typeOrTypes, $handler, bool $handleSubclasses = false): self
{
@@ -18,6 +18,7 @@ use Psr\Http\Server\RequestHandlerInterface;
use function is_array;
use function strtoupper;
/** @api */
class MethodOverrideMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
@@ -29,7 +30,7 @@ class MethodOverrideMiddleware implements MiddlewareInterface
} elseif (strtoupper($request->getMethod()) === 'POST') {
$body = $request->getParsedBody();
if (is_array($body) && !empty($body['_METHOD'])) {
if (is_array($body) && !empty($body['_METHOD']) && is_string($body['_METHOD'])) {
$request = $request->withMethod($body['_METHOD']);
}
@@ -23,6 +23,7 @@ use function ob_end_clean;
use function ob_get_clean;
use function ob_start;
/** @api */
class OutputBufferingMiddleware implements MiddlewareInterface
{
public const APPEND = 'append';
@@ -28,6 +28,10 @@ use function is_string;
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 @@ class MiddlewareDispatcher implements MiddlewareDispatcherInterface
* 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<TContainerInterface>
*/
public function addDeferred(string $middleware): self
{
@@ -165,6 +174,7 @@ class MiddlewareDispatcher implements MiddlewareDispatcherInterface
{
if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {
$callable = $this->callableResolver->resolveMiddleware($this->middleware);
/** @var ResponseInterface */
return $callable($request, $this->next);
}
@@ -183,6 +193,7 @@ class MiddlewareDispatcher implements MiddlewareDispatcherInterface
$instance = null;
$method = null;
/** @psalm-suppress ArgumentTypeCoercion */
// Check for Slim callable as `class:method`
if (preg_match(CallableResolver::$callablePattern, $resolved, $matches)) {
$resolved = $matches[1];
@@ -224,6 +235,7 @@ class MiddlewareDispatcher implements MiddlewareDispatcherInterface
);
}
/** @var ResponseInterface */
return $callable($request, $this->next);
}
};
@@ -237,6 +249,7 @@ class MiddlewareDispatcher implements MiddlewareDispatcherInterface
* 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<TContainerInterface>
*/
public function addCallable(callable $middleware): self
{
@@ -266,6 +279,7 @@ class MiddlewareDispatcher implements MiddlewareDispatcherInterface
public function handle(ServerRequestInterface $request): ResponseInterface
{
/** @var ResponseInterface */
return ($this->middleware)($request, $this->next);
}
};
+16 -12
View File
@@ -33,6 +33,10 @@ use function class_implements;
use function in_array;
use function is_array;
/**
* @api
* @template TContainerInterface of (ContainerInterface|null)
*/
class Route implements RouteInterface, RequestHandlerInterface
{
/**
@@ -71,21 +75,23 @@ class Route implements RouteInterface, RequestHandlerInterface
/**
* Route arguments parameters
*
* @var string[]
* @var array<string, string>
*/
protected array $savedArguments = [];
/**
* Container
* @var TContainerInterface $container
*/
protected ?ContainerInterface $container = null;
/** @var MiddlewareDispatcher<TContainerInterface> $middlewareDispatcher */
protected MiddlewareDispatcher $middlewareDispatcher;
/**
* Route callable
*
* @var callable|string
* @var callable|array{class-string, string}|string
*/
protected $callable;
@@ -101,15 +107,15 @@ class Route implements RouteInterface, RequestHandlerInterface
protected bool $groupMiddlewareAppended = false;
/**
* @param string[] $methods The route HTTP methods
* @param string $pattern The route pattern
* @param callable|string $callable The route callable
* @param ResponseFactoryInterface $responseFactory
* @param CallableResolverInterface $callableResolver
* @param ContainerInterface|null $container
* @param string[] $methods The route HTTP methods
* @param string $pattern The route pattern
* @param callable|array{class-string, string}|string $callable The route callable
* @param ResponseFactoryInterface $responseFactory
* @param CallableResolverInterface $callableResolver
* @param TContainerInterface $container
* @param InvocationStrategyInterface|null $invocationStrategy
* @param RouteGroupInterface[] $groups The parent route groups
* @param int $identifier The route identifier
* @param RouteGroupInterface[] $groups The parent route groups
* @param int $identifier The route identifier
*/
public function __construct(
array $methods,
@@ -323,7 +329,6 @@ class Route implements RouteInterface, RequestHandlerInterface
$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);
}
@@ -343,7 +348,6 @@ class Route implements RouteInterface, RequestHandlerInterface
}
$strategy = $this->invocationStrategy;
/** @var string[] $strategyImplements */
$strategyImplements = class_implements($strategy);
if (
@@ -25,13 +25,14 @@ use Slim\Interfaces\RouteParserInterface;
use function array_pop;
use function dirname;
use function file_exists;
use function sprintf;
use function is_readable;
use function is_writable;
use function sprintf;
/**
* 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 @@ class RouteCollector implements RouteCollectorInterface
{
$route = $this->getNamedRoute($name);
/** @psalm-suppress PossiblyNullArrayOffset */
unset($this->routesByName[$route->getName()], $this->routes[$route->getIdentifier()]);
return $this;
}
@@ -243,8 +248,12 @@ class RouteCollector implements RouteCollectorInterface
return new RouteGroup($pattern, $callable, $this->callableResolver, $routeCollectorProxy);
}
/**
* @return RouteCollectorProxyInterface<TContainerInterface>
*/
protected function createProxy(string $pattern): RouteCollectorProxyInterface
{
/** @var RouteCollectorProxy<TContainerInterface> */
return new RouteCollectorProxy(
$this->responseFactory,
$this->callableResolver,
@@ -273,8 +282,8 @@ class RouteCollector implements RouteCollectorInterface
}
/**
* @param string[] $methods
* @param callable|string $callable
* @param string[] $methods
* @param callable|array{class-string, string}|string $callable
*/
protected function createRoute(array $methods, string $pattern, $callable): RouteInterface
{
@@ -18,18 +18,26 @@ use Slim\Interfaces\RouteCollectorProxyInterface;
use Slim\Interfaces\RouteGroupInterface;
use Slim\Interfaces\RouteInterface;
/**
* @template TContainerInterface of (ContainerInterface|null)
* @template-implements RouteCollectorProxyInterface<TContainerInterface>
*/
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 @@ class RouteCollectorProxy implements RouteCollectorProxyInterface
/**
* {@inheritdoc}
* @return TContainerInterface
*/
public function getContainer(): ?ContainerInterface
{
@@ -15,6 +15,7 @@ use RuntimeException;
use Slim\Interfaces\RouteInterface;
use Slim\Interfaces\RouteParserInterface;
/** @api */
final class RouteContext
{
public const ROUTE = '__route__';
@@ -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 @@ class RouteGroup implements RouteGroupInterface
/**
* {@inheritdoc}
* @param MiddlewareDispatcher<\Psr\Container\ContainerInterface|null> $dispatcher
*/
public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher): RouteGroupInterface
{
@@ -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 @@ class RouteRunner implements RequestHandlerInterface
);
}
/** @var Route $route */
/** @var Route<\Psr\Container\ContainerInterface|null> $route */
$route = $request->getAttribute(RouteContext::ROUTE);
return $route->run($request);
}
@@ -14,6 +14,7 @@ use Slim\Interfaces\DispatcherInterface;
use function rawurldecode;
/** @api */
class RoutingResults
{
public const NOT_FOUND = 0;
+14 -11
View File
@@ -14,17 +14,17 @@
{
"name": "Andrew Smith",
"email": "[email protected]",
"homepage": "http://silentworks.co.uk"
"homepage": "https://silentworks.co.uk"
},
{
"name": "Rob Allen",
"email": "[email protected]",
"homepage": "http://akrabat.com"
"homepage": "https://akrabat.com"
},
{
"name": "Pierre Berube",
"email": "[email protected]",
"homepage": "http://www.lgse.com"
"homepage": "https://www.lgse.com"
},
{
"name": "Gabriel Manricks",
@@ -43,11 +43,11 @@
"wiki": "https://github.com/slimphp/Slim/wiki"
},
"require": {
"php": "^7.4 || ^8.0",
"php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
"ext-json": "*",
"nikic/fast-route": "^1.3",
"psr/container": "^1.0 || ^2.0",
"psr/http-factory": "^1.0",
"psr/http-factory": "^1.1",
"psr/http-message": "^1.1 || ^2.0",
"psr/http-server-handler": "^1.0",
"psr/http-server-middleware": "^1.0",
@@ -55,7 +55,7 @@
},
"require-dev": {
"ext-simplexml": "*",
"adriansuter/php-autoload-override": "^1.4",
"adriansuter/php-autoload-override": "^1.4 || ^2",
"guzzlehttp/psr7": "^2.6",
"httpsoft/http-message": "^1.1",
"httpsoft/http-server-request": "^1.1",
@@ -64,11 +64,12 @@
"nyholm/psr7-server": "^1.1",
"phpspec/prophecy": "^1.19",
"phpspec/prophecy-phpunit": "^2.1",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.6",
"phpstan/phpstan": "^1 || ^2",
"phpunit/phpunit": "^9.6 || ^10 || ^11 || ^12",
"slim/http": "^1.3",
"slim/psr7": "^1.6",
"squizlabs/php_codesniffer": "^3.9"
"squizlabs/php_codesniffer": "^3.10",
"vimeo/psalm": "^5 || ^6"
},
"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",
+1 -1
View File
@@ -812,7 +812,7 @@ All rights reserved.</copyright>
<library>
<location>slim/slim</location>
<name>Slim Framework</name>
<version>4.13.0</version>
<version>4.15.1</version>
<license>MIT</license>
<repository>https://github.com/slimphp/Slim</repository>
</library>