From 0b125c5a3223afc31e0af35edf0b12bc66b17442 Mon Sep 17 00:00:00 2001 From: radiantjade Date: Fri, 15 May 2026 00:46:09 +0900 Subject: [PATCH] Modernize the PHP dependency stack for maintained runtime support Slim 4 removes the old Slim container, request, response, and error handler APIs, so the app now uses PSR-7/PSR-11 primitives and a small local container while keeping the existing route names and Twig path_for helper stable. phpdotenv and PHPUnit were upgraded at the same time so dependency resolution and the functional tests run on the modern stack. Constraint: Issue #98 requests Slim, phpdotenv, and PHPUnit major upgrades with code changes for breaking APIs Constraint: Docker daemon was unavailable locally, so verification used Homebrew PHP 8.5 with sources:init-provisioned docs Rejected: Keep Slim 3 compatibility wrappers | would leave the requested Slim 4 migration incomplete Rejected: Migrate league/commonmark to 2.x in this PR | separate renderer API migration beyond the requested dependency set Confidence: medium Scope-risk: moderate Directive: Do not remove the path_for Twig compatibility function until templates are migrated to Slim 4 url_for naming Tested: composer validate --strict; composer test; php -l over src tests public Not-tested: Docker compose install/test path because the local Docker daemon was not running --- composer.json | 14 +- composer.lock | 2701 +++++++++++++++++++++++-- src/Container.php | 61 + src/Containers/ErrorHandlers.php | 29 - src/Containers/Logger.php | 6 +- src/Containers/Services.php | 14 +- src/Containers/View.php | 13 +- src/DocsApp.php | 61 +- src/Helpers/SettingsParser.php | 26 +- src/Middlewares/RequestMiddleware.php | 21 +- src/Model/PageRequest.php | 4 +- src/Model/SearchResults.php | 2 + src/Services/TranslationService.php | 4 +- src/Services/VersionsService.php | 6 +- src/Twig/DocExtensions.php | 28 +- src/Views/Base.php | 6 +- src/Views/Doc.php | 15 +- src/Views/Error.php | 6 +- src/Views/NotFound.php | 8 +- src/Views/Search.php | 29 +- src/Views/Stats/NotFoundRequests.php | 10 +- src/Views/Stats/Searches.php | 10 +- tests/BaseTestCase.php | 22 +- tests/Functional/DocTest.php | 4 +- tests/Functional/HomepageTest.php | 6 +- 25 files changed, 2743 insertions(+), 363 deletions(-) create mode 100644 src/Container.php delete mode 100644 src/Containers/ErrorHandlers.php diff --git a/composer.json b/composer.json index df397fe5..335d5549 100644 --- a/composer.json +++ b/composer.json @@ -18,19 +18,21 @@ "ext-sqlite3": "*", "ext-fileinfo": "*", "ext-mbstring": "*", - "slim/slim": "^3.1", - "slim/php-view": "^2.0", - "slim/twig-view": "^2.3", + "slim/slim": "^4", + "slim/php-view": "^3", + "slim/twig-view": "^3", "spatie/yaml-front-matter": "^2.0", "league/commonmark": "^1.5", "caseyamcl/toc": "^3.0", - "vlucas/phpdotenv": "^3.3", + "vlucas/phpdotenv": "^5", "symfony/console": "^5.2", "symfony/process": "^5.2", - "voku/stop-words": "^2.0" + "voku/stop-words": "^2.0", + "slim/psr7": "^1" }, "require-dev": { - "ext-intl": "*" + "ext-intl": "*", + "phpunit/phpunit": "^9" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index ea010d24..ea6e48a9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "309a5cc08a51d2a8c2e9b29f9e585805", + "content-hash": "ea31f088c5e933c1157140768470a873", "packages": [ { "name": "caseyamcl/toc", @@ -141,6 +141,124 @@ }, "time": "2023-08-05T09:42:11+00:00" }, + { + "name": "fig/http-message-util", + "version": "1.1.5", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message-util.git", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "suggest": { + "psr/http-message": "The package containing the PSR-7 interfaces" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Fig\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-message-util/issues", + "source": "https://github.com/php-fig/http-message-util/tree/1.1.5" + }, + "time": "2020-11-24T22:02:12+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.4", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:43:20+00:00" + }, { "name": "knplabs/knp-menu", "version": "v3.3.0", @@ -425,16 +543,16 @@ }, { "name": "phpoption/phpoption", - "version": "1.9.3", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", "shasum": "" }, "require": { @@ -442,7 +560,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" }, "type": "library", "extra": { @@ -484,7 +602,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" }, "funding": [ { @@ -496,38 +614,29 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:41:07+00:00" + "time": "2025-12-27T19:41:33+00:00" }, { - "name": "pimple/pimple", - "version": "v3.5.0", + "name": "psr/container", + "version": "1.1.2", "source": { "type": "git", - "url": "https://github.com/silexphp/Pimple.git", - "reference": "a94b3a4db7fb774b3d78dad2315ddc07629e1bed" + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/silexphp/Pimple/zipball/a94b3a4db7fb774b3d78dad2315ddc07629e1bed", - "reference": "a94b3a4db7fb774b3d78dad2315ddc07629e1bed", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/container": "^1.1 || ^2.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "^5.4@dev" + "php": ">=7.4.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4.x-dev" - } - }, "autoload": { - "psr-0": { - "Pimple": "src/" + "psr-4": { + "Psr\\Container\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -536,42 +645,52 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Pimple, a simple Dependency Injection Container", - "homepage": "https://pimple.symfony.com", + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", "keywords": [ + "PSR-11", "container", - "dependency injection" + "container-interface", + "container-interop", + "psr" ], "support": { - "source": "https://github.com/silexphp/Pimple/tree/v3.5.0" + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" }, - "time": "2021-10-28T11:13:42+00:00" + "time": "2021-11-05T16:50:12+00:00" }, { - "name": "psr/container", - "version": "1.1.2", + "name": "psr/http-factory", + "version": "1.1.0", "source": { "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", "shasum": "" }, "require": { - "php": ">=7.4.0" + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-4": { - "Psr\\Container\\": "src/" + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -584,20 +703,21 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" ], "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" + "source": "https://github.com/php-fig/http-factory" }, - "time": "2021-11-05T16:50:12+00:00" + "time": "2024-04-15T12:06:14+00:00" }, { "name": "psr/http-message", @@ -653,30 +773,32 @@ "time": "2023-04-04T09:50:52+00:00" }, { - "name": "slim/php-view", - "version": "2.2.1", + "name": "psr/http-server-handler", + "version": "1.0.2", "source": { "type": "git", - "url": "https://github.com/slimphp/PHP-View.git", - "reference": "a13ada9d7962ca1b48799c0d9ffbca4c33245aed" + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slimphp/PHP-View/zipball/a13ada9d7962ca1b48799c0d9ffbca4c33245aed", - "reference": "a13ada9d7962ca1b48799c0d9ffbca4c33245aed", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4", "shasum": "" }, "require": { - "psr/http-message": "^1.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8", - "slim/slim": "^3.0" + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-4": { - "Slim\\Views\\": "src" + "Psr\\Http\\Server\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -685,61 +807,55 @@ ], "authors": [ { - "name": "Glenn Eggleton", - "email": "geggleto@gmail.com" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Render PHP view scripts into a PSR-7 Response object.", + "description": "Common interface for HTTP server-side request handler", "keywords": [ - "framework", - "php", - "phtml", - "renderer", - "slim", - "template", - "view" + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" ], "support": { - "issues": "https://github.com/slimphp/PHP-View/issues", - "source": "https://github.com/slimphp/PHP-View/tree/2.2.1" + "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2" }, - "time": "2019-04-15T20:43:28+00:00" + "time": "2023-04-10T20:06:20+00:00" }, { - "name": "slim/slim", - "version": "3.12.5", + "name": "psr/http-server-middleware", + "version": "1.0.2", "source": { "type": "git", - "url": "https://github.com/slimphp/Slim.git", - "reference": "565632b2d9b64ecedf89546edbbf4f3648089f0c" + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim/zipball/565632b2d9b64ecedf89546edbbf4f3648089f0c", - "reference": "565632b2d9b64ecedf89546edbbf4f3648089f0c", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829", "shasum": "" }, "require": { - "ext-json": "*", - "ext-libxml": "*", - "ext-simplexml": "*", - "nikic/fast-route": "^1.0", - "php": ">=5.5.0", - "pimple/pimple": "^3.0", - "psr/container": "^1.0", - "psr/http-message": "^1.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0", - "squizlabs/php_codesniffer": "^3.6.0" + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0", + "psr/http-server-handler": "^1.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-4": { - "Slim\\": "Slim" + "Psr\\Http\\Server\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -748,77 +864,53 @@ ], "authors": [ { - "name": "Josh Lockhart", - "email": "hello@joshlockhart.com", - "homepage": "https://joshlockhart.com" - }, - { - "name": "Andrew Smith", - "email": "a.smith@silentworks.co.uk", - "homepage": "http://silentworks.co.uk" - }, - { - "name": "Rob Allen", - "email": "rob@akrabat.com", - "homepage": "http://akrabat.com" - }, - { - "name": "Gabriel Manricks", - "email": "gmanricks@me.com", - "homepage": "http://gabrielmanricks.com" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", - "homepage": "https://slimframework.com", + "description": "Common interface for HTTP server-side middleware", "keywords": [ - "api", - "framework", - "micro", - "router" + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" ], "support": { - "issues": "https://github.com/slimphp/Slim/issues", - "source": "https://github.com/slimphp/Slim/tree/3.12.5" + "issues": "https://github.com/php-fig/http-server-middleware/issues", + "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2" }, - "funding": [ - { - "url": "https://opencollective.com/slimphp", - "type": "open_collective" - }, - { - "url": "https://tidelift.com/funding/github/packagist/slim/slim", - "type": "tidelift" - } - ], - "time": "2023-07-23T04:32:51+00:00" + "time": "2023-04-11T06:14:47+00:00" }, { - "name": "slim/twig-view", - "version": "2.5.1", + "name": "psr/log", + "version": "1.1.4", "source": { "type": "git", - "url": "https://github.com/slimphp/Twig-View.git", - "reference": "47bd5cc1cbbdf5196d0873ece0ee97c6c7b352e9" + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slimphp/Twig-View/zipball/47bd5cc1cbbdf5196d0873ece0ee97c6c7b352e9", - "reference": "47bd5cc1cbbdf5196d0873ece0ee97c6c7b352e9", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", "shasum": "" }, "require": { - "php": ">=5.5.0", - "psr/http-message": "^1.0", - "twig/twig": "^1.38|^2.7|^3.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8|^5.7", - "slim/slim": "^3.10" + "php": ">=5.3.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, "autoload": { "psr-4": { - "Slim\\Views\\": "src" + "Psr\\Log\\": "Psr/Log/" } }, "notification-url": "https://packagist.org/downloads/", @@ -827,42 +919,401 @@ ], "authors": [ { - "name": "Josh Lockhart", - "email": "hello@joshlockhart.com", - "homepage": "http://joshlockhart.com" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Slim Framework 3 view helper built on top of the Twig 2 templating component", - "homepage": "http://slimframework.com", + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", "keywords": [ - "framework", - "slim", - "template", - "twig", - "view" + "log", + "psr", + "psr-3" ], "support": { - "issues": "https://github.com/slimphp/Twig-View/issues", - "source": "https://github.com/slimphp/Twig-View/tree/master" + "source": "https://github.com/php-fig/log/tree/1.1.4" }, - "time": "2019-11-28T18:03:50+00:00" + "time": "2021-05-03T11:20:27+00:00" }, { - "name": "spatie/yaml-front-matter", - "version": "2.0.9", + "name": "ralouphie/getallheaders", + "version": "3.0.3", "source": { "type": "git", - "url": "https://github.com/spatie/yaml-front-matter.git", - "reference": "cbe67e1cdd0a29a96d74ccab9400fe663e078392" + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/yaml-front-matter/zipball/cbe67e1cdd0a29a96d74ccab9400fe663e078392", - "reference": "cbe67e1cdd0a29a96d74ccab9400fe663e078392", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", "shasum": "" }, "require": { - "php": "^7.0|^8.0", + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "slim/php-view", + "version": "3.4.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/PHP-View.git", + "reference": "ef1821663a6a028b9e446e8c6818fd257bf70313" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/PHP-View/zipball/ef1821663a6a028b9e446e8c6818fd257bf70313", + "reference": "ef1821663a6a028b9e446e8c6818fd257bf70313", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "psr/http-message": "^1.1 || ^2.0" + }, + "require-dev": { + "phpstan/phpstan": "^1", + "phpunit/phpunit": "^9 || ^10", + "slim/psr7": "^1.6", + "squizlabs/php_codesniffer": "^3.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\Views\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Glenn Eggleton", + "email": "geggleto@gmail.com" + } + ], + "description": "Render PHP view scripts into a PSR-7 Response object.", + "keywords": [ + "framework", + "php", + "phtml", + "renderer", + "slim", + "template", + "view" + ], + "support": { + "issues": "https://github.com/slimphp/PHP-View/issues", + "source": "https://github.com/slimphp/PHP-View/tree/3.4.0" + }, + "time": "2024-07-19T18:54:54+00:00" + }, + { + "name": "slim/psr7", + "version": "1.6.2", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim-Psr7.git", + "reference": "5c64088c146673473f5667cbeb501edf5508dfaf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/5c64088c146673473f5667cbeb501edf5508dfaf", + "reference": "5c64088c146673473f5667cbeb501edf5508dfaf", + "shasum": "" + }, + "require": { + "fig/http-message-util": "^1.1.5", + "php": "^7.4 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0", + "symfony/polyfill-php80": "^1.26" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.3", + "ext-json": "*", + "http-interop/http-factory-tests": "^1.0 || ^2.0", + "php-http/psr7-integration-tests": "^1.4", + "phpspec/prophecy": "^1.15", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/phpstan": "^1.8", + "phpunit/phpunit": "^9.5 || ^10", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\Psr7\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "http://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" + } + ], + "description": "Strict PSR-7 implementation", + "homepage": "https://www.slimframework.com", + "keywords": [ + "http", + "psr-7", + "psr7" + ], + "support": { + "issues": "https://github.com/slimphp/Slim-Psr7/issues", + "source": "https://github.com/slimphp/Slim-Psr7/tree/1.6.2" + }, + "time": "2025-03-23T11:43:29+00:00" + }, + { + "name": "slim/slim", + "version": "4.15.1", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim.git", + "reference": "887893516557506f254d950425ce7f5387a26970" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/887893516557506f254d950425ce7f5387a26970", + "reference": "887893516557506f254d950425ce7f5387a26970", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nikic/fast-route": "^1.3", + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "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": { + "adriansuter/php-autoload-override": "^1.4 || ^2", + "ext-simplexml": "*", + "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 || ^10 || ^11 || ^12", + "slim/http": "^1.3", + "slim/psr7": "^1.6", + "squizlabs/php_codesniffer": "^3.10", + "vimeo/psalm": "^5 || ^6" + }, + "suggest": { + "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", + "ext-xml": "Needed to support XML format in BodyParsingMiddleware", + "php-di/php-di": "PHP-DI is the recommended container library to be used with Slim", + "slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information." + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\": "Slim" + } + }, + "notification-url": "https://packagist.org/downloads/", + "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" + } + ], + "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", + "homepage": "https://www.slimframework.com", + "keywords": [ + "api", + "framework", + "micro", + "router" + ], + "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" + }, + "funding": [ + { + "url": "https://opencollective.com/slimphp", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slim/slim", + "type": "tidelift" + } + ], + "time": "2025-11-21T12:23:44+00:00" + }, + { + "name": "slim/twig-view", + "version": "3.4.1", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Twig-View.git", + "reference": "b4268d87d0e327feba5f88d32031e9123655b909" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Twig-View/zipball/b4268d87d0e327feba5f88d32031e9123655b909", + "reference": "b4268d87d0e327feba5f88d32031e9123655b909", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "psr/http-message": "^1.1 || ^2.0", + "slim/slim": "^4.12", + "symfony/polyfill-php81": "^1.29", + "twig/twig": "^3.11" + }, + "require-dev": { + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/phpstan": "^1.10.59", + "phpunit/phpunit": "^9.6 || ^10", + "psr/http-factory": "^1.0", + "squizlabs/php_codesniffer": "^3.9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\Views\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "http://joshlockhart.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" + } + ], + "description": "Slim Framework 4 view helper built on top of the Twig 3 templating component", + "homepage": "https://www.slimframework.com", + "keywords": [ + "framework", + "slim", + "template", + "twig", + "view" + ], + "support": { + "issues": "https://github.com/slimphp/Twig-View/issues", + "source": "https://github.com/slimphp/Twig-View/tree/3.4.1" + }, + "time": "2024-09-26T05:42:02+00:00" + }, + { + "name": "spatie/yaml-front-matter", + "version": "2.0.9", + "source": { + "type": "git", + "url": "https://github.com/spatie/yaml-front-matter.git", + "reference": "cbe67e1cdd0a29a96d74ccab9400fe663e078392" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/yaml-front-matter/zipball/cbe67e1cdd0a29a96d74ccab9400fe663e078392", + "reference": "cbe67e1cdd0a29a96d74ccab9400fe663e078392", + "shasum": "" + }, + "require": { + "php": "^7.0|^8.0", "symfony/yaml": "^3.0|^4.0|^5.0|^6.0|^7.0" }, "require-dev": { @@ -1077,16 +1528,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.31.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + "reference": "141046a8f9477948ff284fa65be2095baafb94f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2", + "reference": "141046a8f9477948ff284fa65be2095baafb94f2", "shasum": "" }, "require": { @@ -1136,7 +1587,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0" }, "funding": [ { @@ -1147,12 +1598,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -1315,19 +1770,20 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.31.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6a21eb99c6973357967f6ce3708cd55a6bec6315", + "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315", "shasum": "" }, "require": { + "ext-iconv": "*", "php": ">=7.2" }, "provide": { @@ -1375,7 +1831,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.37.0" }, "funding": [ { @@ -1386,12 +1842,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-04-10T17:25:58+00:00" }, { "name": "symfony/polyfill-php73", @@ -1471,16 +1931,16 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.31.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411", + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411", "shasum": "" }, "require": { @@ -1531,7 +1991,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0" }, "funding": [ { @@ -1542,16 +2002,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.31.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", @@ -1607,7 +2071,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.37.0" }, "funding": [ { @@ -1618,6 +2082,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -1627,16 +2095,16 @@ }, { "name": "symfony/process", - "version": "v5.4.47", + "version": "v5.4.51", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "5d1662fb32ebc94f17ddb8d635454a776066733d" + "reference": "467bfc56f18f5ef6d5ccb09324d7e988c1c0a98f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/5d1662fb32ebc94f17ddb8d635454a776066733d", - "reference": "5d1662fb32ebc94f17ddb8d635454a776066733d", + "url": "https://api.github.com/repos/symfony/process/zipball/467bfc56f18f5ef6d5ccb09324d7e988c1c0a98f", + "reference": "467bfc56f18f5ef6d5ccb09324d7e988c1c0a98f", "shasum": "" }, "require": { @@ -1669,7 +2137,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.47" + "source": "https://github.com/symfony/process/tree/v5.4.51" }, "funding": [ { @@ -1680,12 +2148,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-06T11:36:42+00:00" + "time": "2026-01-26T15:53:37+00:00" }, { "name": "symfony/service-contracts", @@ -2013,36 +2485,43 @@ }, { "name": "vlucas/phpdotenv", - "version": "v3.6.10", + "version": "v5.6.3", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "5b547cdb25825f10251370f57ba5d9d924e6f68e" + "reference": "955e7815d677a3eaa7075231212f2110983adecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/5b547cdb25825f10251370f57ba5d9d924e6f68e", - "reference": "5b547cdb25825f10251370f57ba5d9d924e6f68e", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", "shasum": "" }, "require": { - "php": "^5.4 || ^7.0 || ^8.0", - "phpoption/phpoption": "^1.5.2", - "symfony/polyfill-ctype": "^1.17" + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.4", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" }, "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", "ext-filter": "*", - "ext-pcre": "*", - "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.21" + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" }, "suggest": { - "ext-filter": "Required to use the boolean validator.", - "ext-pcre": "Required to use most of the library." + "ext-filter": "Required to use the boolean validator." }, "type": "library", "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, "branch-alias": { - "dev-master": "3.6-dev" + "dev-master": "5.6-dev" } }, "autoload": { @@ -2074,7 +2553,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v3.6.10" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" }, "funding": [ { @@ -2086,7 +2565,7 @@ "type": "tidelift" } ], - "time": "2021-12-12T23:02:06+00:00" + "time": "2025-12-27T19:49:13+00:00" }, { "name": "voku/stop-words", @@ -2136,10 +2615,1808 @@ "time": "2018-11-23T01:37:27+00:00" } ], - "packages-dev": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.30 || ^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.5.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:15:36+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.7.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" + }, + "time": "2025-12-06T11:56:16+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.32", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.19.1 || ^5.1.0", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.6" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-08-22T04:23:01+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.34", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "b36f02317466907a230d3aa1d34467041271ef4a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b36f02317466907a230d3aa1d34467041271ef4a", + "reference": "b36f02317466907a230d3aa1d34467041271ef4a", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.5.0 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.32", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", + "sebastian/comparator": "^4.0.10", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.8", + "sebastian/global-state": "^5.0.8", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.34" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2026-01-27T05:45:00+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:27:43+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.10", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e4df00b9b3571187db2831ae9aada2c6efbd715d", + "reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.10" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" + } + ], + "time": "2026-01-24T09:22:56+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:19:30+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:30:58+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/14c6ba52f95a36c3d27c835d65efc7123c446e8c", + "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" + } + ], + "time": "2025-09-24T06:03:27+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6", + "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" + } + ], + "time": "2025-08-10T07:10:35+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:20:34+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "539c6691e0623af6dc6f9c20384c120f963465a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0", + "reference": "539c6691e0623af6dc6f9c20384c120f963465a0", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" + } + ], + "time": "2025-08-10T06:57:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-14T16:00:52+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2025-11-17T20:03:58+00:00" + } + ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -2156,5 +4433,5 @@ "platform-overrides": { "php": "7.4.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/src/Container.php b/src/Container.php new file mode 100644 index 00000000..d9f2a81e --- /dev/null +++ b/src/Container.php @@ -0,0 +1,61 @@ +entries = $entries; + } + + public function get($id) + { + if (!$this->has($id)) { + throw new \RuntimeException(sprintf('Container entry "%s" was not found.', $id)); + } + + if (!array_key_exists($id, $this->resolved)) { + $entry = $this->entries[$id]; + $this->resolved[$id] = is_callable($entry) ? $entry($this) : $entry; + } + + return $this->resolved[$id]; + } + + public function has($id): bool + { + return array_key_exists($id, $this->entries); + } + + #[\ReturnTypeWillChange] + public function offsetExists($offset): bool + { + return $this->has($offset); + } + + #[\ReturnTypeWillChange] + public function offsetGet($offset) + { + return $this->get($offset); + } + + #[\ReturnTypeWillChange] + public function offsetSet($offset, $value): void + { + $this->entries[$offset] = $value; + unset($this->resolved[$offset]); + } + + #[\ReturnTypeWillChange] + public function offsetUnset($offset): void + { + unset($this->entries[$offset], $this->resolved[$offset]); + } +} diff --git a/src/Containers/ErrorHandlers.php b/src/Containers/ErrorHandlers.php deleted file mode 100644 index f7cbb450..00000000 --- a/src/Containers/ErrorHandlers.php +++ /dev/null @@ -1,29 +0,0 @@ -get($request, $response); - }; - }; - $container['errorHandler'] = $container['phpErrorHandler'] = function ($container) { - return function ($request, $response, $exception) use ($container) { - $pageNotFound = new Error($container, $exception); - - return $pageNotFound->get($request, $response); - }; - }; - } -} diff --git a/src/Containers/Logger.php b/src/Containers/Logger.php index 3ae452b6..4639005a 100644 --- a/src/Containers/Logger.php +++ b/src/Containers/Logger.php @@ -5,11 +5,11 @@ use Monolog\Logger as MonologLogger; use Monolog\Processor\UidProcessor; use Monolog\Handler\StreamHandler; -use Slim\Container; +use Psr\Container\ContainerInterface; class Logger { - public static function load(Container $container) + public static function load(ContainerInterface $container) { $container['logger'] = function () { @@ -24,4 +24,4 @@ public static function load(Container $container) return $logger; }; } -} \ No newline at end of file +} diff --git a/src/Containers/Services.php b/src/Containers/Services.php index e51bec55..caab1ff9 100644 --- a/src/Containers/Services.php +++ b/src/Containers/Services.php @@ -5,7 +5,7 @@ use MODXDocs\Services\IndexService; use MODXDocs\Services\SearchService; use MODXDocs\Services\TranslationService; -use Slim\Container; +use Psr\Container\ContainerInterface; use MODXDocs\Services\FilePathService; use MODXDocs\Services\DocumentService; @@ -13,39 +13,39 @@ class Services { - public static function load(Container $container): void + public static function load(ContainerInterface $container): void { $container[FilePathService::class] = function () { return new FilePathService(); }; - $container[DocumentService::class] = function (Container $container) { + $container[DocumentService::class] = function (ContainerInterface $container) { return new DocumentService( $container->get(FilePathService::class), $container->get('db') ); }; - $container[VersionsService::class] = function (Container $container) { + $container[VersionsService::class] = function (ContainerInterface $container) { return new VersionsService( $container->get('router') ); }; - $container[TranslationService::class] = function (Container $container) { + $container[TranslationService::class] = function (ContainerInterface $container) { return new TranslationService( $container->get('db'), $container->get('router') ); }; - $container[SearchService::class] = function (Container $container) { + $container[SearchService::class] = function (ContainerInterface $container) { return new SearchService( $container->get('db'), $container->get(DocumentService::class) ); }; - $container[IndexService::class] = function (Container $container) { + $container[IndexService::class] = function (ContainerInterface $container) { return new IndexService( $container->get('db'), $container->get(DocumentService::class) diff --git a/src/Containers/View.php b/src/Containers/View.php index 569f678f..76c0415d 100644 --- a/src/Containers/View.php +++ b/src/Containers/View.php @@ -4,7 +4,6 @@ use Psr\Container\ContainerInterface; use Slim\Views\Twig; -use Slim\Views\TwigExtension; use Twig\Extension\DebugExtension; use MODXDocs\Twig\DocExtensions; @@ -16,20 +15,12 @@ class View public static function load(ContainerInterface $container) { $container['view'] = function (ContainerInterface $container) { - $request = $container->get('request'); - $router = $container->get('router'); - - $view = new Twig(getenv('TEMPLATE_DIRECTORY'), [ + $view = Twig::create(getenv('TEMPLATE_DIRECTORY'), [ 'cache' => getenv('DEV') === '1' ? false : getenv('CACHE_DIRECTORY') . '/twig', 'debug' => true, ]); $view->addExtension(new DebugExtension()); - - - // Instantiate and add Slim specific extension - $basePath = rtrim(str_ireplace(static::BASE_REQUEST_HANDLER, '', $request->getUri()->getBasePath()), '/'); - $view->addExtension(new TwigExtension($router, $basePath)); - $view->addExtension(new DocExtensions($router, $request)); + $view->addExtension(new DocExtensions($container->get('router'))); return $view; }; diff --git a/src/DocsApp.php b/src/DocsApp.php index b307491b..8c11b9b7 100644 --- a/src/DocsApp.php +++ b/src/DocsApp.php @@ -7,27 +7,37 @@ use MODXDocs\Views\Stats\NotFoundRequests; use MODXDocs\Views\Stats\Searches; use Slim\App; -use Slim\Http\Request; -use Slim\Http\Response; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Slim\Exception\HttpMethodNotAllowedException; +use Slim\Exception\HttpNotFoundException; +use Slim\Factory\AppFactory; use MODXDocs\Containers\View; -use MODXDocs\Containers\ErrorHandlers; use MODXDocs\Containers\Logger; use MODXDocs\Containers\Services; use MODXDocs\Middlewares\RequestMiddleware; use MODXDocs\Views\Doc; +use MODXDocs\Views\Error; +use MODXDocs\Views\NotFound; class DocsApp { /** @var App */ private $app; + /** @var Container */ + private $container; public function __construct(array $settings) { - $this->app = new App($settings); + $this->container = new Container($settings); + $this->app = AppFactory::create(null, $this->container); + $this->container['router'] = function () { + return $this->app->getRouteCollector()->getRouteParser(); + }; - $this->routes(); $this->dependencies(); + $this->routes(); $this->middlewares(); } @@ -43,6 +53,40 @@ private function routes() private function middlewares() { $this->app->add(new RequestMiddleware()); + $container = $this->container; + $responseFactory = $this->app->getResponseFactory(); + + $errorMiddleware = $this->app->addErrorMiddleware( + (bool)$this->container->get('settings')['displayErrorDetails'], + true, + true + ); + $errorMiddleware->setDefaultErrorHandler(function ( + ServerRequestInterface $request, + \Throwable $exception + ) use ($container, $responseFactory): ResponseInterface { + return (new Error($container, $exception))->get( + $request, + $responseFactory->createResponse() + ); + }); + $errorMiddleware->setErrorHandler(HttpNotFoundException::class, function ( + ServerRequestInterface $request + ) use ($container, $responseFactory): ResponseInterface { + return (new NotFound($container))->get( + $request, + $responseFactory->createResponse() + ); + }); + $errorMiddleware->setErrorHandler(HttpMethodNotAllowedException::class, function ( + ServerRequestInterface $request, + HttpMethodNotAllowedException $exception + ) use ($responseFactory): ResponseInterface { + $response = $responseFactory->createResponse(405); + $response->getBody()->write($exception->getMessage()); + + return $response; + }); } private function dependencies() @@ -50,7 +94,6 @@ private function dependencies() $containers = [ DB::class, View::class, - ErrorHandlers::class, Logger::class, Services::class ]; @@ -62,7 +105,7 @@ private function dependencies() public function getContainer() { - return $this->app->getContainer(); + return $this->container; } public function run() @@ -70,9 +113,9 @@ public function run() $this->app->run(); } - public function process(Request $request, Response $response) + public function process(ServerRequestInterface $request): ResponseInterface { - return $this->app->process($request, $response); + return $this->app->handle($request); } } diff --git a/src/Helpers/SettingsParser.php b/src/Helpers/SettingsParser.php index b9b325a5..b09efe89 100644 --- a/src/Helpers/SettingsParser.php +++ b/src/Helpers/SettingsParser.php @@ -13,8 +13,12 @@ public function __construct() { $baseDir = dirname(dirname(__DIR__)) . '/'; $dotFile = static::getDotFile($baseDir); - $dotEnv = Dotenv::create($baseDir, $dotFile); - $dotEnv->load(); + $dotEnv = Dotenv::createUnsafeImmutable($baseDir, $dotFile); + $dotEnv->safeLoad(); + + if (!is_dir((string)getenv('BASE_DIRECTORY'))) { + $this->setLocalPaths($baseDir); + } } public function getSlimConfig() @@ -35,4 +39,20 @@ private static function getDotFile($baseDir) return SettingsParser::DEV_FILE; } -} \ No newline at end of file + + private function setLocalPaths(string $baseDir): void + { + $paths = [ + 'BASE_DIRECTORY' => $baseDir, + 'DOCS_DIRECTORY' => $baseDir . 'docs/', + 'TEMPLATE_DIRECTORY' => $baseDir . 'templates/', + 'CACHE_DIRECTORY' => $baseDir . 'cache', + ]; + + foreach ($paths as $key => $value) { + $_ENV[$key] = $value; + $_SERVER[$key] = $value; + putenv($key . '=' . $value); + } + } +} diff --git a/src/Middlewares/RequestMiddleware.php b/src/Middlewares/RequestMiddleware.php index 0b8a41f1..b5859f2f 100644 --- a/src/Middlewares/RequestMiddleware.php +++ b/src/Middlewares/RequestMiddleware.php @@ -2,12 +2,15 @@ namespace MODXDocs\Middlewares; -use Slim\Http\Response; -use Slim\Http\Request; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; +use Slim\Psr7\Response; -class RequestMiddleware +class RequestMiddleware implements MiddlewareInterface { - public function __invoke(Request $request, Response $response, $next) + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $uri = $request->getUri(); $path = $uri->getPath(); @@ -18,12 +21,14 @@ public function __invoke(Request $request, Response $response, $next) $uri = $uri->withPath(substr($path, 0, -1)); if ($request->getMethod() === 'GET') { - return $response->withRedirect((string)$uri, 301); + return (new Response()) + ->withHeader('Location', (string)$uri) + ->withStatus(301); } - return $next($request->withUri($uri), $response); + return $handler->handle($request->withUri($uri)); } - return $next($request, $response); + return $handler->handle($request); } -} \ No newline at end of file +} diff --git a/src/Model/PageRequest.php b/src/Model/PageRequest.php index 629d99a8..1d8a1b34 100644 --- a/src/Model/PageRequest.php +++ b/src/Model/PageRequest.php @@ -4,7 +4,7 @@ namespace MODXDocs\Model; use MODXDocs\Services\VersionsService; -use Slim\Http\Request; +use Psr\Http\Message\ServerRequestInterface; class PageRequest { private $version; @@ -20,7 +20,7 @@ public function __construct(string $version, string $language, string $path) $this->versionBranch = $this->version === VersionsService::getCurrentVersion() ? VersionsService::getCurrentVersionBranch() : $this->version; } - public static function fromRequest(Request $request): self + public static function fromRequest(ServerRequestInterface $request): self { return new static( $request->getAttribute('version', VersionsService::getCurrentVersion()), diff --git a/src/Model/SearchResults.php b/src/Model/SearchResults.php index c8a4ebf7..1aab833b 100644 --- a/src/Model/SearchResults.php +++ b/src/Model/SearchResults.php @@ -19,6 +19,8 @@ class SearchResults { private $resultDetails = []; private $results = []; + private $exactTerms = []; + private $fuzzyTerms = []; public function __construct(DocumentService $documentService, SearchQuery $query) { diff --git a/src/Services/TranslationService.php b/src/Services/TranslationService.php index ad587461..71129a18 100644 --- a/src/Services/TranslationService.php +++ b/src/Services/TranslationService.php @@ -3,7 +3,7 @@ namespace MODXDocs\Services; use MODXDocs\Model\PageRequest; -use Slim\Router; +use Slim\Interfaces\RouteParserInterface; class TranslationService { @@ -12,7 +12,7 @@ class TranslationService */ private $db; - public function __construct(\PDO $db, Router $router) + public function __construct(\PDO $db, RouteParserInterface $router) { $this->db = $db; } diff --git a/src/Services/VersionsService.php b/src/Services/VersionsService.php index c54d6ba4..e7e95396 100644 --- a/src/Services/VersionsService.php +++ b/src/Services/VersionsService.php @@ -3,7 +3,7 @@ namespace MODXDocs\Services; use MODXDocs\Model\PageRequest; -use Slim\Router; +use Slim\Interfaces\RouteParserInterface; class VersionsService { @@ -14,7 +14,7 @@ class VersionsService private $router; - public function __construct(Router $router) + public function __construct(RouteParserInterface $router) { $this->router = $router; } @@ -82,7 +82,7 @@ private function createVersion(PageRequest $request, \DirectoryIterator $fileInf 'title' => static::getVersionTitle($fileInfo->getFilename()), 'active' => $versionKey === $request->getVersion(), 'key' => $versionKey, - 'uri' => $this->router->pathFor('documentation', [ + 'uri' => $this->router->urlFor('documentation', [ 'version' => $versionKey, 'language' => $request->getLanguage(), 'path' => $request->getPath(), diff --git a/src/Twig/DocExtensions.php b/src/Twig/DocExtensions.php index 3e88646b..6e5ab774 100644 --- a/src/Twig/DocExtensions.php +++ b/src/Twig/DocExtensions.php @@ -3,34 +3,50 @@ namespace MODXDocs\Twig; use MODXDocs\Views\Base; +use Psr\Http\Message\ServerRequestInterface; +use Slim\Interfaces\RouteParserInterface; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; -use Slim\Http\Request; -use Slim\Interfaces\RouterInterface; class DocExtensions extends AbstractExtension { + /** @var RouteParserInterface */ private $router; - private $request; + /** @var ServerRequestInterface|null */ + private static $request; - public function __construct(RouterInterface $router, Request $request) + public function __construct(RouteParserInterface $router) { $this->router = $router; - $this->request = $request; + } + + public static function setRequest(ServerRequestInterface $request): void + { + static::$request = $request; } public function getFunctions() { return [ + new TwigFunction('path_for', [$this, 'pathFor']), new TwigFunction('base_href', [$this, 'getBaseHref']), new TwigFunction('icon', [$this, 'getInlineSvg'], ['is_safe' => ['html']]), ]; } + public function pathFor(string $routeName, array $data = [], array $queryParams = []): string + { + return $this->router->urlFor($routeName, $data, $queryParams); + } + public function getBaseHref() { $scheme = getenv('SSL') === '1' ? 'https' : 'http'; - $uri = $this->request->getUri(); + if (!static::$request) { + return $scheme . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost') . '/'; + } + + $uri = static::$request->getUri(); $port = \in_array($uri->getPort(), [80, 443, null], true) ? '' : (':' . $uri->getPort()); return $scheme . '://' . $uri->getHost() . $port . '/'; diff --git a/src/Views/Base.php b/src/Views/Base.php index cd54c2d2..4b75800e 100644 --- a/src/Views/Base.php +++ b/src/Views/Base.php @@ -5,8 +5,9 @@ use MODXDocs\Model\PageRequest; use MODXDocs\Services\CacheService; use MODXDocs\Services\VersionsService; -use Slim\Http\Request; -use Slim\Http\Response; +use MODXDocs\Twig\DocExtensions; +use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Message\ResponseInterface as Response; use Slim\Views\Twig; use Psr\Container\ContainerInterface; @@ -30,6 +31,7 @@ public function __construct(ContainerInterface $container) protected function render(Request $request, Response $response, $template, array $data = []): \Psr\Http\Message\ResponseInterface { + DocExtensions::setRequest($request); $pageRequest = PageRequest::fromRequest($request); $initialData = [ diff --git a/src/Views/Doc.php b/src/Views/Doc.php index 858fb75a..c3857aa8 100644 --- a/src/Views/Doc.php +++ b/src/Views/Doc.php @@ -7,12 +7,13 @@ use MODXDocs\Model\PageRequest; use MODXDocs\Services\TranslationService; use Psr\Container\ContainerInterface; -use Slim\Http\Request; -use Slim\Http\Response; +use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Message\ResponseInterface as Response; use MODXDocs\Services\DocumentService; use MODXDocs\Services\VersionsService; -use Slim\Http\Stream; +use Slim\Exception\HttpNotFoundException; +use Slim\Psr7\Stream; class Doc extends Base { @@ -33,7 +34,7 @@ public function __construct(ContainerInterface $container) * @param Request $request * @param Response $response * @return \Psr\Http\Message\ResponseInterface - * @throws \Slim\Exception\NotFoundException + * @throws HttpNotFoundException */ public function get(Request $request, Response $response) { @@ -47,7 +48,7 @@ public function get(Request $request, Response $response) if (file_exists($filePath)) { return $this->renderFile($request, $response, $filePath); } - throw new \Slim\Exception\NotFoundException($request, $response); + throw new HttpNotFoundException($request); } $crumbs = []; @@ -107,7 +108,7 @@ private function getTranslations(PageRequest $pageRequest) * @param Response $response * @param $filePath * @return Response - * @throws \Slim\Exception\NotFoundException + * @throws HttpNotFoundException */ protected function renderFile(Request $request, Response $response, $filePath): Response { @@ -132,7 +133,7 @@ protected function renderFile(Request $request, Response $response, $filePath): ->withHeader('ETag', $etag); } - throw new \Slim\Exception\NotFoundException($request, $response); + throw new HttpNotFoundException($request); } private function getSuggestedLanguages(Request $request, PageRequest $pageRequest) diff --git a/src/Views/Error.php b/src/Views/Error.php index 75236d1a..f7fb51f4 100644 --- a/src/Views/Error.php +++ b/src/Views/Error.php @@ -3,9 +3,10 @@ namespace MODXDocs\Views; use MODXDocs\Model\PageRequest; +use MODXDocs\Twig\DocExtensions; use Psr\Container\ContainerInterface; -use Slim\Http\Request; -use Slim\Http\Response; +use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Message\ResponseInterface as Response; use MODXDocs\Exceptions\RedirectNotFoundException; use MODXDocs\Helpers\Redirector; @@ -22,6 +23,7 @@ public function __construct(ContainerInterface $container, \Throwable $e) public function get(Request $request, Response $response) { + DocExtensions::setRequest($request); $pageRequest = PageRequest::fromRequest($request); diff --git a/src/Views/NotFound.php b/src/Views/NotFound.php index 6b9218b6..559bab31 100644 --- a/src/Views/NotFound.php +++ b/src/Views/NotFound.php @@ -9,8 +9,8 @@ use MODXDocs\Services\VersionsService; use PDO; use Psr\Container\ContainerInterface; -use Slim\Http\Request; -use Slim\Http\Response; +use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Message\ResponseInterface as Response; use MODXDocs\Exceptions\RedirectNotFoundException; use MODXDocs\Helpers\Redirector; @@ -39,13 +39,13 @@ public function get(Request $request, Response $response) // Make sure links ending in .md get redirected if (substr($currentUri, -strlen(static::MARKDOWN_SUFFIX)) === static::MARKDOWN_SUFFIX) { $uri = substr($currentUri, 0, -strlen(static::MARKDOWN_SUFFIX)); - return $response->withRedirect($uri, 301); + return $response->withHeader('Location', $uri)->withStatus(301); } try { $redirectUri = Redirector::findNewURI($currentUri); - return $response->withRedirect($redirectUri, 301); + return $response->withHeader('Location', $redirectUri)->withStatus(301); } catch (RedirectNotFoundException $e) { $this->logNotFoundRequest($currentUri); diff --git a/src/Views/Search.php b/src/Views/Search.php index 0a91fd52..35f35607 100644 --- a/src/Views/Search.php +++ b/src/Views/Search.php @@ -9,13 +9,13 @@ use MODXDocs\Services\SearchService; use MODXDocs\Services\VersionsService; use Psr\Container\ContainerInterface; -use Slim\Http\Request; -use Slim\Http\Response; -use Slim\Router; +use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Message\ResponseInterface as Response; +use Slim\Interfaces\RouteParserInterface; class Search extends Base { - /** @var Router */ + /** @var RouteParserInterface */ private $router; /** @var SearchService */ @@ -39,22 +39,23 @@ public function get(Request $request, Response $response) // The PageRequest gives us the version/language/etc. $pageRequest = PageRequest::fromRequest($request); - $query = trim((string)$request->getParam('q', '')); + $params = $request->getQueryParams(); + $query = trim((string)($params['q'] ?? '')); $title = 'Search the documentation'; - $live = (bool)$request->getParam('live'); + $live = (bool)($params['live'] ?? false); $crumbs = []; $crumbs[] = [ 'title' => 'Search ' . $pageRequest->getVersion(), // @todo i18n - 'href' => $this->router->pathFor('search', ['version' => $pageRequest->getVersion(), 'language' => $pageRequest->getLanguage()]) + 'href' => $this->router->urlFor('search', ['version' => $pageRequest->getVersion(), 'language' => $pageRequest->getLanguage()]) ]; $searchValues = []; if (!empty($query)) { $crumbs[] = [ 'title' => '"' . $query . '"', - 'href' => $this->router->pathFor('search', ['version' => $pageRequest->getVersion(), 'language' => $pageRequest->getLanguage()], ['q' => $query]) + 'href' => $this->router->urlFor('search', ['version' => $pageRequest->getVersion(), 'language' => $pageRequest->getLanguage()], ['q' => $query]) ]; $startTime = microtime(true); @@ -64,7 +65,7 @@ public function get(Request $request, Response $response) $resultCount = $result->getCount(); $limit = 10; - $page = abs((int)$request->getParam('page', 1)); + $page = abs((int)($params['page'] ?? 1)); $totalPages = ceil($resultCount / $limit); $start = 0 + ($page - 1) * $limit; @@ -125,7 +126,7 @@ protected function getPagination(int $page, PageRequest $pageRequest, string $qu $looped++; $pagination[] = [ 'page' => $prev, - 'href' => $this->router->pathFor('search', + 'href' => $this->router->urlFor('search', ['version' => $pageRequest->getVersion(), 'language' => $pageRequest->getLanguage()], ['q' => $query, 'page' => $prev]) ]; @@ -135,7 +136,7 @@ protected function getPagination(int $page, PageRequest $pageRequest, string $qu if ($page > 1) { $pagination[] = [ 'page' => 'First', - 'href' => $this->router->pathFor('search', + 'href' => $this->router->urlFor('search', ['version' => $pageRequest->getVersion(), 'language' => $pageRequest->getLanguage()], ['q' => $query]) ]; @@ -147,7 +148,7 @@ protected function getPagination(int $page, PageRequest $pageRequest, string $qu $pagination[] = [ 'current' => true, 'page' => $page, - 'href' => $this->router->pathFor('search', + 'href' => $this->router->urlFor('search', ['version' => $pageRequest->getVersion(), 'language' => $pageRequest->getLanguage()], ['q' => $query, 'page' => $page]) ]; @@ -158,7 +159,7 @@ protected function getPagination(int $page, PageRequest $pageRequest, string $qu $looped++; $pagination[] = [ 'page' => $next, - 'href' => $this->router->pathFor('search', + 'href' => $this->router->urlFor('search', ['version' => $pageRequest->getVersion(), 'language' => $pageRequest->getLanguage()], ['q' => $query, 'page' => $next]) ]; @@ -169,7 +170,7 @@ protected function getPagination(int $page, PageRequest $pageRequest, string $qu $pagination[] = [ 'page' => 'Last', - 'href' => $this->router->pathFor('search', + 'href' => $this->router->urlFor('search', ['version' => $pageRequest->getVersion(), 'language' => $pageRequest->getLanguage()], ['q' => $query, 'page' => $totalPages]) ]; diff --git a/src/Views/Stats/NotFoundRequests.php b/src/Views/Stats/NotFoundRequests.php index 46291c4f..247ba874 100644 --- a/src/Views/Stats/NotFoundRequests.php +++ b/src/Views/Stats/NotFoundRequests.php @@ -6,9 +6,9 @@ use MODXDocs\Services\CacheService; use MODXDocs\Views\Base; use Psr\Container\ContainerInterface; -use Slim\Http\Request; -use Slim\Http\Response; -use Slim\Router; +use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Message\ResponseInterface as Response; +use Slim\Interfaces\RouteParserInterface; class NotFoundRequests extends Base { @@ -18,7 +18,7 @@ class NotFoundRequests extends Base private $cache; /** @var DB */ private $db; - /** @var Router */ + /** @var RouteParserInterface */ private $router; public function __construct(ContainerInterface $container) @@ -40,7 +40,7 @@ public function get(Request $request, Response $response) $crumbs = []; $crumbs[] = [ 'title' => 'Page Not Found Errors', // @todo i18n - 'href' => $this->router->pathFor('stats/page-not-found') + 'href' => $this->router->urlFor('stats/page-not-found') ]; $phs = [ diff --git a/src/Views/Stats/Searches.php b/src/Views/Stats/Searches.php index bf3ef521..dcf8c24e 100644 --- a/src/Views/Stats/Searches.php +++ b/src/Views/Stats/Searches.php @@ -7,9 +7,9 @@ use MODXDocs\Services\CacheService; use MODXDocs\Views\Base; use Psr\Container\ContainerInterface; -use Slim\Http\Request; -use Slim\Http\Response; -use Slim\Router; +use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Message\ResponseInterface as Response; +use Slim\Interfaces\RouteParserInterface; class Searches extends Base { @@ -19,7 +19,7 @@ class Searches extends Base private $cache; /** @var DB */ private $db; - /** @var Router */ + /** @var RouteParserInterface */ private $router; public function __construct(ContainerInterface $container) @@ -41,7 +41,7 @@ public function get(Request $request, Response $response) $crumbs = []; $crumbs[] = [ 'title' => 'Search Statistics', // @todo i18n - 'href' => $this->router->pathFor('stats/searches') + 'href' => $this->router->urlFor('stats/searches') ]; $startTime = microtime(true); diff --git a/tests/BaseTestCase.php b/tests/BaseTestCase.php index c0dc4932..3f8e6d6b 100644 --- a/tests/BaseTestCase.php +++ b/tests/BaseTestCase.php @@ -4,9 +4,7 @@ namespace Tests; use PHPUnit\Framework\TestCase; -use Slim\Http\Request; -use Slim\Http\Response; -use Slim\Http\Environment; +use Slim\Psr7\Factory\ServerRequestFactory; /** * This is an example class that shows how you could set up a method that @@ -29,32 +27,20 @@ class BaseTestCase extends TestCase * @param string $requestMethod the request method (e.g. GET, POST, etc.) * @param string $requestUri the request URI * @param array|object|null $requestData the request data - * @return \Slim\Http\Response + * @return \Psr\Http\Message\ResponseInterface */ public function runApp($requestMethod, $requestUri, $requestData = null) { global $app; - // Create a mock environment for testing with - $environment = Environment::mock( - [ - 'REQUEST_METHOD' => $requestMethod, - 'REQUEST_URI' => $requestUri - ] - ); - - // Set up a request object based on the environment - $request = Request::createFromEnvironment($environment); + $request = (new ServerRequestFactory())->createServerRequest($requestMethod, $requestUri); // Add request data, if it exists if ($requestData !== null) { $request = $request->withParsedBody($requestData); } - // Set up a response object - $response = new Response(); - // Process the application - $response = $app->process($request, $response); + $response = $app->process($request); // Return the response return $response; diff --git a/tests/Functional/DocTest.php b/tests/Functional/DocTest.php index 7eeced98..ae0750e9 100644 --- a/tests/Functional/DocTest.php +++ b/tests/Functional/DocTest.php @@ -12,7 +12,7 @@ public function testGetGettingStarted() : void $response = $this->runApp('GET', '/2.x/en/getting-started'); $this->assertEquals(200, $response->getStatusCode()); - $this->assertContains('Welcome to MODX Revolution', (string)$response->getBody()); - $this->assertNotContains('WordPress', (string)$response->getBody()); + $this->assertStringContainsString('Welcome to MODX Revolution', (string)$response->getBody()); + $this->assertStringNotContainsString('WordPress', (string)$response->getBody()); } } diff --git a/tests/Functional/HomepageTest.php b/tests/Functional/HomepageTest.php index fb87989e..61fa3044 100644 --- a/tests/Functional/HomepageTest.php +++ b/tests/Functional/HomepageTest.php @@ -15,8 +15,8 @@ public function testGetHomepageWithoutName() : void $response = $this->runApp('GET', '/'); $this->assertEquals(200, $response->getStatusCode()); - $this->assertContains('Creative Freedom', (string)$response->getBody()); - $this->assertNotContains('Hello', (string)$response->getBody()); + $this->assertStringContainsString('Creative Freedom', (string)$response->getBody()); + $this->assertStringNotContainsString('Hello', (string)$response->getBody()); } /** @@ -27,6 +27,6 @@ public function testPostHomepageNotAllowed() : void $response = $this->runApp('POST', '/', ['test']); $this->assertEquals(405, $response->getStatusCode()); - $this->assertContains('Method not allowed', (string)$response->getBody()); + $this->assertStringContainsString('Method not allowed', (string)$response->getBody()); } }