Commit inicial con archivos existentes

This commit is contained in:
2026-01-17 16:14:00 -06:00
parent 48671dc88e
commit 4c48c279de
2539 changed files with 2412708 additions and 0 deletions

339
vendor/slim/slim/CHANGELOG.md vendored Executable file
View File

@@ -0,0 +1,339 @@
# Changelog
## [Unreleased]
### Fixed
### Added
### Changed
### Removed
## 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]
- [3183: Update phpstan/phpstan requirement from ^1.4 to ^1.5](https://github.com/slimphp/Slim/pull/3183) thanks to @dependabot[bot]
- [3184: Update adriansuter/php-autoload-override requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/3184) thanks to @dependabot[bot]
- [3189: Update phpstan/phpstan requirement from ^1.5 to ^1.6](https://github.com/slimphp/Slim/pull/3189) thanks to @dependabot[bot]
- [3191: Adding property types to Middleware classes](https://github.com/slimphp/Slim/pull/3191) thanks to @ashleycoles
- [3193: Handlers types](https://github.com/slimphp/Slim/pull/3193) thanks to @ashleycoles
- [3194: Adding types to AbstractErrorRenderer](https://github.com/slimphp/Slim/pull/3194) thanks to @ashleycoles
- [3195: Adding prop types for Exception classes](https://github.com/slimphp/Slim/pull/3195) thanks to @ashleycoles
- [3196: Adding property type declarations for Factory classes](https://github.com/slimphp/Slim/pull/3196) thanks to @ashleycoles
- [3197: Remove redundant docblock types](https://github.com/slimphp/Slim/pull/3197) thanks to @theodorejb
- [3199: Update laminas/laminas-diactoros requirement from ^2.9 to ^2.11](https://github.com/slimphp/Slim/pull/3199) thanks to @dependabot[bot]
- [3200: Update phpstan/phpstan requirement from ^1.6 to ^1.7](https://github.com/slimphp/Slim/pull/3200) thanks to @dependabot[bot]
- [3205: Update guzzlehttp/psr7 requirement from ^2.2 to ^2.4](https://github.com/slimphp/Slim/pull/3205) thanks to @dependabot[bot]
- [3206: Update squizlabs/php_codesniffer requirement from ^3.6 to ^3.7](https://github.com/slimphp/Slim/pull/3206) thanks to @dependabot[bot]
- [3207: Update phpstan/phpstan requirement from ^1.7 to ^1.8](https://github.com/slimphp/Slim/pull/3207) thanks to @dependabot[bot]
- [3211: Assign null coalescing to coalesce equal](https://github.com/slimphp/Slim/pull/3211) thanks to @MathiasReker
- [3213: Void return](https://github.com/slimphp/Slim/pull/3213) thanks to @MathiasReker
- [3214: Is null](https://github.com/slimphp/Slim/pull/3214) thanks to @MathiasReker
- [3216: Refactor](https://github.com/slimphp/Slim/pull/3216) thanks to @mehdihasanpour
- [3218: Refactor some code](https://github.com/slimphp/Slim/pull/3218) thanks to @mehdihasanpour
- [3221: Cleanup](https://github.com/slimphp/Slim/pull/3221) thanks to @mehdihasanpour
- [3225: Update laminas/laminas-diactoros requirement from ^2.11 to ^2.14](https://github.com/slimphp/Slim/pull/3225) thanks to @dependabot[bot]
- [3228: Using assertSame to let assert equal be restricted](https://github.com/slimphp/Slim/pull/3228) thanks to @peter279k
- [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
- [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]
- [3127: PHPStan v1.0](https://github.com/slimphp/Slim/pull/3127) thanks to @t0mmy742
- [3128: Update phpstan/phpstan requirement from ^1.0 to ^1.2](https://github.com/slimphp/Slim/pull/3128) thanks to @dependabot[bot]
- [3129: Deprecate PHP 7.3](https://github.com/slimphp/Slim/pull/3129) thanks to @l0gicgate
- [3130: Removed double defined PHP 7.4](https://github.com/slimphp/Slim/pull/3130) thanks to @flangofas
- [3132: Add new `RequestResponseNamedArgs` route strategy](https://github.com/slimphp/Slim/pull/3132) thanks to @adoy
- [3133: Improve typehinting for `RouteParserInterface`](https://github.com/slimphp/Slim/pull/3133) thanks to @jerowork
- [3135: Update phpstan/phpstan requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/3135) thanks to @dependabot[bot]
- [3137: Update phpspec/prophecy requirement from ^1.14 to ^1.15](https://github.com/slimphp/Slim/pull/3137) thanks to @dependabot[bot]
- [3138: Update license year](https://github.com/slimphp/Slim/pull/3138) thanks to @Awilum
- [3139: Fixed #1730 (reintroduced in 4.x)](https://github.com/slimphp/Slim/pull/3139) thanks to @adoy
- [3145: Update phpstan/phpstan requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3145) thanks to @dependabot[bot]
- [3146: Inherit HttpException from RuntimeException](https://github.com/slimphp/Slim/pull/3146) thanks to @nbayramberdiyev
- [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
- [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]
- [3093: Update phpstan/phpstan requirement from ^0.12.85 to ^0.12.90](https://github.com/slimphp/Slim/pull/3093) thanks to @dependabot[bot]
- [3099: Allow updated psr log](https://github.com/slimphp/Slim/pull/3099) thanks to @t0mmy742
- [3104: Drop php7.2](https://github.com/slimphp/Slim/pull/3104) thanks to @t0mmy742
- [3106: Use PSR-17 factory from Guzzle/psr7 2.0](https://github.com/slimphp/Slim/pull/3106) thanks to @t0mmy742
- [3108: Update README file](https://github.com/slimphp/Slim/pull/3108) thanks to @t0mmy742
- [3112: Update laminas/laminas-diactoros requirement from ^2.6 to ^2.8](https://github.com/slimphp/Slim/pull/3112) thanks to @dependabot[bot]
- [3114: Update slim/psr7 requirement from ^1.4 to ^1.5](https://github.com/slimphp/Slim/pull/3114) thanks to @dependabot[bot]
- [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
- [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
- [3045: Update phpstan/phpstan requirement from ^0.12.58 to ^0.12.64](https://github.com/slimphp/Slim/pull/3045) thanks to @dependabot-preview[bot]
- [3047: documentation: min php 7.2 required](https://github.com/slimphp/Slim/pull/3047) thanks to @Rotzbua
- [3054: Update phpstan/phpstan requirement from ^0.12.64 to ^0.12.70](https://github.com/slimphp/Slim/pull/3054) thanks to @dependabot-preview[bot]
- [3056: Fix docblock in ErrorMiddleware](https://github.com/slimphp/Slim/pull/3056) thanks to @piotr-cz
- [3060: Update phpstan/phpstan requirement from ^0.12.70 to ^0.12.80](https://github.com/slimphp/Slim/pull/3060) thanks to @dependabot-preview[bot]
- [3061: Update nyholm/psr7 requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3061) thanks to @dependabot-preview[bot]
- [3063: Allow ^1.0 || ^2.0 in psr/container](https://github.com/slimphp/Slim/pull/3063) thanks to @Ayesh
- [3069: Classname/Method Callable Arrays](https://github.com/slimphp/Slim/pull/3069) thanks to @ddrv
- [3078: Update squizlabs/php&#95;codesniffer requirement from ^3.5 to ^3.6](https://github.com/slimphp/Slim/pull/3078) thanks to @dependabot[bot]
- [3079: Update phpspec/prophecy requirement from ^1.12 to ^1.13](https://github.com/slimphp/Slim/pull/3079) thanks to @dependabot[bot]
- [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
### Fixed
- [3027: Fix: FastRoute dispatcher and data generator should match](https://github.com/slimphp/Slim/pull/3027) thanks to @edudobay
### Added
- [3015: PHP 8 support](https://github.com/slimphp/Slim/pull/3015) thanks to @edudobay
### Optimizations
- [3024: Randomize tests](https://github.com/slimphp/Slim/pull/3024) thanks to @pawel-slowik
## 4.6.0 - 2020-11-15
### Fixed
- [2942: Fix PHPdoc for error handlers in ErrorMiddleware ](https://github.com/slimphp/Slim/pull/2942) thanks to @TiMESPLiNTER
- [2944: Remove unused function in ErrorHandler](https://github.com/slimphp/Slim/pull/2944) thanks to @l0gicgate
- [2960: Fix phpstan 0.12 errors](https://github.com/slimphp/Slim/pull/2960) thanks to @adriansuter
- [2982: Removing cloning statements in tests](https://github.com/slimphp/Slim/pull/2982) thanks to @l0gicgate
- [3017: Fix request creator factory test](https://github.com/slimphp/Slim/pull/3017) thanks to @pawel-slowik
- [3022: Ensure RouteParser Always Present After Routing](https://github.com/slimphp/Slim/pull/3022) thanks to @l0gicgate
### Added
- [2949: Add the support in composer.json](https://github.com/slimphp/Slim/pull/2949) thanks to @ddrv
- [2958: Strict empty string content type checking in BodyParsingMiddleware::getMediaType](https://github.com/slimphp/Slim/pull/2958) thanks to @Ayesh
- [2997: Add hints to methods](https://github.com/slimphp/Slim/pull/2997) thanks to @evgsavosin - [3000: Fix route controller test](https://github.com/slimphp/Slim/pull/3000) thanks to @pawel-slowik
- [3001: Add missing `$strategy` parameter in a Route test](https://github.com/slimphp/Slim/pull/3001) thanks to @pawel-slowik
### Optimizations
- [2951: Minor optimizations in if() blocks](https://github.com/slimphp/Slim/pull/2951) thanks to @Ayesh
- [2959: Micro optimization: Declare closures in BodyParsingMiddleware as static](https://github.com/slimphp/Slim/pull/2959) thanks to @Ayesh
- [2978: Split the routing results to its own function.](https://github.com/slimphp/Slim/pull/2978) thanks to @dlundgren
### Dependencies Updated
- [2953: Update nyholm/psr7-server requirement from ^0.4.1](https://github.com/slimphp/Slim/pull/2953) thanks to @dependabot-preview[bot]
- [2954: Update laminas/laminas-diactoros requirement from ^2.1 to ^2.3](https://github.com/slimphp/Slim/pull/2954) thanks to @dependabot-preview[bot]
- [2955: Update guzzlehttp/psr7 requirement from ^1.5 to ^1.6](https://github.com/slimphp/Slim/pull/2955) thanks to @dependabot-preview[bot]
- [2956: Update slim/psr7 requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/2956) thanks to @dependabot-preview[bot]
- [2957: Update nyholm/psr7 requirement from ^1.1 to ^1.2](https://github.com/slimphp/Slim/pull/2957) thanks to @dependabot-preview[bot]
- [2963: Update phpstan/phpstan requirement from ^0.12.23 to ^0.12.25](https://github.com/slimphp/Slim/pull/2963) thanks to @dependabot-preview[bot]
- [2965: Update adriansuter/php-autoload-override requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/2965) thanks to @dependabot-preview[bot]
- [2967: Update nyholm/psr7 requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/2967) thanks to @dependabot-preview[bot]
- [2969: Update nyholm/psr7-server requirement from ^0.4.1 to ^1.0.0](https://github.com/slimphp/Slim/pull/2969) thanks to @dependabot-preview[bot]
- [2970: Update phpstan/phpstan requirement from ^0.12.25 to ^0.12.26](https://github.com/slimphp/Slim/pull/2970) thanks to @dependabot-preview[bot]
- [2971: Update phpstan/phpstan requirement from ^0.12.26 to ^0.12.27](https://github.com/slimphp/Slim/pull/2971) thanks to @dependabot-preview[bot]
- [2972: Update phpstan/phpstan requirement from ^0.12.27 to ^0.12.28](https://github.com/slimphp/Slim/pull/2972) thanks to @dependabot-preview[bot]
- [2973: Update phpstan/phpstan requirement from ^0.12.28 to ^0.12.29](https://github.com/slimphp/Slim/pull/2973) thanks to @dependabot-preview[bot]
- [2975: Update phpstan/phpstan requirement from ^0.12.29 to ^0.12.30](https://github.com/slimphp/Slim/pull/2975) thanks to @dependabot-preview[bot]
- [2976: Update phpstan/phpstan requirement from ^0.12.30 to ^0.12.31](https://github.com/slimphp/Slim/pull/2976) thanks to @dependabot-preview[bot]
- [2980: Update phpstan/phpstan requirement from ^0.12.31 to ^0.12.32](https://github.com/slimphp/Slim/pull/2980) thanks to @dependabot-preview[bot]
- [2981: Update phpspec/prophecy requirement from ^1.10 to ^1.11](https://github.com/slimphp/Slim/pull/2981) thanks to @dependabot-preview[bot]
- [2986: Update phpstan/phpstan requirement from ^0.12.32 to ^0.12.33](https://github.com/slimphp/Slim/pull/2986) thanks to @dependabot-preview[bot]
- [2990: Update phpstan/phpstan requirement from ^0.12.33 to ^0.12.34](https://github.com/slimphp/Slim/pull/2990) thanks to @dependabot-preview[bot]
- [2991: Update phpstan/phpstan requirement from ^0.12.34 to ^0.12.35](https://github.com/slimphp/Slim/pull/2991) thanks to @dependabot-preview[bot]
- [2993: Update phpstan/phpstan requirement from ^0.12.35 to ^0.12.36](https://github.com/slimphp/Slim/pull/2993) thanks to @dependabot-preview[bot]
- [2995: Update phpstan/phpstan requirement from ^0.12.36 to ^0.12.37](https://github.com/slimphp/Slim/pull/2995) thanks to @dependabot-preview[bot]
- [3010: Update guzzlehttp/psr7 requirement from ^1.6 to ^1.7](https://github.com/slimphp/Slim/pull/3010) thanks to @dependabot-preview[bot]
- [3011: Update phpspec/prophecy requirement from ^1.11 to ^1.12](https://github.com/slimphp/Slim/pull/3011) thanks to @dependabot-preview[bot]
- [3012: Update slim/http requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/3012) thanks to @dependabot-preview[bot]
- [3013: Update slim/psr7 requirement from ^1.1 to ^1.2](https://github.com/slimphp/Slim/pull/3013) thanks to @dependabot-preview[bot]
- [3014: Update laminas/laminas-diactoros requirement from ^2.3 to ^2.4](https://github.com/slimphp/Slim/pull/3014) thanks to @dependabot-preview[bot]
- [3018: Update phpstan/phpstan requirement from ^0.12.37 to ^0.12.54](https://github.com/slimphp/Slim/pull/3018) thanks to @dependabot-preview[bot]
## 4.5.0 - 2020-04-14
### Added
- [2928](https://github.com/slimphp/Slim/pull/2928) Test against PHP 7.4
- [2937](https://github.com/slimphp/Slim/pull/2937) Add support for PSR-3
### Fixed
- [2916](https://github.com/slimphp/Slim/pull/2916) Rename phpcs.xml to phpcs.xml.dist
- [2917](https://github.com/slimphp/Slim/pull/2917) Update .editorconfig
- [2925](https://github.com/slimphp/Slim/pull/2925) ResponseEmitter: Don't remove Content-Type and Content-Length when body is empt
- [2932](https://github.com/slimphp/Slim/pull/2932) Update the Tidelift enterprise language
- [2938](https://github.com/slimphp/Slim/pull/2938) Modify usage of deprecated expectExceptionMessageRegExp() method
## 4.4.0 - 2020-01-04
### Added
- [2862](https://github.com/slimphp/Slim/pull/2862) Optionally handle subclasses of exceptions in custom error handler
- [2869](https://github.com/slimphp/Slim/pull/2869) php-di/php-di added in composer suggestion
- [2874](https://github.com/slimphp/Slim/pull/2874) Add `null` to param type-hints
- [2889](https://github.com/slimphp/Slim/pull/2889) Make `RouteContext` attributes customizable and change default to use private names
- [2907](https://github.com/slimphp/Slim/pull/2907) Migrate to PSR-12 convention
- [2910](https://github.com/slimphp/Slim/pull/2910) Migrate Zend to Laminas
- [2912](https://github.com/slimphp/Slim/pull/2912) Add Laminas PSR17 Factory
- [2913](https://github.com/slimphp/Slim/pull/2913) Update php-autoload-override version
- [2914](https://github.com/slimphp/Slim/pull/2914) Added ability to add handled exceptions as an array
### Fixed
- [2864](https://github.com/slimphp/Slim/pull/2864) Optimize error message in error handling if displayErrorDetails was not set
- [2876](https://github.com/slimphp/Slim/pull/2876) Update links from http to https
- [2877](https://github.com/slimphp/Slim/pull/2877) Fix docblock for `Slim\Routing\RouteCollector::cacheFile`
- [2878](https://github.com/slimphp/Slim/pull/2878) check body is writable only on ouput buffering append
- [2896](https://github.com/slimphp/Slim/pull/2896) Render errors uniformly
- [2902](https://github.com/slimphp/Slim/pull/2902) Fix prophecies
- [2908](https://github.com/slimphp/Slim/pull/2908) Use autoload-dev for `Slim\Tests` namespace
### Removed
- [2871](https://github.com/slimphp/Slim/pull/2871) Remove explicit type-hint
- [2872](https://github.com/slimphp/Slim/pull/2872) Remove type-hint
## 4.3.0 - 2019-10-05
### Added
- [2819](https://github.com/slimphp/Slim/pull/2819) Added description to addRoutingMiddleware()
- [2820](https://github.com/slimphp/Slim/pull/2820) Update link to homepage in composer.json
- [2828](https://github.com/slimphp/Slim/pull/2828) Allow URIs with leading multi-slashes
- [2832](https://github.com/slimphp/Slim/pull/2832) Refactor `FastRouteDispatcher`
- [2835](https://github.com/slimphp/Slim/pull/2835) Rename `pathFor` to `urlFor` in docblock
- [2846](https://github.com/slimphp/Slim/pull/2846) Correcting the branch name as per issue-2843
- [2849](https://github.com/slimphp/Slim/pull/2849) Create class alias for FastRoute\RouteCollector
- [2855](https://github.com/slimphp/Slim/pull/2855) Add list of allowed methods to HttpMethodNotAllowedException
- [2860](https://github.com/slimphp/Slim/pull/2860) Add base path to `$request` and use `RouteContext` to read
### Fixed
- [2839](https://github.com/slimphp/Slim/pull/2839) Fix description for handler signature in phpdocs
- [2844](https://github.com/slimphp/Slim/pull/2844) Handle base path by routeCollector instead of RouteCollectorProxy
- [2845](https://github.com/slimphp/Slim/pull/2845) Fix composer scripts
- [2851](https://github.com/slimphp/Slim/pull/2851) Fix example of 'Hello World' app
- [2854](https://github.com/slimphp/Slim/pull/2854) Fix undefined property in tests
### Removed
- [2853](https://github.com/slimphp/Slim/pull/2853) Remove unused classes
## 4.2.0 - 2019-08-20
### Added
- [2787](https://github.com/slimphp/Slim/pull/2787) Add an advanced callable resolver
- [2791](https://github.com/slimphp/Slim/pull/2791) Add `inferPrivatePropertyTypeFromConstructor` to phpstan
- [2793](https://github.com/slimphp/Slim/pull/2793) Add ability to configure application via a container in `AppFactory`
- [2798](https://github.com/slimphp/Slim/pull/2798) Add PSR-7 Agnostic Body Parsing Middleware
- [2801](https://github.com/slimphp/Slim/pull/2801) Add `setLogErrorRenderer()` method to `ErrorHandler`
- [2807](https://github.com/slimphp/Slim/pull/2807) Add check for Slim callable notation if no resolver given
- [2803](https://github.com/slimphp/Slim/pull/2803) Add ability to emit non seekable streams in `ResponseEmitter`
- [2817](https://github.com/slimphp/Slim/pull/2817) Add the ability to pass in a custom `MiddlewareDispatcherInterface` to the `App`
### Fixed
- [2789](https://github.com/slimphp/Slim/pull/2789) Fix Cookie header detection in `ResponseEmitter`
- [2796](https://github.com/slimphp/Slim/pull/2796) Fix http message format
- [2800](https://github.com/slimphp/Slim/pull/2800) Fix null comparisons more clear in `ErrorHandler`
- [2802](https://github.com/slimphp/Slim/pull/2802) Fix incorrect search of a header in stack
- [2806](https://github.com/slimphp/Slim/pull/2806) Simplify `Route::prepare()` method argument preparation
- [2809](https://github.com/slimphp/Slim/pull/2809) Eliminate a duplicate code via HOF in `MiddlewareDispatcher`
- [2816](https://github.com/slimphp/Slim/pull/2816) Fix RouteCollectorProxy::redirect() bug
### Removed
- [2811](https://github.com/slimphp/Slim/pull/2811) Remove `DeferredCallable`
## 4.1.0 - 2019-08-06
### Added
- [#2779](https://github.com/slimphp/Slim/pull/2774) Add support for Slim callables `Class:method` resolution & Container Closure auto-binding in `MiddlewareDispatcher`
- [#2774](https://github.com/slimphp/Slim/pull/2774) Add possibility for custom `RequestHandler` invocation strategies
### Fixed
- [#2776](https://github.com/slimphp/Slim/pull/2774) Fix group middleware on multiple nested groups

19
vendor/slim/slim/LICENSE.md vendored Executable file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2011-2022 Josh Lockhart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

17
vendor/slim/slim/MAINTAINERS.md vendored Executable file
View File

@@ -0,0 +1,17 @@
# 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.

14
vendor/slim/slim/SECURITY.md vendored Executable file
View File

@@ -0,0 +1,14 @@
# Security Policy
### Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 3.x.x | :white_check_mark: |
| 4.x.x | :white_check_mark: |
### Reporting a Vulnerability
To report a vulnerability please send an email to security@slimframework.com

226
vendor/slim/slim/Slim/App.php vendored Executable file
View File

@@ -0,0 +1,226 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Log\LoggerInterface;
use Slim\Factory\ServerRequestCreatorFactory;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\MiddlewareDispatcherInterface;
use Slim\Interfaces\RouteCollectorInterface;
use Slim\Interfaces\RouteResolverInterface;
use Slim\Middleware\BodyParsingMiddleware;
use Slim\Middleware\ErrorMiddleware;
use Slim\Middleware\RoutingMiddleware;
use Slim\Routing\RouteCollectorProxy;
use Slim\Routing\RouteResolver;
use Slim\Routing\RouteRunner;
use function strtoupper;
/**
* @api
* @template TContainerInterface of (ContainerInterface|null)
* @template-extends RouteCollectorProxy<TContainerInterface>
*/
class App extends RouteCollectorProxy implements RequestHandlerInterface
{
/**
* Current version
*
* @var string
*/
public const VERSION = '4.15.0';
protected RouteResolverInterface $routeResolver;
protected MiddlewareDispatcherInterface $middlewareDispatcher;
/**
* @param TContainerInterface $container
*/
public function __construct(
ResponseFactoryInterface $responseFactory,
?ContainerInterface $container = null,
?CallableResolverInterface $callableResolver = null,
?RouteCollectorInterface $routeCollector = null,
?RouteResolverInterface $routeResolver = null,
?MiddlewareDispatcherInterface $middlewareDispatcher = null
) {
parent::__construct(
$responseFactory,
$callableResolver ?? new CallableResolver($container),
$container,
$routeCollector
);
$this->routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector);
$routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser(), $this);
if (!$middlewareDispatcher) {
$middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container);
} else {
$middlewareDispatcher->seedMiddlewareStack($routeRunner);
}
$this->middlewareDispatcher = $middlewareDispatcher;
}
/**
* @return RouteResolverInterface
*/
public function getRouteResolver(): RouteResolverInterface
{
return $this->routeResolver;
}
/**
* @return MiddlewareDispatcherInterface
*/
public function getMiddlewareDispatcher(): MiddlewareDispatcherInterface
{
return $this->middlewareDispatcher;
}
/**
* @param MiddlewareInterface|string|callable $middleware
* @return App<TContainerInterface>
*/
public function add($middleware): self
{
$this->middlewareDispatcher->add($middleware);
return $this;
}
/**
* @param MiddlewareInterface $middleware
* @return App<TContainerInterface>
*/
public function addMiddleware(MiddlewareInterface $middleware): self
{
$this->middlewareDispatcher->addMiddleware($middleware);
return $this;
}
/**
* Add the Slim built-in routing middleware to the app middleware stack
*
* This method can be used to control middleware order and is not required for default routing operation.
*
* @return RoutingMiddleware
*/
public function addRoutingMiddleware(): RoutingMiddleware
{
$routingMiddleware = new RoutingMiddleware(
$this->getRouteResolver(),
$this->getRouteCollector()->getRouteParser()
);
$this->add($routingMiddleware);
return $routingMiddleware;
}
/**
* Add the Slim built-in error middleware to the app middleware stack
*
* @param bool $displayErrorDetails
* @param bool $logErrors
* @param bool $logErrorDetails
* @param LoggerInterface|null $logger
*
* @return ErrorMiddleware
*/
public function addErrorMiddleware(
bool $displayErrorDetails,
bool $logErrors,
bool $logErrorDetails,
?LoggerInterface $logger = null
): ErrorMiddleware {
$errorMiddleware = new ErrorMiddleware(
$this->getCallableResolver(),
$this->getResponseFactory(),
$displayErrorDetails,
$logErrors,
$logErrorDetails,
$logger
);
$this->add($errorMiddleware);
return $errorMiddleware;
}
/**
* Add the Slim body parsing middleware to the app middleware stack
*
* @param callable[] $bodyParsers
*
* @return BodyParsingMiddleware
*/
public function addBodyParsingMiddleware(array $bodyParsers = []): BodyParsingMiddleware
{
$bodyParsingMiddleware = new BodyParsingMiddleware($bodyParsers);
$this->add($bodyParsingMiddleware);
return $bodyParsingMiddleware;
}
/**
* Run application
*
* This method traverses the application middleware stack and then sends the
* resultant Response object to the HTTP client.
*
* @param ServerRequestInterface|null $request
* @return void
*/
public function run(?ServerRequestInterface $request = null): void
{
if (!$request) {
$serverRequestCreator = ServerRequestCreatorFactory::create();
$request = $serverRequestCreator->createServerRequestFromGlobals();
}
$response = $this->handle($request);
$responseEmitter = new ResponseEmitter();
$responseEmitter->emit($response);
}
/**
* Handle a request
*
* This method traverses the application middleware stack and then returns the
* resultant Response object.
*
* @param ServerRequestInterface $request
* @return ResponseInterface
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
$response = $this->middlewareDispatcher->handle($request);
/**
* This is to be in compliance with RFC 2616, Section 9.
* If the incoming request method is HEAD, we need to ensure that the response body
* is empty as the request may fall back on a GET route handler due to FastRoute's
* routing logic which could potentially append content to the response body
* https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4
*/
$method = strtoupper($request->getMethod());
if ($method === 'HEAD') {
$emptyBody = $this->responseFactory->createResponse()->getBody();
return $response->withBody($emptyBody);
}
return $response;
}
}

200
vendor/slim/slim/Slim/CallableResolver.php vendored Executable file
View File

@@ -0,0 +1,200 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim;
use Closure;
use Psr\Container\ContainerInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use RuntimeException;
use Slim\Interfaces\AdvancedCallableResolverInterface;
use function class_exists;
use function is_array;
use function is_callable;
use function is_object;
use function is_string;
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;
}
/**
* {@inheritdoc}
*/
public function resolve($toResolve): callable
{
$toResolve = $this->prepareToResolve($toResolve);
if (is_callable($toResolve)) {
return $this->bindToContainer($toResolve);
}
$resolved = $toResolve;
if (is_string($toResolve)) {
$resolved = $this->resolveSlimNotation($toResolve);
$resolved[1] ??= '__invoke';
}
$callable = $this->assertCallable($resolved, $toResolve);
return $this->bindToContainer($callable);
}
/**
* {@inheritdoc}
*/
public function resolveRoute($toResolve): callable
{
return $this->resolveByPredicate($toResolve, [$this, 'isRoute'], 'handle');
}
/**
* {@inheritdoc}
*/
public function resolveMiddleware($toResolve): callable
{
return $this->resolveByPredicate($toResolve, [$this, 'isMiddleware'], 'process');
}
/**
* @param callable|array{class-string, string}|string $toResolve
*
* @throws RuntimeException
*/
private function resolveByPredicate($toResolve, callable $predicate, string $defaultMethod): callable
{
$toResolve = $this->prepareToResolve($toResolve);
if (is_callable($toResolve)) {
return $this->bindToContainer($toResolve);
}
$resolved = $toResolve;
if ($predicate($toResolve)) {
$resolved = [$toResolve, $defaultMethod];
}
if (is_string($toResolve)) {
[$instance, $method] = $this->resolveSlimNotation($toResolve);
if ($method === null && $predicate($instance)) {
$method = $defaultMethod;
}
$resolved = [$instance, $method ?? '__invoke'];
}
$callable = $this->assertCallable($resolved, $toResolve);
return $this->bindToContainer($callable);
}
/**
* @param mixed $toResolve
*/
private function isRoute($toResolve): bool
{
return $toResolve instanceof RequestHandlerInterface;
}
/**
* @param mixed $toResolve
*/
private function isMiddleware($toResolve): bool
{
return $toResolve instanceof MiddlewareInterface;
}
/**
* @throws RuntimeException
*
* @return array{object, string|null} [Instance, Method Name]
*/
private function resolveSlimNotation(string $toResolve): array
{
/** @psalm-suppress ArgumentTypeCoercion */
preg_match(CallableResolver::$callablePattern, $toResolve, $matches);
[$class, $method] = $matches ? [$matches[1], $matches[2]] : [$toResolve, null];
if ($this->container && $this->container->has($class)) {
$instance = $this->container->get($class);
if (!is_object($instance)) {
throw new RuntimeException(sprintf('%s container entry is not an object', $class));
}
} else {
if (!class_exists($class)) {
if ($method) {
$class .= '::' . $method . '()';
}
throw new RuntimeException(sprintf('Callable %s does not exist', $class));
}
$instance = new $class($this->container);
}
return [$instance, $method];
}
/**
* @param mixed $resolved
* @param mixed $toResolve
*
* @throws RuntimeException
*/
private function assertCallable($resolved, $toResolve): callable
{
if (!is_callable($resolved)) {
if (is_callable($toResolve) || is_object($toResolve) || is_array($toResolve)) {
$formatedToResolve = ($toResolveJson = json_encode($toResolve)) !== false ? $toResolveJson : '';
} else {
$formatedToResolve = is_string($toResolve) ? $toResolve : '';
}
throw new RuntimeException(sprintf('%s is not resolvable', $formatedToResolve));
}
return $resolved;
}
private function bindToContainer(callable $callable): callable
{
if (is_array($callable) && $callable[0] instanceof Closure) {
$callable = $callable[0];
}
if ($this->container && $callable instanceof Closure) {
/** @var Closure $callable */
$callable = $callable->bindTo($this->container);
}
return $callable;
}
/**
* @param callable|string|array{class-string, string}|mixed $toResolve
*
* @return callable|string|array{class-string, string}|mixed
*/
private function prepareToResolve($toResolve)
{
if (!is_array($toResolve)) {
return $toResolve;
}
$candidate = $toResolve;
$class = array_shift($candidate);
$method = array_shift($candidate);
if (is_string($class) && is_string($method)) {
return $class . ':' . $method;
}
return $toResolve;
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Error;
use Slim\Exception\HttpException;
use Slim\Interfaces\ErrorRendererInterface;
use Throwable;
/**
* Abstract Slim application error renderer
*
* It outputs the error message and diagnostic information in one of the following formats:
* JSON, XML, Plain Text or HTML
*/
abstract class AbstractErrorRenderer implements ErrorRendererInterface
{
protected string $defaultErrorTitle = 'Slim Application Error';
protected string $defaultErrorDescription = 'A website error has occurred. Sorry for the temporary inconvenience.';
protected function getErrorTitle(Throwable $exception): string
{
if ($exception instanceof HttpException) {
return $exception->getTitle();
}
return $this->defaultErrorTitle;
}
protected function getErrorDescription(Throwable $exception): string
{
if ($exception instanceof HttpException) {
return $exception->getDescription();
}
return $this->defaultErrorDescription;
}
}

View File

@@ -0,0 +1,83 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Error\Renderers;
use Slim\Error\AbstractErrorRenderer;
use Throwable;
use function get_class;
use function htmlentities;
use function sprintf;
/**
* Default Slim application HTML Error Renderer
*/
class HtmlErrorRenderer extends AbstractErrorRenderer
{
public function __invoke(Throwable $exception, bool $displayErrorDetails): string
{
if ($displayErrorDetails) {
$html = '<p>The application could not run because of the following error:</p>';
$html .= '<h2>Details</h2>';
$html .= $this->renderExceptionFragment($exception);
} else {
$html = "<p>{$this->getErrorDescription($exception)}</p>";
}
return $this->renderHtmlBody($this->getErrorTitle($exception), $html);
}
private function renderExceptionFragment(Throwable $exception): string
{
$html = sprintf('<div><strong>Type:</strong> %s</div>', get_class($exception));
$code = $exception->getCode();
$html .= sprintf('<div><strong>Code:</strong> %s</div>', $code);
$html .= sprintf('<div><strong>Message:</strong> %s</div>', htmlentities($exception->getMessage()));
$html .= sprintf('<div><strong>File:</strong> %s</div>', $exception->getFile());
$html .= sprintf('<div><strong>Line:</strong> %s</div>', $exception->getLine());
$html .= '<h2>Trace</h2>';
$html .= sprintf('<pre>%s</pre>', htmlentities($exception->getTraceAsString()));
return $html;
}
public function renderHtmlBody(string $title = '', string $html = ''): string
{
return sprintf(
'<!doctype html>' .
'<html lang="en">' .
' <head>' .
' <meta charset="utf-8">' .
' <meta name="viewport" content="width=device-width, initial-scale=1">' .
' <title>%s</title>' .
' <style>' .
' body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana,sans-serif}' .
' h1{margin:0;font-size:48px;font-weight:normal;line-height:48px}' .
' strong{display:inline-block;width:65px}' .
' </style>' .
' </head>' .
' <body>' .
' <h1>%s</h1>' .
' <div>%s</div>' .
' <a href="#" onclick="window.history.go(-1)">Go Back</a>' .
' </body>' .
'</html>',
$title,
$title,
$html
);
}
}

View File

@@ -0,0 +1,55 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Error\Renderers;
use Slim\Error\AbstractErrorRenderer;
use Throwable;
use function get_class;
use function json_encode;
use const JSON_PRETTY_PRINT;
use const JSON_UNESCAPED_SLASHES;
/**
* Default Slim application JSON Error Renderer
*/
class JsonErrorRenderer extends AbstractErrorRenderer
{
public function __invoke(Throwable $exception, bool $displayErrorDetails): string
{
$error = ['message' => $this->getErrorTitle($exception)];
if ($displayErrorDetails) {
$error['exception'] = [];
do {
$error['exception'][] = $this->formatExceptionFragment($exception);
} while ($exception = $exception->getPrevious());
}
return (string) json_encode($error, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
/**
* @return array<string|int>
*/
private function formatExceptionFragment(Throwable $exception): array
{
$code = $exception->getCode();
return [
'type' => get_class($exception),
'code' => $code,
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
];
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Error\Renderers;
use Slim\Error\AbstractErrorRenderer;
use Throwable;
use function get_class;
use function htmlentities;
use function sprintf;
/**
* Default Slim application Plain Text Error Renderer
*/
class PlainTextErrorRenderer extends AbstractErrorRenderer
{
public function __invoke(Throwable $exception, bool $displayErrorDetails): string
{
$text = "{$this->getErrorTitle($exception)}\n";
if ($displayErrorDetails) {
$text .= $this->formatExceptionFragment($exception);
while ($exception = $exception->getPrevious()) {
$text .= "\nPrevious Error:\n";
$text .= $this->formatExceptionFragment($exception);
}
}
return $text;
}
private function formatExceptionFragment(Throwable $exception): string
{
$text = sprintf("Type: %s\n", get_class($exception));
$code = $exception->getCode();
$text .= sprintf("Code: %s\n", $code);
$text .= sprintf("Message: %s\n", $exception->getMessage());
$text .= sprintf("File: %s\n", $exception->getFile());
$text .= sprintf("Line: %s\n", $exception->getLine());
$text .= sprintf('Trace: %s', $exception->getTraceAsString());
return $text;
}
}

View File

@@ -0,0 +1,54 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Error\Renderers;
use Slim\Error\AbstractErrorRenderer;
use Throwable;
use function get_class;
use function sprintf;
use function str_replace;
/**
* Default Slim application XML Error Renderer
*/
class XmlErrorRenderer extends AbstractErrorRenderer
{
public function __invoke(Throwable $exception, bool $displayErrorDetails): string
{
$xml = '<' . '?xml version="1.0" encoding="UTF-8" standalone="yes"?' . ">\n";
$xml .= "<error>\n <message>" . $this->createCdataSection($this->getErrorTitle($exception)) . "</message>\n";
if ($displayErrorDetails) {
do {
$xml .= " <exception>\n";
$xml .= ' <type>' . get_class($exception) . "</type>\n";
$xml .= ' <code>' . $exception->getCode() . "</code>\n";
$xml .= ' <message>' . $this->createCdataSection($exception->getMessage()) . "</message>\n";
$xml .= ' <file>' . $exception->getFile() . "</file>\n";
$xml .= ' <line>' . $exception->getLine() . "</line>\n";
$xml .= " </exception>\n";
} while ($exception = $exception->getPrevious());
}
$xml .= '</error>';
return $xml;
}
/**
* Returns a CDATA section with the given content.
*/
private function createCdataSection(string $content): string
{
return sprintf('<![CDATA[%s]]>', str_replace(']]>', ']]]]><![CDATA[>', $content));
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpBadRequestException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 400;
/**
* @var string
*/
protected $message = 'Bad request.';
protected string $title = '400 Bad Request';
protected string $description = 'The server cannot or will not process ' .
'the request due to an apparent client error.';
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Exception;
use Psr\Http\Message\ServerRequestInterface;
use RuntimeException;
use Throwable;
/**
* @api
* @method int getCode()
*/
class HttpException extends RuntimeException
{
protected ServerRequestInterface $request;
protected string $title = '';
protected string $description = '';
public function __construct(
ServerRequestInterface $request,
string $message = '',
int $code = 0,
?Throwable $previous = null
) {
parent::__construct($message, $code, $previous);
$this->request = $request;
}
public function getRequest(): ServerRequestInterface
{
return $this->request;
}
public function getTitle(): string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getDescription(): string
{
return $this->description;
}
public function setDescription(string $description): self
{
$this->description = $description;
return $this;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpForbiddenException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 403;
/**
* @var string
*/
protected $message = 'Forbidden.';
protected string $title = '403 Forbidden';
protected string $description = 'You are not permitted to perform the requested operation.';
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpGoneException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 410;
/**
* @var string
*/
protected $message = 'Gone.';
protected string $title = '410 Gone';
protected string $description = 'The target resource is no longer available at the origin server.';
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpInternalServerErrorException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 500;
/**
* @var string
*/
protected $message = 'Internal server error.';
protected string $title = '500 Internal Server Error';
protected string $description = 'Unexpected condition encountered preventing server from fulfilling request.';
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Exception;
use function implode;
class HttpMethodNotAllowedException extends HttpSpecializedException
{
/**
* @var string[]
*/
protected array $allowedMethods = [];
/**
* @var int
*/
protected $code = 405;
/**
* @var string
*/
protected $message = 'Method not allowed.';
protected string $title = '405 Method Not Allowed';
protected string $description = 'The request method is not supported for the requested resource.';
/**
* @return string[]
*/
public function getAllowedMethods(): array
{
return $this->allowedMethods;
}
/**
* @param string[] $methods
*/
public function setAllowedMethods(array $methods): self
{
$this->allowedMethods = $methods;
$this->message = 'Method not allowed. Must be one of: ' . implode(', ', $methods);
return $this;
}
}

View File

@@ -0,0 +1,27 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Exception;
class HttpNotFoundException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 404;
/**
* @var string
*/
protected $message = 'Not found.';
protected string $title = '404 Not Found';
protected string $description = 'The requested resource could not be found. Please verify the URI and try again.';
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpNotImplementedException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 501;
/**
* @var string
*/
protected $message = 'Not implemented.';
protected string $title = '501 Not Implemented';
protected string $description = 'The server does not support the functionality required to fulfill the request.';
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Exception;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;
abstract class HttpSpecializedException extends HttpException
{
/**
* @param ServerRequestInterface $request
* @param string|null $message
* @param Throwable|null $previous
*/
public function __construct(ServerRequestInterface $request, ?string $message = null, ?Throwable $previous = null)
{
if ($message !== null) {
$this->message = $message;
}
// @phpstan-ignore-next-line
parent::__construct($request, $this->message, $this->code, $previous);
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpTooManyRequestsException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 429;
/**
* @var string
*/
protected $message = 'Too many requests.';
protected string $title = '429 Too Many Requests';
protected string $description = 'The client application has surpassed its rate limit, ' .
'or number of requests they can send in a given period of time.';
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Exception;
/** @api */
class HttpUnauthorizedException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 401;
/**
* @var string
*/
protected $message = 'Unauthorized.';
protected string $title = '401 Unauthorized';
protected string $description = 'The request requires valid user authentication.';
}

217
vendor/slim/slim/Slim/Factory/AppFactory.php vendored Executable file
View File

@@ -0,0 +1,217 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Factory;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use RuntimeException;
use Slim\App;
use Slim\Factory\Psr17\Psr17Factory;
use Slim\Factory\Psr17\Psr17FactoryProvider;
use Slim\Factory\Psr17\SlimHttpPsr17Factory;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\MiddlewareDispatcherInterface;
use Slim\Interfaces\Psr17FactoryProviderInterface;
use Slim\Interfaces\RouteCollectorInterface;
use Slim\Interfaces\RouteResolverInterface;
/** @api */
class AppFactory
{
protected static ?Psr17FactoryProviderInterface $psr17FactoryProvider = null;
protected static ?ResponseFactoryInterface $responseFactory = null;
protected static ?StreamFactoryInterface $streamFactory = null;
protected static ?ContainerInterface $container = null;
protected static ?CallableResolverInterface $callableResolver = null;
protected static ?RouteCollectorInterface $routeCollector = null;
protected static ?RouteResolverInterface $routeResolver = null;
protected static ?MiddlewareDispatcherInterface $middlewareDispatcher = null;
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,
?CallableResolverInterface $callableResolver = null,
?RouteCollectorInterface $routeCollector = null,
?RouteResolverInterface $routeResolver = null,
?MiddlewareDispatcherInterface $middlewareDispatcher = null
): App {
static::$responseFactory = $responseFactory ?? static::$responseFactory;
return new App(
self::determineResponseFactory(),
$container ?? static::$container,
$callableResolver ?? static::$callableResolver,
$routeCollector ?? static::$routeCollector,
$routeResolver ?? static::$routeResolver,
$middlewareDispatcher ?? static::$middlewareDispatcher
);
}
/**
* @template TContainerInterface of (ContainerInterface)
* @param TContainerInterface $container
* @return App<TContainerInterface>
*/
public static function createFromContainer(ContainerInterface $container): App
{
$responseFactory = $container->has(ResponseFactoryInterface::class)
&& (
$responseFactoryFromContainer = $container->get(ResponseFactoryInterface::class)
) instanceof ResponseFactoryInterface
? $responseFactoryFromContainer
: self::determineResponseFactory();
$callableResolver = $container->has(CallableResolverInterface::class)
&& (
$callableResolverFromContainer = $container->get(CallableResolverInterface::class)
) instanceof CallableResolverInterface
? $callableResolverFromContainer
: null;
$routeCollector = $container->has(RouteCollectorInterface::class)
&& (
$routeCollectorFromContainer = $container->get(RouteCollectorInterface::class)
) instanceof RouteCollectorInterface
? $routeCollectorFromContainer
: null;
$routeResolver = $container->has(RouteResolverInterface::class)
&& (
$routeResolverFromContainer = $container->get(RouteResolverInterface::class)
) instanceof RouteResolverInterface
? $routeResolverFromContainer
: null;
$middlewareDispatcher = $container->has(MiddlewareDispatcherInterface::class)
&& (
$middlewareDispatcherFromContainer = $container->get(MiddlewareDispatcherInterface::class)
) instanceof MiddlewareDispatcherInterface
? $middlewareDispatcherFromContainer
: null;
return new App(
$responseFactory,
$container,
$callableResolver,
$routeCollector,
$routeResolver,
$middlewareDispatcher
);
}
/**
* @throws RuntimeException
*/
public static function determineResponseFactory(): ResponseFactoryInterface
{
if (static::$responseFactory) {
if (static::$streamFactory) {
return static::attemptResponseFactoryDecoration(static::$responseFactory, static::$streamFactory);
}
return static::$responseFactory;
}
$psr17FactoryProvider = static::$psr17FactoryProvider ?? new Psr17FactoryProvider();
/** @var Psr17Factory $psr17factory */
foreach ($psr17FactoryProvider->getFactories() as $psr17factory) {
if ($psr17factory::isResponseFactoryAvailable()) {
$responseFactory = $psr17factory::getResponseFactory();
if (static::$streamFactory || $psr17factory::isStreamFactoryAvailable()) {
$streamFactory = static::$streamFactory ?? $psr17factory::getStreamFactory();
return static::attemptResponseFactoryDecoration($responseFactory, $streamFactory);
}
return $responseFactory;
}
}
throw new RuntimeException(
"Could not detect any PSR-17 ResponseFactory implementations. " .
"Please install a supported implementation in order to use `AppFactory::create()`. " .
"See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations."
);
}
protected static function attemptResponseFactoryDecoration(
ResponseFactoryInterface $responseFactory,
StreamFactoryInterface $streamFactory
): ResponseFactoryInterface {
if (
static::$slimHttpDecoratorsAutomaticDetectionEnabled
&& SlimHttpPsr17Factory::isResponseFactoryAvailable()
) {
return SlimHttpPsr17Factory::createDecoratedResponseFactory($responseFactory, $streamFactory);
}
return $responseFactory;
}
public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider): void
{
static::$psr17FactoryProvider = $psr17FactoryProvider;
}
public static function setResponseFactory(ResponseFactoryInterface $responseFactory): void
{
static::$responseFactory = $responseFactory;
}
public static function setStreamFactory(StreamFactoryInterface $streamFactory): void
{
static::$streamFactory = $streamFactory;
}
public static function setContainer(ContainerInterface $container): void
{
static::$container = $container;
}
public static function setCallableResolver(CallableResolverInterface $callableResolver): void
{
static::$callableResolver = $callableResolver;
}
public static function setRouteCollector(RouteCollectorInterface $routeCollector): void
{
static::$routeCollector = $routeCollector;
}
public static function setRouteResolver(RouteResolverInterface $routeResolver): void
{
static::$routeResolver = $routeResolver;
}
public static function setMiddlewareDispatcher(MiddlewareDispatcherInterface $middlewareDispatcher): void
{
static::$middlewareDispatcher = $middlewareDispatcher;
}
public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled): void
{
static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled;
}
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Factory\Psr17;
class GuzzlePsr17Factory extends Psr17Factory
{
protected static string $responseFactoryClass = 'GuzzleHttp\Psr7\HttpFactory';
protected static string $streamFactoryClass = 'GuzzleHttp\Psr7\HttpFactory';
protected static string $serverRequestCreatorClass = 'GuzzleHttp\Psr7\ServerRequest';
protected static string $serverRequestCreatorMethod = 'fromGlobals';
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Factory\Psr17;
class HttpSoftPsr17Factory extends Psr17Factory
{
protected static string $responseFactoryClass = 'HttpSoft\Message\ResponseFactory';
protected static string $streamFactoryClass = 'HttpSoft\Message\StreamFactory';
protected static string $serverRequestCreatorClass = 'HttpSoft\ServerRequest\ServerRequestCreator';
protected static string $serverRequestCreatorMethod = 'createFromGlobals';
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Factory\Psr17;
class LaminasDiactorosPsr17Factory extends Psr17Factory
{
protected static string $responseFactoryClass = 'Laminas\Diactoros\ResponseFactory';
protected static string $streamFactoryClass = 'Laminas\Diactoros\StreamFactory';
protected static string $serverRequestCreatorClass = 'Laminas\Diactoros\ServerRequestFactory';
protected static string $serverRequestCreatorMethod = 'fromGlobals';
}

View File

@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Slim\Factory\Psr17;
use Slim\Interfaces\ServerRequestCreatorInterface;
class NyholmPsr17Factory extends Psr17Factory
{
protected static string $responseFactoryClass = 'Nyholm\Psr7\Factory\Psr17Factory';
protected static string $streamFactoryClass = 'Nyholm\Psr7\Factory\Psr17Factory';
protected static string $serverRequestCreatorClass = 'Nyholm\Psr7Server\ServerRequestCreator';
protected static string $serverRequestCreatorMethod = 'fromGlobals';
/**
* {@inheritdoc}
*/
public static function getServerRequestCreator(): ServerRequestCreatorInterface
{
/*
* Nyholm Psr17Factory implements all factories in one unified
* factory which implements all of the PSR-17 factory interfaces
*/
$psr17Factory = new static::$responseFactoryClass();
$serverRequestCreator = new static::$serverRequestCreatorClass(
$psr17Factory,
$psr17Factory,
$psr17Factory,
$psr17Factory
);
return new ServerRequestCreator($serverRequestCreator, static::$serverRequestCreatorMethod);
}
}

View File

@@ -0,0 +1,101 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Factory\Psr17;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use RuntimeException;
use Slim\Interfaces\Psr17FactoryInterface;
use Slim\Interfaces\ServerRequestCreatorInterface;
use function class_exists;
use function get_called_class;
abstract class Psr17Factory implements Psr17FactoryInterface
{
protected static string $responseFactoryClass;
protected static string $streamFactoryClass;
protected static string $serverRequestCreatorClass;
protected static string $serverRequestCreatorMethod;
/**
* {@inheritdoc}
*/
public static function getResponseFactory(): ResponseFactoryInterface
{
if (
!static::isResponseFactoryAvailable()
|| !(($responseFactory = new static::$responseFactoryClass()) instanceof ResponseFactoryInterface)
) {
throw new RuntimeException(get_called_class() . ' could not instantiate a response factory.');
}
return $responseFactory;
}
/**
* {@inheritdoc}
*/
public static function getStreamFactory(): StreamFactoryInterface
{
if (
!static::isStreamFactoryAvailable()
|| !(($streamFactory = new static::$streamFactoryClass()) instanceof StreamFactoryInterface)
) {
throw new RuntimeException(get_called_class() . ' could not instantiate a stream factory.');
}
return $streamFactory;
}
/**
* {@inheritdoc}
*/
public static function getServerRequestCreator(): ServerRequestCreatorInterface
{
if (!static::isServerRequestCreatorAvailable()) {
throw new RuntimeException(get_called_class() . ' could not instantiate a server request creator.');
}
return new ServerRequestCreator(static::$serverRequestCreatorClass, static::$serverRequestCreatorMethod);
}
/**
* {@inheritdoc}
*/
public static function isResponseFactoryAvailable(): bool
{
return static::$responseFactoryClass && class_exists(static::$responseFactoryClass);
}
/**
* {@inheritdoc}
*/
public static function isStreamFactoryAvailable(): bool
{
return static::$streamFactoryClass && class_exists(static::$streamFactoryClass);
}
/**
* {@inheritdoc}
*/
public static function isServerRequestCreatorAvailable(): bool
{
return (
static::$serverRequestCreatorClass
&& static::$serverRequestCreatorMethod
&& class_exists(static::$serverRequestCreatorClass)
);
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Factory\Psr17;
use Slim\Interfaces\Psr17FactoryProviderInterface;
use function array_unshift;
class Psr17FactoryProvider implements Psr17FactoryProviderInterface
{
/**
* @var string[]
*/
protected static array $factories = [
SlimPsr17Factory::class,
HttpSoftPsr17Factory::class,
NyholmPsr17Factory::class,
LaminasDiactorosPsr17Factory::class,
GuzzlePsr17Factory::class,
];
/**
* {@inheritdoc}
*/
public static function getFactories(): array
{
return static::$factories;
}
/**
* {@inheritdoc}
*/
public static function setFactories(array $factories): void
{
static::$factories = $factories;
}
/**
* {@inheritdoc}
*/
public static function addFactory(string $factory): void
{
array_unshift(static::$factories, $factory);
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Factory\Psr17;
use Closure;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Interfaces\ServerRequestCreatorInterface;
class ServerRequestCreator implements ServerRequestCreatorInterface
{
/**
* @var object|string
*/
protected $serverRequestCreator;
protected string $serverRequestCreatorMethod;
/**
* @param object|string $serverRequestCreator
*/
public function __construct($serverRequestCreator, string $serverRequestCreatorMethod)
{
$this->serverRequestCreator = $serverRequestCreator;
$this->serverRequestCreatorMethod = $serverRequestCreatorMethod;
}
/**
* {@inheritdoc}
*/
public function createServerRequestFromGlobals(): ServerRequestInterface
{
/** @var callable $callable */
$callable = [$this->serverRequestCreator, $this->serverRequestCreatorMethod];
/** @var ServerRequestInterface */
return (Closure::fromCallable($callable))();
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Factory\Psr17;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use RuntimeException;
class SlimHttpPsr17Factory extends Psr17Factory
{
protected static string $responseFactoryClass = 'Slim\Http\Factory\DecoratedResponseFactory';
/**
* @throws RuntimeException when the factory could not be instantiated
*/
public static function createDecoratedResponseFactory(
ResponseFactoryInterface $responseFactory,
StreamFactoryInterface $streamFactory
): ResponseFactoryInterface {
if (
!((
$decoratedResponseFactory = new static::$responseFactoryClass($responseFactory, $streamFactory)
) instanceof ResponseFactoryInterface
)
) {
throw new RuntimeException(get_called_class() . ' could not instantiate a decorated response factory.');
}
return $decoratedResponseFactory;
}
}

View File

@@ -0,0 +1,56 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Factory\Psr17;
use Psr\Http\Message\ServerRequestInterface;
use RuntimeException;
use Slim\Interfaces\ServerRequestCreatorInterface;
use function class_exists;
class SlimHttpServerRequestCreator implements ServerRequestCreatorInterface
{
protected ServerRequestCreatorInterface $serverRequestCreator;
protected static string $serverRequestDecoratorClass = 'Slim\Http\ServerRequest';
public function __construct(ServerRequestCreatorInterface $serverRequestCreator)
{
$this->serverRequestCreator = $serverRequestCreator;
}
/**
* {@inheritdoc}
*/
public function createServerRequestFromGlobals(): ServerRequestInterface
{
if (!static::isServerRequestDecoratorAvailable()) {
throw new RuntimeException('The Slim-Http ServerRequest decorator is not available.');
}
$request = $this->serverRequestCreator->createServerRequestFromGlobals();
if (
!((
$decoratedServerRequest = new static::$serverRequestDecoratorClass($request)
) instanceof ServerRequestInterface)
) {
throw new RuntimeException(get_called_class() . ' could not instantiate a decorated server request.');
}
return $decoratedServerRequest;
}
public static function isServerRequestDecoratorAvailable(): bool
{
return class_exists(static::$serverRequestDecoratorClass);
}
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Factory\Psr17;
class SlimPsr17Factory extends Psr17Factory
{
protected static string $responseFactoryClass = 'Slim\Psr7\Factory\ResponseFactory';
protected static string $streamFactoryClass = 'Slim\Psr7\Factory\StreamFactory';
protected static string $serverRequestCreatorClass = 'Slim\Psr7\Factory\ServerRequestFactory';
protected static string $serverRequestCreatorMethod = 'createFromGlobals';
}

View File

@@ -0,0 +1,88 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Factory;
use RuntimeException;
use Slim\Factory\Psr17\Psr17Factory;
use Slim\Factory\Psr17\Psr17FactoryProvider;
use Slim\Factory\Psr17\SlimHttpServerRequestCreator;
use Slim\Interfaces\Psr17FactoryProviderInterface;
use Slim\Interfaces\ServerRequestCreatorInterface;
/** @api */
class ServerRequestCreatorFactory
{
protected static ?Psr17FactoryProviderInterface $psr17FactoryProvider = null;
protected static ?ServerRequestCreatorInterface $serverRequestCreator = null;
protected static bool $slimHttpDecoratorsAutomaticDetectionEnabled = true;
public static function create(): ServerRequestCreatorInterface
{
return static::determineServerRequestCreator();
}
/**
* @throws RuntimeException
*/
public static function determineServerRequestCreator(): ServerRequestCreatorInterface
{
if (static::$serverRequestCreator) {
return static::attemptServerRequestCreatorDecoration(static::$serverRequestCreator);
}
$psr17FactoryProvider = static::$psr17FactoryProvider ?? new Psr17FactoryProvider();
/** @var Psr17Factory $psr17Factory */
foreach ($psr17FactoryProvider->getFactories() as $psr17Factory) {
if ($psr17Factory::isServerRequestCreatorAvailable()) {
$serverRequestCreator = $psr17Factory::getServerRequestCreator();
return static::attemptServerRequestCreatorDecoration($serverRequestCreator);
}
}
throw new RuntimeException(
"Could not detect any ServerRequest creator implementations. " .
"Please install a supported implementation in order to use `App::run()` " .
"without having to pass in a `ServerRequest` object. " .
"See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations."
);
}
protected static function attemptServerRequestCreatorDecoration(
ServerRequestCreatorInterface $serverRequestCreator
): ServerRequestCreatorInterface {
if (
static::$slimHttpDecoratorsAutomaticDetectionEnabled
&& SlimHttpServerRequestCreator::isServerRequestDecoratorAvailable()
) {
return new SlimHttpServerRequestCreator($serverRequestCreator);
}
return $serverRequestCreator;
}
public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider): void
{
static::$psr17FactoryProvider = $psr17FactoryProvider;
}
public static function setServerRequestCreator(ServerRequestCreatorInterface $serverRequestCreator): void
{
self::$serverRequestCreator = $serverRequestCreator;
}
public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled): void
{
static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled;
}
}

View File

@@ -0,0 +1,314 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Handlers;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Slim\Error\Renderers\HtmlErrorRenderer;
use Slim\Error\Renderers\JsonErrorRenderer;
use Slim\Error\Renderers\PlainTextErrorRenderer;
use Slim\Error\Renderers\XmlErrorRenderer;
use Slim\Exception\HttpException;
use Slim\Exception\HttpMethodNotAllowedException;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\ErrorHandlerInterface;
use Slim\Interfaces\ErrorRendererInterface;
use Slim\Logger;
use Throwable;
use function array_intersect;
use function array_key_exists;
use function array_keys;
use function call_user_func;
use function count;
use function current;
use function explode;
use function implode;
use function next;
use function preg_match;
/**
* Default Slim application error handler
*
* 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
{
protected string $defaultErrorRendererContentType = 'text/html';
/**
* @var ErrorRendererInterface|string|callable
*/
protected $defaultErrorRenderer = HtmlErrorRenderer::class;
/**
* @var ErrorRendererInterface|string|callable
*/
protected $logErrorRenderer = PlainTextErrorRenderer::class;
/**
* @var array<string|callable>
*/
protected array $errorRenderers = [
'application/json' => JsonErrorRenderer::class,
'application/xml' => XmlErrorRenderer::class,
'text/xml' => XmlErrorRenderer::class,
'text/html' => HtmlErrorRenderer::class,
'text/plain' => PlainTextErrorRenderer::class,
];
protected bool $displayErrorDetails = false;
protected bool $logErrors;
protected bool $logErrorDetails = false;
protected ?string $contentType = null;
protected ?string $method = null;
protected ServerRequestInterface $request;
protected Throwable $exception;
protected int $statusCode;
protected CallableResolverInterface $callableResolver;
protected ResponseFactoryInterface $responseFactory;
protected LoggerInterface $logger;
public function __construct(
CallableResolverInterface $callableResolver,
ResponseFactoryInterface $responseFactory,
?LoggerInterface $logger = null
) {
$this->callableResolver = $callableResolver;
$this->responseFactory = $responseFactory;
$this->logger = $logger ?: $this->getDefaultLogger();
}
/**
* Invoke error handler
*
* @param ServerRequestInterface $request The most recent Request object
* @param Throwable $exception The caught Exception object
* @param bool $displayErrorDetails Whether or not to display the error details
* @param bool $logErrors Whether or not to log errors
* @param bool $logErrorDetails Whether or not to log error details
*/
public function __invoke(
ServerRequestInterface $request,
Throwable $exception,
bool $displayErrorDetails,
bool $logErrors,
bool $logErrorDetails
): ResponseInterface {
$this->displayErrorDetails = $displayErrorDetails;
$this->logErrors = $logErrors;
$this->logErrorDetails = $logErrorDetails;
$this->request = $request;
$this->exception = $exception;
$this->method = $request->getMethod();
$this->statusCode = $this->determineStatusCode();
if ($this->contentType === null) {
$this->contentType = $this->determineContentType($request);
}
if ($logErrors) {
$this->writeToErrorLog();
}
return $this->respond();
}
/**
* Force the content type for all error handler responses.
*
* @param string|null $contentType The content type
*/
public function forceContentType(?string $contentType): void
{
$this->contentType = $contentType;
}
protected function determineStatusCode(): int
{
if ($this->method === 'OPTIONS') {
return 200;
}
if ($this->exception instanceof HttpException) {
return $this->exception->getCode();
}
return 500;
}
/**
* Determine which content type we know about is wanted using Accept header
*
* Note: This method is a bare-bones implementation designed specifically for
* Slim's error handling requirements. Consider a fully-feature solution such
* as willdurand/negotiation for any other situation.
*/
protected function determineContentType(ServerRequestInterface $request): ?string
{
$acceptHeader = $request->getHeaderLine('Accept');
$selectedContentTypes = array_intersect(
explode(',', $acceptHeader),
array_keys($this->errorRenderers)
);
$count = count($selectedContentTypes);
if ($count) {
$current = current($selectedContentTypes);
/**
* Ensure other supported content types take precedence over text/plain
* when multiple content types are provided via Accept header.
*/
if ($current === 'text/plain' && $count > 1) {
$next = next($selectedContentTypes);
if (is_string($next)) {
return $next;
}
}
// @phpstan-ignore-next-line
if (is_string($current)) {
return $current;
}
}
if (preg_match('/\+(json|xml)/', $acceptHeader, $matches)) {
$mediaType = 'application/' . $matches[1];
if (array_key_exists($mediaType, $this->errorRenderers)) {
return $mediaType;
}
}
return null;
}
/**
* Determine which renderer to use based on content type
*
* @throws RuntimeException
*/
protected function determineRenderer(): callable
{
if ($this->contentType !== null && array_key_exists($this->contentType, $this->errorRenderers)) {
$renderer = $this->errorRenderers[$this->contentType];
} else {
$renderer = $this->defaultErrorRenderer;
}
return $this->callableResolver->resolve($renderer);
}
/**
* Register an error renderer for a specific content-type
*
* @param string $contentType The content-type this renderer should be registered to
* @param ErrorRendererInterface|string|callable $errorRenderer The error renderer
*/
public function registerErrorRenderer(string $contentType, $errorRenderer): void
{
$this->errorRenderers[$contentType] = $errorRenderer;
}
/**
* Set the default error renderer
*
* @param string $contentType The content type of the default error renderer
* @param ErrorRendererInterface|string|callable $errorRenderer The default error renderer
*/
public function setDefaultErrorRenderer(string $contentType, $errorRenderer): void
{
$this->defaultErrorRendererContentType = $contentType;
$this->defaultErrorRenderer = $errorRenderer;
}
/**
* Set the renderer for the error logger
*
* @param ErrorRendererInterface|string|callable $logErrorRenderer
*/
public function setLogErrorRenderer($logErrorRenderer): void
{
$this->logErrorRenderer = $logErrorRenderer;
}
/**
* Write to the error log if $logErrors has been set to true
*/
protected function writeToErrorLog(): void
{
$renderer = $this->callableResolver->resolve($this->logErrorRenderer);
/** @var string $error */
$error = $renderer($this->exception, $this->logErrorDetails);
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);
}
/**
* Wraps the error_log function so that this can be easily tested
*/
protected function logError(string $error): void
{
$this->logger->error($error);
}
/**
* Returns a default logger implementation.
*/
protected function getDefaultLogger(): LoggerInterface
{
return new Logger();
}
protected function respond(): ResponseInterface
{
$response = $this->responseFactory->createResponse($this->statusCode);
if ($this->contentType !== null && array_key_exists($this->contentType, $this->errorRenderers)) {
$response = $response->withHeader('Content-type', $this->contentType);
} else {
$response = $response->withHeader('Content-type', $this->defaultErrorRendererContentType);
}
if ($this->exception instanceof HttpMethodNotAllowedException) {
$allowedMethods = implode(', ', $this->exception->getAllowedMethods());
$response = $response->withHeader('Allow', $allowedMethods);
}
$renderer = $this->determineRenderer();
$body = call_user_func($renderer, $this->exception, $this->displayErrorDetails);
if ($body !== false) {
/** @var string $body */
$response->getBody()->write($body);
}
return $response;
}
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Handlers\Strategies;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Interfaces\RequestHandlerInvocationStrategyInterface;
/**
* PSR-15 RequestHandler invocation strategy
*/
class RequestHandler implements RequestHandlerInvocationStrategyInterface
{
protected bool $appendRouteArgumentsToRequestAttributes;
public function __construct(bool $appendRouteArgumentsToRequestAttributes = false)
{
$this->appendRouteArgumentsToRequestAttributes = $appendRouteArgumentsToRequestAttributes;
}
/**
* Invoke a route callable that implements RequestHandlerInterface
*
* @param array<string, string> $routeArguments
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
if ($this->appendRouteArgumentsToRequestAttributes) {
foreach ($routeArguments as $k => $v) {
$request = $request->withAttribute($k, $v);
}
}
/** @var ResponseInterface */
return $callable($request);
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Handlers\Strategies;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Interfaces\InvocationStrategyInterface;
/**
* Default route callback strategy with route parameters as an array of arguments.
*/
class RequestResponse implements InvocationStrategyInterface
{
/**
* Invoke a route callable with request, response, and all route parameters
* as an array of arguments.
*
* @param array<string, string> $routeArguments
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
foreach ($routeArguments as $k => $v) {
$request = $request->withAttribute($k, $v);
}
/** @var ResponseInterface */
return $callable($request, $response, $routeArguments);
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Handlers\Strategies;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Interfaces\InvocationStrategyInterface;
use function array_values;
/**
* Route callback strategy with route parameters as individual arguments.
* @api
*/
class RequestResponseArgs implements InvocationStrategyInterface
{
/**
* Invoke a route callable with request, response and all route parameters
* as individual arguments.
*
* @param array<string, string> $routeArguments
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
/** @var ResponseInterface */
return $callable($request, $response, ...array_values($routeArguments));
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Handlers\Strategies;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Interfaces\InvocationStrategyInterface;
use RuntimeException;
/**
* Route callback strategy with route parameters as individual arguments.
* @api
*/
class RequestResponseNamedArgs implements InvocationStrategyInterface
{
/**
* Invoke a route callable with request, response and all route parameters
* as individual arguments.
*
* @param array<string, string> $routeArguments
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
/** @var ResponseInterface */
return $callable($request, $response, ...$routeArguments);
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
interface AdvancedCallableResolverInterface extends CallableResolverInterface
{
/**
* Resolve $toResolve into a callable
*
* @param callable|array{class-string, string}|string $toResolve
*/
public function resolveRoute($toResolve): callable;
/**
* Resolve $toResolve into a callable
*
* @param callable|array{class-string, string}|string $toResolve
*/
public function resolveMiddleware($toResolve): callable;
}

View File

@@ -0,0 +1,21 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
interface CallableResolverInterface
{
/**
* Resolve $toResolve into a callable
*
* @param callable|array{class-string, string}|string $toResolve
*/
public function resolve($toResolve): callable;
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
use Slim\Routing\RoutingResults;
interface DispatcherInterface
{
/**
* Get routing results for a given request method and uri
*/
public function dispatch(string $method, string $uri): RoutingResults;
/**
* Get allowed methods for a given uri
*
* @return string[]
*/
public function getAllowedMethods(string $uri): array;
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;
interface ErrorHandlerInterface
{
public function __invoke(
ServerRequestInterface $request,
Throwable $exception,
bool $displayErrorDetails,
bool $logErrors,
bool $logErrorDetails
): ResponseInterface;
}

View File

@@ -0,0 +1,18 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
use Throwable;
interface ErrorRendererInterface
{
public function __invoke(Throwable $exception, bool $displayErrorDetails): string;
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
/**
* Defines a contract for invoking a route callable.
*/
interface InvocationStrategyInterface
{
/**
* Invoke a route callable.
*
* @param callable $callable The callable to invoke using the strategy.
* @param ServerRequestInterface $request The request object.
* @param ResponseInterface $response The response object.
* @param array<string, string> $routeArguments The route's placeholder arguments
*
* @return ResponseInterface The response from the callable.
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface;
}

View File

@@ -0,0 +1,43 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
/** @api */
interface MiddlewareDispatcherInterface extends RequestHandlerInterface
{
/**
* Add a new middleware to the stack
*
* 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).
*
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware): self;
/**
* Add a new middleware to the stack
*
* 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).
*/
public function addMiddleware(MiddlewareInterface $middleware): self;
/**
* Seed the middleware stack with the inner request handler
*/
public function seedMiddlewareStack(RequestHandlerInterface $kernel): void;
}

View File

@@ -0,0 +1,48 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use RuntimeException;
interface Psr17FactoryInterface
{
/**
* @throws RuntimeException when the factory could not be instantiated
*/
public static function getResponseFactory(): ResponseFactoryInterface;
/**
* @throws RuntimeException when the factory could not be instantiated
*/
public static function getStreamFactory(): StreamFactoryInterface;
/**
* @throws RuntimeException when the factory could not be instantiated
*/
public static function getServerRequestCreator(): ServerRequestCreatorInterface;
/**
* Is the PSR-17 ResponseFactory available
*/
public static function isResponseFactoryAvailable(): bool;
/**
* Is the PSR-17 StreamFactory available
*/
public static function isStreamFactoryAvailable(): bool;
/**
* Is the ServerRequest creator available
*/
public static function isServerRequestCreatorAvailable(): bool;
}

View File

@@ -0,0 +1,27 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
/** @api */
interface Psr17FactoryProviderInterface
{
/**
* @return string[]
*/
public static function getFactories(): array;
/**
* @param string[] $factories
*/
public static function setFactories(array $factories): void;
public static function addFactory(string $factory): void;
}

View File

@@ -0,0 +1,15 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
interface RequestHandlerInvocationStrategyInterface extends InvocationStrategyInterface
{
}

View File

@@ -0,0 +1,103 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
use InvalidArgumentException;
use RuntimeException;
/** @api */
interface RouteCollectorInterface
{
/**
* Get the route parser
*/
public function getRouteParser(): RouteParserInterface;
/**
* Get default route invocation strategy
*/
public function getDefaultInvocationStrategy(): InvocationStrategyInterface;
/**
* Set default route invocation strategy
*/
public function setDefaultInvocationStrategy(InvocationStrategyInterface $strategy): RouteCollectorInterface;
/**
* Get path to FastRoute cache file
*/
public function getCacheFile(): ?string;
/**
* Set path to FastRoute cache file
*
* @throws InvalidArgumentException
* @throws RuntimeException
*/
public function setCacheFile(string $cacheFile): RouteCollectorInterface;
/**
* Get the base path used in pathFor()
*/
public function getBasePath(): string;
/**
* Set the base path used in pathFor()
*/
public function setBasePath(string $basePath): RouteCollectorInterface;
/**
* Get route objects
*
* @return RouteInterface[]
*/
public function getRoutes(): array;
/**
* Get named route object
*
* @param string $name Route name
*
* @throws RuntimeException If named route does not exist
*/
public function getNamedRoute(string $name): RouteInterface;
/**
* Remove named route
*
* @param string $name Route name
*
* @throws RuntimeException If named route does not exist
*/
public function removeNamedRoute(string $name): RouteCollectorInterface;
/**
* Lookup a route via the route's unique identifier
*
* @throws RuntimeException If route of identifier does not exist
*/
public function lookupRoute(string $identifier): RouteInterface;
/**
* Add route group
* @param string|callable $callable
*/
public function group(string $pattern, $callable): RouteGroupInterface;
/**
* Add route
*
* @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;
}

View File

@@ -0,0 +1,126 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
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;
/**
* Get the RouteCollectorProxy's base path
*/
public function getBasePath(): string;
/**
* 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|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|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|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|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|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|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|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|array{class-string, string}|string $callable The route callback routine
*/
public function map(array $methods, string $pattern, $callable): RouteInterface;
/**
* Route Groups
*
* This method accepts a route pattern and a callback. All route
* declarations in the callback will be prepended by the group(s)
* that it is in.
* @param string|callable $callable
*/
public function group(string $pattern, $callable): RouteGroupInterface;
/**
* Add a route that sends an HTTP redirect
*
* @param string|UriInterface $to
*/
public function redirect(string $from, $to, int $status = 302): RouteInterface;
}

View File

@@ -0,0 +1,43 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
use Psr\Http\Server\MiddlewareInterface;
use Slim\MiddlewareDispatcher;
/** @api */
interface RouteGroupInterface
{
public function collectRoutes(): RouteGroupInterface;
/**
* Add middleware to the route group
*
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware): RouteGroupInterface;
/**
* Add middleware to the route group
*/
public function addMiddleware(MiddlewareInterface $middleware): RouteGroupInterface;
/**
* Append the group's middleware to the MiddlewareDispatcher
* @param MiddlewareDispatcher<\Psr\Container\ContainerInterface|null> $dispatcher
*/
public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher): RouteGroupInterface;
/**
* Get the RouteGroup's pattern
*/
public function getPattern(): string;
}

View File

@@ -0,0 +1,128 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
/** @api */
interface RouteInterface
{
/**
* Get route invocation strategy
*/
public function getInvocationStrategy(): InvocationStrategyInterface;
/**
* Set route invocation strategy
*/
public function setInvocationStrategy(InvocationStrategyInterface $invocationStrategy): RouteInterface;
/**
* Get route methods
*
* @return string[]
*/
public function getMethods(): array;
/**
* Get route pattern
*/
public function getPattern(): string;
/**
* Set route pattern
*/
public function setPattern(string $pattern): RouteInterface;
/**
* Get route callable
*
* @return callable|array{class-string, string}|string
*/
public function getCallable();
/**
* Set route callable
*
* @param callable|array{class-string, string}|string $callable
*/
public function setCallable($callable): RouteInterface;
/**
* Get route name
*/
public function getName(): ?string;
/**
* Set route name
*
* @return static
*/
public function setName(string $name): RouteInterface;
/**
* Get the route's unique identifier
*/
public function getIdentifier(): string;
/**
* Retrieve a specific route argument
*/
public function getArgument(string $name, ?string $default = null): ?string;
/**
* Get route arguments
*
* @return array<string, string>
*/
public function getArguments(): array;
/**
* Set a route argument
*
* @deprecated 4.14.1 Use a middleware for custom route arguments now.
*/
public function setArgument(string $name, string $value): 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;
/**
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware): self;
public function addMiddleware(MiddlewareInterface $middleware): self;
/**
* Prepare the route for use
*
* @param array<string, string> $arguments
*/
public function prepare(array $arguments): self;
/**
* Run route
*
* This method traverses the middleware stack, including the route's callable
* and captures the resultant HTTP response object. It then sends the response
* back to the Application.
*/
public function run(ServerRequestInterface $request): ResponseInterface;
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
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 | array<array-key, string>> $queryParams Optional query string parameters
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
*/
public function relativeUrlFor(string $routeName, array $data = [], array $queryParams = []): string;
/**
* 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 | array<array-key, string>> $queryParams Optional query string parameters
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
*/
public function urlFor(string $routeName, array $data = [], array $queryParams = []): string;
/**
* 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 | array<array-key, string>> $queryParams Optional query string parameters
*/
public function fullUrlFor(UriInterface $uri, string $routeName, array $data = [], array $queryParams = []): string;
}

View File

@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace Slim\Interfaces;
use Slim\Routing\RoutingResults;
interface RouteResolverInterface
{
/**
* @param string $uri Should be ServerRequestInterface::getUri()->getPath()
*/
public function computeRoutingResults(string $uri, string $method): RoutingResults;
public function resolveRoute(string $identifier): RouteInterface;
}

View File

@@ -0,0 +1,18 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Interfaces;
use Psr\Http\Message\ServerRequestInterface;
interface ServerRequestCreatorInterface
{
public function createServerRequestFromGlobals(): ServerRequestInterface;
}

32
vendor/slim/slim/Slim/Logger.php vendored Executable file
View File

@@ -0,0 +1,32 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim;
use Psr\Log\AbstractLogger;
use Psr\Log\InvalidArgumentException;
use Stringable;
use function error_log;
class Logger extends AbstractLogger
{
/**
* @param mixed $level
* @param string|Stringable $message
* @param array<mixed> $context
*
* @throws InvalidArgumentException
*/
public function log($level, $message, array $context = []): void
{
error_log((string) $message);
}
}

View File

@@ -0,0 +1,201 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use RuntimeException;
use function count;
use function explode;
use function is_array;
use function is_object;
use function is_string;
use function json_decode;
use function libxml_clear_errors;
use function libxml_disable_entity_loader;
use function libxml_use_internal_errors;
use function parse_str;
use function simplexml_load_string;
use function strtolower;
use function trim;
use const LIBXML_VERSION;
/** @api */
class BodyParsingMiddleware implements MiddlewareInterface
{
/**
* @var callable[]
*/
protected array $bodyParsers;
/**
* @param callable[] $bodyParsers list of body parsers as an associative array of mediaType => callable
*/
public function __construct(array $bodyParsers = [])
{
$this->registerDefaultBodyParsers();
foreach ($bodyParsers as $mediaType => $parser) {
$this->registerBodyParser($mediaType, $parser);
}
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$parsedBody = $request->getParsedBody();
if (empty($parsedBody)) {
$parsedBody = $this->parseBody($request);
$request = $request->withParsedBody($parsedBody);
}
return $handler->handle($request);
}
/**
* @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
{
$this->bodyParsers[$mediaType] = $callable;
return $this;
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
*/
public function hasBodyParser(string $mediaType): bool
{
return isset($this->bodyParsers[$mediaType]);
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
* @throws RuntimeException
*/
public function getBodyParser(string $mediaType): callable
{
if (!isset($this->bodyParsers[$mediaType])) {
throw new RuntimeException('No parser for type ' . $mediaType);
}
return $this->bodyParsers[$mediaType];
}
protected function registerDefaultBodyParsers(): void
{
$this->registerBodyParser('application/json', static function ($input) {
/** @var string $input */
$result = json_decode($input, true);
if (!is_array($result)) {
return null;
}
return $result;
});
$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);
self::disableXmlEntityLoader($backup);
libxml_clear_errors();
libxml_use_internal_errors($backup_errors);
if ($result === false) {
return null;
}
return $result;
};
$this->registerBodyParser('application/xml', $xmlCallable);
$this->registerBodyParser('text/xml', $xmlCallable);
}
/**
* @return null|array<mixed>|object
*/
protected function parseBody(ServerRequestInterface $request)
{
$mediaType = $this->getMediaType($request);
if ($mediaType === null) {
return null;
}
// Check if this specific media type has a parser registered first
if (!isset($this->bodyParsers[$mediaType])) {
// If not, look for a media type with a structured syntax suffix (RFC 6839)
$parts = explode('+', $mediaType);
if (count($parts) >= 2) {
$mediaType = 'application/' . $parts[count($parts) - 1];
}
}
if (isset($this->bodyParsers[$mediaType])) {
$body = (string)$request->getBody();
$parsed = $this->bodyParsers[$mediaType]($body);
if ($parsed !== null && !is_object($parsed) && !is_array($parsed)) {
throw new RuntimeException(
'Request body media type parser return value must be an array, an object, or null'
);
}
return $parsed;
}
return null;
}
/**
* @return string|null The serverRequest media type, minus content-type params
*/
protected function getMediaType(ServerRequestInterface $request): ?string
{
$contentType = $request->getHeader('Content-Type')[0] ?? null;
if (is_string($contentType) && trim($contentType) !== '') {
$contentTypeParts = explode(';', $contentType);
return strtolower(trim($contentTypeParts[0]));
}
return null;
}
protected static function disableXmlEntityLoader(bool $disable): bool
{
if (LIBXML_VERSION >= 20900) {
// libxml >= 2.9.0 disables entity loading by default, so it is
// safe to skip the real call (deprecated in PHP 8).
return true;
}
// @codeCoverageIgnoreStart
return libxml_disable_entity_loader($disable);
// @codeCoverageIgnoreEnd
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Middleware;
use Psr\Http\Message\ResponseInterface;
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
{
$response = $handler->handle($request);
// Add Content-Length header if not already added
$size = $response->getBody()->getSize();
if ($size !== null && !$response->hasHeader('Content-Length')) {
$response = $response->withHeader('Content-Length', (string) $size);
}
return $response;
}
}

View File

@@ -0,0 +1,215 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Middleware;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Log\LoggerInterface;
use Slim\Exception\HttpException;
use Slim\Handlers\ErrorHandler;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\ErrorHandlerInterface;
use Throwable;
use function get_class;
use function is_subclass_of;
/** @api */
class ErrorMiddleware implements MiddlewareInterface
{
protected CallableResolverInterface $callableResolver;
protected ResponseFactoryInterface $responseFactory;
protected bool $displayErrorDetails;
protected bool $logErrors;
protected bool $logErrorDetails;
protected ?LoggerInterface $logger = null;
/**
* @var ErrorHandlerInterface[]|callable[]|string[]
*/
protected array $handlers = [];
/**
* @var ErrorHandlerInterface[]|callable[]|string[]
*/
protected array $subClassHandlers = [];
/**
* @var ErrorHandlerInterface|callable|string|null
*/
protected $defaultErrorHandler;
public function __construct(
CallableResolverInterface $callableResolver,
ResponseFactoryInterface $responseFactory,
bool $displayErrorDetails,
bool $logErrors,
bool $logErrorDetails,
?LoggerInterface $logger = null
) {
$this->callableResolver = $callableResolver;
$this->responseFactory = $responseFactory;
$this->displayErrorDetails = $displayErrorDetails;
$this->logErrors = $logErrors;
$this->logErrorDetails = $logErrorDetails;
$this->logger = $logger;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
try {
return $handler->handle($request);
} catch (Throwable $e) {
return $this->handleException($request, $e);
}
}
public function handleException(ServerRequestInterface $request, Throwable $exception): ResponseInterface
{
if ($exception instanceof HttpException) {
$request = $exception->getRequest();
}
$exceptionType = get_class($exception);
$handler = $this->getErrorHandler($exceptionType);
/** @var ResponseInterface */
return $handler($request, $exception, $this->displayErrorDetails, $this->logErrors, $this->logErrorDetails);
}
/**
* Get callable to handle scenarios where an error
* occurs when processing the current request.
*
* @param string $type Exception/Throwable name. ie: RuntimeException::class
* @return callable|ErrorHandler
*/
public function getErrorHandler(string $type)
{
if (isset($this->handlers[$type])) {
return $this->callableResolver->resolve($this->handlers[$type]);
}
if (isset($this->subClassHandlers[$type])) {
return $this->callableResolver->resolve($this->subClassHandlers[$type]);
}
foreach ($this->subClassHandlers as $class => $handler) {
if (is_subclass_of($type, $class)) {
return $this->callableResolver->resolve($handler);
}
}
return $this->getDefaultErrorHandler();
}
/**
* Get default error handler
*
* @return ErrorHandler|callable
*/
public function getDefaultErrorHandler()
{
if ($this->defaultErrorHandler === null) {
$this->defaultErrorHandler = new ErrorHandler(
$this->callableResolver,
$this->responseFactory,
$this->logger
);
}
return $this->callableResolver->resolve($this->defaultErrorHandler);
}
/**
* Set callable as the default Slim application error handler.
*
* The callable signature MUST match the ErrorHandlerInterface
*
* @param string|callable|ErrorHandler $handler
* @see ErrorHandlerInterface
*
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
* 2. Instance of \Throwable
* 3. Boolean $displayErrorDetails
* 4. Boolean $logErrors
* 5. Boolean $logErrorDetails
*
* The callable MUST return an instance of
* \Psr\Http\Message\ResponseInterface.
*
*/
public function setDefaultErrorHandler($handler): self
{
$this->defaultErrorHandler = $handler;
return $this;
}
/**
* Set callable to handle scenarios where an error
* occurs when processing the current request.
*
* The callable signature MUST match the ErrorHandlerInterface
*
* 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.
*
* @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
* 3. Boolean $displayErrorDetails
* 4. Boolean $logErrors
* 5. Boolean $logErrorDetails
*
* The callable MUST return an instance of
* \Psr\Http\Message\ResponseInterface.
*
*/
public function setErrorHandler($typeOrTypes, $handler, bool $handleSubclasses = false): self
{
if (is_array($typeOrTypes)) {
foreach ($typeOrTypes as $type) {
$this->addErrorHandler($type, $handler, $handleSubclasses);
}
} else {
$this->addErrorHandler($typeOrTypes, $handler, $handleSubclasses);
}
return $this;
}
/**
* Used internally to avoid code repetition when passing multiple exceptions to setErrorHandler().
* @param string|callable|ErrorHandlerInterface $handler
*/
private function addErrorHandler(string $type, $handler, bool $handleSubclasses): void
{
if ($handleSubclasses) {
$this->subClassHandlers[$type] = $handler;
} else {
$this->handlers[$type] = $handler;
}
}
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
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
{
$methodHeader = $request->getHeaderLine('X-Http-Method-Override');
if ($methodHeader) {
$request = $request->withMethod($methodHeader);
} elseif (strtoupper($request->getMethod()) === 'POST') {
$body = $request->getParsedBody();
if (is_array($body) && !empty($body['_METHOD']) && is_string($body['_METHOD'])) {
$request = $request->withMethod($body['_METHOD']);
}
if ($request->getBody()->eof()) {
$request->getBody()->rewind();
}
}
return $handler->handle($request);
}
}

View File

@@ -0,0 +1,75 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Middleware;
use InvalidArgumentException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Throwable;
use function in_array;
use function ob_end_clean;
use function ob_get_clean;
use function ob_start;
/** @api */
class OutputBufferingMiddleware implements MiddlewareInterface
{
public const APPEND = 'append';
public const PREPEND = 'prepend';
protected StreamFactoryInterface $streamFactory;
protected string $style;
/**
* @param string $style Either "append" or "prepend"
*/
public function __construct(StreamFactoryInterface $streamFactory, string $style = 'append')
{
$this->streamFactory = $streamFactory;
$this->style = $style;
if (!in_array($style, [static::APPEND, static::PREPEND], true)) {
throw new InvalidArgumentException("Invalid style `{$style}`. Must be `append` or `prepend`");
}
}
/**
* @throws Throwable
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
try {
ob_start();
$response = $handler->handle($request);
$output = ob_get_clean();
} catch (Throwable $e) {
ob_end_clean();
throw $e;
}
if (!empty($output)) {
if ($this->style === static::PREPEND) {
$body = $this->streamFactory->createStream();
$body->write($output . $response->getBody());
$response = $response->withBody($body);
} elseif ($this->style === static::APPEND && $response->getBody()->isWritable()) {
$response->getBody()->write($output);
}
}
return $response;
}
}

View File

@@ -0,0 +1,98 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use RuntimeException;
use Slim\Exception\HttpMethodNotAllowedException;
use Slim\Exception\HttpNotFoundException;
use Slim\Interfaces\RouteParserInterface;
use Slim\Interfaces\RouteResolverInterface;
use Slim\Routing\RouteContext;
use Slim\Routing\RoutingResults;
class RoutingMiddleware implements MiddlewareInterface
{
protected RouteResolverInterface $routeResolver;
protected RouteParserInterface $routeParser;
public function __construct(RouteResolverInterface $routeResolver, RouteParserInterface $routeParser)
{
$this->routeResolver = $routeResolver;
$this->routeParser = $routeParser;
}
/**
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
* @throws RuntimeException
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$request = $this->performRouting($request);
return $handler->handle($request);
}
/**
* Perform routing
*
* @param ServerRequestInterface $request PSR7 Server Request
*
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
* @throws RuntimeException
*/
public function performRouting(ServerRequestInterface $request): ServerRequestInterface
{
$request = $request->withAttribute(RouteContext::ROUTE_PARSER, $this->routeParser);
$routingResults = $this->resolveRoutingResultsFromRequest($request);
$routeStatus = $routingResults->getRouteStatus();
$request = $request->withAttribute(RouteContext::ROUTING_RESULTS, $routingResults);
switch ($routeStatus) {
case RoutingResults::FOUND:
$routeArguments = $routingResults->getRouteArguments();
$routeIdentifier = $routingResults->getRouteIdentifier() ?? '';
$route = $this->routeResolver
->resolveRoute($routeIdentifier)
->prepare($routeArguments);
return $request->withAttribute(RouteContext::ROUTE, $route);
case RoutingResults::NOT_FOUND:
throw new HttpNotFoundException($request);
case RoutingResults::METHOD_NOT_ALLOWED:
$exception = new HttpMethodNotAllowedException($request);
$exception->setAllowedMethods($routingResults->getAllowedMethods());
throw $exception;
default:
throw new RuntimeException('An unexpected error occurred while performing routing.');
}
}
/**
* Resolves the route from the given request
*/
protected function resolveRoutingResultsFromRequest(ServerRequestInterface $request): RoutingResults
{
return $this->routeResolver->computeRoutingResults(
$request->getUri()->getPath(),
$request->getMethod()
);
}
}

289
vendor/slim/slim/Slim/MiddlewareDispatcher.php vendored Executable file
View File

@@ -0,0 +1,289 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim;
use Closure;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use RuntimeException;
use Slim\Interfaces\AdvancedCallableResolverInterface;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\MiddlewareDispatcherInterface;
use function class_exists;
use function function_exists;
use function is_callable;
use function is_string;
use function preg_match;
use function sprintf;
/**
* @api
* @template TContainerInterface of (ContainerInterface|null)
*/
class MiddlewareDispatcher implements MiddlewareDispatcherInterface
{
/**
* Tip of the middleware call stack
*/
protected RequestHandlerInterface $tip;
protected ?CallableResolverInterface $callableResolver;
/** @var TContainerInterface $container */
protected ?ContainerInterface $container;
/**
* @param TContainerInterface $container
*/
public function __construct(
RequestHandlerInterface $kernel,
?CallableResolverInterface $callableResolver = null,
?ContainerInterface $container = null
) {
$this->seedMiddlewareStack($kernel);
$this->callableResolver = $callableResolver;
$this->container = $container;
}
/**
* {@inheritdoc}
*/
public function seedMiddlewareStack(RequestHandlerInterface $kernel): void
{
$this->tip = $kernel;
}
/**
* Invoke the middleware stack
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
return $this->tip->handle($request);
}
/**
* Add a new middleware to the stack
*
* 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).
*
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware): MiddlewareDispatcherInterface
{
if ($middleware instanceof MiddlewareInterface) {
return $this->addMiddleware($middleware);
}
if (is_string($middleware)) {
return $this->addDeferred($middleware);
}
if (is_callable($middleware)) {
return $this->addCallable($middleware);
}
/** @phpstan-ignore-next-line */
throw new RuntimeException(
'A middleware must be an object/class name referencing an implementation of ' .
'MiddlewareInterface or a callable with a matching signature.'
);
}
/**
* Add a new middleware to the stack
*
* 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).
*/
public function addMiddleware(MiddlewareInterface $middleware): MiddlewareDispatcherInterface
{
$next = $this->tip;
$this->tip = new class ($middleware, $next) implements RequestHandlerInterface {
private MiddlewareInterface $middleware;
private RequestHandlerInterface $next;
public function __construct(MiddlewareInterface $middleware, RequestHandlerInterface $next)
{
$this->middleware = $middleware;
$this->next = $next;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
return $this->middleware->process($request, $this->next);
}
};
return $this;
}
/**
* Add a new middleware by class name
*
* 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
{
$next = $this->tip;
$this->tip = new class (
$middleware,
$next,
$this->container,
$this->callableResolver
) implements RequestHandlerInterface {
private string $middleware;
private RequestHandlerInterface $next;
private ?ContainerInterface $container;
private ?CallableResolverInterface $callableResolver;
public function __construct(
string $middleware,
RequestHandlerInterface $next,
?ContainerInterface $container = null,
?CallableResolverInterface $callableResolver = null
) {
$this->middleware = $middleware;
$this->next = $next;
$this->container = $container;
$this->callableResolver = $callableResolver;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {
$callable = $this->callableResolver->resolveMiddleware($this->middleware);
/** @var ResponseInterface */
return $callable($request, $this->next);
}
$callable = null;
if ($this->callableResolver instanceof CallableResolverInterface) {
try {
$callable = $this->callableResolver->resolve($this->middleware);
} catch (RuntimeException $e) {
// Do Nothing
}
}
if (!$callable) {
$resolved = $this->middleware;
$instance = null;
$method = null;
/** @psalm-suppress ArgumentTypeCoercion */
// Check for Slim callable as `class:method`
if (preg_match(CallableResolver::$callablePattern, $resolved, $matches)) {
$resolved = $matches[1];
$method = $matches[2];
}
if ($this->container && $this->container->has($resolved)) {
$instance = $this->container->get($resolved);
if ($instance instanceof MiddlewareInterface) {
return $instance->process($request, $this->next);
}
} elseif (!function_exists($resolved)) {
if (!class_exists($resolved)) {
throw new RuntimeException(sprintf('Middleware %s does not exist', $resolved));
}
$instance = new $resolved($this->container);
}
if ($instance && $instance instanceof MiddlewareInterface) {
return $instance->process($request, $this->next);
}
$callable = $instance ?? $resolved;
if ($instance && $method) {
$callable = [$instance, $method];
}
if ($this->container && $callable instanceof Closure) {
$callable = $callable->bindTo($this->container);
}
}
if (!is_callable($callable)) {
throw new RuntimeException(
sprintf(
'Middleware %s is not resolvable',
$this->middleware
)
);
}
/** @var ResponseInterface */
return $callable($request, $this->next);
}
};
return $this;
}
/**
* Add a (non-standard) callable middleware to the stack
*
* 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
{
$next = $this->tip;
if ($this->container && $middleware instanceof Closure) {
/** @var Closure $middleware */
$middleware = $middleware->bindTo($this->container);
}
$this->tip = new class ($middleware, $next) implements RequestHandlerInterface {
/**
* @var callable
*/
private $middleware;
/**
* @var RequestHandlerInterface
*/
private $next;
public function __construct(callable $middleware, RequestHandlerInterface $next)
{
$this->middleware = $middleware;
$this->next = $next;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
/** @var ResponseInterface */
return ($this->middleware)($request, $this->next);
}
};
return $this;
}
}

136
vendor/slim/slim/Slim/ResponseEmitter.php vendored Executable file
View File

@@ -0,0 +1,136 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim;
use Psr\Http\Message\ResponseInterface;
use function connection_status;
use function header;
use function headers_sent;
use function in_array;
use function min;
use function sprintf;
use function strlen;
use function strtolower;
use const CONNECTION_NORMAL;
class ResponseEmitter
{
private int $responseChunkSize;
public function __construct(int $responseChunkSize = 4096)
{
$this->responseChunkSize = $responseChunkSize;
}
/**
* Send the response the client
*/
public function emit(ResponseInterface $response): void
{
$isEmpty = $this->isResponseEmpty($response);
if (headers_sent() === false) {
$this->emitHeaders($response);
// Set the status _after_ the headers, because of PHP's "helpful" behavior with location headers.
// See https://github.com/slimphp/Slim/issues/1730
$this->emitStatusLine($response);
}
if (!$isEmpty) {
$this->emitBody($response);
}
}
/**
* Emit Response Headers
*/
private function emitHeaders(ResponseInterface $response): void
{
foreach ($response->getHeaders() as $name => $values) {
$first = strtolower($name) !== 'set-cookie';
foreach ($values as $value) {
$header = sprintf('%s: %s', $name, $value);
header($header, $first);
$first = false;
}
}
}
/**
* Emit Status Line
*/
private function emitStatusLine(ResponseInterface $response): void
{
$statusLine = sprintf(
'HTTP/%s %s %s',
$response->getProtocolVersion(),
$response->getStatusCode(),
$response->getReasonPhrase()
);
header($statusLine, true, $response->getStatusCode());
}
/**
* Emit Body
*/
private function emitBody(ResponseInterface $response): void
{
$body = $response->getBody();
if ($body->isSeekable()) {
$body->rewind();
}
$amountToRead = (int) $response->getHeaderLine('Content-Length');
if (!$amountToRead) {
$amountToRead = $body->getSize();
}
if ($amountToRead) {
while ($amountToRead > 0 && !$body->eof()) {
$length = min($this->responseChunkSize, $amountToRead);
$data = $body->read($length);
echo $data;
$amountToRead -= strlen($data);
if (connection_status() !== CONNECTION_NORMAL) {
break;
}
}
} else {
while (!$body->eof()) {
echo $body->read($this->responseChunkSize);
if (connection_status() !== CONNECTION_NORMAL) {
break;
}
}
}
}
/**
* Asserts response body is empty or status code is 204, 205 or 304
*/
public function isResponseEmpty(ResponseInterface $response): bool
{
if (in_array($response->getStatusCode(), [204, 205, 304], true)) {
return true;
}
$stream = $response->getBody();
$seekable = $stream->isSeekable();
if ($seekable) {
$stream->rewind();
}
return $seekable ? $stream->read(1) === '' : $stream->eof();
}
}

78
vendor/slim/slim/Slim/Routing/Dispatcher.php vendored Executable file
View File

@@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace Slim\Routing;
use FastRoute\DataGenerator\GroupCountBased;
use FastRoute\RouteCollector as FastRouteCollector;
use FastRoute\RouteParser\Std;
use Slim\Interfaces\DispatcherInterface;
use Slim\Interfaces\RouteCollectorInterface;
class Dispatcher implements DispatcherInterface
{
private RouteCollectorInterface $routeCollector;
private ?FastRouteDispatcher $dispatcher = null;
public function __construct(RouteCollectorInterface $routeCollector)
{
$this->routeCollector = $routeCollector;
}
protected function createDispatcher(): FastRouteDispatcher
{
if ($this->dispatcher) {
return $this->dispatcher;
}
$routeDefinitionCallback = function (FastRouteCollector $r): void {
$basePath = $this->routeCollector->getBasePath();
foreach ($this->routeCollector->getRoutes() as $route) {
$r->addRoute($route->getMethods(), $basePath . $route->getPattern(), $route->getIdentifier());
}
};
$cacheFile = $this->routeCollector->getCacheFile();
if ($cacheFile) {
/** @var FastRouteDispatcher $dispatcher */
$dispatcher = \FastRoute\cachedDispatcher($routeDefinitionCallback, [
'dataGenerator' => GroupCountBased::class,
'dispatcher' => FastRouteDispatcher::class,
'routeParser' => new Std(),
'cacheFile' => $cacheFile,
]);
} else {
/** @var FastRouteDispatcher $dispatcher */
$dispatcher = \FastRoute\simpleDispatcher($routeDefinitionCallback, [
'dataGenerator' => GroupCountBased::class,
'dispatcher' => FastRouteDispatcher::class,
'routeParser' => new Std(),
]);
}
$this->dispatcher = $dispatcher;
return $this->dispatcher;
}
/**
* {@inheritdoc}
*/
public function dispatch(string $method, string $uri): RoutingResults
{
$dispatcher = $this->createDispatcher();
$results = $dispatcher->dispatch($method, $uri);
return new RoutingResults($this, $method, $uri, $results[0], $results[1], $results[2]);
}
/**
* {@inheritdoc}
*/
public function getAllowedMethods(string $uri): array
{
$dispatcher = $this->createDispatcher();
return $dispatcher->getAllowedMethods($uri);
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Routing;
use FastRoute\Dispatcher\GroupCountBased;
class FastRouteDispatcher extends GroupCountBased
{
/**
* @var string[][]
*/
private array $allowedMethods = [];
/**
* @param string $httpMethod
* @param string $uri
*
* @return array{int, string|null, array<string, string>}
*/
public function dispatch($httpMethod, $uri): array
{
$routingResults = $this->routingResults($httpMethod, $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
// For HEAD requests, attempt fallback to GET
if ($httpMethod === 'HEAD') {
$routingResults = $this->routingResults('GET', $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
}
// If nothing else matches, try fallback routes
$routingResults = $this->routingResults('*', $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
if (!empty($this->getAllowedMethods($uri))) {
return [self::METHOD_NOT_ALLOWED, null, []];
}
return [self::NOT_FOUND, null, []];
}
/**
* @param string $httpMethod
* @param string $uri
*
* @return array{int, string|null, array<string, string>}
*/
private function routingResults(string $httpMethod, string $uri): array
{
if (isset($this->staticRouteMap[$httpMethod][$uri])) {
/** @var string $routeIdentifier */
$routeIdentifier = $this->staticRouteMap[$httpMethod][$uri];
return [self::FOUND, $routeIdentifier, []];
}
if (isset($this->variableRouteData[$httpMethod])) {
/** @var array{0: int, 1?: string, 2?: array<string, string>} $result */
$result = $this->dispatchVariableRoute($this->variableRouteData[$httpMethod], $uri);
if ($result[0] === self::FOUND) {
/** @var array{int, string, array<string, string>} $result */
return [self::FOUND, $result[1], $result[2]];
}
}
return [self::NOT_FOUND, null, []];
}
/**
* @param string $uri
*
* @return string[]
*/
public function getAllowedMethods(string $uri): array
{
if (isset($this->allowedMethods[$uri])) {
return $this->allowedMethods[$uri];
}
$allowedMethods = [];
foreach ($this->staticRouteMap as $method => $uriMap) {
if (isset($uriMap[$uri])) {
$allowedMethods[$method] = true;
}
}
foreach ($this->variableRouteData as $method => $routeData) {
$result = $this->dispatchVariableRoute($routeData, $uri);
if ($result[0] === self::FOUND) {
$allowedMethods[$method] = true;
}
}
return $this->allowedMethods[$uri] = array_keys($allowedMethods);
}
}

364
vendor/slim/slim/Slim/Routing/Route.php vendored Executable file
View File

@@ -0,0 +1,364 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Routing;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Handlers\Strategies\RequestHandler;
use Slim\Handlers\Strategies\RequestResponse;
use Slim\Interfaces\AdvancedCallableResolverInterface;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\InvocationStrategyInterface;
use Slim\Interfaces\RequestHandlerInvocationStrategyInterface;
use Slim\Interfaces\RouteGroupInterface;
use Slim\Interfaces\RouteInterface;
use Slim\MiddlewareDispatcher;
use function array_key_exists;
use function array_replace;
use function array_reverse;
use function class_implements;
use function in_array;
use function is_array;
/**
* @api
* @template TContainerInterface of (ContainerInterface|null)
*/
class Route implements RouteInterface, RequestHandlerInterface
{
/**
* HTTP methods supported by this route
*
* @var string[]
*/
protected array $methods = [];
/**
* Route identifier
*/
protected string $identifier;
/**
* Route name
*/
protected ?string $name = null;
/**
* Parent route groups
*
* @var RouteGroupInterface[]
*/
protected array $groups;
protected InvocationStrategyInterface $invocationStrategy;
/**
* Route parameters
*
* @var array<string, string>
*/
protected array $arguments = [];
/**
* Route arguments parameters
*
* @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|array{class-string, string}|string
*/
protected $callable;
protected CallableResolverInterface $callableResolver;
protected ResponseFactoryInterface $responseFactory;
/**
* Route pattern
*/
protected string $pattern;
protected bool $groupMiddlewareAppended = false;
/**
* @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
*/
public function __construct(
array $methods,
string $pattern,
$callable,
ResponseFactoryInterface $responseFactory,
CallableResolverInterface $callableResolver,
?ContainerInterface $container = null,
?InvocationStrategyInterface $invocationStrategy = null,
array $groups = [],
int $identifier = 0
) {
$this->methods = $methods;
$this->pattern = $pattern;
$this->callable = $callable;
$this->responseFactory = $responseFactory;
$this->callableResolver = $callableResolver;
$this->container = $container;
$this->invocationStrategy = $invocationStrategy ?? new RequestResponse();
$this->groups = $groups;
$this->identifier = 'route' . $identifier;
$this->middlewareDispatcher = new MiddlewareDispatcher($this, $callableResolver, $container);
}
public function getCallableResolver(): CallableResolverInterface
{
return $this->callableResolver;
}
/**
* {@inheritdoc}
*/
public function getInvocationStrategy(): InvocationStrategyInterface
{
return $this->invocationStrategy;
}
/**
* {@inheritdoc}
*/
public function setInvocationStrategy(InvocationStrategyInterface $invocationStrategy): RouteInterface
{
$this->invocationStrategy = $invocationStrategy;
return $this;
}
/**
* {@inheritdoc}
*/
public function getMethods(): array
{
return $this->methods;
}
/**
* {@inheritdoc}
*/
public function getPattern(): string
{
return $this->pattern;
}
/**
* {@inheritdoc}
*/
public function setPattern(string $pattern): RouteInterface
{
$this->pattern = $pattern;
return $this;
}
/**
* {@inheritdoc}
*/
public function getCallable()
{
return $this->callable;
}
/**
* {@inheritdoc}
*/
public function setCallable($callable): RouteInterface
{
$this->callable = $callable;
return $this;
}
/**
* {@inheritdoc}
*/
public function getName(): ?string
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function setName(string $name): RouteInterface
{
$this->name = $name;
return $this;
}
/**
* {@inheritdoc}
*/
public function getIdentifier(): string
{
return $this->identifier;
}
/**
* {@inheritdoc}
*/
public function getArgument(string $name, ?string $default = null): ?string
{
if (array_key_exists($name, $this->arguments)) {
return $this->arguments[$name];
}
return $default;
}
/**
* {@inheritdoc}
*/
public function getArguments(): array
{
return $this->arguments;
}
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments, bool $includeInSavedArguments = true): RouteInterface
{
if ($includeInSavedArguments) {
$this->savedArguments = $arguments;
}
$this->arguments = $arguments;
return $this;
}
/**
* @return RouteGroupInterface[]
*/
public function getGroups(): array
{
return $this->groups;
}
/**
* {@inheritdoc}
*/
public function add($middleware): RouteInterface
{
$this->middlewareDispatcher->add($middleware);
return $this;
}
/**
* {@inheritdoc}
*/
public function addMiddleware(MiddlewareInterface $middleware): RouteInterface
{
$this->middlewareDispatcher->addMiddleware($middleware);
return $this;
}
/**
* {@inheritdoc}
*/
public function prepare(array $arguments): RouteInterface
{
$this->arguments = array_replace($this->savedArguments, $arguments);
return $this;
}
/**
* {@inheritdoc}
*/
public function setArgument(string $name, string $value, bool $includeInSavedArguments = true): RouteInterface
{
if ($includeInSavedArguments) {
$this->savedArguments[$name] = $value;
}
$this->arguments[$name] = $value;
return $this;
}
/**
* {@inheritdoc}
*/
public function run(ServerRequestInterface $request): ResponseInterface
{
if (!$this->groupMiddlewareAppended) {
$this->appendGroupMiddlewareToRoute();
}
return $this->middlewareDispatcher->handle($request);
}
/**
* @return void
*/
protected function appendGroupMiddlewareToRoute(): void
{
$inner = $this->middlewareDispatcher;
$this->middlewareDispatcher = new MiddlewareDispatcher($inner, $this->callableResolver, $this->container);
foreach (array_reverse($this->groups) as $group) {
$group->appendMiddlewareToDispatcher($this->middlewareDispatcher);
}
$this->groupMiddlewareAppended = true;
}
/**
* {@inheritdoc}
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {
$callable = $this->callableResolver->resolveRoute($this->callable);
} else {
$callable = $this->callableResolver->resolve($this->callable);
}
$strategy = $this->invocationStrategy;
$strategyImplements = class_implements($strategy);
if (
is_array($callable)
&& $callable[0] instanceof RequestHandlerInterface
&& !in_array(RequestHandlerInvocationStrategyInterface::class, $strategyImplements)
) {
$strategy = new RequestHandler();
}
$response = $this->responseFactory->createResponse();
return $strategy($callable, $request, $response, $this->arguments);
}
}

View File

@@ -0,0 +1,302 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Routing;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use RuntimeException;
use Slim\Handlers\Strategies\RequestResponse;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\InvocationStrategyInterface;
use Slim\Interfaces\RouteCollectorInterface;
use Slim\Interfaces\RouteCollectorProxyInterface;
use Slim\Interfaces\RouteGroupInterface;
use Slim\Interfaces\RouteInterface;
use Slim\Interfaces\RouteParserInterface;
use function array_pop;
use function dirname;
use function file_exists;
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
{
protected RouteParserInterface $routeParser;
protected CallableResolverInterface $callableResolver;
protected ?ContainerInterface $container = null;
protected InvocationStrategyInterface $defaultInvocationStrategy;
/**
* Base path used in pathFor()
*/
protected string $basePath = '';
/**
* Path to fast route cache file. Set to null to disable route caching
*/
protected ?string $cacheFile = null;
/**
* Routes
*
* @var RouteInterface[]
*/
protected array $routes = [];
/**
* Routes indexed by name
*
* @var RouteInterface[]
*/
protected array $routesByName = [];
/**
* Route groups
*
* @var RouteGroupInterface[]
*/
protected array $routeGroups = [];
/**
* Route counter incrementer
*/
protected int $routeCounter = 0;
protected ResponseFactoryInterface $responseFactory;
/**
* @param TContainerInterface $container
*/
public function __construct(
ResponseFactoryInterface $responseFactory,
CallableResolverInterface $callableResolver,
?ContainerInterface $container = null,
?InvocationStrategyInterface $defaultInvocationStrategy = null,
?RouteParserInterface $routeParser = null,
?string $cacheFile = null
) {
$this->responseFactory = $responseFactory;
$this->callableResolver = $callableResolver;
$this->container = $container;
$this->defaultInvocationStrategy = $defaultInvocationStrategy ?? new RequestResponse();
$this->routeParser = $routeParser ?? new RouteParser($this);
if ($cacheFile) {
$this->setCacheFile($cacheFile);
}
}
public function getRouteParser(): RouteParserInterface
{
return $this->routeParser;
}
/**
* Get default route invocation strategy
*/
public function getDefaultInvocationStrategy(): InvocationStrategyInterface
{
return $this->defaultInvocationStrategy;
}
public function setDefaultInvocationStrategy(InvocationStrategyInterface $strategy): RouteCollectorInterface
{
$this->defaultInvocationStrategy = $strategy;
return $this;
}
/**
* {@inheritdoc}
*/
public function getCacheFile(): ?string
{
return $this->cacheFile;
}
/**
* {@inheritdoc}
*/
public function setCacheFile(string $cacheFile): RouteCollectorInterface
{
if (file_exists($cacheFile) && !is_readable($cacheFile)) {
throw new RuntimeException(
sprintf('Route collector cache file `%s` is not readable', $cacheFile)
);
}
if (!file_exists($cacheFile) && !is_writable(dirname($cacheFile))) {
throw new RuntimeException(
sprintf('Route collector cache file directory `%s` is not writable', dirname($cacheFile))
);
}
$this->cacheFile = $cacheFile;
return $this;
}
/**
* {@inheritdoc}
*/
public function getBasePath(): string
{
return $this->basePath;
}
/**
* Set the base path used in urlFor()
*/
public function setBasePath(string $basePath): RouteCollectorInterface
{
$this->basePath = $basePath;
return $this;
}
/**
* {@inheritdoc}
*/
public function getRoutes(): array
{
return $this->routes;
}
/**
* {@inheritdoc}
*/
public function removeNamedRoute(string $name): RouteCollectorInterface
{
$route = $this->getNamedRoute($name);
/** @psalm-suppress PossiblyNullArrayOffset */
unset($this->routesByName[$route->getName()], $this->routes[$route->getIdentifier()]);
return $this;
}
/**
* {@inheritdoc}
*/
public function getNamedRoute(string $name): RouteInterface
{
if (isset($this->routesByName[$name])) {
$route = $this->routesByName[$name];
if ($route->getName() === $name) {
return $route;
}
unset($this->routesByName[$name]);
}
foreach ($this->routes as $route) {
if ($name === $route->getName()) {
$this->routesByName[$name] = $route;
return $route;
}
}
throw new RuntimeException('Named route does not exist for name: ' . $name);
}
/**
* {@inheritdoc}
*/
public function lookupRoute(string $identifier): RouteInterface
{
if (!isset($this->routes[$identifier])) {
throw new RuntimeException('Route not found, looks like your route cache is stale.');
}
return $this->routes[$identifier];
}
/**
* {@inheritdoc}
*/
public function group(string $pattern, $callable): RouteGroupInterface
{
$routeGroup = $this->createGroup($pattern, $callable);
$this->routeGroups[] = $routeGroup;
$routeGroup->collectRoutes();
array_pop($this->routeGroups);
return $routeGroup;
}
/**
* @param string|callable $callable
*/
protected function createGroup(string $pattern, $callable): RouteGroupInterface
{
$routeCollectorProxy = $this->createProxy($pattern);
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,
$this->container,
$this,
$pattern
);
}
/**
* {@inheritdoc}
*/
public function map(array $methods, string $pattern, $handler): RouteInterface
{
$route = $this->createRoute($methods, $pattern, $handler);
$this->routes[$route->getIdentifier()] = $route;
$routeName = $route->getName();
if ($routeName !== null && !isset($this->routesByName[$routeName])) {
$this->routesByName[$routeName] = $route;
}
$this->routeCounter++;
return $route;
}
/**
* @param string[] $methods
* @param callable|array{class-string, string}|string $callable
*/
protected function createRoute(array $methods, string $pattern, $callable): RouteInterface
{
return new Route(
$methods,
$pattern,
$callable,
$this->responseFactory,
$this->callableResolver,
$this->container,
$this->defaultInvocationStrategy,
$this->routeGroups,
$this->routeCounter
);
}
}

View File

@@ -0,0 +1,196 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Routing;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\RouteCollectorInterface;
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,
?ContainerInterface $container = null,
?RouteCollectorInterface $routeCollector = null,
string $groupPattern = ''
) {
$this->responseFactory = $responseFactory;
$this->callableResolver = $callableResolver;
$this->container = $container;
$this->routeCollector = $routeCollector ?? new RouteCollector($responseFactory, $callableResolver, $container);
$this->groupPattern = $groupPattern;
}
/**
* {@inheritdoc}
*/
public function getResponseFactory(): ResponseFactoryInterface
{
return $this->responseFactory;
}
/**
* {@inheritdoc}
*/
public function getCallableResolver(): CallableResolverInterface
{
return $this->callableResolver;
}
/**
* {@inheritdoc}
* @return TContainerInterface
*/
public function getContainer(): ?ContainerInterface
{
return $this->container;
}
/**
* {@inheritdoc}
*/
public function getRouteCollector(): RouteCollectorInterface
{
return $this->routeCollector;
}
/**
* {@inheritdoc}
*/
public function getBasePath(): string
{
return $this->routeCollector->getBasePath();
}
/**
* {@inheritdoc}
*/
public function setBasePath(string $basePath): RouteCollectorProxyInterface
{
$this->routeCollector->setBasePath($basePath);
return $this;
}
/**
* {@inheritdoc}
*/
public function get(string $pattern, $callable): RouteInterface
{
return $this->map(['GET'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function post(string $pattern, $callable): RouteInterface
{
return $this->map(['POST'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function put(string $pattern, $callable): RouteInterface
{
return $this->map(['PUT'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function patch(string $pattern, $callable): RouteInterface
{
return $this->map(['PATCH'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function delete(string $pattern, $callable): RouteInterface
{
return $this->map(['DELETE'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function options(string $pattern, $callable): RouteInterface
{
return $this->map(['OPTIONS'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function any(string $pattern, $callable): RouteInterface
{
return $this->map(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function map(array $methods, string $pattern, $callable): RouteInterface
{
$pattern = $this->groupPattern . $pattern;
return $this->routeCollector->map($methods, $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function group(string $pattern, $callable): RouteGroupInterface
{
$pattern = $this->groupPattern . $pattern;
return $this->routeCollector->group($pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function redirect(string $from, $to, int $status = 302): RouteInterface
{
$responseFactory = $this->responseFactory;
$handler = function () use ($to, $status, $responseFactory) {
$response = $responseFactory->createResponse($status);
return $response->withHeader('Location', (string) $to);
};
return $this->get($from, $handler);
}
}

View File

@@ -0,0 +1,89 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Routing;
use Psr\Http\Message\ServerRequestInterface;
use RuntimeException;
use Slim\Interfaces\RouteInterface;
use Slim\Interfaces\RouteParserInterface;
/** @api */
final class RouteContext
{
public const ROUTE = '__route__';
public const ROUTE_PARSER = '__routeParser__';
public const ROUTING_RESULTS = '__routingResults__';
public const BASE_PATH = '__basePath__';
public static function fromRequest(ServerRequestInterface $serverRequest): self
{
$route = $serverRequest->getAttribute(self::ROUTE);
$routeParser = $serverRequest->getAttribute(self::ROUTE_PARSER);
$routingResults = $serverRequest->getAttribute(self::ROUTING_RESULTS);
$basePath = $serverRequest->getAttribute(self::BASE_PATH);
if ($routeParser === null || $routingResults === null) {
throw new RuntimeException('Cannot create RouteContext before routing has been completed');
}
/** @var RouteInterface|null $route */
/** @var RouteParserInterface $routeParser */
/** @var RoutingResults $routingResults */
/** @var string|null $basePath */
return new self($route, $routeParser, $routingResults, $basePath);
}
private ?RouteInterface $route;
private RouteParserInterface $routeParser;
private RoutingResults $routingResults;
private ?string $basePath;
private function __construct(
?RouteInterface $route,
RouteParserInterface $routeParser,
RoutingResults $routingResults,
?string $basePath = null
) {
$this->route = $route;
$this->routeParser = $routeParser;
$this->routingResults = $routingResults;
$this->basePath = $basePath;
}
public function getRoute(): ?RouteInterface
{
return $this->route;
}
public function getRouteParser(): RouteParserInterface
{
return $this->routeParser;
}
public function getRoutingResults(): RoutingResults
{
return $this->routingResults;
}
public function getBasePath(): string
{
if ($this->basePath === null) {
throw new RuntimeException('No base path defined.');
}
return $this->basePath;
}
}

109
vendor/slim/slim/Slim/Routing/RouteGroup.php vendored Executable file
View File

@@ -0,0 +1,109 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Routing;
use Psr\Http\Server\MiddlewareInterface;
use Slim\Interfaces\AdvancedCallableResolverInterface;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\RouteCollectorProxyInterface;
use Slim\Interfaces\RouteGroupInterface;
use Slim\MiddlewareDispatcher;
class RouteGroup implements RouteGroupInterface
{
/**
* @var callable|string
*/
protected $callable;
protected CallableResolverInterface $callableResolver;
/**
* @var RouteCollectorProxyInterface<\Psr\Container\ContainerInterface|null>
*/
protected RouteCollectorProxyInterface $routeCollectorProxy;
/**
* @var MiddlewareInterface[]|string[]|callable[]
*/
protected array $middleware = [];
protected string $pattern;
/**
* @param callable|string $callable
* @param RouteCollectorProxyInterface<\Psr\Container\ContainerInterface|null> $routeCollectorProxy
*/
public function __construct(
string $pattern,
$callable,
CallableResolverInterface $callableResolver,
RouteCollectorProxyInterface $routeCollectorProxy
) {
$this->pattern = $pattern;
$this->callable = $callable;
$this->callableResolver = $callableResolver;
$this->routeCollectorProxy = $routeCollectorProxy;
}
/**
* {@inheritdoc}
*/
public function collectRoutes(): RouteGroupInterface
{
if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {
$callable = $this->callableResolver->resolveRoute($this->callable);
} else {
$callable = $this->callableResolver->resolve($this->callable);
}
$callable($this->routeCollectorProxy);
return $this;
}
/**
* {@inheritdoc}
*/
public function add($middleware): RouteGroupInterface
{
$this->middleware[] = $middleware;
return $this;
}
/**
* {@inheritdoc}
*/
public function addMiddleware(MiddlewareInterface $middleware): RouteGroupInterface
{
$this->middleware[] = $middleware;
return $this;
}
/**
* {@inheritdoc}
* @param MiddlewareDispatcher<\Psr\Container\ContainerInterface|null> $dispatcher
*/
public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher): RouteGroupInterface
{
foreach ($this->middleware as $middleware) {
$dispatcher->add($middleware);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function getPattern(): string
{
return $this->pattern;
}
}

127
vendor/slim/slim/Slim/Routing/RouteParser.php vendored Executable file
View File

@@ -0,0 +1,127 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Routing;
use FastRoute\RouteParser\Std;
use InvalidArgumentException;
use Psr\Http\Message\UriInterface;
use Slim\Interfaces\RouteCollectorInterface;
use Slim\Interfaces\RouteParserInterface;
use function array_key_exists;
use function array_reverse;
use function http_build_query;
use function implode;
use function is_string;
class RouteParser implements RouteParserInterface
{
private RouteCollectorInterface $routeCollector;
private Std $routeParser;
public function __construct(RouteCollectorInterface $routeCollector)
{
$this->routeCollector = $routeCollector;
$this->routeParser = new Std();
}
/**
* {@inheritdoc}
*/
public function relativeUrlFor(string $routeName, array $data = [], array $queryParams = []): string
{
$route = $this->routeCollector->getNamedRoute($routeName);
$pattern = $route->getPattern();
$segments = [];
$segmentName = '';
/*
* $routes is an associative array of expressions representing a route as multiple segments
* There is an expression for each optional parameter plus one without the optional parameters
* The most specific is last, hence why we reverse the array before iterating over it
*/
$expressions = array_reverse($this->routeParser->parse($pattern));
foreach ($expressions as $expression) {
foreach ($expression as $segment) {
/*
* Each $segment is either a string or an array of strings
* containing optional parameters of an expression
*/
if (is_string($segment)) {
$segments[] = $segment;
continue;
}
/** @var string[] $segment */
/*
* If we don't have a data element for this segment in the provided $data
* we cancel testing to move onto the next expression with a less specific item
*/
if (!array_key_exists($segment[0], $data)) {
$segments = [];
$segmentName = $segment[0];
break;
}
$segments[] = $data[$segment[0]];
}
/*
* If we get to this logic block we have found all the parameters
* for the provided $data which means we don't need to continue testing
* less specific expressions
*/
if (!empty($segments)) {
break;
}
}
if (empty($segments)) {
throw new InvalidArgumentException('Missing data for URL segment: ' . $segmentName);
}
$url = implode('', $segments);
if ($queryParams) {
$url .= '?' . http_build_query($queryParams);
}
return $url;
}
/**
* {@inheritdoc}
*/
public function urlFor(string $routeName, array $data = [], array $queryParams = []): string
{
$basePath = $this->routeCollector->getBasePath();
$url = $this->relativeUrlFor($routeName, $data, $queryParams);
if ($basePath) {
$url = $basePath . $url;
}
return $url;
}
/**
* {@inheritdoc}
*/
public function fullUrlFor(UriInterface $uri, string $routeName, array $data = [], array $queryParams = []): string
{
$path = $this->urlFor($routeName, $data, $queryParams);
$scheme = $uri->getScheme();
$authority = $uri->getAuthority();
$protocol = ($scheme ? $scheme . ':' : '') . ($authority ? '//' . $authority : '');
return $protocol . $path;
}
}

View File

@@ -0,0 +1,56 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Routing;
use RuntimeException;
use Slim\Interfaces\DispatcherInterface;
use Slim\Interfaces\RouteCollectorInterface;
use Slim\Interfaces\RouteInterface;
use Slim\Interfaces\RouteResolverInterface;
use function rawurldecode;
/**
* RouteResolver instantiates the FastRoute dispatcher
* and computes the routing results of a given URI and request method
*/
class RouteResolver implements RouteResolverInterface
{
protected RouteCollectorInterface $routeCollector;
private DispatcherInterface $dispatcher;
public function __construct(RouteCollectorInterface $routeCollector, ?DispatcherInterface $dispatcher = null)
{
$this->routeCollector = $routeCollector;
$this->dispatcher = $dispatcher ?? new Dispatcher($routeCollector);
}
/**
* @param string $uri Should be $request->getUri()->getPath()
*/
public function computeRoutingResults(string $uri, string $method): RoutingResults
{
$uri = rawurldecode($uri);
if ($uri === '' || $uri[0] !== '/') {
$uri = '/' . $uri;
}
return $this->dispatcher->dispatch($method, $uri);
}
/**
* @throws RuntimeException
*/
public function resolveRoute(string $identifier): RouteInterface
{
return $this->routeCollector->lookupRoute($identifier);
}
}

76
vendor/slim/slim/Slim/Routing/RouteRunner.php vendored Executable file
View File

@@ -0,0 +1,76 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Routing;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Exception\HttpMethodNotAllowedException;
use Slim\Exception\HttpNotFoundException;
use Slim\Interfaces\RouteCollectorProxyInterface;
use Slim\Interfaces\RouteParserInterface;
use Slim\Interfaces\RouteResolverInterface;
use Slim\Middleware\RoutingMiddleware;
class RouteRunner implements RequestHandlerInterface
{
private RouteResolverInterface $routeResolver;
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,
?RouteCollectorProxyInterface $routeCollectorProxy = null
) {
$this->routeResolver = $routeResolver;
$this->routeParser = $routeParser;
$this->routeCollectorProxy = $routeCollectorProxy;
}
/**
* This request handler is instantiated automatically in App::__construct()
* It is at the very tip of the middleware queue meaning it will be executed
* last and it detects whether or not routing has been performed in the user
* defined middleware stack. In the event that the user did not perform routing
* it is done here
*
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
// If routing hasn't been done, then do it now so we can dispatch
if ($request->getAttribute(RouteContext::ROUTING_RESULTS) === null) {
$routingMiddleware = new RoutingMiddleware($this->routeResolver, $this->routeParser);
$request = $routingMiddleware->performRouting($request);
}
if ($this->routeCollectorProxy !== null) {
$request = $request->withAttribute(
RouteContext::BASE_PATH,
$this->routeCollectorProxy->getBasePath()
);
}
/** @var Route<\Psr\Container\ContainerInterface|null> $route */
$route = $request->getAttribute(RouteContext::ROUTE);
return $route->run($request);
}
}

View File

@@ -0,0 +1,113 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Routing;
use Slim\Interfaces\DispatcherInterface;
use function rawurldecode;
/** @api */
class RoutingResults
{
public const NOT_FOUND = 0;
public const FOUND = 1;
public const METHOD_NOT_ALLOWED = 2;
protected DispatcherInterface $dispatcher;
protected string $method;
protected string $uri;
/**
* The status is one of the constants shown above
* NOT_FOUND = 0
* FOUND = 1
* METHOD_NOT_ALLOWED = 2
*/
protected int $routeStatus;
protected ?string $routeIdentifier = null;
/**
* @var array<string, string>
*/
protected array $routeArguments;
/**
* @param array<string, string> $routeArguments
*/
public function __construct(
DispatcherInterface $dispatcher,
string $method,
string $uri,
int $routeStatus,
?string $routeIdentifier = null,
array $routeArguments = []
) {
$this->dispatcher = $dispatcher;
$this->method = $method;
$this->uri = $uri;
$this->routeStatus = $routeStatus;
$this->routeIdentifier = $routeIdentifier;
$this->routeArguments = $routeArguments;
}
public function getDispatcher(): DispatcherInterface
{
return $this->dispatcher;
}
public function getMethod(): string
{
return $this->method;
}
public function getUri(): string
{
return $this->uri;
}
public function getRouteStatus(): int
{
return $this->routeStatus;
}
public function getRouteIdentifier(): ?string
{
return $this->routeIdentifier;
}
/**
* @return array<string, string>
*/
public function getRouteArguments(bool $urlDecode = true): array
{
if (!$urlDecode) {
return $this->routeArguments;
}
$routeArguments = [];
foreach ($this->routeArguments as $key => $value) {
$routeArguments[$key] = rawurldecode($value);
}
return $routeArguments;
}
/**
* @return string[]
*/
public function getAllowedMethods(): array
{
return $this->dispatcher->getAllowedMethods($this->uri);
}
}

105
vendor/slim/slim/composer.json vendored Executable file
View File

@@ -0,0 +1,105 @@
{
"name": "slim/slim",
"type": "library",
"description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
"keywords": ["framework","micro","api","router"],
"homepage": "https://www.slimframework.com",
"license": "MIT",
"authors": [
{
"name": "Josh Lockhart",
"email": "hello@joshlockhart.com",
"homepage": "https://joshlockhart.com"
},
{
"name": "Andrew Smith",
"email": "a.smith@silentworks.co.uk",
"homepage": "https://silentworks.co.uk"
},
{
"name": "Rob Allen",
"email": "rob@akrabat.com",
"homepage": "https://akrabat.com"
},
{
"name": "Pierre Berube",
"email": "pierre@lgse.com",
"homepage": "https://www.lgse.com"
},
{
"name": "Gabriel Manricks",
"email": "gmanricks@me.com",
"homepage": "http://gabrielmanricks.com"
}
],
"support": {
"docs": "https://www.slimframework.com/docs/v4/",
"forum": "https://discourse.slimframework.com/",
"irc": "irc://irc.freenode.net:6667/slimphp",
"issues": "https://github.com/slimphp/Slim/issues",
"rss": "https://www.slimframework.com/blog/feed.rss",
"slack": "https://slimphp.slack.com/",
"source": "https://github.com/slimphp/Slim",
"wiki": "https://github.com/slimphp/Slim/wiki"
},
"require": {
"php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
"ext-json": "*",
"nikic/fast-route": "^1.3",
"psr/container": "^1.0 || ^2.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",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"require-dev": {
"ext-simplexml": "*",
"adriansuter/php-autoload-override": "^1.4 || ^2",
"guzzlehttp/psr7": "^2.6",
"httpsoft/http-message": "^1.1",
"httpsoft/http-server-request": "^1.1",
"laminas/laminas-diactoros": "^2.17 || ^3",
"nyholm/psr7": "^1.8",
"nyholm/psr7-server": "^1.1",
"phpspec/prophecy": "^1.19",
"phpspec/prophecy-phpunit": "^2.1",
"phpstan/phpstan": "^1 || ^2",
"phpunit/phpunit": "^9.6",
"slim/http": "^1.3",
"slim/psr7": "^1.6",
"squizlabs/php_codesniffer": "^3.10",
"vimeo/psalm": "^5 || ^6"
},
"autoload": {
"psr-4": {
"Slim\\": "Slim"
}
},
"autoload-dev": {
"psr-4": {
"Slim\\Tests\\": "tests"
}
},
"scripts": {
"test": [
"@phpunit",
"@phpcs",
"@phpstan",
"@psalm"
],
"phpunit": "phpunit",
"phpcs": "phpcs",
"phpstan": "phpstan --memory-limit=-1",
"psalm": "psalm --no-cache"
},
"suggest": {
"ext-simplexml": "Needed to support XML format in BodyParsingMiddleware",
"ext-xml": "Needed to support XML format in BodyParsingMiddleware",
"slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information.",
"php-di/php-di": "PHP-DI is the recommended container library to be used with Slim"
},
"config": {
"sort-packages": true
}
}

17
vendor/slim/slim/psalm.xml vendored Executable file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<psalm
errorLevel="3"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
findUnusedBaselineEntry="true"
findUnusedCode="true"
>
<projectFiles>
<directory name="Slim" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
</psalm>