From d1f47eeec21b9a422fda6f7b91d1953c1b9bafe8 Mon Sep 17 00:00:00 2001 From: Martin Dumoulin Date: Thu, 26 Feb 2026 12:02:13 +0100 Subject: [PATCH 1/7] Lot of change --- .github/workflows/project-ci.yml | 28 + .github/workflows/project-sonar.yml | 26 + .travis.yml | 8 - CONTRIBUTE.md | 33 + composer.json | 37 +- composer.lock | 5061 ++++++++++++++++++++++++--- phpdoc.dist.xml | 12 - phpstan.neon | 4 + phpunit.xml | 25 + phpunit.xml.dist | 20 - rector.php | 46 + sonar-project.properties | 6 + src/Hal.php | 154 +- src/HalJsonRenderer.php | 67 +- src/HalLink.php | 62 +- src/HalLinkContainer.php | 19 +- src/HalRenderer.php | 11 +- src/HalXmlRenderer.php | 68 +- src/JsonHalFactory.php | 64 +- src/XmlHalFactory.php | 54 +- {tests => test}/Hal/HalTest.php | 396 +-- {tests => test}/Hal/TestCase.php | 5 +- 22 files changed, 5193 insertions(+), 1013 deletions(-) create mode 100644 .github/workflows/project-ci.yml create mode 100644 .github/workflows/project-sonar.yml delete mode 100644 .travis.yml create mode 100644 CONTRIBUTE.md delete mode 100644 phpdoc.dist.xml create mode 100644 phpstan.neon create mode 100644 phpunit.xml delete mode 100644 phpunit.xml.dist create mode 100644 rector.php create mode 100644 sonar-project.properties rename {tests => test}/Hal/HalTest.php (69%) rename {tests => test}/Hal/TestCase.php (97%) diff --git a/.github/workflows/project-ci.yml b/.github/workflows/project-ci.yml new file mode 100644 index 0000000..88df7f0 --- /dev/null +++ b/.github/workflows/project-ci.yml @@ -0,0 +1,28 @@ +name: Unit tests & static analysis + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + check: + runs-on: ubuntu-latest + strategy: + matrix: + php_version: [ "8.2", "8.3", "8.4" ] + container: + image: ghcr.io/shoppingflux/php:${{ matrix.php_version }}-unit + env: + COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }} + XDEBUG_MODE: off + credentials: + username: ${{ secrets.CR_USER }} + password: ${{ secrets.CR_PAT }} + steps: + - name: Composer install + uses: shoppingflux/github-actions/composer-install@main + + - name: Run test script + run: composer test diff --git a/.github/workflows/project-sonar.yml b/.github/workflows/project-sonar.yml new file mode 100644 index 0000000..a73005f --- /dev/null +++ b/.github/workflows/project-sonar.yml @@ -0,0 +1,26 @@ +name: Sonarcloud reporting + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + sonarcloud: + runs-on: ubuntu-latest + container: + image: ghcr.io/shoppingflux/php:8.2-unit + env: + COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }} + XDEBUG_MODE: coverage + credentials: + username: ${{ secrets.CR_USER }} + password: ${{ secrets.CR_PAT }} + + steps: + - name: Sonarcloud scan + uses: shoppingflux/github-actions/sonarcloud@main + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + sonar-token: ${{ secrets.SONARCLOUD_TOKEN }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 61b7113..0000000 --- a/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: php -php: - - 7.1 - - 7.2 - - 7.3 - - 7.4 -install: - - composer update diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md new file mode 100644 index 0000000..f9b4adc --- /dev/null +++ b/CONTRIBUTE.md @@ -0,0 +1,33 @@ +# shoppingfeed/hal + +## Installation + +``` +composer require shoppingfeed/hal +``` + +## Contributing + +To connect to a php 8.2 container correctly configured + +- Create a container : `docker run --name hal-php -v $PWD:/var/www -d ghcr.io/shoppingflux/php:8.2-unit` +- Start container : `docker start hal-php` +- Connect to container : `docker exec -it hal-php bash` + +Once connected to the container you can : + +- Update composer dependencies : `composer update` +- Run test : `composer test` + +## Enable debugger + +```bash +export XDEBUG_TRIGGER=1 +export XDEBUG_CONFIG="client_host=172.17.0.1" +export PHP_IDE_CONFIG=serverName=api.shopping-feed.lan +export XDEBUG_MODE=debug +``` + +## Documentation + +Documentation is available at [docs/index.md](docs/index.md) diff --git a/composer.json b/composer.json index bba839f..7fbc716 100644 --- a/composer.json +++ b/composer.json @@ -13,13 +13,19 @@ } ], "require": { - "php": ">=5.3.0", + "php": ">=8.2", "psr/link": "~1.0" }, "require-dev": { - "phpunit/phpunit": "^7.0 || ^6.4 || ^5.7 || ^4.8.35" + "overtrue/phplint": "^9.4", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^11.0", + "rector/rector": "^2.2", + "roave/security-advisories": "dev-latest", + "laminas/laminas-servicemanager": "^4.5", + "shoppingfeed/coding-style-php": "^2.0", + "symfony/cache": "^7.3" }, - "minimum-stability": "dev", "autoload": { "psr-4": { "Nocarrier\\": "src" @@ -27,10 +33,31 @@ }, "autoload-dev": { "psr-4": { - "Nocarrier\\Tests\\": "tests/Hal" + "Nocarrier\\Test\\": "test/Hal" } }, + "scripts": { + "phpunit": "vendor/bin/phpunit", + "phpcs": "vendor/bin/sfcs src test --progress -vvv", + "phpcsfix": "vendor/bin/sfcs src test --progress -vvv --autofix", + "phpstan": "vendor/bin/phpstan analyse", + "phplint": "vendor/bin/phplint src --cache=build/phplint.cache", + "rector": "vendor/bin/rector process --ansi", + "test": [ + "@phplint", + "@phpunit", + "@phpstan", + "@phpcs" + ], + "codefix": [ + "@rector", + "@phpcsfix", + "@test" + ] + }, "config": { - "bin-dir": "bin" + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } } } diff --git a/composer.lock b/composer.lock index c1982c9..65cbbe7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,24 +4,24 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a5715fea738eb8ca4fc1f13cba56ca9e", + "content-hash": "d79a320d439b598e10df7e1df1dd6d20", "packages": [ { "name": "psr/link", - "version": "dev-master", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/php-fig/link.git", - "reference": "131b5c337db3599ef922e9d6c22889ad237b80b9" + "reference": "846c25f58a1f02b93a00f2404e3626b6bf9b7807" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/link/zipball/131b5c337db3599ef922e9d6c22889ad237b80b9", - "reference": "131b5c337db3599ef922e9d6c22889ad237b80b9", + "url": "https://api.github.com/repos/php-fig/link/zipball/846c25f58a1f02b93a00f2404e3626b6bf9b7807", + "reference": "846c25f58a1f02b93a00f2404e3626b6bf9b7807", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { @@ -54,75 +54,96 @@ "psr-13", "rest" ], - "time": "2016-11-17T00:27:01+00:00" + "support": { + "source": "https://github.com/php-fig/link/tree/1.1.1" + }, + "time": "2021-03-11T22:59:13+00:00" } ], "packages-dev": [ { - "name": "dflydev/markdown", - "version": "v1.0.0", + "name": "brick/varexporter", + "version": "0.6.0", "source": { "type": "git", - "url": "https://github.com/dflydev/dflydev-markdown.git", - "reference": "76501a808522dbe40a5a71d272bd08d54cbae03d" + "url": "https://github.com/brick/varexporter.git", + "reference": "af98bfc2b702a312abbcaff37656dbe419cec5bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dflydev/dflydev-markdown/zipball/76501a808522dbe40a5a71d272bd08d54cbae03d", - "reference": "76501a808522dbe40a5a71d272bd08d54cbae03d", + "url": "https://api.github.com/repos/brick/varexporter/zipball/af98bfc2b702a312abbcaff37656dbe419cec5bc", + "reference": "af98bfc2b702a312abbcaff37656dbe419cec5bc", "shasum": "" }, "require": { - "php": ">=5.3" + "nikic/php-parser": "^5.0", + "php": "^8.1" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^10.5", + "vimeo/psalm": "6.8.4" }, "type": "library", "autoload": { - "psr-0": { - "dflydev\\markdown": "src" + "psr-4": { + "Brick\\VarExporter\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "New BSD License" + "MIT" + ], + "description": "A powerful alternative to var_export(), which can export closures and objects without __set_state()", + "keywords": [ + "var_export" ], - "description": "PHP Markdown & Extra", - "homepage": "http://github.com/dflydev/dflydev-markdown", - "abandoned": "michelf/php-markdown", - "time": "2012-01-02T23:11:32+00:00" + "support": { + "issues": "https://github.com/brick/varexporter/issues", + "source": "https://github.com/brick/varexporter/tree/0.6.0" + }, + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + } + ], + "time": "2025-02-20T17:42:39+00:00" }, { - "name": "doctrine/instantiator", - "version": "1.0.4", + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.2.0", "source": { "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119" + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119", - "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/845eb62303d2ca9b289ef216356568ccc075ffd1", + "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "composer-plugin-api": "^2.2", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^3.1.0 || ^4.0" }, "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "2.0.*@ALPHA" + "composer/composer": "^2.2", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpcompatibility/php-compatibility": "^9.0 || ^10.0.0@dev", + "yoast/phpunit-polyfills": "^1.0" }, - "type": "library", + "type": "composer-plugin", "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" }, "autoload": { - "psr-0": { - "Doctrine\\Instantiator\\": "src" + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -131,172 +152,301 @@ ], "authors": [ { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" + "name": "Franck Nijhof", + "email": "opensource@frenck.dev", + "homepage": "https://frenck.dev", + "role": "Open source developer" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" } ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", "keywords": [ - "constructor", - "instantiate" + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" ], "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/master" + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "security": "https://github.com/PHPCSStandards/composer-installer/security/policy", + "source": "https://github.com/PHPCSStandards/composer-installer" }, - "time": "2014-10-13T12:58:55+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-11-11T04:32:07+00:00" }, { - "name": "phpdocumentor/reflection-docblock", - "version": "2.0.0a1", + "name": "laminas/laminas-servicemanager", + "version": "4.5.0", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "841897062442e2a0e8b3def1518caa25f6498dfd" + "url": "https://github.com/laminas/laminas-servicemanager.git", + "reference": "a6996829c8ce55025cca1b57b1e8a8b165e3926c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/841897062442e2a0e8b3def1518caa25f6498dfd", - "reference": "841897062442e2a0e8b3def1518caa25f6498dfd", + "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/a6996829c8ce55025cca1b57b1e8a8b165e3926c", + "reference": "a6996829c8ce55025cca1b57b1e8a8b165e3926c", "shasum": "" }, "require": { - "dflydev/markdown": "1.0.*", - "php": ">=5.3.2" + "brick/varexporter": "^0.3.8 || ^0.4.0 || ^0.5.0 || ^0.6.0", + "laminas/laminas-stdlib": "^3.19", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "psr/container": "^1.1 || ^2.0" + }, + "conflict": { + "laminas/laminas-code": "<4.10.0", + "zendframework/zend-code": "<3.3.1" + }, + "provide": { + "psr/container-implementation": "^1.0 || ^2.0" }, "require-dev": { - "phpunit/phpunit": "*@stable" + "composer/package-versions-deprecated": "^1.11.99.5", + "friendsofphp/proxy-manager-lts": "^1.0.18", + "laminas/laminas-cli": "^1.11", + "laminas/laminas-coding-standard": "~3.1.0", + "laminas/laminas-container-config-test": "^1.1", + "mikey179/vfsstream": "^1.6.12", + "phpbench/phpbench": "^1.4.1", + "phpunit/phpunit": "^10.5.58", + "psalm/plugin-phpunit": "^0.19.5", + "symfony/console": "^6.4.17 || ^7.3.4", + "vimeo/psalm": "^6.13.1" + }, + "suggest": { + "friendsofphp/proxy-manager-lts": "To handle lazy initialization of services", + "laminas/laminas-cli": "To consume CLI commands provided by this component" }, "type": "library", + "extra": { + "laminas": { + "module": "Laminas\\ServiceManager", + "config-provider": "Laminas\\ServiceManager\\ConfigProvider" + } + }, "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/" - ] + "psr-4": { + "Laminas\\ServiceManager\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], - "authors": [ - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } + "description": "Factory-Driven Dependency Injection Container", + "homepage": "https://laminas.dev", + "keywords": [ + "PSR-11", + "dependency-injection", + "di", + "dic", + "laminas", + "service-manager", + "servicemanager" ], "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/2.0.0a1" + "chat": "https://laminas.dev/chat", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-servicemanager/issues", + "source": "https://github.com/laminas/laminas-servicemanager/tree/4.5.0" }, - "time": "2012-11-27T17:52:28+00:00" + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2025-10-14T09:41:04+00:00" }, { - "name": "phpspec/prophecy", - "version": "v1.3.1", + "name": "laminas/laminas-stdlib", + "version": "3.21.0", "source": { "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9" + "url": "https://github.com/laminas/laminas-stdlib.git", + "reference": "b1c81514cfe158aadf724c42b34d3d0a8164c096" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/9ca52329bcdd1500de24427542577ebf3fc2f1c9", - "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9", + "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/b1c81514cfe158aadf724c42b34d3d0a8164c096", + "reference": "b1c81514cfe158aadf724c42b34d3d0a8164c096", "shasum": "" }, "require": { - "doctrine/instantiator": "~1.0,>=1.0.2", - "phpdocumentor/reflection-docblock": "~2.0" + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "conflict": { + "zendframework/zend-stdlib": "*" }, "require-dev": { - "phpspec/phpspec": "~2.0" + "laminas/laminas-coding-standard": "^3.1.0", + "phpbench/phpbench": "^1.4.1", + "phpunit/phpunit": "^11.5.42", + "psalm/plugin-phpunit": "^0.19.5", + "vimeo/psalm": "^6.13.1" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" + "psr-4": { + "Laminas\\Stdlib\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, + "description": "SPL extensions, array utilities, error handlers, and more", + "homepage": "https://laminas.dev", + "keywords": [ + "laminas", + "stdlib" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-stdlib/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-stdlib/issues", + "rss": "https://github.com/laminas/laminas-stdlib/releases.atom", + "source": "https://github.com/laminas/laminas-stdlib" + }, + "funding": [ { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2025-10-11T18:13:12+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": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "http://phpspec.org", + "description": "Create deep copies (clones) of your objects", "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" + "clone", + "copy", + "duplicate", + "object", + "object graph" ], "support": { - "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/v1.3.1" + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" }, - "time": "2014-11-17T16:23:49+00:00" + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" }, { - "name": "phpunit/php-code-coverage", - "version": "2.1.0", + "name": "nikic/php-parser", + "version": "v5.7.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ba315f46873fd6e86fdb98685a1a900e7379c886" + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ba315f46873fd6e86fdb98685a1a900e7379c886", - "reference": "ba315f46873fd6e86fdb98685a1a900e7379c886", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", "shasum": "" }, "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "~1.3", - "sebastian/environment": "~1.0", - "sebastian/version": "~1.0" + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" }, "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~4" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.2.1", - "ext-xmlwriter": "*" + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" }, + "bin": [ + "bin/php-parse" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -304,142 +454,196 @@ ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" + "name": "Nikita Popov" } ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "description": "A PHP parser written in PHP", "keywords": [ - "coverage", - "testing", - "xunit" + "parser", + "php" ], "support": { - "irc": "irc://irc.freenode.net/phpunit", - "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/2.1.0" + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" }, - "time": "2015-05-30T12:58:40+00:00" + "time": "2025-12-06T11:56:16+00:00" }, { - "name": "phpunit/php-file-iterator", - "version": "1.4.0", + "name": "overtrue/phplint", + "version": "9.6.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb" + "url": "https://github.com/overtrue/phplint.git", + "reference": "b0ec1d07b37a37e7fc872c8bdbddacadcecbe047" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a923bb15680d0089e2316f7a4af8f437046e96bb", - "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb", + "url": "https://api.github.com/repos/overtrue/phplint/zipball/b0ec1d07b37a37e7fc872c8bdbddacadcecbe047", + "reference": "b0ec1d07b37a37e7fc872c8bdbddacadcecbe047", "shasum": "" }, "require": { - "php": ">=5.3.3" + "composer-runtime-api": "^2.0", + "ext-dom": "*", + "ext-json": "*", + "ext-mbstring": "*", + "php": "^8.1", + "symfony/cache": "^6.4 || ^7.0", + "symfony/console": "^6.4 || ^7.0", + "symfony/event-dispatcher": "^6.4 || ^7.0", + "symfony/finder": "^6.4 || ^7.0", + "symfony/options-resolver": "^6.4 || ^7.0", + "symfony/process": "^6.4 || ^7.0", + "symfony/yaml": "^6.4 || ^7.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4", + "brainmaestro/composer-git-hooks": "^3.0.0", + "jetbrains/phpstorm-stubs": "^2024.1", + "php-parallel-lint/php-console-highlighter": "^1.0" }, + "bin": [ + "bin/phplint" + ], "type": "library", "extra": { + "hooks": { + "pre-commit": [ + "composer style:fix", + "composer code:check" + ] + }, + "bamarni-bin": { + "bin-links": true, + "forward-command": true, + "target-directory": "vendor-bin" + }, "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-main": "9.6.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Overtrue\\PHPLint\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" + "name": "overtrue", + "email": "anzhengchao@gmail.com" + }, + { + "name": "Laurent Laville", + "homepage": "https://github.com/llaville" } ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "description": "`phplint` is a tool that can speed up linting of php files by running several lint processes at once.", "keywords": [ - "filesystem", - "iterator" + "check", + "lint", + "phplint", + "static analysis", + "syntax" ], "support": { - "irc": "irc://irc.freenode.net/phpunit", - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/master" + "issues": "https://github.com/overtrue/phplint/issues", + "source": "https://github.com/overtrue/phplint/tree/9.6.3" }, - "time": "2015-04-02T05:19:05+00:00" + "funding": [ + { + "url": "https://github.com/overtrue", + "type": "github" + } + ], + "time": "2025-11-27T13:49:59+00:00" }, { - "name": "phpunit/php-text-template", - "version": "1.2.0", + "name": "phar-io/manifest", + "version": "2.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", - "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { - "php": ">=5.3.3" + "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": [ - "Text/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], "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": "sb@sebastian-bergmann.de", - "role": "lead" + "email": "sebastian@phpunit.de", + "role": "Developer" } ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { - "irc": "irc://irc.freenode.net/phpunit", - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.0" + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2014-01-30T17:20:04+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { - "name": "phpunit/php-timer", - "version": "1.0.6", + "name": "phar-io/version", + "version": "3.2.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "83fe1bdc5d47658b727595c14da140da92b3d66d" + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/83fe1bdc5d47658b727595c14da140da92b3d66d", - "reference": "83fe1bdc5d47658b727595c14da140da92b3d66d", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { @@ -452,122 +656,169 @@ "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": "sb@sebastian-bergmann.de", - "role": "lead" + "email": "sebastian@phpunit.de", + "role": "Developer" } ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], + "description": "Library for handling version information and constraints", "support": { - "irc": "irc://irc.freenode.net/phpunit", - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/1.0.6" + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" }, - "time": "2015-06-13T07:35:30+00:00" + "time": "2022-02-21T01:04:05+00:00" }, { - "name": "phpunit/php-token-stream", - "version": "1.3.0", + "name": "phpstan/phpdoc-parser", + "version": "2.3.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "f8d5d08c56de5cfd592b3340424a81733259a876" + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/f8d5d08c56de5cfd592b3340424a81733259a876", - "reference": "f8d5d08c56de5cfd592b3340424a81733259a876", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", "shasum": "" }, "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" + "php": "^7.4 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "~4.2" + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^5.3.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "symfony/process": "^5.2" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] } }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" + }, + "time": "2026-01-25T14:56:51+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "2.1.40", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", + "reference": "9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", "autoload": { - "classmap": [ - "src/" + "files": [ + "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } + "MIT" ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "description": "PHPStan - PHP Static Analysis Tool", "keywords": [ - "tokenizer" + "dev", + "static analysis" ], "support": { - "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", - "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, - "time": "2014-08-31T06:12:13+00:00" + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2026-02-23T15:04:35+00:00" }, { - "name": "phpunit/phpunit", - "version": "4.8.35", + "name": "phpunit/php-code-coverage", + "version": "11.0.12", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87" + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/791b1a67c25af50e230f841ee7a9c6eba507dc87", - "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", "shasum": "" }, "require": { "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.3.3", - "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": "~2.1", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "~2.3", - "sebastian/comparator": "~1.2.2", - "sebastian/diff": "~1.2", - "sebastian/environment": "~1.3", - "sebastian/exporter": "~1.2", - "sebastian/global-state": "~1.0", - "sebastian/version": "~1.0", - "symfony/yaml": "~2.1|~3.0" + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.7.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.1", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.3.1" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.46" }, "suggest": { - "phpunit/php-invoker": "~1.1" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, - "bin": [ - "phpunit" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "4.8.x-dev" + "dev-main": "11.0.x-dev" } }, "autoload": { @@ -586,48 +837,62 @@ "role": "lead" } ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", "keywords": [ - "phpunit", + "coverage", "testing", "xunit" ], "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/4.8.35" + "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/11.0.12" }, - "time": "2017-02-06T05:18:07+00:00" + "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/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2025-12-24T07:01:01+00:00" }, { - "name": "phpunit/phpunit-mock-objects", - "version": "2.3.0", + "name": "phpunit/php-file-iterator", + "version": "5.1.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "c63d2367247365f688544f0d500af90a11a44c65" + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/c63d2367247365f688544f0d500af90a11a44c65", - "reference": "c63d2367247365f688544f0d500af90a11a44c65", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", "shasum": "" }, "require": { - "doctrine/instantiator": "~1.0,>=1.0.1", - "php": ">=5.3.3", - "phpunit/php-text-template": "~1.2" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "~4.3" - }, - "suggest": { - "ext-soap": "*" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3.x-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -639,37 +904,72 @@ "license": [ "BSD-3-Clause" ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "abandoned": true, - "time": "2014-10-03T05:12:11+00:00" - }, + "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", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.1" + }, + "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/phpunit/php-file-iterator", + "type": "tidelift" + } + ], + "time": "2026-02-02T13:52:54+00:00" + }, { - "name": "sebastian/comparator", - "version": "1.2.2", + "name": "phpunit/php-invoker", + "version": "5.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f" + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/6a1ed12e8b2409076ab22e3897126211ff8b1f7f", - "reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2 || ~2.0" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcntl": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -682,60 +982,54 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", "keywords": [ - "comparator", - "compare", - "equality" + "process" ], "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/master" + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" }, - "time": "2016-11-19T09:18:40+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:07:44+00:00" }, { - "name": "sebastian/diff", - "version": "1.2.0", + "name": "phpunit/php-text-template", + "version": "4.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "5843509fed39dee4b356a306401e9dd1a931fec7" + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/5843509fed39dee4b356a306401e9dd1a931fec7", - "reference": "5843509fed39dee4b356a306401e9dd1a931fec7", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "~4.2" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -748,50 +1042,54 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Diff implementation", - "homepage": "http://www.github.com/sebastianbergmann/diff", + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", "keywords": [ - "diff" + "template" ], "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/master" + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" }, - "time": "2014-08-15T10:29:00+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:08:43+00:00" }, { - "name": "sebastian/environment", - "version": "1.3.0", + "name": "phpunit/php-timer", + "version": "7.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "4fe0a44cddd8cc19583a024bdc7374eb2fef0b87" + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4fe0a44cddd8cc19583a024bdc7374eb2fef0b87", - "reference": "4fe0a44cddd8cc19583a024bdc7374eb2fef0b87", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -806,50 +1104,87 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", "keywords": [ - "Xdebug", - "environment", - "hhvm" + "timer" ], "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/1.3.0" + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" }, - "time": "2015-07-26T06:42:57+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:09:35+00:00" }, { - "name": "sebastian/exporter", - "version": "1.2.0", + "name": "phpunit/phpunit", + "version": "11.5.55", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "84839970d05254c73cde183a721c7af13aede943" + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943", - "reference": "84839970d05254c73cde183a721c7af13aede943", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00", + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~1.0" + "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": ">=8.2", + "phpunit/php-code-coverage": "^11.0.12", + "phpunit/php-file-iterator": "^5.1.1", + "phpunit/php-invoker": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "phpunit/php-timer": "^7.0.1", + "sebastian/cli-parser": "^3.0.2", + "sebastian/code-unit": "^3.0.3", + "sebastian/comparator": "^6.3.3", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.1", + "sebastian/exporter": "^6.3.2", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/recursion-context": "^6.0.3", + "sebastian/type": "^5.1.3", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" }, - "require-dev": { - "phpunit/phpunit": "~4.4" + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" }, + "bin": [ + "phpunit" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-main": "11.5-dev" } }, "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], "classmap": [ "src/" ] @@ -860,216 +1195,225 @@ ], "authors": [ { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" + "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/11.5.55" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" }, { - "name": "Volker Dusch", - "email": "github@wallbash.com" + "url": "https://github.com/sebastianbergmann", + "type": "github" }, { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" }, { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" } ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/master" - }, - "time": "2015-01-27T07:23:06+00:00" + "time": "2026-02-18T12:37:06+00:00" }, { - "name": "sebastian/global-state", - "version": "1.0.0", + "name": "psr/cache", + "version": "3.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01" + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c7428acdb62ece0a45e6306f1ae85e1c05b09c01", - "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", "shasum": "" }, "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "suggest": { - "ext-uopz": "*" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Psr\\Cache\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", + "description": "Common interface for caching libraries", "keywords": [ - "global state" + "cache", + "psr", + "psr-6" ], "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/master" + "source": "https://github.com/php-fig/cache/tree/3.0.0" }, - "time": "2014-10-06T09:23:50+00:00" + "time": "2021-02-03T23:26:27+00:00" }, { - "name": "sebastian/recursion-context", - "version": "1.0.0", + "name": "psr/container", + "version": "2.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "3989662bbb30a29d20d9faa04a846af79b276252" + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252", - "reference": "3989662bbb30a29d20d9faa04a846af79b276252", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", "shasum": "" }, "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" + "php": ">=7.4.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Psr\\Container\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/1.0.0" + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" }, - "time": "2015-01-24T09:48:32+00:00" + "time": "2021-11-05T16:47:00+00:00" }, { - "name": "sebastian/version", + "name": "psr/event-dispatcher", "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "16b021aed448b654ae05846e394e057e9a6f04cb" + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/16b021aed448b654ae05846e394e057e9a6f04cb", - "reference": "16b021aed448b654ae05846e394e057e9a6f04cb", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", "shasum": "" }, + "require": { + "php": ">=7.2.0" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" } ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/1.0.0" + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" }, - "time": "2013-01-05T14:27:32+00:00" + "time": "2019-01-08T18:20:26+00:00" }, { - "name": "symfony/yaml", - "version": "v2.1.0", - "target-dir": "Symfony/Component/Yaml", + "name": "psr/log", + "version": "3.0.2", "source": { "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "f18e004fc975707bb4695df1dbbe9b0d8c8b7715" + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/f18e004fc975707bb4695df1dbbe9b0d8c8b7715", - "reference": "f18e004fc975707bb4695df1dbbe9b0d8c8b7715", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "3.x-dev" } }, "autoload": { - "psr-0": { - "Symfony\\Component\\Yaml": "" + "psr-4": { + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1078,30 +1422,3767 @@ ], "authors": [ { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Symfony Yaml Component", - "homepage": "http://symfony.com", + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], "support": { - "source": "https://github.com/symfony/yaml/tree/v2.1.2" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2012-08-22T13:48:41+00:00" - } - ], - "aliases": [], - "minimum-stability": "dev", - "stability-flags": [], + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "rector/rector", + "version": "2.3.8", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/rector.git", + "reference": "bbd37aedd8df749916cffa2a947cfc4714d1ba2c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/bbd37aedd8df749916cffa2a947cfc4714d1ba2c", + "reference": "bbd37aedd8df749916cffa2a947cfc4714d1ba2c", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0", + "phpstan/phpstan": "^2.1.38" + }, + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" + }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + }, + "bin": [ + "bin/rector" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "homepage": "https://getrector.com/", + "keywords": [ + "automation", + "dev", + "migration", + "refactoring" + ], + "support": { + "issues": "https://github.com/rectorphp/rector/issues", + "source": "https://github.com/rectorphp/rector/tree/2.3.8" + }, + "funding": [ + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2026-02-22T09:45:50+00:00" + }, + { + "name": "roave/security-advisories", + "version": "dev-latest", + "source": { + "type": "git", + "url": "https://github.com/Roave/SecurityAdvisories.git", + "reference": "67b44a783410e6d9912db53af50c8ddf048c9845" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/67b44a783410e6d9912db53af50c8ddf048c9845", + "reference": "67b44a783410e6d9912db53af50c8ddf048c9845", + "shasum": "" + }, + "conflict": { + "3f/pygmentize": "<1.2", + "adaptcms/adaptcms": "<=1.3", + "admidio/admidio": "<=4.3.16", + "adodb/adodb-php": "<=5.22.9", + "aheinze/cockpit": "<2.2", + "aimeos/ai-admin-graphql": ">=2022.04.1,<2022.10.10|>=2023.04.1,<2023.10.6|>=2024.04.1,<2024.07.2", + "aimeos/ai-admin-jsonadm": "<2020.10.13|>=2021.04.1,<2021.10.6|>=2022.04.1,<2022.10.3|>=2023.04.1,<2023.10.4|==2024.04.1", + "aimeos/ai-client-html": ">=2020.04.1,<2020.10.27|>=2021.04.1,<2021.10.22|>=2022.04.1,<2022.10.13|>=2023.04.1,<2023.10.15|>=2024.04.1,<2024.04.7", + "aimeos/ai-cms-grapesjs": ">=2021.04.1,<2021.10.8|>=2022.04.1,<2022.10.9|>=2023.04.1,<2023.10.15|>=2024.04.1,<2024.10.8|>=2025.04.1,<2025.10.2", + "aimeos/ai-controller-frontend": "<2020.10.15|>=2021.04.1,<2021.10.8|>=2022.04.1,<2022.10.8|>=2023.04.1,<2023.10.9|==2024.04.1", + "aimeos/aimeos-core": ">=2022.04.1,<2022.10.17|>=2023.04.1,<2023.10.17|>=2024.04.1,<2024.04.7", + "aimeos/aimeos-laravel": "==2021.10", + "aimeos/aimeos-typo3": "<19.10.12|>=20,<20.10.5", + "airesvsg/acf-to-rest-api": "<=3.1", + "akaunting/akaunting": "<2.1.13", + "akeneo/pim-community-dev": "<5.0.119|>=6,<6.0.53", + "alextselegidis/easyappointments": "<=1.5.2", + "alexusmai/laravel-file-manager": "<=3.3.1", + "algolia/algoliasearch-magento-2": "<=3.16.1|>=3.17.0.0-beta1,<=3.17.1", + "alt-design/alt-redirect": "<1.6.4", + "altcha-org/altcha": "<1.3.1", + "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", + "amazing/media2click": ">=1,<1.3.3", + "ameos/ameos_tarteaucitron": "<1.2.23", + "amphp/artax": "<1.0.6|>=2,<2.0.6", + "amphp/http": "<=1.7.2|>=2,<=2.1", + "amphp/http-client": ">=4,<4.4", + "amphp/http-server": ">=2.0.0.0-RC1-dev,<2.1.10|>=3.0.0.0-beta1,<3.4.4", + "anchorcms/anchor-cms": "<=0.12.7", + "andreapollastri/cipi": "<=3.1.15", + "andrewhaine/silverstripe-form-capture": ">=0.2,<=0.2.3|>=1,<1.0.2|>=2,<2.2.5", + "aoe/restler": "<1.7.1", + "apache-solr-for-typo3/solr": "<2.8.3", + "apereo/phpcas": "<1.6", + "api-platform/core": "<3.4.17|>=4,<4.0.22|>=4.1,<4.1.5", + "api-platform/graphql": "<3.4.17|>=4,<4.0.22|>=4.1,<4.1.5", + "appwrite/server-ce": "<=1.2.1", + "arc/web": "<3", + "area17/twill": "<1.2.5|>=2,<2.5.3", + "artesaos/seotools": "<0.17.2", + "asymmetricrypt/asymmetricrypt": "<9.9.99", + "athlon1600/php-proxy": "<=5.1", + "athlon1600/php-proxy-app": "<=3", + "athlon1600/youtube-downloader": "<=4", + "austintoddj/canvas": "<=3.4.2", + "auth0/auth0-php": ">=3.3,<8.18", + "auth0/login": "<7.20", + "auth0/symfony": "<=5.5", + "auth0/wordpress": "<=5.4", + "automad/automad": "<2.0.0.0-alpha5", + "automattic/jetpack": "<9.8", + "awesome-support/awesome-support": "<=6.0.7", + "aws/aws-sdk-php": "<3.368", + "azuracast/azuracast": "<=0.23.1", + "b13/seo_basics": "<0.8.2", + "backdrop/backdrop": "<=1.32", + "backpack/crud": "<3.4.9", + "backpack/filemanager": "<2.0.2|>=3,<3.0.9", + "bacula-web/bacula-web": "<9.7.1", + "badaso/core": "<=2.9.11", + "bagisto/bagisto": "<2.3.10", + "barrelstrength/sprout-base-email": "<1.2.7", + "barrelstrength/sprout-forms": "<3.9", + "barryvdh/laravel-translation-manager": "<0.6.8", + "barzahlen/barzahlen-php": "<2.0.1", + "baserproject/basercms": "<=5.1.1", + "bassjobsen/bootstrap-3-typeahead": ">4.0.2", + "bbpress/bbpress": "<2.6.5", + "bcit-ci/codeigniter": "<3.1.3", + "bcosca/fatfree": "<3.7.2", + "bedita/bedita": "<4", + "bednee/cooluri": "<1.0.30", + "bigfork/silverstripe-form-capture": ">=3,<3.1.1", + "billz/raspap-webgui": "<3.3.6", + "binarytorch/larecipe": "<2.8.1", + "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", + "blueimp/jquery-file-upload": "==6.4.4", + "bmarshall511/wordpress_zero_spam": "<5.2.13", + "bolt/bolt": "<3.7.2", + "bolt/core": "<=4.2", + "born05/craft-twofactorauthentication": "<3.3.4", + "bottelet/flarepoint": "<2.2.1", + "bref/bref": "<2.1.17", + "brightlocal/phpwhois": "<=4.2.5", + "brotkrueml/codehighlight": "<2.7", + "brotkrueml/schema": "<1.13.1|>=2,<2.5.1", + "brotkrueml/typo3-matomo-integration": "<1.3.2", + "buddypress/buddypress": "<7.2.1", + "bugsnag/bugsnag-laravel": ">=2,<2.0.2", + "bvbmedia/multishop": "<2.0.39", + "bytefury/crater": "<6.0.2", + "cachethq/cachet": "<2.5.1", + "cadmium-org/cadmium-cms": "<=0.4.9", + "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.1,<4.1.4|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10|>=5.2.10,<5.2.12|==5.3", + "cakephp/database": ">=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", + "cardgate/magento2": "<2.0.33", + "cardgate/woocommerce": "<=3.1.15", + "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", + "cart2quote/module-quotation-encoded": ">=4.1.6,<=4.4.5|>=5,<5.4.4", + "cartalyst/sentry": "<=2.1.6", + "catfan/medoo": "<1.7.5", + "causal/oidc": "<4", + "cecil/cecil": "<7.47.1", + "centreon/centreon": "<22.10.15", + "cesargb/laravel-magiclink": ">=2,<2.25.1", + "cesnet/simplesamlphp-module-proxystatistics": "<3.1", + "chriskacerguis/codeigniter-restserver": "<=2.7.1", + "chrome-php/chrome": "<1.14", + "ci4-cms-erp/ci4ms": "<0.28.5", + "civicrm/civicrm-core": ">=4.2,<4.2.9|>=4.3,<4.3.3", + "ckeditor/ckeditor": "<4.25", + "clickstorm/cs-seo": ">=6,<6.8|>=7,<7.5|>=8,<8.4|>=9,<9.3", + "co-stack/fal_sftp": "<0.2.6", + "cockpit-hq/cockpit": "<2.11.4", + "code16/sharp": "<9.11.1", + "codeception/codeception": "<3.1.3|>=4,<4.1.22", + "codeigniter/framework": "<3.1.10", + "codeigniter4/framework": "<4.6.2", + "codeigniter4/shield": "<1.0.0.0-beta8", + "codiad/codiad": "<=2.8.4", + "codingms/additional-tca": ">=1.7,<1.15.17|>=1.16,<1.16.9", + "codingms/modules": "<4.3.11|>=5,<5.7.4|>=6,<6.4.2|>=7,<7.5.5", + "commerceteam/commerce": ">=0.9.6,<0.9.9", + "components/jquery": ">=1.0.3,<3.5", + "composer/composer": "<1.10.27|>=2,<2.2.26|>=2.3,<2.9.3", + "concrete5/concrete5": "<9.4.3", + "concrete5/core": "<8.5.8|>=9,<9.1", + "contao-components/mediaelement": ">=2.14.2,<2.21.1", + "contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4", + "contao/contao": ">=3,<3.5.37|>=4,<4.4.56|>=4.5,<4.13.56|>=5,<5.3.38|>=5.4.0.0-RC1-dev,<5.6.1", + "contao/core": "<3.5.39", + "contao/core-bundle": "<4.13.57|>=5,<5.3.42|>=5.4,<5.6.5", + "contao/listing-bundle": ">=3,<=3.5.30|>=4,<4.4.8", + "contao/managed-edition": "<=1.5", + "coreshop/core-shop": "<4.1.9", + "corveda/phpsandbox": "<1.3.5", + "cosenary/instagram": "<=2.3", + "couleurcitron/tarteaucitron-wp": "<0.3", + "cpsit/typo3-mailqueue": "<0.4.3|>=0.5,<0.5.1", + "craftcms/cms": "<4.17.0.0-beta1|>=5,<5.9.0.0-beta1", + "craftcms/commerce": ">=4.0.0.0-RC1-dev,<=4.10|>=5,<=5.5.1", + "craftcms/composer": ">=4.0.0.0-RC1-dev,<=4.10|>=5.0.0.0-RC1-dev,<=5.5.1", + "craftcms/craft": ">=3.5,<=4.16.17|>=5.0.0.0-RC1-dev,<=5.8.21", + "croogo/croogo": "<=4.0.7", + "cuyz/valinor": "<0.12", + "czim/file-handling": "<1.5|>=2,<2.3", + "czproject/git-php": "<4.0.3", + "damienharper/auditor-bundle": "<5.2.6", + "dapphp/securimage": "<3.6.6", + "darylldoyle/safe-svg": "<1.9.10", + "datadog/dd-trace": ">=0.30,<0.30.2", + "datahihi1/tiny-env": "<1.0.3|>=1.0.9,<1.0.11", + "datatables/datatables": "<1.10.10", + "david-garcia/phpwhois": "<=4.3.1", + "dbrisinajumi/d2files": "<1", + "dcat/laravel-admin": "<=2.1.3|==2.2.0.0-beta|==2.2.2.0-beta", + "derhansen/fe_change_pwd": "<2.0.5|>=3,<3.0.3", + "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1|>=7,<7.4", + "desperado/xml-bundle": "<=0.1.7", + "dev-lancer/minecraft-motd-parser": "<=1.0.5", + "devcode-it/openstamanager": "<=2.9.8", + "devgroup/dotplant": "<2020.09.14-dev", + "digimix/wp-svg-upload": "<=1", + "directmailteam/direct-mail": "<6.0.3|>=7,<7.0.3|>=8,<9.5.2", + "directorytree/imapengine": "<1.22.3", + "dl/yag": "<3.0.1", + "dmk/webkitpdf": "<1.1.4", + "dnadesign/silverstripe-elemental": "<5.3.12", + "doctrine/annotations": "<1.2.7", + "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", + "doctrine/common": "<2.4.3|>=2.5,<2.5.1", + "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2|>=3,<3.1.4", + "doctrine/doctrine-bundle": "<1.5.2", + "doctrine/doctrine-module": "<0.7.2", + "doctrine/mongodb-odm": "<1.0.2", + "doctrine/mongodb-odm-bundle": "<3.0.1", + "doctrine/orm": ">=1,<1.2.4|>=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", + "dolibarr/dolibarr": "<21.0.3", + "dompdf/dompdf": "<2.0.4", + "doublethreedigital/guest-entries": "<3.1.2", + "drupal-pattern-lab/unified-twig-extensions": "<=0.1", + "drupal/access_code": "<2.0.5", + "drupal/acquia_dam": "<1.1.5", + "drupal/admin_audit_trail": "<1.0.5", + "drupal/ai": "<1.0.5", + "drupal/alogin": "<2.0.6", + "drupal/cache_utility": "<1.2.1", + "drupal/civictheme": "<1.12", + "drupal/commerce_alphabank_redirect": "<1.0.3", + "drupal/commerce_eurobank_redirect": "<2.1.1", + "drupal/config_split": "<1.10|>=2,<2.0.2", + "drupal/core": ">=6,<6.38|>=7,<7.103|>=8,<10.4.9|>=10.5,<10.5.6|>=11,<11.1.9|>=11.2,<11.2.8", + "drupal/core-recommended": ">=7,<7.102|>=8,<10.2.11|>=10.3,<10.3.9|>=11,<11.0.8", + "drupal/currency": "<3.5", + "drupal/drupal": ">=5,<5.11|>=6,<6.38|>=7,<7.102|>=8,<10.2.11|>=10.3,<10.3.9|>=11,<11.0.8", + "drupal/email_tfa": "<2.0.6", + "drupal/formatter_suite": "<2.1", + "drupal/gdpr": "<3.0.1|>=3.1,<3.1.2", + "drupal/google_tag": "<1.8|>=2,<2.0.8", + "drupal/ignition": "<1.0.4", + "drupal/json_field": "<1.5", + "drupal/lightgallery": "<1.6", + "drupal/link_field_display_mode_formatter": "<1.6", + "drupal/matomo": "<1.24", + "drupal/oauth2_client": "<4.1.3", + "drupal/oauth2_server": "<2.1", + "drupal/obfuscate": "<2.0.1", + "drupal/plausible_tracking": "<1.0.2", + "drupal/quick_node_block": "<2", + "drupal/rapidoc_elements_field_formatter": "<1.0.1", + "drupal/reverse_proxy_header": "<1.1.2", + "drupal/simple_multistep": "<2", + "drupal/simple_oauth": ">=6,<6.0.7", + "drupal/spamspan": "<3.2.1", + "drupal/tfa": "<1.10", + "drupal/umami_analytics": "<1.0.1", + "duncanmcclean/guest-entries": "<3.1.2", + "dweeves/magmi": "<=0.7.24", + "ec-cube/ec-cube": "<2.4.4|>=2.11,<=2.17.1|>=3,<=3.0.18.0-patch4|>=4,<=4.1.2", + "ecodev/newsletter": "<=4", + "ectouch/ectouch": "<=2.7.2", + "egroupware/egroupware": "<23.1.20260113|>=26.0.20251208,<26.0.20260113", + "elefant/cms": "<2.0.7", + "elgg/elgg": "<3.3.24|>=4,<4.0.5", + "elijaa/phpmemcacheadmin": "<=1.3", + "elmsln/haxcms": "<11.0.14", + "encore/laravel-admin": "<=1.8.19", + "endroid/qr-code-bundle": "<3.4.2", + "enhavo/enhavo-app": "<=0.13.1", + "enshrined/svg-sanitize": "<0.22", + "erusev/parsedown": "<1.7.2", + "ether/logs": "<3.0.4", + "evolutioncms/evolution": "<=3.2.3", + "exceedone/exment": "<4.4.3|>=5,<5.0.3", + "exceedone/laravel-admin": "<2.2.3|==3", + "ezsystems/demobundle": ">=5.4,<5.4.6.1-dev", + "ezsystems/ez-support-tools": ">=2.2,<2.2.3", + "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1-dev", + "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1-dev|>=5.4,<5.4.11.1-dev|>=2017.12,<2017.12.0.1-dev", + "ezsystems/ezplatform": "<=1.13.6|>=2,<=2.5.24", + "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6|>=1.5,<1.5.29|>=2.3,<2.3.39|>=3.3,<3.3.39", + "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1|>=5.3.0.0-beta1,<5.3.5", + "ezsystems/ezplatform-graphql": ">=1.0.0.0-RC1-dev,<1.0.13|>=2.0.0.0-beta1,<2.3.12", + "ezsystems/ezplatform-http-cache": "<2.3.16", + "ezsystems/ezplatform-kernel": "<=1.2.5|>=1.3,<1.3.35", + "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<1.3.8", + "ezsystems/ezplatform-richtext": ">=2.3,<2.3.26|>=3.3,<3.3.40", + "ezsystems/ezplatform-solr-search-engine": ">=1.7,<1.7.12|>=2,<2.0.2|>=3.3,<3.3.15", + "ezsystems/ezplatform-user": ">=1,<1.0.1", + "ezsystems/ezpublish-kernel": "<=6.13.8.1|>=7,<7.5.31", + "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.6,<=2019.03.5.1", + "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", + "ezsystems/repository-forms": ">=2.3,<2.3.2.1-dev|>=2.5,<2.5.15", + "ezyang/htmlpurifier": "<=4.2", + "facade/ignition": "<1.16.15|>=2,<2.4.2|>=2.5,<2.5.2", + "facturascripts/facturascripts": "<2025.81", + "fastly/magento2": "<1.2.26", + "feehi/cms": "<=2.1.1", + "feehi/feehicms": "<=2.1.1", + "fenom/fenom": "<=2.12.1", + "filament/actions": ">=3.2,<3.2.123", + "filament/filament": ">=4,<4.3.1", + "filament/infolists": ">=3,<3.2.115", + "filament/tables": ">=3,<3.2.115", + "filegator/filegator": "<7.8", + "filp/whoops": "<2.1.13", + "fineuploader/php-traditional-server": "<=1.2.2", + "firebase/php-jwt": "<7", + "fisharebest/webtrees": "<=2.1.18", + "fixpunkt/fp-masterquiz": "<2.2.1|>=3,<3.5.2", + "fixpunkt/fp-newsletter": "<1.1.1|>=1.2,<2.1.2|>=2.2,<3.2.6", + "flarum/core": "<1.8.10", + "flarum/flarum": "<0.1.0.0-beta8", + "flarum/framework": "<1.8.10", + "flarum/mentions": "<1.6.3", + "flarum/sticky": ">=0.1.0.0-beta14,<=0.1.0.0-beta15", + "flarum/tags": "<=0.1.0.0-beta13", + "floriangaerber/magnesium": "<0.3.1", + "fluidtypo3/vhs": "<5.1.1", + "fof/byobu": ">=0.3.0.0-beta2,<1.1.7", + "fof/pretty-mail": "<=1.1.2", + "fof/upload": "<1.2.3", + "foodcoopshop/foodcoopshop": ">=3.2,<3.6.1", + "fooman/tcpdf": "<6.2.22", + "forkcms/forkcms": "<5.11.1", + "fossar/tcpdf-parser": "<6.2.22", + "francoisjacquet/rosariosis": "<=11.5.1", + "frappant/frp-form-answers": "<3.1.2|>=4,<4.0.2", + "friendsofsymfony/oauth2-php": "<1.3", + "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", + "friendsofsymfony/user-bundle": ">=1,<1.3.5", + "friendsofsymfony1/swiftmailer": ">=4,<5.4.13|>=6,<6.2.5", + "friendsofsymfony1/symfony1": ">=1.1,<1.5.19", + "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", + "friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6", + "froala/wysiwyg-editor": "<=4.3", + "frosh/adminer-platform": "<2.2.1", + "froxlor/froxlor": "<=2.2.5", + "frozennode/administrator": "<=5.0.12", + "fuel/core": "<1.8.1", + "funadmin/funadmin": "<=5.0.2", + "gaoming13/wechat-php-sdk": "<=1.10.2", + "genix/cms": "<=1.1.11", + "georgringer/news": "<1.3.3", + "geshi/geshi": "<=1.0.9.1", + "getformwork/formwork": "<=2.3.3", + "getgrav/grav": "<1.11.0.0-beta1", + "getkirby/cms": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1|>=5,<=5.2.1", + "getkirby/kirby": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1", + "getkirby/panel": "<2.5.14", + "getkirby/starterkit": "<=3.7.0.2", + "gilacms/gila": "<=1.15.4", + "gleez/cms": "<=1.3|==2", + "globalpayments/php-sdk": "<2", + "goalgorilla/open_social": "<12.3.11|>=12.4,<12.4.10|>=13.0.0.0-alpha1,<13.0.0.0-alpha11", + "gogentooss/samlbase": "<1.2.7", + "google/protobuf": "<3.4", + "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", + "gp247/core": "<1.1.24", + "gree/jose": "<2.2.1", + "gregwar/rst": "<1.0.3", + "grumpydictator/firefly-iii": "<6.1.17", + "gugoan/economizzer": "<=0.9.0.0-beta1", + "guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5", + "guzzlehttp/oauth-subscriber": "<0.8.1", + "guzzlehttp/psr7": "<1.9.1|>=2,<2.4.5", + "haffner/jh_captcha": "<=2.1.3|>=3,<=3.0.2", + "handcraftedinthealps/goodby-csv": "<1.4.3", + "harvesthq/chosen": "<1.8.7", + "helloxz/imgurl": "<=2.31", + "hhxsv5/laravel-s": "<3.7.36", + "hillelcoren/invoice-ninja": "<5.3.35", + "himiklab/yii2-jqgrid-widget": "<1.0.8", + "hjue/justwriting": "<=1", + "hov/jobfair": "<1.0.13|>=2,<2.0.2", + "httpsoft/http-message": "<1.0.12", + "hyn/multi-tenant": ">=5.6,<5.7.2", + "ibexa/admin-ui": ">=4.2,<4.2.3|>=4.6,<4.6.25|>=5,<5.0.3", + "ibexa/admin-ui-assets": ">=4.6.0.0-alpha1,<4.6.21", + "ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3|>=4.5,<4.5.6|>=4.6,<4.6.2", + "ibexa/fieldtype-richtext": ">=4.6,<4.6.25|>=5,<5.0.3", + "ibexa/graphql": ">=2.5,<2.5.31|>=3.3,<3.3.28|>=4.2,<4.2.3", + "ibexa/http-cache": ">=4.6,<4.6.14", + "ibexa/post-install": "<1.0.16|>=4.6,<4.6.14", + "ibexa/solr": ">=4.5,<4.5.4", + "ibexa/user": ">=4,<4.4.3|>=5,<5.0.4", + "icecoder/icecoder": "<=8.1", + "idno/known": "<=1.6.2", + "ilicmiljan/secure-props": ">=1.2,<1.2.2", + "illuminate/auth": "<5.5.10", + "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<6.18.31|>=7,<7.22.4", + "illuminate/database": "<6.20.26|>=7,<7.30.5|>=8,<8.40", + "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", + "illuminate/view": "<6.20.42|>=7,<7.30.6|>=8,<8.75", + "imdbphp/imdbphp": "<=5.1.1", + "impresscms/impresscms": "<=1.4.5", + "impresspages/impresspages": "<1.0.13", + "in2code/femanager": "<6.4.2|>=7,<7.5.3|>=8,<8.3.1", + "in2code/ipandlanguageredirect": "<5.1.2", + "in2code/lux": "<17.6.1|>=18,<24.0.2", + "in2code/powermail": "<7.5.1|>=8,<8.5.1|>=9,<10.9.1|>=11,<12.5.3|==13", + "innologi/typo3-appointments": "<2.0.6", + "intelliants/subrion": "<4.2.2", + "inter-mediator/inter-mediator": "==5.5", + "ipl/web": "<0.10.1", + "islandora/crayfish": "<4.1", + "islandora/islandora": ">=2,<2.4.1", + "ivankristianto/phpwhois": "<=4.3", + "jackalope/jackalope-doctrine-dbal": "<1.7.4", + "jambagecom/div2007": "<0.10.2", + "james-heinrich/getid3": "<1.9.21", + "james-heinrich/phpthumb": "<=1.7.23", + "jasig/phpcas": "<1.3.3", + "jbartels/wec-map": "<3.0.3", + "jcbrand/converse.js": "<3.3.3", + "joelbutcher/socialstream": "<5.6|>=6,<6.2", + "johnbillion/wp-crontrol": "<1.16.2|>=1.17,<1.19.2", + "joomla/application": "<1.0.13", + "joomla/archive": "<1.1.12|>=2,<2.0.1", + "joomla/database": ">=1,<2.2|>=3,<3.4", + "joomla/filesystem": "<1.6.2|>=2,<2.0.1", + "joomla/filter": "<2.0.6|>=3,<3.0.5|==4", + "joomla/framework": "<1.5.7|>=2.5.4,<=3.8.12", + "joomla/input": ">=2,<2.0.2", + "joomla/joomla-cms": "<3.9.12|>=4,<4.4.13|>=5,<5.2.6", + "joomla/joomla-platform": "<1.5.4", + "joomla/session": "<1.3.1", + "joyqi/hyper-down": "<=2.4.27", + "jsdecena/laracom": "<2.0.9", + "jsmitty12/phpwhois": "<5.1", + "juzaweb/cms": "<=3.4.2", + "jweiland/events2": "<8.3.8|>=9,<9.0.6", + "jweiland/kk-downloader": "<1.2.2", + "kazist/phpwhois": "<=4.2.6", + "kelvinmo/simplexrd": "<3.1.1", + "kevinpapst/kimai2": "<1.16.7", + "khodakhah/nodcms": "<=3", + "kimai/kimai": "<2.46", + "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", + "klaviyo/magento2-extension": ">=1,<3", + "knplabs/knp-snappy": "<=1.4.2", + "kohana/core": "<3.3.3", + "koillection/koillection": "<1.6.12", + "krayin/laravel-crm": "<=1.3", + "kreait/firebase-php": ">=3.2,<3.8.1", + "kumbiaphp/kumbiapp": "<=1.1.1", + "la-haute-societe/tcpdf": "<6.2.22", + "laminas/laminas-diactoros": "<2.18.1|==2.19|==2.20|==2.21|==2.22|==2.23|>=2.24,<2.24.2|>=2.25,<2.25.2", + "laminas/laminas-form": "<2.17.1|>=3,<3.0.2|>=3.1,<3.1.1", + "laminas/laminas-http": "<2.14.2", + "lara-zeus/artemis": ">=1,<=1.0.6", + "lara-zeus/dynamic-dashboard": ">=3,<=3.0.1", + "laravel/fortify": "<1.11.1", + "laravel/framework": "<10.48.29|>=11,<11.44.1|>=12,<12.1.1", + "laravel/laravel": ">=5.4,<5.4.22", + "laravel/pulse": "<1.3.1", + "laravel/reverb": "<1.7", + "laravel/socialite": ">=1,<2.0.10", + "latte/latte": "<2.10.8", + "lavalite/cms": "<=10.1", + "lavitto/typo3-form-to-database": "<2.2.5|>=3,<3.2.2|>=4,<4.2.3|>=5,<5.0.2", + "lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5", + "league/commonmark": "<2.7", + "league/flysystem": "<1.1.4|>=2,<2.1.1", + "league/oauth2-server": ">=8.3.2,<8.4.2|>=8.5,<8.5.3", + "leantime/leantime": "<3.3", + "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", + "libreform/libreform": ">=2,<=2.0.8", + "librenms/librenms": "<26.2", + "liftkit/database": "<2.13.2", + "lightsaml/lightsaml": "<1.3.5", + "limesurvey/limesurvey": "<6.5.12", + "livehelperchat/livehelperchat": "<=3.91", + "livewire-filemanager/filemanager": "<=1.0.4", + "livewire/livewire": "<2.12.7|>=3.0.0.0-beta1,<3.6.4", + "livewire/volt": "<1.7", + "lms/routes": "<2.1.1", + "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", + "lomkit/laravel-rest-api": "<2.13", + "luracast/restler": "<3.1", + "luyadev/yii-helpers": "<1.2.1", + "macropay-solutions/laravel-crud-wizard-free": "<3.4.17", + "maestroerror/php-heic-to-jpg": "<1.0.5", + "magento/community-edition": "<2.4.6.0-patch13|>=2.4.7.0-beta1,<2.4.7.0-patch8|>=2.4.8.0-beta1,<2.4.8.0-patch3|>=2.4.9.0-alpha1,<2.4.9.0-alpha3|==2.4.9", + "magento/core": "<=1.9.4.5", + "magento/magento1ce": "<1.9.4.3-dev", + "magento/magento1ee": ">=1,<1.14.4.3-dev", + "magento/product-community-edition": "<2.4.4.0-patch9|>=2.4.5,<2.4.5.0-patch8|>=2.4.6,<2.4.6.0-patch6|>=2.4.7,<2.4.7.0-patch1", + "magento/project-community-edition": "<=2.0.2", + "magneto/core": "<1.9.4.4-dev", + "mahocommerce/maho": "<25.9", + "maikuolan/phpmussel": ">=1,<1.6", + "mainwp/mainwp": "<=4.4.3.3", + "manogi/nova-tiptap": "<=3.2.6", + "mantisbt/mantisbt": "<2.27.2", + "marcwillmann/turn": "<0.3.3", + "marshmallow/nova-tiptap": "<5.7", + "matomo/matomo": "<1.11", + "matyhtf/framework": "<3.0.6", + "mautic/core": "<5.2.10|>=6,<6.0.8|>=7.0.0.0-alpha,<7.0.1", + "mautic/core-lib": ">=1.0.0.0-beta,<4.4.13|>=5.0.0.0-alpha,<5.1.1", + "mautic/grapes-js-builder-bundle": ">=4,<4.4.18|>=5,<5.2.9|>=6,<6.0.7", + "maximebf/debugbar": "<1.19", + "mdanter/ecc": "<2", + "mediawiki/abuse-filter": "<1.39.9|>=1.40,<1.41.3|>=1.42,<1.42.2", + "mediawiki/cargo": "<3.8.3", + "mediawiki/core": "<1.39.5|==1.40", + "mediawiki/data-transfer": ">=1.39,<1.39.11|>=1.41,<1.41.3|>=1.42,<1.42.2", + "mediawiki/matomo": "<2.4.3", + "mediawiki/semantic-media-wiki": "<4.0.2", + "mehrwert/phpmyadmin": "<3.2", + "melisplatform/melis-asset-manager": "<5.0.1", + "melisplatform/melis-cms": "<5.3.4", + "melisplatform/melis-cms-slider": "<5.3.1", + "melisplatform/melis-core": "<5.3.11", + "melisplatform/melis-front": "<5.0.1", + "mezzio/mezzio-swoole": "<3.7|>=4,<4.3", + "mgallegos/laravel-jqgrid": "<=1.3", + "microsoft/microsoft-graph": ">=1.16,<1.109.1|>=2,<2.0.1", + "microsoft/microsoft-graph-beta": "<2.0.1", + "microsoft/microsoft-graph-core": "<2.0.2", + "microweber/microweber": "<2.0.20", + "mikehaertl/php-shellcommand": "<1.6.1", + "mineadmin/mineadmin": "<=3.0.9", + "miniorange/miniorange-saml": "<1.4.3", + "mittwald/typo3_forum": "<1.2.1", + "mobiledetect/mobiledetectlib": "<2.8.32", + "modx/revolution": "<=3.1", + "mojo42/jirafeau": "<4.4", + "mongodb/mongodb": ">=1,<1.9.2", + "mongodb/mongodb-extension": "<1.21.2", + "monolog/monolog": ">=1.8,<1.12", + "moodle/moodle": "<4.5.9|>=5.0.0.0-beta,<5.0.5|>=5.1.0.0-beta,<5.1.2", + "moonshine/moonshine": "<=3.12.5", + "mos/cimage": "<0.7.19", + "movim/moxl": ">=0.8,<=0.10", + "movingbytes/social-network": "<=1.2.1", + "mpdf/mpdf": "<=7.1.7", + "munkireport/comment": "<4", + "munkireport/managedinstalls": "<2.6", + "munkireport/munki_facts": "<1.5", + "munkireport/reportdata": "<3.5", + "munkireport/softwareupdate": "<1.6", + "mustache/mustache": ">=2,<2.14.1", + "mwdelaney/wp-enable-svg": "<=0.2", + "namshi/jose": "<2.2", + "nasirkhan/laravel-starter": "<11.11", + "nategood/httpful": "<1", + "neoan3-apps/template": "<1.1.1", + "neorazorx/facturascripts": "<2022.04", + "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", + "neos/form": ">=1.2,<4.3.3|>=5,<5.0.9|>=5.1,<5.1.3", + "neos/media-browser": "<7.3.19|>=8,<8.0.16|>=8.1,<8.1.11|>=8.2,<8.2.11|>=8.3,<8.3.9", + "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<5.3.10|>=7,<7.0.9|>=7.1,<7.1.7|>=7.2,<7.2.6|>=7.3,<7.3.4|>=8,<8.0.2", + "neos/swiftmailer": "<5.4.5", + "nesbot/carbon": "<2.72.6|>=3,<3.8.4", + "netcarver/textile": "<=4.1.2", + "netgen/tagsbundle": ">=3.4,<3.4.11|>=4,<4.0.15", + "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", + "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", + "neuron-core/neuron-ai": "<=2.8.11", + "nilsteampassnet/teampass": "<3.1.3.1-dev", + "nitsan/ns-backup": "<13.0.1", + "nonfiction/nterchange": "<4.1.1", + "notrinos/notrinos-erp": "<=0.7", + "noumo/easyii": "<=0.9", + "novaksolutions/infusionsoft-php-sdk": "<1", + "novosga/novosga": "<=2.2.12", + "nukeviet/nukeviet": "<4.5.02", + "nyholm/psr7": "<1.6.1", + "nystudio107/craft-seomatic": "<3.4.12", + "nzedb/nzedb": "<0.8", + "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", + "october/backend": "<1.1.2", + "october/cms": "<1.0.469|==1.0.469|==1.0.471|==1.1.1", + "october/october": "<3.7.5", + "october/rain": "<1.0.472|>=1.1,<1.1.2", + "october/system": "<=3.7.12|>=4,<=4.0.11", + "oliverklee/phpunit": "<3.5.15", + "omeka/omeka-s": "<4.0.3", + "onelogin/php-saml": "<2.21.1|>=3,<3.8.1|>=4,<4.3.1", + "oneup/uploader-bundle": ">=1,<1.9.3|>=2,<2.1.5", + "open-web-analytics/open-web-analytics": "<1.8.1", + "opencart/opencart": ">=0", + "openid/php-openid": "<2.3", + "openmage/magento-lts": "<20.16.1", + "opensolutions/vimbadmin": "<=3.0.15", + "opensource-workshop/connect-cms": "<1.8.7|>=2,<2.4.7", + "orchid/platform": ">=8,<14.43", + "oro/calendar-bundle": ">=4.2,<=4.2.6|>=5,<=5.0.6|>=5.1,<5.1.1", + "oro/commerce": ">=4.1,<5.0.11|>=5.1,<5.1.1", + "oro/crm": ">=1.7,<1.7.4|>=3.1,<4.1.17|>=4.2,<4.2.7", + "oro/crm-call-bundle": ">=4.2,<=4.2.5|>=5,<5.0.4|>=5.1,<5.1.1", + "oro/customer-portal": ">=4.1,<=4.1.13|>=4.2,<=4.2.10|>=5,<=5.0.11|>=5.1,<=5.1.3", + "oro/platform": ">=1.7,<1.7.4|>=3.1,<3.1.29|>=4.1,<4.1.17|>=4.2,<=4.2.10|>=5,<=5.0.12|>=5.1,<=5.1.3", + "oveleon/contao-cookiebar": "<1.16.3|>=2,<2.1.3", + "oxid-esales/oxideshop-ce": "<=7.0.5", + "oxid-esales/paymorrow-module": ">=1,<1.0.2|>=2,<2.0.1", + "packbackbooks/lti-1-3-php-library": "<5", + "padraic/humbug_get_contents": "<1.1.2", + "pagarme/pagarme-php": "<3", + "pagekit/pagekit": "<=1.0.18", + "paragonie/ecc": "<2.0.1", + "paragonie/random_compat": "<2", + "paragonie/sodium_compat": "<1.24|>=2,<2.5", + "passbolt/passbolt_api": "<4.6.2", + "paypal/adaptivepayments-sdk-php": "<=3.9.2", + "paypal/invoice-sdk-php": "<=3.9", + "paypal/merchant-sdk-php": "<3.12", + "paypal/permissions-sdk-php": "<=3.9.1", + "pear/archive_tar": "<1.4.14", + "pear/auth": "<1.2.4", + "pear/crypt_gpg": "<1.6.7", + "pear/http_request2": "<2.7", + "pear/pear": "<=1.10.1", + "pegasus/google-for-jobs": "<1.5.1|>=2,<2.1.1", + "personnummer/personnummer": "<3.0.2", + "ph7software/ph7builder": "<=17.9.1", + "phanan/koel": "<5.1.4", + "phenx/php-svg-lib": "<0.5.2", + "php-censor/php-censor": "<2.0.13|>=2.1,<2.1.5", + "php-mod/curl": "<2.3.2", + "phpbb/phpbb": "<3.3.11", + "phpems/phpems": ">=6,<=6.1.3", + "phpfastcache/phpfastcache": "<6.1.5|>=7,<7.1.2|>=8,<8.0.7", + "phpmailer/phpmailer": "<6.5", + "phpmussel/phpmussel": ">=1,<1.6", + "phpmyadmin/phpmyadmin": "<5.2.2", + "phpmyfaq/phpmyfaq": "<=4.0.16", + "phpoffice/common": "<0.2.9", + "phpoffice/math": "<=0.2", + "phpoffice/phpexcel": "<=1.8.2", + "phpoffice/phpspreadsheet": "<1.30|>=2,<2.1.12|>=2.2,<2.4|>=3,<3.10|>=4,<5", + "phppgadmin/phppgadmin": "<=7.13", + "phpseclib/phpseclib": "<2.0.47|>=3,<3.0.36", + "phpservermon/phpservermon": "<3.6", + "phpsysinfo/phpsysinfo": "<3.4.3", + "phpunit/phpunit": "<8.5.52|>=9,<9.6.33|>=10,<10.5.62|>=11,<11.5.50|>=12,<12.5.8", + "phpwhois/phpwhois": "<=4.2.5", + "phpxmlrpc/extras": "<0.6.1", + "phpxmlrpc/phpxmlrpc": "<4.9.2", + "phraseanet/phraseanet": "==4.0.3", + "pi/pi": "<=2.5", + "pimcore/admin-ui-classic-bundle": "<=1.7.15|>=2.0.0.0-RC1-dev,<=2.2.2", + "pimcore/customer-management-framework-bundle": "<4.2.1", + "pimcore/data-hub": "<1.2.4", + "pimcore/data-importer": "<1.8.9|>=1.9,<1.9.3", + "pimcore/demo": "<10.3", + "pimcore/ecommerce-framework-bundle": "<1.0.10", + "pimcore/perspective-editor": "<1.5.1", + "pimcore/pimcore": "<=11.5.14.1|>=12,<12.3.3", + "pimcore/web2print-tools-bundle": "<=5.2.1|>=6.0.0.0-RC1-dev,<=6.1", + "piwik/piwik": "<1.11", + "pixelfed/pixelfed": "<0.12.5", + "plotly/plotly.js": "<2.25.2", + "pocketmine/bedrock-protocol": "<8.0.2", + "pocketmine/pocketmine-mp": "<5.32.1", + "pocketmine/raklib": ">=0.14,<0.14.6|>=0.15,<0.15.1", + "pressbooks/pressbooks": "<5.18", + "prestashop/autoupgrade": ">=4,<4.10.1", + "prestashop/blockreassurance": "<=5.1.3", + "prestashop/blockwishlist": ">=2,<2.1.1", + "prestashop/contactform": ">=1.0.1,<4.3", + "prestashop/gamification": "<2.3.2", + "prestashop/prestashop": "<8.2.4|>=9.0.0.0-alpha1,<9.0.3", + "prestashop/productcomments": "<5.0.2", + "prestashop/ps_checkout": "<4.4.1|>=5,<5.0.5", + "prestashop/ps_contactinfo": "<=3.3.2", + "prestashop/ps_emailsubscription": "<2.6.1", + "prestashop/ps_facetedsearch": "<3.4.1", + "prestashop/ps_linklist": "<3.1", + "privatebin/privatebin": "<1.4|>=1.5,<1.7.4|>=1.7.7,<2.0.3", + "processwire/processwire": "<=3.0.246", + "propel/propel": ">=2.0.0.0-alpha1,<=2.0.0.0-alpha7", + "propel/propel1": ">=1,<=1.7.1", + "psy/psysh": "<=0.11.22|>=0.12,<=0.12.18", + "pterodactyl/panel": "<1.12.1", + "ptheofan/yii2-statemachine": ">=2.0.0.0-RC1-dev,<=2", + "ptrofimov/beanstalk_console": "<1.7.14", + "pubnub/pubnub": "<6.1", + "punktde/pt_extbase": "<1.5.1", + "pusher/pusher-php-server": "<2.2.1", + "pwweb/laravel-core": "<=0.3.6.0-beta", + "pxlrbt/filament-excel": "<1.1.14|>=2.0.0.0-alpha,<2.3.3", + "pyrocms/pyrocms": "<=3.9.1", + "qcubed/qcubed": "<=3.1.1", + "quickapps/cms": "<=2.0.0.0-beta2", + "rainlab/blog-plugin": "<1.4.1", + "rainlab/debugbar-plugin": "<3.1", + "rainlab/user-plugin": "<=1.4.5", + "rankmath/seo-by-rank-math": "<=1.0.95", + "rap2hpoutre/laravel-log-viewer": "<0.13", + "react/http": ">=0.7,<1.9", + "really-simple-plugins/complianz-gdpr": "<6.4.2", + "redaxo/source": "<=5.20.1", + "remdex/livehelperchat": "<4.29", + "renolit/reint-downloadmanager": "<4.0.2|>=5,<5.0.1", + "reportico-web/reportico": "<=8.1", + "rhukster/dom-sanitizer": "<1.0.7", + "rmccue/requests": ">=1.6,<1.8", + "robrichards/xmlseclibs": "<=3.1.3", + "roots/soil": "<4.1", + "roundcube/roundcubemail": "<1.5.10|>=1.6,<1.6.11", + "rudloff/alltube": "<3.0.3", + "rudloff/rtmpdump-bin": "<=2.3.1", + "s-cart/core": "<=9.0.5", + "s-cart/s-cart": "<6.9", + "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", + "sabre/dav": ">=1.6,<1.7.11|>=1.8,<1.8.9", + "samwilson/unlinked-wikibase": "<1.42", + "scheb/two-factor-bundle": "<3.26|>=4,<4.11", + "sensiolabs/connect": "<4.2.3", + "serluck/phpwhois": "<=4.2.6", + "setasign/fpdi": "<2.6.4", + "sfroemken/url_redirect": "<=1.2.1", + "sheng/yiicms": "<1.2.1", + "shopware/core": "<6.6.10.9-dev|>=6.7,<6.7.6.1-dev", + "shopware/platform": "<6.6.10.7-dev|>=6.7,<6.7.3.1-dev", + "shopware/production": "<=6.3.5.2", + "shopware/shopware": "<=5.7.17|>=6.4.6,<6.6.10.10-dev|>=6.7,<6.7.6.1-dev", + "shopware/storefront": "<6.6.10.10-dev|>=6.7,<6.7.5.1-dev", + "shopxo/shopxo": "<=6.4", + "showdoc/showdoc": "<2.10.4", + "shuchkin/simplexlsx": ">=1.0.12,<1.1.13", + "silverstripe-australia/advancedreports": ">=1,<=2", + "silverstripe/admin": "<1.13.19|>=2,<2.1.8", + "silverstripe/assets": ">=1,<1.11.1", + "silverstripe/cms": "<4.11.3", + "silverstripe/comments": ">=1.3,<3.1.1", + "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", + "silverstripe/framework": "<5.3.23", + "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.8.2|>=4,<4.3.7|>=5,<5.1.3", + "silverstripe/hybridsessions": ">=1,<2.4.1|>=2.5,<2.5.1", + "silverstripe/recipe-cms": ">=4.5,<4.5.3", + "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", + "silverstripe/reports": "<5.2.3", + "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4|>=2.1,<2.1.2", + "silverstripe/silverstripe-omnipay": "<2.5.2|>=3,<3.0.2|>=3.1,<3.1.4|>=3.2,<3.2.1", + "silverstripe/subsites": ">=2,<2.6.1", + "silverstripe/taxonomy": ">=1.3,<1.3.1|>=2,<2.0.1", + "silverstripe/userforms": "<3|>=5,<5.4.2", + "silverstripe/versioned-admin": ">=1,<1.11.1", + "simogeo/filemanager": "<=2.5", + "simple-updates/phpwhois": "<=1", + "simplesamlphp/saml2": "<=4.16.15|>=5.0.0.0-alpha1,<=5.0.0.0-alpha19", + "simplesamlphp/saml2-legacy": "<=4.16.15", + "simplesamlphp/simplesamlphp": "<1.18.6", + "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", + "simplesamlphp/simplesamlphp-module-openid": "<1", + "simplesamlphp/simplesamlphp-module-openidprovider": "<0.9", + "simplesamlphp/xml-common": "<1.20", + "simplesamlphp/xml-security": "==1.6.11", + "simplito/elliptic-php": "<1.0.6", + "sitegeist/fluid-components": "<3.5", + "sjbr/sr-feuser-register": "<2.6.2|>=5.1,<12.5", + "sjbr/sr-freecap": "<2.4.6|>=2.5,<2.5.3", + "sjbr/static-info-tables": "<2.3.1", + "slim/psr7": "<1.4.1|>=1.5,<1.5.1|>=1.6,<1.6.1", + "slim/slim": "<2.6", + "slub/slub-events": "<3.0.3", + "smarty/smarty": "<4.5.3|>=5,<5.1.1", + "snipe/snipe-it": "<=8.3.4", + "socalnick/scn-social-auth": "<1.15.2", + "socialiteproviders/steam": "<1.1", + "solspace/craft-freeform": "<4.1.29|>=5,<=5.14.6", + "soosyze/soosyze": "<=2", + "spatie/browsershot": "<5.0.5", + "spatie/image-optimizer": "<1.7.3", + "spencer14420/sp-php-email-handler": "<1", + "spipu/html2pdf": "<5.2.8", + "spiral/roadrunner": "<2025.1", + "spoon/library": "<1.4.1", + "spoonity/tcpdf": "<6.2.22", + "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", + "ssddanbrown/bookstack": "<24.05.1", + "starcitizentools/citizen-skin": ">=1.9.4,<3.9", + "starcitizentools/short-description": ">=4,<4.0.1", + "starcitizentools/tabber-neue": ">=1.9.1,<2.7.2|>=3,<3.1.1", + "starcitizenwiki/embedvideo": "<=4", + "statamic/cms": "<5.73.10|>=6,<6.3.3", + "stormpath/sdk": "<9.9.99", + "studio-42/elfinder": "<=2.1.64", + "studiomitte/friendlycaptcha": "<0.1.4", + "subhh/libconnect": "<7.0.8|>=8,<8.1", + "sukohi/surpass": "<1", + "sulu/form-bundle": ">=2,<2.5.3", + "sulu/sulu": "<1.6.44|>=2,<2.5.25|>=2.6,<2.6.9|>=3.0.0.0-alpha1,<3.0.0.0-alpha3", + "sumocoders/framework-user-bundle": "<1.4", + "superbig/craft-audit": "<3.0.2", + "svewap/a21glossary": "<=0.4.10", + "swag/paypal": "<5.4.4", + "swiftmailer/swiftmailer": "<6.2.5", + "swiftyedit/swiftyedit": "<1.2", + "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", + "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", + "sylius/grid-bundle": "<1.10.1", + "sylius/paypal-plugin": "<1.6.2|>=1.7,<1.7.2|>=2,<2.0.2", + "sylius/resource-bundle": ">=1,<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", + "sylius/sylius": "<1.12.19|>=1.13.0.0-alpha1,<1.13.4", + "symbiote/silverstripe-multivaluefield": ">=3,<3.1", + "symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4", + "symbiote/silverstripe-seed": "<6.0.3", + "symbiote/silverstripe-versionedfiles": "<=2.0.3", + "symfont/process": ">=0", + "symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", + "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", + "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", + "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=5.3.14,<5.3.15|>=5.4.3,<5.4.4|>=6.0.3,<6.0.4", + "symfony/http-client": ">=4.3,<5.4.47|>=6,<6.4.15|>=7,<7.1.8", + "symfony/http-foundation": "<5.4.50|>=6,<6.4.29|>=7,<7.3.7", + "symfony/http-kernel": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.2.6", + "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/maker-bundle": ">=1.27,<1.29.2|>=1.30,<1.31.1", + "symfony/mime": ">=4.3,<4.3.8", + "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/polyfill": ">=1,<1.10", + "symfony/polyfill-php55": ">=1,<1.10", + "symfony/process": "<5.4.51|>=6,<6.4.33|>=7,<7.1.7|>=7.3,<7.3.11|>=7.4,<7.4.5|>=8,<8.0.5", + "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/routing": ">=2,<2.0.19", + "symfony/runtime": ">=5.3,<5.4.46|>=6,<6.4.14|>=7,<7.1.7", + "symfony/security": ">=2,<2.7.51|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.8", + "symfony/security-bundle": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.4.10|>=7,<7.0.10|>=7.1,<7.1.3", + "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.9", + "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security-guard": ">=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", + "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7|>=5.1,<5.2.8|>=5.3,<5.4.47|>=6,<6.4.15|>=7,<7.1.8", + "symfony/serializer": ">=2,<2.0.11|>=4.1,<4.4.35|>=5,<5.3.12", + "symfony/symfony": "<5.4.51|>=6,<6.4.33|>=7,<7.3.11|>=7.4,<7.4.5|>=8,<8.0.5", + "symfony/translation": ">=2,<2.0.17", + "symfony/twig-bridge": ">=2,<4.4.51|>=5,<5.4.31|>=6,<6.3.8", + "symfony/ux-autocomplete": "<2.11.2", + "symfony/ux-live-component": "<2.25.1", + "symfony/ux-twig-component": "<2.25.1", + "symfony/validator": "<5.4.43|>=6,<6.4.11|>=7,<7.1.4", + "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", + "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", + "symfony/webhook": ">=6.3,<6.3.8", + "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7|>=2.2.0.0-beta1,<2.2.0.0-beta2", + "symphonycms/symphony-2": "<2.6.4", + "t3/dce": "<0.11.5|>=2.2,<2.6.2", + "t3g/svg-sanitizer": "<1.0.3", + "t3s/content-consent": "<1.0.3|>=2,<2.0.2", + "tastyigniter/tastyigniter": "<4", + "tcg/voyager": "<=1.8", + "tecnickcom/tc-lib-pdf-font": "<2.6.4", + "tecnickcom/tcpdf": "<6.8", + "terminal42/contao-tablelookupwizard": "<3.3.5", + "thelia/backoffice-default-template": ">=2.1,<2.1.2", + "thelia/thelia": ">=2.1,<2.1.3", + "theonedemon/phpwhois": "<=4.2.5", + "thinkcmf/thinkcmf": "<6.0.8", + "thorsten/phpmyfaq": "<=4.0.16|>=4.1.0.0-alpha,<=4.1.0.0-beta2", + "tikiwiki/tiki-manager": "<=17.1", + "timber/timber": ">=0.16.6,<1.23.1|>=1.24,<1.24.1|>=2,<2.1", + "tinymce/tinymce": "<7.2", + "tinymighty/wiki-seo": "<1.2.2", + "titon/framework": "<9.9.99", + "tltneon/lgsl": "<7", + "tobiasbg/tablepress": "<=2.0.0.0-RC1", + "topthink/framework": "<6.0.17|>=6.1,<=8.0.4", + "topthink/think": "<=6.1.1", + "topthink/thinkphp": "<=3.2.3|>=6.1.3,<=8.0.4", + "torrentpier/torrentpier": "<=2.8.8", + "tpwd/ke_search": "<4.0.3|>=4.1,<4.6.6|>=5,<5.0.2", + "tribalsystems/zenario": "<=9.7.61188", + "truckersmp/phpwhois": "<=4.3.1", + "ttskch/pagination-service-provider": "<1", + "twbs/bootstrap": "<3.4.1|>=4,<4.3.1", + "twig/twig": "<3.11.2|>=3.12,<3.14.1|>=3.16,<3.19", + "typicms/core": "<16.1.7", + "typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", + "typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", + "typo3/cms-belog": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-beuser": ">=9,<9.5.55|>=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", + "typo3/cms-core": "<=8.7.56|>=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", + "typo3/cms-dashboard": ">=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", + "typo3/cms-extbase": "<6.2.24|>=7,<7.6.8|==8.1.1", + "typo3/cms-extensionmanager": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-felogin": ">=4.2,<4.2.3", + "typo3/cms-fluid": "<4.3.4|>=4.4,<4.4.1", + "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-frontend": "<4.3.9|>=4.4,<4.4.5", + "typo3/cms-indexed-search": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-install": "<4.1.14|>=4.2,<4.2.16|>=4.3,<4.3.9|>=4.4,<4.4.5|>=12.2,<12.4.8|==13.4.2", + "typo3/cms-lowlevel": ">=11,<=11.5.41", + "typo3/cms-recordlist": ">=11,<11.5.48", + "typo3/cms-recycler": ">=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", + "typo3/cms-redirects": ">=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", + "typo3/cms-rte-ckeditor": ">=9.5,<9.5.42|>=10,<10.4.39|>=11,<11.5.30", + "typo3/cms-scheduler": ">=11,<=11.5.41", + "typo3/cms-setup": ">=9,<=9.5.50|>=10,<=10.4.49|>=11,<=11.5.43|>=12,<=12.4.30|>=13,<=13.4.11", + "typo3/cms-webhooks": ">=12,<=12.4.30|>=13,<=13.4.11", + "typo3/cms-workspaces": ">=9,<9.5.55|>=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", + "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", + "typo3/html-sanitizer": ">=1,<=1.5.2|>=2,<=2.1.3", + "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", + "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", + "typo3/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", + "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", + "ua-parser/uap-php": "<3.8", + "uasoft-indonesia/badaso": "<=2.9.7", + "unisharp/laravel-filemanager": "<2.9.1", + "universal-omega/dynamic-page-list3": "<3.6.4", + "unopim/unopim": "<=0.3", + "userfrosting/userfrosting": ">=0.3.1,<4.6.3", + "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", + "uvdesk/community-skeleton": "<=1.1.1", + "uvdesk/core-framework": "<=1.1.1", + "vanilla/safecurl": "<0.9.2", + "verbb/comments": "<1.5.5", + "verbb/formie": "<=2.1.43", + "verbb/image-resizer": "<2.0.9", + "verbb/knock-knock": "<1.2.8", + "verot/class.upload.php": "<=2.1.6", + "vertexvaar/falsftp": "<0.2.6", + "villagedefrance/opencart-overclocked": "<=1.11.1", + "vova07/yii2-fileapi-widget": "<0.1.9", + "vrana/adminer": "<5.4.2", + "vufind/vufind": ">=2,<9.1.1", + "waldhacker/hcaptcha": "<2.1.2", + "wallabag/tcpdf": "<6.2.22", + "wallabag/wallabag": "<2.6.11", + "wanglelecc/laracms": "<=1.0.3", + "wapplersystems/a21glossary": "<=0.4.10", + "web-auth/webauthn-framework": ">=3.3,<3.3.4|>=4.5,<4.9", + "web-auth/webauthn-lib": ">=4.5,<4.9", + "web-feet/coastercms": "==5.5", + "web-tp3/wec_map": "<3.0.3", + "webbuilders-group/silverstripe-kapost-bridge": "<0.4", + "webcoast/deferred-image-processing": "<1.0.2", + "webklex/laravel-imap": "<5.3", + "webklex/php-imap": "<5.3", + "webpa/webpa": "<3.1.2", + "webreinvent/vaahcms": "<=2.3.1", + "wikibase/wikibase": "<=1.39.3", + "wikimedia/parsoid": "<0.12.2", + "willdurand/js-translation-bundle": "<2.1.1", + "winter/wn-backend-module": "<1.2.4", + "winter/wn-cms-module": "<=1.2.9", + "winter/wn-dusk-plugin": "<2.1", + "winter/wn-system-module": "<1.2.4", + "wintercms/winter": "<=1.2.3", + "wireui/wireui": "<1.19.3|>=2,<2.1.3", + "woocommerce/woocommerce": "<6.6|>=8.8,<8.8.5|>=8.9,<8.9.3", + "wp-cli/wp-cli": ">=0.12,<2.5", + "wp-graphql/wp-graphql": "<=1.14.5", + "wp-premium/gravityforms": "<2.4.21", + "wpanel/wpanel4-cms": "<=4.3.1", + "wpcloud/wp-stateless": "<3.2", + "wpglobus/wpglobus": "<=1.9.6", + "wwbn/avideo": "<=21", + "xataface/xataface": "<3", + "xpressengine/xpressengine": "<3.0.15", + "yab/quarx": "<2.4.5", + "yeswiki/yeswiki": "<=4.5.4", + "yetiforce/yetiforce-crm": "<6.5", + "yidashi/yii2cmf": "<=2", + "yii2mod/yii2-cms": "<1.9.2", + "yiisoft/yii": "<1.1.31", + "yiisoft/yii2": "<2.0.52", + "yiisoft/yii2-authclient": "<2.2.15", + "yiisoft/yii2-bootstrap": "<2.0.4", + "yiisoft/yii2-dev": "<=2.0.45", + "yiisoft/yii2-elasticsearch": "<2.0.5", + "yiisoft/yii2-gii": "<=2.2.4", + "yiisoft/yii2-jui": "<2.0.4", + "yiisoft/yii2-redis": "<2.0.20", + "yikesinc/yikes-inc-easy-mailchimp-extender": "<6.8.6", + "yoast-seo-for-typo3/yoast_seo": "<7.2.3", + "yourls/yourls": "<=1.10.2", + "yuan1994/tpadmin": "<=1.3.12", + "yungifez/skuul": "<=2.6.5", + "z-push/z-push-dev": "<2.7.6", + "zencart/zencart": "<=1.5.7.0-beta", + "zendesk/zendesk_api_client_php": "<2.2.11", + "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", + "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", + "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", + "zendframework/zend-db": "<2.2.10|>=2.3,<2.3.5", + "zendframework/zend-developer-tools": ">=1.2.2,<1.2.3", + "zendframework/zend-diactoros": "<1.8.4", + "zendframework/zend-feed": "<2.10.3", + "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-http": "<2.8.1", + "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", + "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", + "zendframework/zend-mail": "<2.4.11|>=2.5,<2.7.2", + "zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-session": ">=2,<2.2.9|>=2.3,<2.3.4", + "zendframework/zend-validator": ">=2.3,<2.3.6", + "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", + "zendframework/zendframework": "<=3", + "zendframework/zendframework1": "<1.12.20", + "zendframework/zendopenid": "<2.0.2", + "zendframework/zendrest": "<2.0.2", + "zendframework/zendservice-amazon": "<2.0.3", + "zendframework/zendservice-api": "<1", + "zendframework/zendservice-audioscrobbler": "<2.0.2", + "zendframework/zendservice-nirvanix": "<2.0.2", + "zendframework/zendservice-slideshare": "<2.0.2", + "zendframework/zendservice-technorati": "<2.0.2", + "zendframework/zendservice-windowsazure": "<2.0.2", + "zendframework/zendxml": ">=1,<1.0.1", + "zenstruck/collection": "<0.2.1", + "zetacomponents/mail": "<1.8.2", + "zf-commons/zfc-user": "<1.2.2", + "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", + "zfr/zfr-oauth2-server-module": "<0.1.2", + "zoujingli/thinkadmin": "<=6.1.53", + "zumba/json-serializer": "<3.2.3" + }, + "default-branch": true, + "type": "metapackage", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "role": "maintainer" + }, + { + "name": "Ilya Tribusean", + "email": "slash3b@gmail.com", + "role": "maintainer" + } + ], + "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", + "keywords": [ + "dev" + ], + "support": { + "issues": "https://github.com/Roave/SecurityAdvisories/issues", + "source": "https://github.com/Roave/SecurityAdvisories/tree/latest" + }, + "funding": [ + { + "url": "https://github.com/Ocramius", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/roave/security-advisories", + "type": "tidelift" + } + ], + "time": "2026-02-25T20:13:14+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.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", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:41:36+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5" + }, + "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", + "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", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-19T07:56:08+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "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": "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", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:45:54+00:00" + }, + { + "name": "sebastian/comparator", + "version": "6.3.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.4" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-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", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.3" + }, + "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:26:40+00:00" + }, + { + "name": "sebastian/complexity", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.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", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:49:50+00:00" + }, + { + "name": "sebastian/diff", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.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", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:53:05+00:00" + }, + { + "name": "sebastian/environment", + "version": "7.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.2-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": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1" + }, + "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/environment", + "type": "tidelift" + } + ], + "time": "2025-05-21T11:55:47+00:00" + }, + { + "name": "sebastian/exporter", + "version": "6.3.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-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", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2" + }, + "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:12:51+00:00" + }, + { + "name": "sebastian/global-state", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.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": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:57:36+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.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", + "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", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:58:38+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.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", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:00:13+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "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": "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", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:01:32+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.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", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.3" + }, + "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-13T04:42:22+00:00" + }, + { + "name": "sebastian/type", + "version": "5.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.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": "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", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.3" + }, + "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/type", + "type": "tidelift" + } + ], + "time": "2025-08-09T06:55:48+00:00" + }, + { + "name": "sebastian/version", + "version": "5.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "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": "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", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-10-09T05:16:32+00:00" + }, + { + "name": "shoppingfeed/coding-style-php", + "version": "2.4.2", + "source": { + "type": "git", + "url": "https://github.com/shoppingflux/coding-style-php.git", + "reference": "daae76d76c823e28d95e52dca7085b9c7875808b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/shoppingflux/coding-style-php/zipball/daae76d76c823e28d95e52dca7085b9c7875808b", + "reference": "daae76d76c823e28d95e52dca7085b9c7875808b", + "shasum": "" + }, + "require": { + "php": ">=8.0", + "slevomat/coding-standard": "^7.0|^8.0", + "squizlabs/php_codesniffer": "^3.6.0", + "symfony/console": "^5.0|^6.0|^7.0", + "symfony/process": "^5.0|^6.0|^7.0" + }, + "bin": [ + "bin/sfcs" + ], + "type": "library", + "autoload": { + "psr-4": { + "ShoppingFeed\\CodeStyle\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "support": { + "issues": "https://github.com/shoppingflux/coding-style-php/issues", + "source": "https://github.com/shoppingflux/coding-style-php/tree/2.4.2" + }, + "time": "2026-01-27T10:45:12+00:00" + }, + { + "name": "slevomat/coding-standard", + "version": "8.22.1", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "1dd80bf3b93692bedb21a6623c496887fad05fec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/1dd80bf3b93692bedb21a6623c496887fad05fec", + "reference": "1dd80bf3b93692bedb21a6623c496887fad05fec", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.1.2", + "php": "^7.4 || ^8.0", + "phpstan/phpdoc-parser": "^2.3.0", + "squizlabs/php_codesniffer": "^3.13.4" + }, + "require-dev": { + "phing/phing": "3.0.1|3.1.0", + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpstan/phpstan": "2.1.24", + "phpstan/phpstan-deprecation-rules": "2.0.3", + "phpstan/phpstan-phpunit": "2.0.7", + "phpstan/phpstan-strict-rules": "2.0.6", + "phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.36|12.3.10" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/8.22.1" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2025-09-13T08:53:30+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.13.5", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-11-04T16:30:35+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "symfony/cache", + "version": "v7.3.11", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "e3e76b9ba0dff3dfe08ebda500723976dd9de407" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/e3e76b9ba0dff3dfe08ebda500723976dd9de407", + "reference": "e3e76b9ba0dff3dfe08ebda500723976dd9de407", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/cache": "^2.0|^3.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^3.6", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/var-exporter": "^6.4|^7.0" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/dependency-injection": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/var-dumper": "<6.4" + }, + "provide": { + "psr/cache-implementation": "2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0", + "symfony/cache-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "symfony/clock": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/filesystem": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "classmap": [ + "Traits/ValueWrapper.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v7.3.11" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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": "2026-01-27T16:12:03+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/5d68a57d66910405e5c0b63d6f0af941e66fc868", + "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/cache": "^3.0" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-13T15:25:07+00:00" + }, + { + "name": "symfony/console", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "6d643a93b47398599124022eb24d97c153c12f27" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/6d643a93b47398599124022eb24d97c153c12f27", + "reference": "6d643a93b47398599124022eb24d97c153c12f27", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^7.2|^8.0" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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": "2026-02-25T17:02:47+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v7.4.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "dc2c0eba1af673e736bb851d747d266108aea746" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dc2c0eba1af673e736bb851d747d266108aea746", + "reference": "dc2c0eba1af673e736bb851d747d266108aea746", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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": "2026-01-05T11:45:34+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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": "2026-01-29T09:40:50+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v7.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "b38026df55197f9e39a44f3215788edf83187b80" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b38026df55197f9e39a44f3215788edf83187b80", + "reference": "b38026df55197f9e39a44f3215788edf83187b80", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v7.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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": "2025-11-12T15:39:26+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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": "2025-06-27T09:58:17+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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-12-23T08:48:59+00:00" + }, + { + "name": "symfony/process", + "version": "v7.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "608476f4604102976d687c483ac63a79ba18cc97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/608476f4604102976d687c483ac63a79ba18cc97", + "reference": "608476f4604102976d687c483ac63a79ba18cc97", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.4.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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": "2026-01-26T15:07:59+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.6.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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": "2025-07-15T11:30:57+00:00" + }, + { + "name": "symfony/string", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/9f209231affa85aa930a5e46e6eb03381424b30b", + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.33", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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": "2026-02-09T09:33:46+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v7.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "03a60f169c79a28513a78c967316fbc8bf17816f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/03a60f169c79a28513a78c967316fbc8bf17816f", + "reference": "03a60f169c79a28513a78c967316fbc8bf17816f", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "require-dev": { + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v7.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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": "2025-09-11T10:15:23+00:00" + }, + { + "name": "symfony/yaml", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "58751048de17bae71c5aa0d13cb19d79bca26391" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/58751048de17bae71c5aa0d13cb19d79bca26391", + "reference": "58751048de17bae71c5aa0d13cb19d79bca26391", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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": "2026-02-09T09:33:46+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": { + "roave/security-advisories": 20 + }, "prefer-stable": false, - "prefer-lowest": true, + "prefer-lowest": false, "platform": { - "php": ">=5.3.0" + "php": ">=8.2" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.6.0" } diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml deleted file mode 100644 index 0165d4d..0000000 --- a/phpdoc.dist.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - build/api - - - build/api - - - src - - diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..886e933 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,4 @@ +parameters: + paths: + - src + level: 8 diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..f531dbc --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,25 @@ + + + + + + + + + + ./test + + + + + src + + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist deleted file mode 100644 index b991b0d..0000000 --- a/phpunit.xml.dist +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - ./tests/Hal/ - - - - - ./src/ - - - - - - - - diff --git a/rector.php b/rector.php new file mode 100644 index 0000000..d53ae56 --- /dev/null +++ b/rector.php @@ -0,0 +1,46 @@ +withPaths([ + __DIR__ . '/src', + ]) + ->withPhpSets(php82: true) + ->withPreparedSets( + deadCode: true, + codeQuality: true, + typeDeclarations: true, + typeDeclarationDocblocks: true, + privatization: true, + instanceOf: true, + earlyReturn: true, + ) + ->withRules([ + Php84\Rector\Param\ExplicitNullableParamTypeRector::class, + + // From 8.3 ruleset + Php83\Rector\ClassConst\AddTypeToConstRector::class, + Php83\Rector\FuncCall\CombineHostPortLdapUriRector::class, + Php83\Rector\FuncCall\RemoveGetClassGetParentClassNoArgsRector::class, + ]); diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..a6d56fa --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,6 @@ +sonar.sources=./src +sonar.php.coverage.reportPaths=build/clover.xml +sonar.php.tests.reportPath=build/junit.xml +sonar.test.inclusions=test/** +sonar.organization=shoppingfeed +sonar.projectKey=shoppingflux_http-client diff --git a/src/Hal.php b/src/Hal.php index d0219a9..1bf7964 100644 --- a/src/Hal.php +++ b/src/Hal.php @@ -1,4 +1,5 @@ */ -class Hal +final class Hal { - /** - * The uri represented by this representation. - * - * @var string - */ - protected $uri; - /** * The data for this resource. An associative array of key value pairs. * @@ -41,10 +41,8 @@ class Hal /** * An array of embedded Hal objects representing embedded resources. - * - * @var array */ - protected $resources = array(); + protected array $resources = []; /** * A collection of \Nocarrier\HalLink objects keyed by the link relation to @@ -56,28 +54,26 @@ class Hal * * @var array */ - protected $links = null; + protected HalLinkContainer $links; /** * A list of rel types for links that will force a rel type to array for one element * - * @var array + * @var list */ - protected $arrayLinkRels = array(); + protected array $arrayLinkRels = []; /** * A list of rel types for links that will force a rel type to array for one element * - * @var array + * @var list */ - protected $arrayResourceRels = array(); + protected array $arrayResourceRels = []; /** * Whether xml attribute markers should be stripped when rendering - * - * @var string */ - protected $shouldStripAttributes = true; + protected bool $shouldStripAttributes = true; /** * Construct a new Hal object from an array of data. You can markup the @@ -100,14 +96,18 @@ class Hal * * @throws \RuntimeException */ - public function __construct($uri = null, $data = array()) - { - $this->uri = $uri; - - if (!is_array($data) && !$data instanceof \Traversable) { - throw new \RuntimeException( - 'The $data parameter must be an array or an object implementing the Traversable interface.'); + public function __construct(/** + * The uri represented by this representation. + */ + protected $uri = null, + $data = [], + ) { + if (! is_array($data) && ! $data instanceof Traversable) { + throw new RuntimeException( + 'The $data parameter must be an array or an object implementing the Traversable interface.', + ); } + $this->data = $data; $this->links = new HalLinkContainer(); @@ -115,43 +115,28 @@ public function __construct($uri = null, $data = array()) /** * Decode a application/hal+json document into a Nocarrier\Hal object. - * - * @param string $data - * @param int $depth - * @static - * @access public - * @return \Nocarrier\Hal */ - public static function fromJson($data, $depth = 0) + public static function fromJson(string $data, int $depth = 0): Hal { - return JsonHalFactory::fromJson(new static(), $data, $depth); + return JsonHalFactory::fromJson(new self(), $data, $depth); } /** * Decode a application/hal+xml document into a Nocarrier\Hal object. - * - * @param int $depth - * - * @static - * @access public - * @return \Nocarrier\Hal */ - public static function fromXml($data, $depth = 0) + public static function fromXml(string|SimpleXMLElement $data, int $depth = 0): Hal { - return XmlHalFactory::fromXml(new static(), $data, $depth); + return XmlHalFactory::fromXml(new self(), $data, $depth); } /** * Add a link to the resource, identified by $rel, located at $uri. * - * @param string $rel - * @param string $uri - * @param array $attributes + * @param array|array $attributes * Other attributes, as defined by HAL spec and RFC 5988. * @param bool $forceArray whether to force a rel to be an array if it has only one entry - * @return \Nocarrier\Hal */ - public function addLink($rel, $uri, array $attributes = array(), $forceArray = false) + public function addLink(string $rel, string $uri, array $attributes = [], bool $forceArray = false): self { return $this->addHalLink($rel, new HalLink($uri, $attributes), $forceArray); } @@ -159,12 +144,9 @@ public function addLink($rel, $uri, array $attributes = array(), $forceArray = f /** * Add a link instance to the resource, identified by $rel. * - * @param string $rel - * @param HalLink $link * @param bool $forceArray whether to force a rel to be an array if it has only one entry - * @return \Nocarrier\Hal */ - public function addHalLink($rel, HalLink $link, $forceArray = false) + public function addHalLink(string $rel, HalLink $link, bool $forceArray = false): self { $this->links[$rel][] = $link; @@ -177,20 +159,9 @@ public function addHalLink($rel, HalLink $link, $forceArray = false) /** * Add an embedded resource, identified by $rel and represented by $resource. - * - * @param string $rel - * @param \Nocarrier\Hal $resource - * - * @return \Nocarrier\Hal */ - public function addResource($rel, \Nocarrier\Hal $resource = null, $forceArray = true) + public function addResource(string $rel, Hal $resource = null, bool $forceArray = true): self { - if (!is_string($rel)) { - throw new \InvalidArgumentException( - "Argument 1 passed to Hal::addResource() must be a string describing the resource relationship" - ); - } - $this->resources[$rel][] = $resource; if ($forceArray) { @@ -206,10 +177,9 @@ public function addResource($rel, \Nocarrier\Hal $resource = null, $forceArray = * Using this method signifies that $rel will only ever be a single object * (only really relevant to JSON rendering) * - * @param string $rel * @param Hal $resource */ - public function setResource($rel, $resource) + public function setResource(string $rel, $resource): self { if (is_array($resource)) { foreach ($resource as $r) { @@ -219,8 +189,8 @@ public function setResource($rel, $resource) return $this; } - if (!($resource instanceof Hal)) { - throw new \InvalidArgumentException('$resource should be of type array or Nocarrier\Hal'); + if (! ($resource instanceof Hal)) { + throw new InvalidArgumentException('$resource should be of type array or Nocarrier\Hal'); } $this->resources[$rel][] = $resource; @@ -231,9 +201,10 @@ public function setResource($rel, $resource) /** * Set resource's data */ - public function setData(Array $data = null) + public function setData(array $data = null): self { $this->data = $data; + return $this; } @@ -246,7 +217,7 @@ public function setData(Array $data = null) public function getData($key = null) { if ($key) { - return isset($this->data[$key]) ? $this->data[$key] : array(); + return $this->data[$key] ?? []; } return $this->data; @@ -258,7 +229,7 @@ public function getData($key = null) * * @return array A collection of \Nocarrier\HalLink */ - public function getLinks() + public function getLinks(): HalLinkContainer { return $this->links; } @@ -267,27 +238,24 @@ public function getLinks() * Lookup and return an array of HalLink objects for a given relation. * Will also resolve CURIE rels if required. * - * @param string $rel The link relation required * @return array|bool * Array of HalLink objects if found. Otherwise false. */ - public function getLink($rel) + public function getLink(string $rel) { return $this->links->get($rel); } /** * Return an array of Nocarrier\Hal objected embedded in this one. - * - * @return array + * @return mixed[][] */ - public function getResources() + public function getResources(): array { - $resources = array_map(function ($resource) { - return is_array($resource) ? $resource : array($resource); - }, $this->getRawResources()); - - return $resources; + return array_map( + fn($resource): array => is_array($resource) ? $resource : [$resource], + $this->getRawResources(), + ); } /** @@ -299,11 +267,7 @@ public function getResource($rel) { $resources = $this->getResources(); - if (isset($resources[$rel])) { - return $resources[$rel]; - } - - return null; + return $resources[$rel] ?? null; } /** @@ -355,9 +319,10 @@ public function getFirstLink($rel) /** * Set resource's URI */ - public function setUri($uri) + public function setUri($uri): self { $this->uri = $uri; + return $this; } @@ -379,7 +344,7 @@ public function getUri() * Enable pretty-printing. * @param bool $encode * Run through json_encode - * @return string + * @return string|array */ public function asJson($pretty = false, $encode = true) { @@ -409,15 +374,10 @@ public function asXml($pretty = false) * e.g, * $hal->addCurie('acme', 'http://.../rels/{rel}'); * $hal->addLink('acme:test', 'http://.../test'); - * - * @param string $name - * @param string $uri - * - * @return \Nocarrier\Hal */ - public function addCurie($name, $uri) + public function addCurie(string $name, string $uri): self { - return $this->addLink('curies', $uri, array('name' => $name, 'templated' => true)); + return $this->addLink('curies', $uri, ['name' => $name, 'templated' => true]); } /** @@ -436,15 +396,15 @@ public function getArrayResourceRels() return $this->arrayResourceRels; } - public function getShouldStripAttributes() + public function getShouldStripAttributes(): bool { return $this->shouldStripAttributes; } - public function setShouldStripAttributes($shouldStripAttributes) + public function setShouldStripAttributes($shouldStripAttributes): self { $this->shouldStripAttributes = $shouldStripAttributes; + return $this; } - } diff --git a/src/HalJsonRenderer.php b/src/HalJsonRenderer.php index 8fa52cb..33475ec 100644 --- a/src/HalJsonRenderer.php +++ b/src/HalJsonRenderer.php @@ -1,4 +1,5 @@ = 0 and $pretty) { + + if (version_compare(PHP_VERSION, '5.4.0') >= 0 && $pretty) { $options = JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT; } $arrayForJson = $this->arrayForJson($resource); + if ($encode) { return json_encode($arrayForJson, $options); } @@ -49,27 +45,32 @@ public function render(Hal $resource, $pretty, $encode = true) * * @param mixed $uri * @param array $links - * @return array */ - protected function linksForJson($uri, $links, $arrayLinkRels) + protected function linksForJson($uri, $links, $arrayLinkRels): array { - $data = array(); - if (!is_null($uri)) { - $data['self'] = array('href' => $uri); + $data = []; + + if (null !== $uri) { + $data['self'] = ['href' => $uri]; } + foreach ($links as $rel => $links) { - if (count($links) === 1 && $rel !== 'curies' && !in_array($rel, $arrayLinkRels)) { - $data[$rel] = array('href' => $links[0]->getUri()); + if (count($links) === 1 && $rel !== 'curies' && ! in_array($rel, $arrayLinkRels)) { + $data[$rel] = ['href' => $links[0]->getUri()]; + foreach ($links[0]->getAttributes() as $attribute => $value) { $data[$rel][$attribute] = $value; } } else { - $data[$rel] = array(); + $data[$rel] = []; + foreach ($links as $link) { - $item = array('href' => $link->getUri()); + $item = ['href' => $link->getUri()]; + foreach ($link->getAttributes() as $attribute => $value) { $item[$attribute] = $value; } + $data[$rel][] = $item; } } @@ -87,16 +88,16 @@ protected function linksForJson($uri, $links, $arrayLinkRels) */ protected function resourcesForJson($resources) { - if (!is_array($resources)) { + if (! is_array($resources)) { return $this->arrayForJson($resources); } - $data = array(); + $data = []; foreach ($resources as $resource) { $res = $this->arrayForJson($resource); - if (!empty($res)) { + if (! empty($res)) { $data[] = $res; } } @@ -110,17 +111,16 @@ protected function resourcesForJson($resources) * * @param array $data * The array to strip @ from the keys. - * @return array */ - protected function stripAttributeMarker(array $data) + protected function stripAttributeMarker(array $data): array { foreach ($data as $key => $value) { - if (substr($key, 0, 5) == '@xml:') { - $data[substr($key, 5)] = $value; - unset ($data[$key]); - } elseif (substr($key, 0, 1) == '@') { - $data[substr($key, 1)] = $value; - unset ($data[$key]); + if (str_starts_with((string) $key, '@xml:')) { + $data[substr((string) $key, 5)] = $value; + unset($data[$key]); + } elseif (str_starts_with((string) $key, '@')) { + $data[substr((string) $key, 1)] = $value; + unset($data[$key]); } if (is_array($value)) { @@ -135,27 +135,28 @@ protected function stripAttributeMarker(array $data) * Return an array (compatible with the hal+json format) representing the * complete response. * - * @param \Nocarrier\Hal $resource * @return array */ protected function arrayForJson(Hal $resource = null) { if ($resource == null) { - return array(); + return []; } $data = $resource->getData(); + if ($resource->getShouldStripAttributes()) { $data = $this->stripAttributeMarker($data); } $links = $this->linksForJson($resource->getUri(), $resource->getLinks(), $resource->getArrayLinkRels()); + if (count($links)) { $data['_links'] = $links; } foreach ($resource->getRawResources() as $rel => $resources) { - if (count($resources) === 1 && !in_array($rel, $resource->getArrayResourceRels())) { + if (count($resources) === 1 && ! in_array($rel, $resource->getArrayResourceRels())) { $resources = $resources[0]; } diff --git a/src/HalLink.php b/src/HalLink.php index 7c76622..5c8e948 100644 --- a/src/HalLink.php +++ b/src/HalLink.php @@ -1,4 +1,5 @@ */ -class HalLink +class HalLink implements Stringable { - /** - * The URI represented by this HalLink. - * - * @var string - */ - protected $uri; - - /** - * Any attributes on this link. - * - * array( - * 'templated' => 0, - * 'type' => 'application/hal+json', - * 'deprecation' => 1, - * 'name' => 'latest', - * 'profile' => 'http://.../profile/order', - * 'title' => 'The latest order', - * 'hreflang' => 'en' - * ) - * - * @var array - */ - protected $attributes; - /** * The \Nocarrier\HalLink object. * @@ -53,18 +33,32 @@ class HalLink * @param array $attributes * Any additional attributes. */ - public function __construct($uri, $attributes) - { - $this->uri = $uri; - $this->attributes = $attributes; + public function __construct( + /** + * The URI represented by this HalLink. + */ + protected string $uri, + /** + * Any attributes on this link. + * + * array( + * 'templated' => 0, + * 'type' => 'application/hal+json', + * 'deprecation' => 1, + * 'name' => 'latest', + * 'profile' => 'http://.../profile/order', + * 'title' => 'The latest order', + * 'hreflang' => 'en' + * ) + */ + protected array $attributes, + ) { } /** * Return the URI from this link. - * - * @return string */ - public function getUri() + public function getUri(): string { return $this->uri; } @@ -74,7 +68,7 @@ public function getUri() * * return array */ - public function getAttributes() + public function getAttributes(): array { return $this->attributes; } @@ -84,7 +78,7 @@ public function getAttributes() * * return string */ - public function __toString() + public function __toString(): string { return $this->uri; } diff --git a/src/HalLinkContainer.php b/src/HalLinkContainer.php index a432dfe..33f9089 100644 --- a/src/HalLinkContainer.php +++ b/src/HalLinkContainer.php @@ -1,4 +1,5 @@ */ -class HalLinkContainer extends \ArrayObject +class HalLinkContainer extends ArrayObject { /** * Retrieve a link from the container by rel. Also resolve any curie links * if they are set. * - * @param string $rel - * The link relation required. * @return array|bool * Link if found. Otherwise false. */ - public function get($rel) + public function get(string $rel) { if (array_key_exists($rel, (array) $this)) { return $this[$rel]; @@ -37,12 +38,14 @@ public function get($rel) if (isset($this['curies'])) { foreach ($this['curies'] as $link) { - $prefix = strstr($link->getUri(), '{rel}', true); - if (strpos($rel, $prefix) === 0) { + $prefix = strstr((string) $link->getUri(), '{rel}', true); + + if (str_starts_with($rel, $prefix)) { // looks like it is $shortrel = substr($rel, strlen($prefix)); - $attrs = $link->getAttributes(); - $curie = "{$attrs['name']}:$shortrel"; + $attrs = $link->getAttributes(); + $curie = "{$attrs['name']}:$shortrel"; + if (isset($this[$curie])) { return $this[$curie]; } diff --git a/src/HalRenderer.php b/src/HalRenderer.php index 0f61ace..4d6481c 100644 --- a/src/HalRenderer.php +++ b/src/HalRenderer.php @@ -1,4 +1,5 @@ '); - if (!is_null($resource->getUri())) { + $doc = new SimpleXMLElement(''); + + if (null !== $resource->getUri()) { $doc->addAttribute('href', $resource->getUri()); } + $this->linksForXml($doc, $resource->getLinks()); $this->arrayToXml($resource->getData(), $doc); @@ -42,9 +41,10 @@ public function render(Hal $resource, $pretty, $encode = true) } $dom = dom_import_simplexml($doc); + if ($pretty) { $dom->ownerDocument->preserveWhiteSpace = false; - $dom->ownerDocument->formatOutput = true; + $dom->ownerDocument->formatOutput = true; } return $dom->ownerDocument->saveXML(); @@ -55,17 +55,16 @@ public function render(Hal $resource, $pretty, $encode = true) * * Add links in hal+xml format to a SimpleXmlElement object. * - * @param \SimpleXmlElement $doc - * @param \Nocarrier\HalLinkContainer $links * @return void */ - protected function linksForXml(\SimpleXmlElement $doc, HalLinkContainer $links) + protected function linksForXml(SimpleXmlElement $doc, HalLinkContainer $links) { foreach ($links as $rel => $links) { foreach ($links as $link) { $element = $doc->addChild('link'); $element->addAttribute('rel', $rel); $element->addAttribute('href', $link->getUri()); + foreach ($link->getAttributes() as $attribute => $value) { $element->addAttribute($attribute, $value); } @@ -77,16 +76,15 @@ protected function linksForXml(\SimpleXmlElement $doc, HalLinkContainer $links) * arrayToXml * * @param array $data - * @param \SimpleXmlElement $element * @param mixed $parent * @access protected * @return void */ - protected function arrayToXml($data, \SimpleXmlElement $element, $parent = null) + protected function arrayToXml($data, SimpleXmlElement $element, $parent = null) { foreach ($data as $key => $value) { - if (is_array($value) || $value instanceof \Traversable) { - if (!is_numeric($key)) { + if (is_iterable($value)) { + if (! is_numeric($key)) { if (count($value) > 0 && isset($value[0])) { $this->arrayToXml($value, $element, $key); } else { @@ -97,20 +95,18 @@ protected function arrayToXml($data, \SimpleXmlElement $element, $parent = null) $subnode = $element->addChild($parent); $this->arrayToXml($value, $subnode, $parent); } - } else { - if (!is_numeric($key)) { - if (substr($key, 0, 1) === '@') { - $element->addAttribute(substr($key, 1), $value); - } elseif ($key === 'value' and count($data) === 1) { - $element[0] = $value; - } elseif (is_bool($value)) { - $element->addChild($key, intval($value)); - } else { - $element->addChild($key, htmlspecialchars($value, ENT_QUOTES)); - } + } elseif (! is_numeric($key)) { + if (str_starts_with($key, '@')) { + $element->addAttribute(substr($key, 1), $value); + } elseif ($key === 'value' && count($data) === 1) { + $element[0] = $value; + } elseif (is_bool($value)) { + $element->addChild($key, intval($value)); } else { - $element->addChild($parent, htmlspecialchars($value, ENT_QUOTES)); + $element->addChild($key, htmlspecialchars((string) $value, ENT_QUOTES)); } + } else { + $element->addChild($parent, htmlspecialchars((string) $value, ENT_QUOTES)); } } } @@ -121,23 +117,21 @@ protected function arrayToXml($data, \SimpleXmlElement $element, $parent = null) * Add resources in hal+xml format (identified by $rel) to a * SimpleXmlElement object. * - * @param \SimpleXmlElement $doc * @param mixed $rel * @param mixed $resources */ - protected function resourcesForXml(\SimpleXmlElement $doc, $rel, $resources) + protected function resourcesForXml(SimpleXmlElement $doc, $rel, $resources) { - if (!is_array($resources)) { - $resources = array($resources); + if (! is_array($resources)) { + $resources = [$resources]; } - foreach($resources as $resource) { - + foreach ($resources as $resource) { $element = $doc->addChild('resource'); $element->addAttribute('rel', $rel); if ($resource) { - if (!is_null($resource->getUri())) { + if (null !== $resource->getUri()) { $element->addAttribute('href', $resource->getUri()); } diff --git a/src/JsonHalFactory.php b/src/JsonHalFactory.php index a99cc3a..d4148b5 100644 --- a/src/JsonHalFactory.php +++ b/src/JsonHalFactory.php @@ -2,60 +2,60 @@ namespace Nocarrier; +use Nocarrier\Hal; +use RuntimeException; + class JsonHalFactory { /** * Decode a application/hal+json document into a Nocarrier\Hal object. - * - * @param string $text - * @param int $depth - * @static - * @access public - * @return \Nocarrier\Hal */ - public static function fromJson(Hal $hal, $text, $depth = 0) + public static function fromJson(Hal $hal, string $text, int $depth = 0): Hal { - list($uri, $links, $embedded, $data) = self::prepareJsonData($text); + [$uri, $links, $embedded, $data] = self::prepareJsonData($text); $hal->setUri($uri)->setData($data); self::addJsonLinkData($hal, $links); if ($depth > 0) { self::setEmbeddedResources($hal, $embedded, $depth); } + $hal->setShouldStripAttributes(false); + return $hal; } /** - * @param string $text + * @return array */ - private static function prepareJsonData($text) + private static function prepareJsonData(string $text): array { $data = json_decode($text, true); - if (json_last_error() != JSON_ERROR_NONE) { - throw new \RuntimeException('The $text parameter must be valid JSON'); + + if (json_last_error() !== JSON_ERROR_NONE) { + throw new RuntimeException('The $text parameter must be valid JSON'); } - $uri = isset($data['_links']['self']['href']) ? $data['_links']['self']['href'] : ""; - unset ($data['_links']['self']); - $links = isset($data['_links']) ? $data['_links'] : array(); - unset ($data['_links']); + $uri = $data['_links']['self']['href'] ?? ''; + unset($data['_links']['self']); - $embedded = isset($data['_embedded']) ? $data['_embedded'] : array(); - unset ($data['_embedded']); + $links = $data['_links'] ?? []; + unset($data['_links']); - return array($uri, $links, $embedded, $data); + $embedded = $data['_embedded'] ?? []; + unset($data['_embedded']); + + return [$uri, $links, $embedded, $data]; } /** - * @param Hal $hal - * @param array $links + * @param array $links */ - private static function addJsonLinkData($hal, $links) + private static function addJsonLinkData(Hal $hal, array $links): void { foreach ($links as $rel => $links) { - if (!isset($links[0]) or !is_array($links[0])) { - $links = array($links); + if (! isset($links[0]) || ! is_array($links[0])) { + $links = [$links]; } foreach ($links as $link) { @@ -66,21 +66,17 @@ private static function addJsonLinkData($hal, $links) } } - /** - * @param Hal $hal - * @param array $embedded - * @param integer $depth - */ - private static function setEmbeddedResources(Hal $hal, $embedded, $depth) + private static function setEmbeddedResources(Hal $hal, array $embedded, int $depth): void { foreach ($embedded as $rel => $embed) { $isIndexed = array_values($embed) === $embed; - $className = get_class($hal); - if (!$isIndexed) { - $hal->setResource($rel, self::fromJson(new $className, json_encode($embed), $depth - 1)); + $className = $hal::class; + + if (! $isIndexed) { + $hal->setResource($rel, self::fromJson(new $className(), json_encode($embed), $depth - 1)); } else { foreach ($embed as $resource) { - $hal->addResource($rel, self::fromJson(new $className, json_encode($resource), $depth - 1)); + $hal->addResource($rel, self::fromJson(new $className(), json_encode($resource), $depth - 1)); } } } diff --git a/src/XmlHalFactory.php b/src/XmlHalFactory.php index 216111b..8d37fef 100644 --- a/src/XmlHalFactory.php +++ b/src/XmlHalFactory.php @@ -2,67 +2,71 @@ namespace Nocarrier; +use Exception; +use RuntimeException; +use SimpleXMLElement; + class XmlHalFactory { /** * Decode a application/hal+xml document into a Nocarrier\Hal object. * - * @param Hal $hal - * @param $data - * @param int $depth - * * @throws \RuntimeException - * @static - * @access public - * @return \Nocarrier\Hal */ - public static function fromXml(Hal $hal, $data, $depth = 0) + public static function fromXml(Hal $hal, SimpleXMLElement|string $data, int $depth = 0): Hal { - if (!$data instanceof \SimpleXMLElement) { + if (! $data instanceof SimpleXMLElement) { try { - $data = new \SimpleXMLElement($data); - } catch (\Exception $e) { - throw new \RuntimeException('The $data parameter must be valid XML'); + $data = new SimpleXMLElement($data); + } catch (Exception $e) { + throw new RuntimeException('The $data parameter must be valid XML', $e->getCode(), $e); } } $children = $data->children(); - $links = clone $children->link; - unset ($children->link); + $links = clone $children->link; + unset($children->link); $embedded = clone $children->resource; - unset ($children->resource); + unset($children->resource); - $hal->setUri((string)$data->attributes()->href); + $hal->setUri((string) $data->attributes()->href); $hal->setData((array) $children); + foreach ($links as $links) { - if (!is_array($links)) { - $links = array($links); + if (! is_array($links)) { + $links = [$links]; } + foreach ($links as $link) { - list($rel, $href, $attributes) = self::extractKnownData($link); + [$rel, $href, $attributes] = self::extractKnownData($link); $hal->addLink($rel, $href, $attributes); } } if ($depth > 0) { foreach ($embedded as $embed) { - list($rel, $href, $attributes) = self::extractKnownData($embed); + [$rel, $href, $attributes] = self::extractKnownData($embed); $hal->addResource($rel, self::fromXml($embed, $depth - 1)); } } + $hal->setShouldStripAttributes(false); + return $hal; } - private static function extractKnownData($data) + /** + * @return array + */ + private static function extractKnownData($data): array { - $attributes = (array)$data->attributes(); + $attributes = (array) $data->attributes(); $attributes = $attributes['@attributes']; - $rel = $attributes['rel']; - $href = $attributes['href']; + $rel = $attributes['rel']; + $href = $attributes['href']; unset($attributes['rel'], $attributes['href']); - return array($rel, $href, $attributes); + return [$rel, $href, $attributes]; } } diff --git a/tests/Hal/HalTest.php b/test/Hal/HalTest.php similarity index 69% rename from tests/Hal/HalTest.php rename to test/Hal/HalTest.php index 241c297..61179f9 100644 --- a/tests/Hal/HalTest.php +++ b/test/Hal/HalTest.php @@ -1,4 +1,5 @@ */ +#[CoversMethod(Hal::class, 'addLink')] +#[CoversMethod(Hal::class, 'addHalLink')] +#[CoversMethod(Hal::class, 'linksForJson')] +#[CoversMethod(Hal::class, 'linksForXml')] class HalTest extends TestCase { - public function testHalJsonResponseAllowsNoSelfLink() + public function testHalJsonResponseAllowsNoSelfLink(): void { $hal = new Hal(); $this->assertEquals('[]', $hal->asJson()); } - public function testHalXmlResponseAllowsNoSelfLink() + public function testHalXmlResponseAllowsNoSelfLink(): void { $hal = new Hal(); $this->assertEquals("\n\n", $hal->asXml()); } - public function testHalResponseReturnsSelfLinkJson() + public function testHalResponseReturnsSelfLinkJson(): void { $hal = new Hal('http://example.com/'); $this->assertEquals('{"_links":{"self":{"href":"http:\/\/example.com\/"}}}', $hal->asJson()); } - public function testHalResponseReturnsSelfLinkXml() + public function testHalResponseReturnsSelfLinkXml(): void { $hal = new Hal('http://example.com/'); $this->assertEquals("\n\n", $hal->asXml()); } - public function testAddLinkJsonResponse() + public function testAddLinkJsonResponse(): void { $hal = new Hal('http://example.com/'); $hal->addLink('test', '/test/1'); @@ -58,28 +68,27 @@ public function testAddLinkJsonResponse() $this->assertEquals('/test/1', $result->_links->test->href); } - public function testAddLinkRelAsArrayJsonResponse() + public function testAddLinkRelAsArrayJsonResponse(): void { $hal = new Hal('http://example.com/'); $hal->addLink('test', '/test/1', array(), true); - $json = $hal->asJson(); + $json = $hal->asJson(); $expectedJson = '{"_links":{"self":{"href":"http:\/\/example.com\/"},"test":[{"href":"\/test\/1"}]}}'; - $this->assertEquals($json,$expectedJson); + $this->assertEquals($json, $expectedJson); } - - public function testAddLinkXmlResponse() + public function testAddLinkXmlResponse(): void { $hal = new Hal('http://example.com/'); $hal->addLink('test', '/test/1'); - $result = new \SimpleXmlElement($hal->asXml()); - $data = $result->link->attributes(); + $result = new SimpleXmlElement($hal->asXml()); + $data = $result->link->attributes(); $this->assertEquals('test', $data['rel']); $this->assertEquals('/test/1', $data['href']); } - public function testXmlPrettyPrintResponse() + public function testXmlPrettyPrintResponse(): void { $hal = new Hal('http://example.com/'); $hal->addLink('test', '/test/1'); @@ -94,7 +103,7 @@ public function testXmlPrettyPrintResponse() $this->assertEquals($response, $hal->asXml(true)); } - public function testResourceJsonResponse() + public function testResourceJsonResponse(): void { $hal = new Hal('http://example.com/'); $res = new Hal('/resource/1', array('field1' => 'value1', 'field2' => 'value2')); @@ -102,13 +111,13 @@ public function testResourceJsonResponse() $resource = json_decode($hal->asJson()); $this->assertInstanceOf('StdClass', $resource->_embedded); - $this->assertInternalType('array', $resource->_embedded->resource); + $this->assertIsArray($resource->_embedded->resource); $this->assertEquals($resource->_embedded->resource[0]->_links->self->href, '/resource/1'); $this->assertEquals($resource->_embedded->resource[0]->field1, 'value1'); $this->assertEquals($resource->_embedded->resource[0]->field2, 'value2'); } - public function testResourceJsonResponseForceAsNoArray() + public function testResourceJsonResponseForceAsNoArray(): void { $hal = new Hal('http://example.com/'); $res = new Hal('/resource/1', array('field1' => 'value1', 'field2' => 'value2')); @@ -122,19 +131,19 @@ public function testResourceJsonResponseForceAsNoArray() $this->assertEquals($resource->_embedded->resource->field2, 'value2'); } - public function testResourceXmlResponse() + public function testResourceXmlResponse(): void { $hal = new Hal('http://example.com/'); $res = new Hal('/resource/1', array('field1' => 'value1', 'field2' => 'value2')); $hal->addResource('resource', $res); - $result = new \SimpleXmlElement($hal->asXml()); + $result = new SimpleXmlElement($hal->asXml()); $this->assertEquals('/resource/1', $result->resource->attributes()->href); $this->assertEquals('value1', $result->resource->field1); $this->assertEquals('value2', $result->resource->field2); } - public function testEmbeddedResourceInResourceJsonResponse() + public function testEmbeddedResourceInResourceJsonResponse(): void { $hal = new Hal('http://example.com/'); $res = new Hal('/resource/1', array('field1' => 'value1', 'field2' => 'value2')); @@ -143,19 +152,22 @@ public function testEmbeddedResourceInResourceJsonResponse() new Hal( '/resource/1/item/1', array( - 'itemField1' => 'itemValue1' - ) - ) + 'itemField1' => 'itemValue1', + ), + ), ); $hal->addResource('resource', $res); $result = json_decode($hal->asJson()); - $this->assertInternalType('array', $result->_embedded->resource[0]->_embedded->item); - $this->assertEquals('/resource/1/item/1', $result->_embedded->resource[0]->_embedded->item[0]->_links->self->href); + $this->assertIsArray($result->_embedded->resource[0]->_embedded->item); + $this->assertEquals( + '/resource/1/item/1', + $result->_embedded->resource[0]->_embedded->item[0]->_links->self->href, + ); $this->assertEquals('itemValue1', $result->_embedded->resource[0]->_embedded->item[0]->itemField1); } - public function testEmbeddedResourceInResourceXmlResponse() + public function testEmbeddedResourceInResourceXmlResponse(): void { $hal = new Hal('http://example.com/'); $res = new Hal('/resource/1', array('field1' => 'value1', 'field2' => 'value2')); @@ -166,21 +178,21 @@ public function testEmbeddedResourceInResourceXmlResponse() array( 'items' => array( array( - 'itemField1' => 'itemValue1' - ) - ) - ) - ) + 'itemField1' => 'itemValue1', + ), + ), + ), + ), ); $hal->addResource('resource', $res); - $result = new \SimpleXmlElement($hal->asXml()); + $result = new SimpleXmlElement($hal->asXml()); $this->assertEquals('item', $result->resource->resource->attributes()->rel); $this->assertEquals('/resource/1/item/1', $result->resource->resource->attributes()->href); $this->assertEquals('itemValue1', $result->resource->resource->items[0]->itemField1); } - public function testResourceWithListRendersCorrectlyInXmlResponse() + public function testResourceWithListRendersCorrectlyInXmlResponse(): void { $hal = new Hal('/orders'); $hal->addLink('next', '/orders?page=2'); @@ -191,33 +203,33 @@ public function testResourceWithListRendersCorrectlyInXmlResponse() array( 'tests' => array( array( - 'total' => 30.00, - 'currency' => 'USD' + 'total' => 30.00, + 'currency' => 'USD', ), array( - 'total' => 40.00, - 'currency' => 'GBP' - ) - ) - ) + 'total' => 40.00, + 'currency' => 'GBP', + ), + ), + ), ); $resource->addLink('customer', '/customer/bob'); $hal->addResource('order', $resource); - $result = new \SimpleXmlElement($hal->asXml()); - $this->assertEquals(30, (string)$result->resource->tests[0]->total); - $this->assertEquals('USD', (string)$result->resource->tests[0]->currency); - $this->assertEquals(40, (string)$result->resource->tests[1]->total); - $this->assertEquals('GBP', (string)$result->resource->tests[1]->currency); + $result = new SimpleXmlElement($hal->asXml()); + $this->assertEquals(30, (string) $result->resource->tests[0]->total); + $this->assertEquals('USD', (string) $result->resource->tests[0]->currency); + $this->assertEquals(40, (string) $result->resource->tests[1]->total); + $this->assertEquals('GBP', (string) $result->resource->tests[1]->currency); } - public function testAddingDataToRootResource() + public function testAddingDataToRootResource(): void { $hal = new Hal( '/root', array( 'firstname' => 'Ben', - 'surname' => 'Longden' - ) + 'surname' => 'Longden', + ), ); $result = json_decode($hal->asJson(true)); @@ -225,7 +237,7 @@ public function testAddingDataToRootResource() $this->assertEquals('Longden', $result->surname); } - public function testAddArrayOfLinksInJson() + public function testAddArrayOfLinksInJson(): void { $hal = new Hal('/'); $hal->addLink('members', '/member/1'); @@ -236,35 +248,35 @@ public function testAddArrayOfLinksInJson() $this->assertEquals('/member/2', $result->_links->members[1]->href); } - public function testAddArrayOfLinksInXml() + public function testAddArrayOfLinksInXml(): void { $hal = new Hal('/'); $hal->addLink('members', '/member/1'); $hal->addLink('members', '/member/2'); - $result = new \SimpleXmlElement($hal->asXml()); + $result = new SimpleXmlElement($hal->asXml()); $this->assertEquals('members', $result->link[0]->attributes()->rel); $this->assertEquals('members', $result->link[1]->attributes()->rel); $this->assertEquals('/member/1', $result->link[0]->attributes()->href); $this->assertEquals('/member/2', $result->link[1]->attributes()->href); } - public function testAttributesInXmlRepresentation() + public function testAttributesInXmlRepresentation(): void { $hal = new Hal( '/', array( 'error' => array( - '@id' => 6, + '@id' => 6, '@xml:lang' => 'en', - 'message' => 'This is a message' - ) - ) + 'message' => 'This is a message', + ), + ), ); - $xml = new \SimpleXMLElement($hal->asXml()); - $this->assertEquals(6, (string)$xml->error->attributes()->id); - $this->assertEquals('en', (string)$xml->error->attributes()->lang); - $this->assertEquals('This is a message', (string)$xml->error->message); + $xml = new SimpleXmlElement($hal->asXml()); + $this->assertEquals(6, (string) $xml->error->attributes()->id); + $this->assertEquals('en', (string) $xml->error->attributes()->lang); + $this->assertEquals('This is a message', (string) $xml->error->message); $json = json_decode($hal->asJson(true)); $this->assertEquals(6, $json->error->id); @@ -272,23 +284,18 @@ public function testAttributesInXmlRepresentation() $this->assertEquals('This is a message', $json->error->message); } - /** - * @covers \Nocarrier\Hal::addLink - * @covers \Nocarrier\Hal::addHalLink - * @covers \Nocarrier\HalJsonRenderer::linksForJson - */ - public function testLinkAttributesInJson() + public function testLinkAttributesInJson(): void { $hal = new Hal('http://example.com/'); $hal->addLink('test', '/test/{?id}', array( - 'anchor' => '#foo', - 'rev' => 'canonical', - 'hreflang' => 'en', - 'media' => 'screen', - 'type' => 'text/html', + 'anchor' => '#foo', + 'rev' => 'canonical', + 'hreflang' => 'en', + 'media' => 'screen', + 'type' => 'text/html', 'templated' => 'true', - 'name' => 'ex', - 'title' => 'My Test' + 'name' => 'ex', + 'title' => 'My Test', )); $result = json_decode($hal->asJson()); @@ -302,34 +309,31 @@ public function testLinkAttributesInJson() $this->assertEquals('My Test', $result->_links->test->title); } - /** - * @covers \Nocarrier\HalJsonRenderer::linksForJson - * Provided for code coverage - */ - public function testLinkAttributesInJsonWithArrayOfLinks() + public function testLinkAttributesInJsonWithArrayOfLinks(): void { $hal = new Hal('http://example.com/'); $hal->addLink('test', '/test/{?id}', array( - 'anchor' => '#foo1', - 'rev' => 'canonical1', - 'hreflang' => 'en1', - 'media' => 'screen1', - 'type' => 'text/html1', + 'anchor' => '#foo1', + 'rev' => 'canonical1', + 'hreflang' => 'en1', + 'media' => 'screen1', + 'type' => 'text/html1', 'templated' => 'true1', - 'name' => 'ex1', + 'name' => 'ex1', )); $hal->addLink('test', '/test/{?id}', array( - 'anchor' => '#foo2', - 'rev' => 'canonical2', - 'hreflang' => 'en2', - 'media' => 'screen2', - 'type' => 'text/html2', + 'anchor' => '#foo2', + 'rev' => 'canonical2', + 'hreflang' => 'en2', + 'media' => 'screen2', + 'type' => 'text/html2', 'templated' => 'true2', - 'name' => 'ex2', + 'name' => 'ex2', )); $result = json_decode($hal->asJson()); - $i = 1; + $i = 1; + foreach ($result->_links->test as $testLink) { $this->assertEquals('#foo' . $i, $testLink->anchor); $this->assertEquals('canonical' . $i, $testLink->rev); @@ -342,26 +346,21 @@ public function testLinkAttributesInJsonWithArrayOfLinks() } } - /** - * @covers \Nocarrier\Hal::addLink - * @covers \Nocarrier\Hal::addHalLink - * @covers \Nocarrier\HalXmlRenderer::linksForXml - */ - public function testLinkAttributesInXml() + public function testLinkAttributesInXml(): void { $hal = new Hal('http://example.com/'); $hal->addLink('test', '/test/{?id}', array( - 'anchor' => '#foo', - 'rev' => 'canonical', - 'hreflang' => 'en', - 'media' => 'screen', - 'type' => 'text/html', + 'anchor' => '#foo', + 'rev' => 'canonical', + 'hreflang' => 'en', + 'media' => 'screen', + 'type' => 'text/html', 'templated' => 'true', - 'name' => 'ex', + 'name' => 'ex', )); - $result = new \SimpleXmlElement($hal->asXml()); - $data = $result->link->attributes(); + $result = new SimpleXmlElement($hal->asXml()); + $data = $result->link->attributes(); $this->assertEquals('#foo', $data['anchor']); $this->assertEquals('canonical', $data['rev']); $this->assertEquals('en', $data['hreflang']); @@ -371,34 +370,31 @@ public function testLinkAttributesInXml() $this->assertEquals('ex', $data['name']); } - /** - * @covers \Nocarrier\HalXmlRenderer::linksForXml - * Provided for code coverage. - */ - public function testLinkAttributesInXmlWithArrayOfLinks() + public function testLinkAttributesInXmlWithArrayOfLinks(): void { $hal = new Hal('http://example.com/'); $hal->addLink('test', '/test/{?id}', array( - 'anchor' => '#foo1', - 'rev' => 'canonical1', - 'hreflang' => 'en1', - 'media' => 'screen1', - 'type' => 'text/html1', + 'anchor' => '#foo1', + 'rev' => 'canonical1', + 'hreflang' => 'en1', + 'media' => 'screen1', + 'type' => 'text/html1', 'templated' => 'true1', - 'name' => 'ex1', + 'name' => 'ex1', )); $hal->addLink('test', '/test/{?id}', array( - 'anchor' => '#foo2', - 'rev' => 'canonical2', - 'hreflang' => 'en2', - 'media' => 'screen2', - 'type' => 'text/html2', + 'anchor' => '#foo2', + 'rev' => 'canonical2', + 'hreflang' => 'en2', + 'media' => 'screen2', + 'type' => 'text/html2', 'templated' => 'true2', - 'name' => 'ex2', + 'name' => 'ex2', )); - $result = new \SimpleXmlElement($hal->asXml()); - $i = 1; + $result = new SimpleXmlElement($hal->asXml()); + $i = 1; + foreach ($result->link as $link) { $data = $link->attributes(); $this->assertEquals('#foo' . $i, $data['anchor']); @@ -412,7 +408,7 @@ public function testLinkAttributesInXmlWithArrayOfLinks() } } - public function testNumericKeysUseParentAsXmlElementName() + public function testNumericKeysUseParentAsXmlElementName(): void { $hal = new Hal('/', array( 'foo' => array( @@ -421,7 +417,7 @@ public function testNumericKeysUseParentAsXmlElementName() ), )); - $result = new \SimpleXmlElement($hal->asXml()); + $result = new SimpleXmlElement($hal->asXml()); $this->assertEquals('bar', $result->foo[0]); $this->assertEquals('baz', $result->foo[1]); @@ -431,95 +427,96 @@ public function testNumericKeysUseParentAsXmlElementName() $this->assertEquals(array('bar', 'baz'), $json['foo']); } - public function testMinimalHalJsonDecoding() + public function testMinimalHalJsonDecoding(): void { $sample = '{"_links":{"self":{"href":"http:\/\/example.com\/"}}}'; - $hal = Hal::fromJson($sample); + $hal = Hal::fromJson($sample); $this->assertEquals($sample, $hal->asJson()); } - public function testHalJsonDecodeWithData() + public function testHalJsonDecodeWithData(): void { $sample = '{"_links":{"self":{"href":"http:\/\/example.com\/"}},"key":"value"}'; - $data = Hal::fromJson($sample)->getData(); + $data = Hal::fromJson($sample)->getData(); $this->assertEquals('value', $data['key']); } - public function testMinimalHalXmlDecoding() + public function testMinimalHalXmlDecoding(): void { $sample = "\n\n"; - $hal = Hal::fromXml($sample); + $hal = Hal::fromXml($sample); $this->assertEquals($sample, $hal->asXml()); } - public function testHalXmlDecodeWithData() + public function testHalXmlDecodeWithData(): void { $sample = "\nvalue\n"; - $data = Hal::fromXml($sample)->getData(); + $data = Hal::fromXml($sample)->getData(); $this->assertEquals('value', $data['key']); } - public function testHalJsonDecodeWithLinks() + public function testHalJsonDecodeWithLinks(): void { - $x = new Hal('/test', array('name' => "Ben Longden")); + $x = new Hal('/test', array('name' => 'Ben Longden')); $x->addLink('a', '/a'); $y = Hal::fromJson($x->asJson()); $this->assertEquals($x->asJson(true), $y->asJson(true)); } - public function testHalXmlDecodeWithLinks() + public function testHalXmlDecodeWithLinks(): void { - $x = new Hal('/test', array('name' => "Ben Longden")); + $x = new Hal('/test', array('name' => 'Ben Longden')); $x->addLink('a', '/a'); $y = Hal::fromXml($x->asXml()); $this->assertEquals($x->asXml(), $y->asXml()); } - public function testHalXmlEntitySetWhenValueSpecifiedInData() + public function testHalXmlEntitySetWhenValueSpecifiedInData(): void { $x = new Hal('/', array('x' => array('value' => 'test'))); - $xml = new \SimpleXMLElement($x->asXml()); - $this->assertEquals('test', (string)$xml->x); + $xml = new SimpleXmlElement($x->asXml()); + $this->assertEquals('test', (string) $xml->x); } - public function testHalXmlEntitySetWhenValueSpecifiedInMultiData() + public function testHalXmlEntitySetWhenValueSpecifiedInMultiData(): void { $x = new Hal('/', array('x' => array('key' => 'test', 'value' => 'test'))); - $xml = new \SimpleXMLElement($x->asXml()); - $this->assertEquals('test', (string)$xml->x->key); - $this->assertEquals('test', (string)$xml->x->value); + $xml = new SimpleXmlElement($x->asXml()); + $this->assertEquals('test', (string) $xml->x->key); + $this->assertEquals('test', (string) $xml->x->value); } - public function testBooleanOutput() + + public function testBooleanOutput(): void { $hal = new Hal('/', array( 'foo' => true, - 'bar' => false + 'bar' => false, )); - $xml = new \SimpleXMLElement($hal->asXml()); - $this->assertSame('1', (string)$xml->foo); - $this->assertSame('0', (string)$xml->bar); + $xml = new SimpleXmlElement($hal->asXml()); + $this->assertSame('1', (string) $xml->foo); + $this->assertSame('0', (string) $xml->bar); $json = json_decode($hal->asJson()); $this->assertTrue($json->foo); $this->assertFalse($json->bar); } - public function testAddCurieConformsToSpecification() + public function testAddCurieConformsToSpecification(): void { $x = new Hal('/orders'); $x->addCurie('acme', 'http://docs.acme.com/relations/{rel}'); $obj = json_decode($x->asJson()); - $this->assertInternalType('array', $obj->_links->curies); + $this->assertIsArray($obj->_links->curies); $this->assertTrue($obj->_links->curies[0]->templated); $this->assertEquals('acme', $obj->_links->curies[0]->name); $this->assertEquals('http://docs.acme.com/relations/{rel}', $obj->_links->curies[0]->href); } - public function testGetLinkByRelation() + public function testGetLinkByRelation(): void { $x = new Hal('/orders'); $x->addLink('test', '/test/orders'); @@ -528,7 +525,7 @@ public function testGetLinkByRelation() $this->assertEquals('/test/orders', $links[0]); } - public function testGetFirstLinkByRelation() + public function testGetFirstLinkByRelation(): void { $x = new Hal('/orders'); $x->addLink('test', '/test/orders'); @@ -537,7 +534,7 @@ public function testGetFirstLinkByRelation() $this->assertEquals('/test/orders', $links); } - public function testGetLinkByCurieRelation() + public function testGetLinkByCurieRelation(): void { $x = new Hal('/orders'); $x->addCurie('acme', 'http://docs.acme.com/relations/{rel}'); @@ -548,20 +545,22 @@ public function testGetLinkByCurieRelation() $this->assertEquals('/widgets', $links[0]); } - public function testGetLinkReturnsFalseOnFailure() + public function testGetLinkReturnsFalseOnFailure(): void { $x = new Hal('/orders'); $this->assertFalse($x->getLink('test')); } - public function testJSONEmptyEmbeddedCollection(){ + public function testJsonEmptyEmbeddedCollection(): void + { $x = new Hal(); $x->addResource('collection'); $this->assertEquals('{"_embedded":{"collection":[]}}', $x->asJson()); } - public function testXMLEmptyEmbeddedCollection(){ + public function testXmlEmptyEmbeddedCollection(): void + { $x = new Hal(); $x->addResource('collection'); $response = <<assertEquals($response, $x->asXml()); } - public function testLinksWithAttributesUnserialiseCorrectlyJson() + public function testLinksWithAttributesUnserialiseCorrectlyJson(): void { $x = new Hal('/'); $x->addCurie('x:test', 'http://test'); @@ -580,7 +579,7 @@ public function testLinksWithAttributesUnserialiseCorrectlyJson() $this->assertEquals($x->asJson(), Hal::fromJson($x->asJson())->asJson()); } - public function testLinksWithAttributesUnserialiseCorrectlyXml() + public function testLinksWithAttributesUnserialiseCorrectlyXml(): void { $x = new Hal('/'); $x->addCurie('x:test', 'http://test'); @@ -588,7 +587,7 @@ public function testLinksWithAttributesUnserialiseCorrectlyXml() $this->assertEquals($x->asXml(), Hal::fromXml($x->asXml())->asXml()); } - public function testResourceWithNullSelfLinkRendersLinksInJson() + public function testResourceWithNullSelfLinkRendersLinksInJson(): void { $x = new Hal(null); $x->addLink('testrel', 'http://test'); @@ -596,10 +595,10 @@ public function testResourceWithNullSelfLinkRendersLinksInJson() $this->assertEquals('http://test', $data->_links->testrel->href); } - public function testDataCanBeTraversable() + public function testDataCanBeTraversable(): void { - $it = new \ArrayIterator(array('traversable' => new \ArrayIterator(array('key' => 'value')))); - $x = new Hal('', $it); + $it = new ArrayIterator(array('traversable' => new ArrayIterator(array('key' => 'value')))); + $x = new Hal('', $it); $response = << @@ -609,34 +608,34 @@ public function testDataCanBeTraversable() $this->assertEquals($response, $x->asXml()); } - public function testJsonAllowingDisableEncode() + public function testJsonAllowingDisableEncode(): void { $hal = new Hal(); $this->assertSame(array(), $hal->asJson(false, false)); } - public function testSetResourceWithArrayOfResources() + public function testSetResourceWithArrayOfResources(): void { - $hal = new Hal('http://example.com/'); + $hal = new Hal('http://example.com/'); $res1 = new Hal('/resource/1', array('field1' => '1')); $res2 = new Hal('/resource/2', array('field1' => '2')); $hal->setResource('resource', array($res1, $res2)); $resource = json_decode($hal->asJson()); $this->assertInstanceOf('StdClass', $resource->_embedded); - $this->assertInternalType('array', $resource->_embedded->resource); + $this->assertIsArray($resource->_embedded->resource); $this->assertEquals($resource->_embedded->resource[0]->field1, '1'); $this->assertEquals($resource->_embedded->resource[1]->field1, '2'); } - public function testSetResourceThrowsIfNotPassedAHalOrArray() + public function testSetResourceThrowsIfNotPassedHalOrArray(): void { $this->setExpectedException('\InvalidArgumentException', '$resource should be of type array or Nocarrier\Hal'); $hal = new Hal('http://example.com/'); - $hal->setResource('resource', new \stdClass()); + $hal->setResource('resource', new stdClass()); } - public function testSetResourceJsonResponse() + public function testSetResourceJsonResponse(): void { $hal = new Hal('http://example.com/'); $res = new Hal('/resource/1', array('field1' => 'value1', 'field2' => 'value2')); @@ -650,21 +649,21 @@ public function testSetResourceJsonResponse() $this->assertEquals($resource->_embedded->resource->field2, 'value2'); } - public function testSetResourceXmlResponse() + public function testSetResourceXmlResponse(): void { $hal = new Hal('http://example.com/'); $res = new Hal('/resource/1', array('field1' => 'value1', 'field2' => 'value2')); $hal->setResource('resource', $res); - $result = new \SimpleXmlElement($hal->asXml()); + $result = new SimpleXmlElement($hal->asXml()); $this->assertEquals('/resource/1', $result->resource->attributes()->href); $this->assertEquals('value1', $result->resource->field1); $this->assertEquals('value2', $result->resource->field2); } - public function testHalJsonDecodeWithCollectionOfEmbeddedItems() + public function testHalJsonDecodeWithCollectionOfEmbeddedItems(): void { - $sample = <<assertEquals('value2', $resources['item'][1]->getData('key')); } - public function testHalJsonDecodeWithSingleEmbeddedItem() + public function testHalJsonDecodeWithSingleEmbeddedItem(): void { - $sample = <<assertEquals('value', $data['key']); } - public function testGetFirstResourceReturnsSingleItem() + public function testGetFirstResourceReturnsSingleItem(): void { $hal = new Hal('http://example.com/'); $res = new Hal('/resource/1', array('field1' => 'value1', 'field2' => 'value2')); $hal->setResource('resource', $res); - $this->assertEquals($res, $hal->getFirstResource("resource")); + $this->assertEquals($res, $hal->getFirstResource('resource')); } - public function testGetFirstResourceReturnsFirstOfMultipleItems() + public function testGetFirstResourceReturnsFirstOfMultipleItems(): void { - $hal = new Hal('http://example.com/'); + $hal = new Hal('http://example.com/'); $res1 = new Hal('/resource/1', array('field1' => 'value1', 'field2' => 'value2')); $res2 = new Hal('/resource/2', array('field2' => 'value2', 'field2' => 'value2')); $hal->addResource('resource', $res1); $hal->addResource('resource', $res2); - $this->assertEquals($res1, $hal->getFirstResource("resource")); + $this->assertEquals($res1, $hal->getFirstResource('resource')); } - /** - * @expectedException RuntimeException - */ - public function testHalFromJsonThrowsExceptionOnInvalidJSON() + public function testHalFromJsonThrowsExceptionOnInvalidJson(): void { + $this->expectException(RuntimeException::class); $invalidJson = 'foo'; Hal::fromJson($invalidJson); } - public function testCanDefineThatAttributesShouldNotBeStripped() + public function testCanDefineThatAttributesShouldNotBeStripped(): void { $hal = new Hal('http://example.com/'); $hal->setShouldStripAttributes(false); $this->assertEquals(false, $hal->getShouldStripAttributes()); } - public function testStripAttributeMarkersIsNotCalledWhenRenderingWithStripAttributesSetToFalse() + public function testStripAttributeMarkersIsNotCalledWhenRenderingWithStripAttributesSetToFalse(): void { $hal = new Hal('http://example.com/', array('@xml:key' => 'value')); $hal->setShouldStripAttributes(false); @@ -759,7 +756,7 @@ public function testStripAttributeMarkersIsNotCalledWhenRenderingWithStripAttrib $this->assertEquals('value', $json->{'@xml:key'}); } - public function testStripAttributeMarkersIsNotCalledWhenRenderingFromJSON() + public function testStripAttributeMarkersIsNotCalledWhenRenderingFromJson(): void { $sample = <<asJson(true)); + $hal = JsonHalFactory::fromJson(new Hal(), $sample); + $json = json_decode($hal->asJson(true)); $this->assertEquals('value', $json->{'@xml:key'}); } - public function testEmbeddingResourceWithSingleElement() + public function testEmbeddingResourceWithSingleElement(): void { $hal = new Hal(); $hal->setResource( 'foo', - (new Hal())->setResource('bar', new Hal()) + (new Hal())->setResource('bar', new Hal()), ); $json = json_decode($hal->asJson()); - $this->assertInternalType('array', $json->_embedded->foo->_embedded->bar); - } - - public function testErrorAddResource() - { - $this->setExpectedException('InvalidArgumentException'); - $hal = new Hal(); - $hal->addResource(new Hal()); + $this->assertIsArray($json->_embedded->foo->_embedded->bar); } } diff --git a/tests/Hal/TestCase.php b/test/Hal/TestCase.php similarity index 97% rename from tests/Hal/TestCase.php rename to test/Hal/TestCase.php index 61408bc..b8b3859 100644 --- a/tests/Hal/TestCase.php +++ b/test/Hal/TestCase.php @@ -1,4 +1,5 @@ expectException($exception); + if ($exceptionMessage !== '') { $this->expectExceptionMessage($exceptionMessage); } + if ($exceptionCode !== null) { $this->expectExceptionCode($exceptionCode); } From d84321ea6dcd1013308b2364913fc3cfb8439b33 Mon Sep 17 00:00:00 2001 From: Martin Dumoulin Date: Thu, 26 Feb 2026 12:25:25 +0100 Subject: [PATCH 2/7] Add types --- src/Hal.php | 71 ++++++++++++++-------------------------- src/HalJsonRenderer.php | 18 +++++----- src/HalLink.php | 2 +- src/HalLinkContainer.php | 4 +-- src/HalXmlRenderer.php | 4 +-- src/JsonHalFactory.php | 6 ++-- test/Hal/HalTest.php | 8 ----- 7 files changed, 40 insertions(+), 73 deletions(-) diff --git a/src/Hal.php b/src/Hal.php index 1bf7964..fd5585e 100644 --- a/src/Hal.php +++ b/src/Hal.php @@ -13,11 +13,9 @@ namespace Nocarrier; -use InvalidArgumentException; +use Nocarrier\HalLink; use Nocarrier\HalLinkContainer; -use RuntimeException; use SimpleXMLElement; -use Traversable; /** * The Hal document class @@ -27,22 +25,11 @@ */ final class Hal { - /** - * The data for this resource. An associative array of key value pairs. - * - * array( - * 'price' => 30.00, - * 'colour' => 'blue' - * ) - * - * @var array - */ - protected $data; - /** * An array of embedded Hal objects representing embedded resources. + * @var mixed[] */ - protected array $resources = []; + private array $resources = []; /** * A collection of \Nocarrier\HalLink objects keyed by the link relation to @@ -54,26 +41,26 @@ final class Hal * * @var array */ - protected HalLinkContainer $links; + private HalLinkContainer $links; /** * A list of rel types for links that will force a rel type to array for one element * * @var list */ - protected array $arrayLinkRels = []; + private array $arrayLinkRels = []; /** * A list of rel types for links that will force a rel type to array for one element * * @var list */ - protected array $arrayResourceRels = []; + private array $arrayResourceRels = []; /** * Whether xml attribute markers should be stripped when rendering */ - protected bool $shouldStripAttributes = true; + private bool $shouldStripAttributes = true; /** * Construct a new Hal object from an array of data. You can markup the @@ -99,17 +86,9 @@ final class Hal public function __construct(/** * The uri represented by this representation. */ - protected $uri = null, - $data = [], + private $uri = null, + private iterable $data = [], ) { - if (! is_array($data) && ! $data instanceof Traversable) { - throw new RuntimeException( - 'The $data parameter must be an array or an object implementing the Traversable interface.', - ); - } - - $this->data = $data; - $this->links = new HalLinkContainer(); } @@ -177,9 +156,9 @@ public function addResource(string $rel, Hal $resource = null, bool $forceArray * Using this method signifies that $rel will only ever be a single object * (only really relevant to JSON rendering) * - * @param Hal $resource + * @param list|Hal $resource */ - public function setResource(string $rel, $resource): self + public function setResource(string $rel, array|Hal $resource): self { if (is_array($resource)) { foreach ($resource as $r) { @@ -189,10 +168,6 @@ public function setResource(string $rel, $resource): self return $this; } - if (! ($resource instanceof Hal)) { - throw new InvalidArgumentException('$resource should be of type array or Nocarrier\Hal'); - } - $this->resources[$rel][] = $resource; return $this; @@ -238,10 +213,10 @@ public function getLinks(): HalLinkContainer * Lookup and return an array of HalLink objects for a given relation. * Will also resolve CURIE rels if required. * - * @return array|bool + * @return list|false * Array of HalLink objects if found. Otherwise false. */ - public function getLink(string $rel) + public function getLink(string $rel): array|false { return $this->links->get($rel); } @@ -254,7 +229,7 @@ public function getResources(): array { return array_map( fn($resource): array => is_array($resource) ? $resource : [$resource], - $this->getRawResources(), + $this->resources, ); } @@ -275,9 +250,9 @@ public function getResource($rel) * may contain an array of resources, or a single resource. For a * consistent approach, use getResources * - * @return array + * @return mixed[] */ - public function getRawResources() + public function getRawResources(): array { return $this->resources; } @@ -305,7 +280,7 @@ public function getFirstResource($rel) * * @return HalLink */ - public function getFirstLink($rel) + public function getFirstLink(string $rel): ?HalLink { $link = $this->getLink($rel); @@ -346,7 +321,7 @@ public function getUri() * Run through json_encode * @return string|array */ - public function asJson($pretty = false, $encode = true) + public function asJson(bool $pretty = false, bool $encode = true): string|array|false { $renderer = new HalJsonRenderer(); @@ -360,7 +335,7 @@ public function asJson($pretty = false, $encode = true) * @param bool $pretty Enable pretty-printing * @return string */ - public function asXml($pretty = false) + public function asXml(bool $pretty = false): string|false { $renderer = new HalXmlRenderer(); @@ -382,16 +357,18 @@ public function addCurie(string $name, string $uri): self /** * Get a list of rel types for links that will be forced to an array for one element + * @return list */ - public function getArrayLinkRels() + public function getArrayLinkRels(): array { return $this->arrayLinkRels; } /** * Get a list of rel types for resources that will be forced to an array for one element + * @return list */ - public function getArrayResourceRels() + public function getArrayResourceRels(): array { return $this->arrayResourceRels; } @@ -401,7 +378,7 @@ public function getShouldStripAttributes(): bool return $this->shouldStripAttributes; } - public function setShouldStripAttributes($shouldStripAttributes): self + public function setShouldStripAttributes(bool $shouldStripAttributes): self { $this->shouldStripAttributes = $shouldStripAttributes; diff --git a/src/HalJsonRenderer.php b/src/HalJsonRenderer.php index 33475ec..5e4c12c 100644 --- a/src/HalJsonRenderer.php +++ b/src/HalJsonRenderer.php @@ -44,9 +44,10 @@ public function render(Hal $resource, bool $pretty, bool $encode = true): false| * associated links. * * @param mixed $uri - * @param array $links + * @param iterable $links + * @param list */ - protected function linksForJson($uri, $links, $arrayLinkRels): array + protected function linksForJson($uri, iterable $container, array $arrayLinkRels): array { $data = []; @@ -54,8 +55,8 @@ protected function linksForJson($uri, $links, $arrayLinkRels): array $data['self'] = ['href' => $uri]; } - foreach ($links as $rel => $links) { - if (count($links) === 1 && $rel !== 'curies' && ! in_array($rel, $arrayLinkRels)) { + foreach ($container as $rel => $links) { + if (count($links) === 1 && $rel !== 'curies' && ! in_array($rel, $arrayLinkRels, true)) { $data[$rel] = ['href' => $links[0]->getUri()]; foreach ($links[0]->getAttributes() as $attribute => $value) { @@ -83,10 +84,9 @@ protected function linksForJson($uri, $links, $arrayLinkRels): array * Return an array (compatible with the hal+json format) representing * associated resources. * - * @param mixed $resources - * @return array + * @param list|Hal $resources */ - protected function resourcesForJson($resources) + protected function resourcesForJson(array|Hal $resources): mixed { if (! is_array($resources)) { return $this->arrayForJson($resources); @@ -134,10 +134,8 @@ protected function stripAttributeMarker(array $data): array /** * Return an array (compatible with the hal+json format) representing the * complete response. - * - * @return array */ - protected function arrayForJson(Hal $resource = null) + protected function arrayForJson(Hal $resource = null): mixed { if ($resource == null) { return []; diff --git a/src/HalLink.php b/src/HalLink.php index 5c8e948..2eb7f71 100644 --- a/src/HalLink.php +++ b/src/HalLink.php @@ -21,7 +21,7 @@ * @package Nocarrier * @author Ben Longden */ -class HalLink implements Stringable +readonly class HalLink implements Stringable { /** * The \Nocarrier\HalLink object. diff --git a/src/HalLinkContainer.php b/src/HalLinkContainer.php index 33f9089..8a4624e 100644 --- a/src/HalLinkContainer.php +++ b/src/HalLinkContainer.php @@ -27,10 +27,10 @@ class HalLinkContainer extends ArrayObject * Retrieve a link from the container by rel. Also resolve any curie links * if they are set. * - * @return array|bool + * @return list|false * Link if found. Otherwise false. */ - public function get(string $rel) + public function get(string $rel): array|false { if (array_key_exists($rel, (array) $this)) { return $this[$rel]; diff --git a/src/HalXmlRenderer.php b/src/HalXmlRenderer.php index 6fe008d..fe1cf55 100644 --- a/src/HalXmlRenderer.php +++ b/src/HalXmlRenderer.php @@ -57,9 +57,9 @@ public function render(Hal $resource, bool $pretty, bool $encode = true): false| * * @return void */ - protected function linksForXml(SimpleXmlElement $doc, HalLinkContainer $links) + protected function linksForXml(SimpleXmlElement $doc, HalLinkContainer $container) { - foreach ($links as $rel => $links) { + foreach ($container as $rel => $links) { foreach ($links as $link) { $element = $doc->addChild('link'); $element->addAttribute('rel', $rel); diff --git a/src/JsonHalFactory.php b/src/JsonHalFactory.php index d4148b5..c990033 100644 --- a/src/JsonHalFactory.php +++ b/src/JsonHalFactory.php @@ -49,11 +49,11 @@ private static function prepareJsonData(string $text): array } /** - * @param array $links + * @param array $container */ - private static function addJsonLinkData(Hal $hal, array $links): void + private static function addJsonLinkData(Hal $hal, array $container): void { - foreach ($links as $rel => $links) { + foreach ($container as $rel => $links) { if (! isset($links[0]) || ! is_array($links[0])) { $links = [$links]; } diff --git a/test/Hal/HalTest.php b/test/Hal/HalTest.php index 61179f9..2e350df 100644 --- a/test/Hal/HalTest.php +++ b/test/Hal/HalTest.php @@ -19,7 +19,6 @@ use PHPUnit\Framework\Attributes\CoversMethod; use RuntimeException; use SimpleXmlElement; -use stdClass; /** * HalTest @@ -628,13 +627,6 @@ public function testSetResourceWithArrayOfResources(): void $this->assertEquals($resource->_embedded->resource[1]->field1, '2'); } - public function testSetResourceThrowsIfNotPassedHalOrArray(): void - { - $this->setExpectedException('\InvalidArgumentException', '$resource should be of type array or Nocarrier\Hal'); - $hal = new Hal('http://example.com/'); - $hal->setResource('resource', new stdClass()); - } - public function testSetResourceJsonResponse(): void { $hal = new Hal('http://example.com/'); From 45caf7b0f2950ba557cf3c8b8331141a8d0d9f86 Mon Sep 17 00:00:00 2001 From: Martin Dumoulin Date: Thu, 26 Feb 2026 18:35:41 +0100 Subject: [PATCH 3/7] Remove some unused code --- composer.json | 3 +- src/Hal.php | 81 ++++++++++------------------------------- src/HalJsonRenderer.php | 21 +++++------ test/Hal/HalTest.php | 29 --------------- 4 files changed, 31 insertions(+), 103 deletions(-) diff --git a/composer.json b/composer.json index 7fbc716..244e3bf 100644 --- a/composer.json +++ b/composer.json @@ -13,8 +13,7 @@ } ], "require": { - "php": ">=8.2", - "psr/link": "~1.0" + "php": ">=8.2" }, "require-dev": { "overtrue/phplint": "^9.4", diff --git a/src/Hal.php b/src/Hal.php index fd5585e..224d686 100644 --- a/src/Hal.php +++ b/src/Hal.php @@ -150,6 +150,16 @@ public function addResource(string $rel, Hal $resource = null, bool $forceArray return $this; } + /** + * Add an embedded resource, identified by $rel and represented by $resource. + */ + public function addIndexedResource(string $rel, int|string $index, Hal $resource): self + { + $this->resources[$rel][$index] = $resource; + + return $this; + } + /** * Set an embedded resource, identified by $rel and represented by $resource * @@ -236,13 +246,11 @@ public function getResources(): array /** * Return an array of Nocarrier\Hal objected embedded in this one. * - * @return Hal + * @return ?list */ - public function getResource($rel) + public function getRelResources(string $rel): ?array { - $resources = $this->getResources(); - - return $resources[$rel] ?? null; + return $this->getResources()[$rel] ?? null; } /** @@ -257,40 +265,6 @@ public function getRawResources(): array return $this->resources; } - /** - * Get the first resource for a given rel. Useful if you're only expecting - * one resource, or you don't care about subsequent resources - * - * @return Hal - */ - public function getFirstResource($rel) - { - $resource = $this->getResource($rel); - - if ($resource) { - return $resource[0]; - } - - return null; - } - - /** - * Get the first link for a given rel. Useful if you're only expecting - * one link, or you don't care about subsequent links - * - * @return HalLink - */ - public function getFirstLink(string $rel): ?HalLink - { - $link = $this->getLink($rel); - - if ($link) { - return $link[0]; - } - - return null; - } - /** * Set resource's URI */ @@ -314,32 +288,19 @@ public function getUri() /** * Return the current object in a application/hal+json format (links and * resources). - * - * @param bool $pretty - * Enable pretty-printing. - * @param bool $encode - * Run through json_encode - * @return string|array */ public function asJson(bool $pretty = false, bool $encode = true): string|array|false { - $renderer = new HalJsonRenderer(); - - return $renderer->render($this, $pretty, $encode); + return (new HalJsonRenderer())->render($this, $pretty, $encode); } /** * Return the current object in a application/hal+xml format (links and * resources). - * - * @param bool $pretty Enable pretty-printing - * @return string */ public function asXml(bool $pretty = false): string|false { - $renderer = new HalXmlRenderer(); - - return $renderer->render($this, $pretty); + return (new HalXmlRenderer())->render($this, $pretty); } /** @@ -357,20 +318,18 @@ public function addCurie(string $name, string $uri): self /** * Get a list of rel types for links that will be forced to an array for one element - * @return list */ - public function getArrayLinkRels(): array + public function isArrayLink(string $rel): bool { - return $this->arrayLinkRels; + return in_array($rel, $this->arrayLinkRels, true); } /** - * Get a list of rel types for resources that will be forced to an array for one element - * @return list + * Check if rel type should be forced to an array for one element */ - public function getArrayResourceRels(): array + public function isArrayResource(string $rel): bool { - return $this->arrayResourceRels; + return in_array($rel, $this->arrayResourceRels, true); } public function getShouldStripAttributes(): bool diff --git a/src/HalJsonRenderer.php b/src/HalJsonRenderer.php index 5e4c12c..ea04d02 100644 --- a/src/HalJsonRenderer.php +++ b/src/HalJsonRenderer.php @@ -13,6 +13,8 @@ namespace Nocarrier; +use Nocarrier\Hal; + /** * HalJsonRenderer * @@ -42,21 +44,18 @@ public function render(Hal $resource, bool $pretty, bool $encode = true): false| /** * Return an array (compatible with the hal+json format) representing * associated links. - * - * @param mixed $uri - * @param iterable $links - * @param list */ - protected function linksForJson($uri, iterable $container, array $arrayLinkRels): array + protected function linksForJson(Hal $resource): array { + $uri = $resource->getUri(); $data = []; if (null !== $uri) { $data['self'] = ['href' => $uri]; } - foreach ($container as $rel => $links) { - if (count($links) === 1 && $rel !== 'curies' && ! in_array($rel, $arrayLinkRels, true)) { + foreach ($resource->getLinks() as $rel => $links) { + if (count($links) === 1 && $rel !== 'curies' && ! $resource->isArrayLink($rel)) { $data[$rel] = ['href' => $links[0]->getUri()]; foreach ($links[0]->getAttributes() as $attribute => $value) { @@ -135,9 +134,9 @@ protected function stripAttributeMarker(array $data): array * Return an array (compatible with the hal+json format) representing the * complete response. */ - protected function arrayForJson(Hal $resource = null): mixed + protected function arrayForJson(?Hal $resource = null): mixed { - if ($resource == null) { + if (! $resource instanceof Hal) { return []; } @@ -147,14 +146,14 @@ protected function arrayForJson(Hal $resource = null): mixed $data = $this->stripAttributeMarker($data); } - $links = $this->linksForJson($resource->getUri(), $resource->getLinks(), $resource->getArrayLinkRels()); + $links = $this->linksForJson($resource); if (count($links)) { $data['_links'] = $links; } foreach ($resource->getRawResources() as $rel => $resources) { - if (count($resources) === 1 && ! in_array($rel, $resource->getArrayResourceRels())) { + if (count($resources) === 1 && ! $resource->isArrayResource($rel)) { $resources = $resources[0]; } diff --git a/test/Hal/HalTest.php b/test/Hal/HalTest.php index 2e350df..0941c9c 100644 --- a/test/Hal/HalTest.php +++ b/test/Hal/HalTest.php @@ -524,15 +524,6 @@ public function testGetLinkByRelation(): void $this->assertEquals('/test/orders', $links[0]); } - public function testGetFirstLinkByRelation(): void - { - $x = new Hal('/orders'); - $x->addLink('test', '/test/orders'); - - $links = $x->getFirstLink('test'); - $this->assertEquals('/test/orders', $links); - } - public function testGetLinkByCurieRelation(): void { $x = new Hal('/orders'); @@ -706,26 +697,6 @@ public function testHalJsonDecodeWithSingleEmbeddedItem(): void $this->assertEquals('value', $data['key']); } - public function testGetFirstResourceReturnsSingleItem(): void - { - $hal = new Hal('http://example.com/'); - $res = new Hal('/resource/1', array('field1' => 'value1', 'field2' => 'value2')); - $hal->setResource('resource', $res); - - $this->assertEquals($res, $hal->getFirstResource('resource')); - } - - public function testGetFirstResourceReturnsFirstOfMultipleItems(): void - { - $hal = new Hal('http://example.com/'); - $res1 = new Hal('/resource/1', array('field1' => 'value1', 'field2' => 'value2')); - $res2 = new Hal('/resource/2', array('field2' => 'value2', 'field2' => 'value2')); - $hal->addResource('resource', $res1); - $hal->addResource('resource', $res2); - - $this->assertEquals($res1, $hal->getFirstResource('resource')); - } - public function testHalFromJsonThrowsExceptionOnInvalidJson(): void { $this->expectException(RuntimeException::class); From 0b3659711404d9a7b5e36b02853c0646ff04febf Mon Sep 17 00:00:00 2001 From: Martin Dumoulin Date: Thu, 26 Feb 2026 18:44:56 +0100 Subject: [PATCH 4/7] Add index to json --- src/HalJsonRenderer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HalJsonRenderer.php b/src/HalJsonRenderer.php index ea04d02..ac67db0 100644 --- a/src/HalJsonRenderer.php +++ b/src/HalJsonRenderer.php @@ -93,11 +93,11 @@ protected function resourcesForJson(array|Hal $resources): mixed $data = []; - foreach ($resources as $resource) { + foreach ($resources as $key => $resource) { $res = $this->arrayForJson($resource); if (! empty($res)) { - $data[] = $res; + $data[$key] = $res; } } From 4ddfb8b2faaa08208896197e8498156e8a18eeb8 Mon Sep 17 00:00:00 2001 From: Martin Dumoulin Date: Fri, 27 Feb 2026 16:37:52 +0100 Subject: [PATCH 5/7] WIP --- composer.lock | 68 +++++------------------------------------ src/Hal.php | 38 +++++++++++------------ src/HalJsonRenderer.php | 2 -- src/HalXmlRenderer.php | 3 +- src/JsonHalFactory.php | 1 - src/XmlHalFactory.php | 2 +- test/Hal/HalTest.php | 1 + test/Hal/TestCase.php | 38 ----------------------- 8 files changed, 27 insertions(+), 126 deletions(-) delete mode 100644 test/Hal/TestCase.php diff --git a/composer.lock b/composer.lock index 65cbbe7..eaa4b26 100644 --- a/composer.lock +++ b/composer.lock @@ -4,62 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d79a320d439b598e10df7e1df1dd6d20", - "packages": [ - { - "name": "psr/link", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/php-fig/link.git", - "reference": "846c25f58a1f02b93a00f2404e3626b6bf9b7807" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/link/zipball/846c25f58a1f02b93a00f2404e3626b6bf9b7807", - "reference": "846c25f58a1f02b93a00f2404e3626b6bf9b7807", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Link\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interfaces for HTTP links", - "homepage": "https://github.com/php-fig/link", - "keywords": [ - "http", - "http-link", - "link", - "psr", - "psr-13", - "rest" - ], - "support": { - "source": "https://github.com/php-fig/link/tree/1.1.1" - }, - "time": "2021-03-11T22:59:13+00:00" - } - ], + "content-hash": "42919a54867989d8a03302d4493575d6", + "packages": [], "packages-dev": [ { "name": "brick/varexporter", @@ -1504,12 +1450,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "67b44a783410e6d9912db53af50c8ddf048c9845" + "reference": "cd20769dbf60afc57ec72a8865aecaf78a95fc71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/67b44a783410e6d9912db53af50c8ddf048c9845", - "reference": "67b44a783410e6d9912db53af50c8ddf048c9845", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/cd20769dbf60afc57ec72a8865aecaf78a95fc71", + "reference": "cd20769dbf60afc57ec72a8865aecaf78a95fc71", "shasum": "" }, "conflict": { @@ -1813,7 +1759,7 @@ "froxlor/froxlor": "<=2.2.5", "frozennode/administrator": "<=5.0.12", "fuel/core": "<1.8.1", - "funadmin/funadmin": "<=5.0.2", + "funadmin/funadmin": "<=7.1.0.0-RC4", "gaoming13/wechat-php-sdk": "<=1.10.2", "genix/cms": "<=1.1.11", "georgringer/news": "<1.3.3", @@ -2523,7 +2469,7 @@ "type": "tidelift" } ], - "time": "2026-02-25T20:13:14+00:00" + "time": "2026-02-26T16:22:02+00:00" }, { "name": "sebastian/cli-parser", diff --git a/src/Hal.php b/src/Hal.php index 224d686..f918772 100644 --- a/src/Hal.php +++ b/src/Hal.php @@ -13,8 +13,6 @@ namespace Nocarrier; -use Nocarrier\HalLink; -use Nocarrier\HalLinkContainer; use SimpleXMLElement; /** @@ -38,22 +36,20 @@ final class Hal * array( * 'next' => [HalLink] * ) - * - * @var array */ private HalLinkContainer $links; /** * A list of rel types for links that will force a rel type to array for one element * - * @var list + * @var array */ private array $arrayLinkRels = []; /** * A list of rel types for links that will force a rel type to array for one element * - * @var list + * @var array */ private array $arrayResourceRels = []; @@ -78,15 +74,13 @@ final class Hal * array('value' => 'example')) will yield example in the XML * representation. This will not affect the JSON representation. * - * @param mixed $uri + * @param ?string $uri The uri represented by this representation * @param array|Traversable $data * * @throws \RuntimeException */ - public function __construct(/** - * The uri represented by this representation. - */ - private $uri = null, + public function __construct( + private ?string $uri = null, private iterable $data = [], ) { $this->links = new HalLinkContainer(); @@ -130,7 +124,7 @@ public function addHalLink(string $rel, HalLink $link, bool $forceArray = false) $this->links[$rel][] = $link; if ($forceArray) { - $this->arrayLinkRels[] = $rel; + $this->arrayLinkRels[$rel] = true; } return $this; @@ -144,7 +138,7 @@ public function addResource(string $rel, Hal $resource = null, bool $forceArray $this->resources[$rel][] = $resource; if ($forceArray) { - $this->arrayResourceRels[] = $rel; + $this->arrayResourceRels[$rel] = true; } return $this; @@ -157,6 +151,10 @@ public function addIndexedResource(string $rel, int|string $index, Hal $resource { $this->resources[$rel][$index] = $resource; + if (! isset($this->arrayResourceRels[$rel])) { + $this->arrayResourceRels[$rel] = true; + } + return $this; } @@ -199,7 +197,7 @@ public function setData(array $data = null): self * @param null|string data key * @return mixed Returns an array if no key is passed in, otherwise returns the data */ - public function getData($key = null) + public function getData($key = null): mixed { if ($key) { return $this->data[$key] ?? []; @@ -246,7 +244,7 @@ public function getResources(): array /** * Return an array of Nocarrier\Hal objected embedded in this one. * - * @return ?list + * @return ?array */ public function getRelResources(string $rel): ?array { @@ -268,7 +266,7 @@ public function getRawResources(): array /** * Set resource's URI */ - public function setUri($uri): self + public function setUri(?string $uri): self { $this->uri = $uri; @@ -277,10 +275,8 @@ public function setUri($uri): self /** * Get resource's URI. - * - * @return mixed */ - public function getUri() + public function getUri(): ?string { return $this->uri; } @@ -321,7 +317,7 @@ public function addCurie(string $name, string $uri): self */ public function isArrayLink(string $rel): bool { - return in_array($rel, $this->arrayLinkRels, true); + return isset($this->arrayLinkRels[$rel]); } /** @@ -329,7 +325,7 @@ public function isArrayLink(string $rel): bool */ public function isArrayResource(string $rel): bool { - return in_array($rel, $this->arrayResourceRels, true); + return isset($this->arrayResourceRels[$rel]); } public function getShouldStripAttributes(): bool diff --git a/src/HalJsonRenderer.php b/src/HalJsonRenderer.php index ac67db0..296d13c 100644 --- a/src/HalJsonRenderer.php +++ b/src/HalJsonRenderer.php @@ -13,8 +13,6 @@ namespace Nocarrier; -use Nocarrier\Hal; - /** * HalJsonRenderer * diff --git a/src/HalXmlRenderer.php b/src/HalXmlRenderer.php index fe1cf55..8334c84 100644 --- a/src/HalXmlRenderer.php +++ b/src/HalXmlRenderer.php @@ -33,7 +33,6 @@ public function render(Hal $resource, bool $pretty, bool $encode = true): false| } $this->linksForXml($doc, $resource->getLinks()); - $this->arrayToXml($resource->getData(), $doc); foreach ($resource->getResources() as $rel => $resources) { @@ -101,7 +100,7 @@ protected function arrayToXml($data, SimpleXmlElement $element, $parent = null) } elseif ($key === 'value' && count($data) === 1) { $element[0] = $value; } elseif (is_bool($value)) { - $element->addChild($key, intval($value)); + $element->addChild($key, (int) $value); } else { $element->addChild($key, htmlspecialchars((string) $value, ENT_QUOTES)); } diff --git a/src/JsonHalFactory.php b/src/JsonHalFactory.php index c990033..094c16f 100644 --- a/src/JsonHalFactory.php +++ b/src/JsonHalFactory.php @@ -2,7 +2,6 @@ namespace Nocarrier; -use Nocarrier\Hal; use RuntimeException; class JsonHalFactory diff --git a/src/XmlHalFactory.php b/src/XmlHalFactory.php index 8d37fef..cb69b7c 100644 --- a/src/XmlHalFactory.php +++ b/src/XmlHalFactory.php @@ -11,7 +11,7 @@ class XmlHalFactory /** * Decode a application/hal+xml document into a Nocarrier\Hal object. * - * @throws \RuntimeException + * @throws RuntimeException */ public static function fromXml(Hal $hal, SimpleXMLElement|string $data, int $depth = 0): Hal { diff --git a/test/Hal/HalTest.php b/test/Hal/HalTest.php index 0941c9c..b87c4b2 100644 --- a/test/Hal/HalTest.php +++ b/test/Hal/HalTest.php @@ -17,6 +17,7 @@ use Nocarrier\Hal; use Nocarrier\JsonHalFactory; use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; use RuntimeException; use SimpleXmlElement; diff --git a/test/Hal/TestCase.php b/test/Hal/TestCase.php deleted file mode 100644 index b8b3859..0000000 --- a/test/Hal/TestCase.php +++ /dev/null @@ -1,38 +0,0 @@ -expectException($exception); - - if ($exceptionMessage !== '') { - $this->expectExceptionMessage($exceptionMessage); - } - - if ($exceptionCode !== null) { - $this->expectExceptionCode($exceptionCode); - } - } else { - // legacy PHPUnit 4 - parent::setExpectedException($exception, $exceptionMessage, $exceptionCode); - } - } -} From 64c31080e3aa30fb637570f78a18d4ddc4f359e1 Mon Sep 17 00:00:00 2001 From: Martin Dumoulin Date: Tue, 3 Mar 2026 12:00:12 +0100 Subject: [PATCH 6/7] Clean --- phpstan.neon | 4 ++++ src/Hal.php | 26 ++++++++++++++------------ src/HalJsonRenderer.php | 2 +- src/HalLinkContainer.php | 11 ++++++----- src/HalXmlRenderer.php | 19 +++++++------------ src/JsonHalFactory.php | 11 ++++++++--- src/XmlHalFactory.php | 8 ++++---- test/Hal/HalTest.php | 4 ++-- 8 files changed, 46 insertions(+), 39 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 886e933..a41489c 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,3 +2,7 @@ parameters: paths: - src level: 8 + + ignoreErrors: + - + identifier: missingType.iterableValue diff --git a/src/Hal.php b/src/Hal.php index f918772..790d251 100644 --- a/src/Hal.php +++ b/src/Hal.php @@ -13,6 +13,8 @@ namespace Nocarrier; +use ArrayAccess; +use DateInterval; use SimpleXMLElement; /** @@ -20,6 +22,8 @@ * * @package Nocarrier * @author Ben Longden + * + * @phpstan-type Data array|ArrayAccess */ final class Hal { @@ -75,13 +79,13 @@ final class Hal * representation. This will not affect the JSON representation. * * @param ?string $uri The uri represented by this representation - * @param array|Traversable $data + * @param Data $data The data to be represented by this representation * * @throws \RuntimeException */ public function __construct( private ?string $uri = null, - private iterable $data = [], + private array|ArrayAccess $data = [], ) { $this->links = new HalLinkContainer(); } @@ -133,7 +137,7 @@ public function addHalLink(string $rel, HalLink $link, bool $forceArray = false) /** * Add an embedded resource, identified by $rel and represented by $resource. */ - public function addResource(string $rel, Hal $resource = null, bool $forceArray = true): self + public function addResource(string $rel, ?Hal $resource = null, bool $forceArray = true): self { $this->resources[$rel][] = $resource; @@ -147,7 +151,7 @@ public function addResource(string $rel, Hal $resource = null, bool $forceArray /** * Add an embedded resource, identified by $rel and represented by $resource. */ - public function addIndexedResource(string $rel, int|string $index, Hal $resource): self + public function addIndexedResource(string $rel, int|string $index, ?Hal $resource): self { $this->resources[$rel][$index] = $resource; @@ -183,8 +187,10 @@ public function setResource(string $rel, array|Hal $resource): self /** * Set resource's data + * + * @param Data $data */ - public function setData(array $data = null): self + public function setData(array|ArrayAccess $data): self { $this->data = $data; @@ -194,10 +200,9 @@ public function setData(array $data = null): self /** * Return an array of data (key => value pairs) representing this resource. * - * @param null|string data key * @return mixed Returns an array if no key is passed in, otherwise returns the data */ - public function getData($key = null): mixed + public function getData(?string $key = null): mixed { if ($key) { return $this->data[$key] ?? []; @@ -209,8 +214,6 @@ public function getData($key = null): mixed /** * Return an array of Nocarrier\HalLink objects representing resources * related to this one. - * - * @return array A collection of \Nocarrier\HalLink */ public function getLinks(): HalLinkContainer { @@ -221,10 +224,9 @@ public function getLinks(): HalLinkContainer * Lookup and return an array of HalLink objects for a given relation. * Will also resolve CURIE rels if required. * - * @return list|false - * Array of HalLink objects if found. Otherwise false. + * @return ?list Array of HalLink objects if found. Otherwise null. */ - public function getLink(string $rel): array|false + public function getLink(string $rel): ?array { return $this->links->get($rel); } diff --git a/src/HalJsonRenderer.php b/src/HalJsonRenderer.php index 296d13c..df358b1 100644 --- a/src/HalJsonRenderer.php +++ b/src/HalJsonRenderer.php @@ -26,7 +26,7 @@ public function render(Hal $resource, bool $pretty, bool $encode = true): false| { $options = 0; - if (version_compare(PHP_VERSION, '5.4.0') >= 0 && $pretty) { + if ($pretty) { $options = JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT; } diff --git a/src/HalLinkContainer.php b/src/HalLinkContainer.php index 8a4624e..bcfd639 100644 --- a/src/HalLinkContainer.php +++ b/src/HalLinkContainer.php @@ -20,6 +20,8 @@ * * @package Nocarrier * @author Ben Longden + * + * @extends ArrayObject> */ class HalLinkContainer extends ArrayObject { @@ -27,10 +29,9 @@ class HalLinkContainer extends ArrayObject * Retrieve a link from the container by rel. Also resolve any curie links * if they are set. * - * @return list|false - * Link if found. Otherwise false. + * @return ?list Link if found. Otherwise null. */ - public function get(string $rel): array|false + public function get(string $rel): ?array { if (array_key_exists($rel, (array) $this)) { return $this[$rel]; @@ -38,7 +39,7 @@ public function get(string $rel): array|false if (isset($this['curies'])) { foreach ($this['curies'] as $link) { - $prefix = strstr((string) $link->getUri(), '{rel}', true); + $prefix = (string) strstr((string) $link->getUri(), '{rel}', true); if (str_starts_with($rel, $prefix)) { // looks like it is @@ -53,6 +54,6 @@ public function get(string $rel): array|false } } - return false; + return null; } } diff --git a/src/HalXmlRenderer.php b/src/HalXmlRenderer.php index 8334c84..261f896 100644 --- a/src/HalXmlRenderer.php +++ b/src/HalXmlRenderer.php @@ -13,6 +13,7 @@ namespace Nocarrier; +use RuntimeException; use SimpleXMLElement; /** @@ -41,6 +42,10 @@ public function render(Hal $resource, bool $pretty, bool $encode = true): false| $dom = dom_import_simplexml($doc); + if (null === $dom->ownerDocument) { + throw new RuntimeException('Failed to convert SimpleXMLElement to DOMDocument'); + } + if ($pretty) { $dom->ownerDocument->preserveWhiteSpace = false; $dom->ownerDocument->formatOutput = true; @@ -50,13 +55,9 @@ public function render(Hal $resource, bool $pretty, bool $encode = true): false| } /** - * linksForXml - * * Add links in hal+xml format to a SimpleXmlElement object. - * - * @return void */ - protected function linksForXml(SimpleXmlElement $doc, HalLinkContainer $container) + protected function linksForXml(SimpleXmlElement $doc, HalLinkContainer $container): void { foreach ($container as $rel => $links) { foreach ($links as $link) { @@ -72,14 +73,10 @@ protected function linksForXml(SimpleXmlElement $doc, HalLinkContainer $containe } /** - * arrayToXml - * * @param array $data * @param mixed $parent - * @access protected - * @return void */ - protected function arrayToXml($data, SimpleXmlElement $element, $parent = null) + protected function arrayToXml($data, SimpleXmlElement $element, $parent = null): void { foreach ($data as $key => $value) { if (is_iterable($value)) { @@ -111,8 +108,6 @@ protected function arrayToXml($data, SimpleXmlElement $element, $parent = null) } /** - * resourcesForXml - * * Add resources in hal+xml format (identified by $rel) to a * SimpleXmlElement object. * diff --git a/src/JsonHalFactory.php b/src/JsonHalFactory.php index 094c16f..427c695 100644 --- a/src/JsonHalFactory.php +++ b/src/JsonHalFactory.php @@ -48,7 +48,7 @@ private static function prepareJsonData(string $text): array } /** - * @param array $container + * @param array $container */ private static function addJsonLinkData(Hal $hal, array $container): void { @@ -72,12 +72,17 @@ private static function setEmbeddedResources(Hal $hal, array $embedded, int $dep $className = $hal::class; if (! $isIndexed) { - $hal->setResource($rel, self::fromJson(new $className(), json_encode($embed), $depth - 1)); + $hal->setResource($rel, self::fromJson(new $className(), self::jsonEncode($embed), $depth - 1)); } else { foreach ($embed as $resource) { - $hal->addResource($rel, self::fromJson(new $className(), json_encode($resource), $depth - 1)); + $hal->addResource($rel, self::fromJson(new $className(), self::jsonEncode($resource), $depth - 1)); } } } } + + private static function jsonEncode(mixed $data): string + { + return json_encode($data, JSON_THROW_ON_ERROR); + } } diff --git a/src/XmlHalFactory.php b/src/XmlHalFactory.php index cb69b7c..2b83dff 100644 --- a/src/XmlHalFactory.php +++ b/src/XmlHalFactory.php @@ -23,8 +23,8 @@ public static function fromXml(Hal $hal, SimpleXMLElement|string $data, int $dep } } - $children = $data->children(); - $links = clone $children->link; + $children = $data->children(); + $childrenLinks = clone $children->link; unset($children->link); $embedded = clone $children->resource; @@ -33,7 +33,7 @@ public static function fromXml(Hal $hal, SimpleXMLElement|string $data, int $dep $hal->setUri((string) $data->attributes()->href); $hal->setData((array) $children); - foreach ($links as $links) { + foreach ($childrenLinks as $links) { if (! is_array($links)) { $links = [$links]; } @@ -59,7 +59,7 @@ public static function fromXml(Hal $hal, SimpleXMLElement|string $data, int $dep /** * @return array */ - private static function extractKnownData($data): array + private static function extractKnownData(SimpleXMLElement $data): array { $attributes = (array) $data->attributes(); $attributes = $attributes['@attributes']; diff --git a/test/Hal/HalTest.php b/test/Hal/HalTest.php index b87c4b2..2369dee 100644 --- a/test/Hal/HalTest.php +++ b/test/Hal/HalTest.php @@ -539,7 +539,7 @@ public function testGetLinkByCurieRelation(): void public function testGetLinkReturnsFalseOnFailure(): void { $x = new Hal('/orders'); - $this->assertFalse($x->getLink('test')); + $this->assertNull($x->getLink('test')); } public function testJsonEmptyEmbeddedCollection(): void @@ -586,7 +586,7 @@ public function testResourceWithNullSelfLinkRendersLinksInJson(): void $this->assertEquals('http://test', $data->_links->testrel->href); } - public function testDataCanBeTraversable(): void + public function testDataCanBeArrayAccess(): void { $it = new ArrayIterator(array('traversable' => new ArrayIterator(array('key' => 'value')))); $x = new Hal('', $it); From 950ab707d233af6c135e6a4a7b92bad20bff77bc Mon Sep 17 00:00:00 2001 From: Martin Dumoulin Date: Tue, 3 Mar 2026 12:02:45 +0100 Subject: [PATCH 7/7] Rector --- phpstan-baseline.neon | 109 +++++++++++++++++++++++++++++++++++++++++ phpstan.neon | 7 ++- src/Hal.php | 1 - src/HalXmlRenderer.php | 3 +- 4 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 phpstan-baseline.neon diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..f121289 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,109 @@ +parameters: + ignoreErrors: + - + message: '#^Method Nocarrier\\Hal\:\:asJson\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/Hal.php + + - + message: '#^Method Nocarrier\\HalJsonRenderer\:\:linksForJson\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/HalJsonRenderer.php + + - + message: '#^Method Nocarrier\\HalJsonRenderer\:\:render\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/HalJsonRenderer.php + + - + message: '#^Method Nocarrier\\HalJsonRenderer\:\:stripAttributeMarker\(\) has parameter \$data with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/HalJsonRenderer.php + + - + message: '#^Method Nocarrier\\HalJsonRenderer\:\:stripAttributeMarker\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/HalJsonRenderer.php + + - + message: '#^Method Nocarrier\\HalLink\:\:__construct\(\) has parameter \$attributes with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/HalLink.php + + - + message: '#^Method Nocarrier\\HalLink\:\:getAttributes\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/HalLink.php + + - + message: '#^Cannot access offset 0 on iterable\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: src/HalXmlRenderer.php + + - + message: '#^Method Nocarrier\\HalXmlRenderer\:\:arrayToXml\(\) has parameter \$data with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/HalXmlRenderer.php + + - + message: '#^Method Nocarrier\\HalXmlRenderer\:\:resourcesForXml\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: src/HalXmlRenderer.php + + - + message: '#^Parameter \#1 \$data of method Nocarrier\\HalXmlRenderer\:\:arrayToXml\(\) expects array, array\|\(ArrayAccess&iterable\) given\.$#' + identifier: argument.type + count: 1 + path: src/HalXmlRenderer.php + + - + message: '#^Parameter \#1 \$data of method Nocarrier\\HalXmlRenderer\:\:arrayToXml\(\) expects array, iterable given\.$#' + identifier: argument.type + count: 2 + path: src/HalXmlRenderer.php + + - + message: '#^Parameter \#1 \$value of function count expects array\|Countable, iterable given\.$#' + identifier: argument.type + count: 1 + path: src/HalXmlRenderer.php + + - + message: '#^Parameter \#2 \$value of method SimpleXMLElement\:\:addChild\(\) expects string\|null, int given\.$#' + identifier: argument.type + count: 1 + path: src/HalXmlRenderer.php + + - + message: '#^Method Nocarrier\\JsonHalFactory\:\:setEmbeddedResources\(\) has parameter \$embedded with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/JsonHalFactory.php + + - + message: '#^Call to function is_array\(\) with SimpleXMLElement will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: src/XmlHalFactory.php + + - + message: '#^Parameter \#1 \$hal of static method Nocarrier\\XmlHalFactory\:\:fromXml\(\) expects Nocarrier\\Hal, SimpleXMLElement given\.$#' + identifier: argument.type + count: 1 + path: src/XmlHalFactory.php + + - + message: '#^Parameter \#2 \$data of static method Nocarrier\\XmlHalFactory\:\:fromXml\(\) expects SimpleXMLElement\|string, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: src/XmlHalFactory.php diff --git a/phpstan.neon b/phpstan.neon index a41489c..013014e 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,8 +1,7 @@ +includes: + - phpstan-baseline.neon + parameters: paths: - src level: 8 - - ignoreErrors: - - - identifier: missingType.iterableValue diff --git a/src/Hal.php b/src/Hal.php index 790d251..6f46994 100644 --- a/src/Hal.php +++ b/src/Hal.php @@ -14,7 +14,6 @@ namespace Nocarrier; use ArrayAccess; -use DateInterval; use SimpleXMLElement; /** diff --git a/src/HalXmlRenderer.php b/src/HalXmlRenderer.php index 261f896..7a571ce 100644 --- a/src/HalXmlRenderer.php +++ b/src/HalXmlRenderer.php @@ -13,6 +13,7 @@ namespace Nocarrier; +use DOMDocument; use RuntimeException; use SimpleXMLElement; @@ -42,7 +43,7 @@ public function render(Hal $resource, bool $pretty, bool $encode = true): false| $dom = dom_import_simplexml($doc); - if (null === $dom->ownerDocument) { + if (! $dom->ownerDocument instanceof DOMDocument) { throw new RuntimeException('Failed to convert SimpleXMLElement to DOMDocument'); }