diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5fc53c5..86c6f0e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,8 +3,7 @@ name: CI on: push: branches-ignore: - - develop - - main + - main # main is never pushed to directly; releases are tag-driven tags: - '*' pull_request: @@ -62,17 +61,46 @@ jobs: test-namespace: 'PayplugPluginCore\tests\' # ----------------------------------------------------------------------- - # 5. PACKAGE — zip and store the artifact on PR merged → develop + # 5. PUSH-DIST — push transpiled code to dist/{php-target}/{branch} + # Runs in parallel with validate, as soon as downgrade succeeds. + # On feature branch push → dist/php72/feature/xxxx + # On push to develop → dist/php72/develop + # ----------------------------------------------------------------------- + push-dist: + if: github.ref_type != 'tag' && github.event.action != 'closed' + needs: validate + permissions: + contents: write + uses: payplug/template-ci/.github/workflows/php72-push-dist.yml@main + with: + artifact-name: 'payplug-core-php72' + source-branch: ${{ github.head_ref || github.ref_name }} + php-target: 'php72' + + # ----------------------------------------------------------------------- + # 6. PACKAGE — zip and store the artifact on PR merged → develop # ----------------------------------------------------------------------- package: - if: github.event_name == 'pull_request' && github.event.pull_request.merged == true + if: github.ref_type != 'tag' && github.event.action != 'closed' uses: payplug/template-ci/.github/workflows/php-package.yml@main with: php-version: '8.4' zip-prefix: 'payplug-plugin-core-php72' # ----------------------------------------------------------------------- - # 6. RELEASE — create a GitHub Release from a tag on main + # 7. CLEANUP-DIST — delete dist/php72/feature/xxxx when PR is merged + # ----------------------------------------------------------------------- + cleanup-dist: + if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true + permissions: + contents: write + uses: payplug/template-ci/.github/workflows/php72-delete-dist.yml@main + with: + source-branch: ${{ github.head_ref }} + php-target: 'php72' + + # ----------------------------------------------------------------------- + # 8. RELEASE — create a GitHub Release from a tag on main # ----------------------------------------------------------------------- release: if: github.event_name == 'push' && github.ref_type == 'tag' diff --git a/.gitignore b/.gitignore index 01b521a..2f3bd80 100644 --- a/.gitignore +++ b/.gitignore @@ -37,5 +37,5 @@ vendor # PHPStan var/ -/ +payplug-core/ .claude \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 073ec2a..57adc3e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM php:8.4-cli +FROM php:8.1-cli # Install system dependencies RUN apt-get update && apt-get install -y \ diff --git a/Makefile b/Makefile index 0776437..9f522c2 100644 --- a/Makefile +++ b/Makefile @@ -25,32 +25,42 @@ update: $(PHP) composer update ## Quality -test: - $(PHP) vendor/bin/phpunit +test-unit: + $(PHP) vendor/bin/phpunit tests + +test-unit-inte: + $(PHP) vendor/bin/phpunit tests --group integration + +test-unit-units: + $(PHP) vendor/bin/phpunit tests --group units + +tu-dep: + $(PHP) vendor/bin/phpunit tests --display-phpunit-deprecations stan: $(PHP) vendor/bin/phpstan analyse -lint: +cs-lint: $(PHP) vendor/bin/php-cs-fixer fix --diff --dry-run -fix: +cs-fix: $(PHP) vendor/bin/php-cs-fixer fix rector-dry: $(PHP) vendor/bin/rector process --dry-run -## Release (downgrade src/ to PHP 7.2 into release/) +## Release (downgrade src/ to PHP 7.2 into payplug-core/) release: - rm -rf payplug-core && cp -r src payplug-core && cp -r tests payplug-core - $(PHP) vendor/bin/rector process + rm -rf payplug-core && mkdir payplug-core && cp -r src payplug-core/ && cp -r tests payplug-core/ + $(PHP) vendor/bin/rector process --config rector.php + $(PHP) php scripts/generate-release-composer.php ## Debug (Xdebug step-debug enabled) debug: $(PHP_DEBUG) bash ## CI (runs all checks) -ci: stan lint test +ci: stan cs-lint test-unit install: build update comp-install diff --git a/Readme.md b/Readme.md index 0ad08eb..daa7627 100644 --- a/Readme.md +++ b/Readme.md @@ -101,3 +101,17 @@ Module core for Payplug integration. Enables management of payments, merchants, ## Next step Dev : - [ ] Develop endpoint to create a payment link + + +## Quick start: + +```bash +composer install # Hooks are installed automatically +composer cs:fix # Manual code formatting +composer hooks:install # Reinstall hooks if needed +composer hooks:install # Reinstall hooks if needed + +composer phpunit:unit # Run only unitary phpUnit tests +composer phpunit:inte # Run only integration phpUnit tests +composer phpunit:all # Run all phpUnit tests +``` \ No newline at end of file diff --git a/captainhook.json b/captainhook.json index 6f34eb2..248e361 100644 --- a/captainhook.json +++ b/captainhook.json @@ -15,7 +15,7 @@ { "action": "\\CaptainHook\\App\\Hook\\Branch\\Action\\EnsureNaming", "options": { - "regex": "/^(feature|fix|hotfix|refactor|release)\\/(PRE|MAG|SYL|SMP)-\\d+/" + "regex": "/^(feature|fix|hotfix|refactor|release)\\/(PRE|MAG|SYL|SMP)-\\d+(-[a-z0-9]+)*$/" } }, { diff --git a/composer.json b/composer.json index f365a8a..9ed17d6 100644 --- a/composer.json +++ b/composer.json @@ -11,14 +11,17 @@ } ], "require": { - "php": ">=8.4", + "php": ">=8.1", "captainhook/captainhook": "^5.28", "payplug/payplug-php": "^4.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.0", + "mockery/mockery": "^1.6", "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^11.0", + "phpstan/phpstan-mockery": "*", + "phpstan/phpstan-phpunit": "*", + "phpunit/phpunit": "^10.0", "rector/rector": "^2.0" }, "autoload": { @@ -28,20 +31,22 @@ }, "autoload-dev": { "psr-4": { - "PayplugPluginCore\\tests\\": "tests/" + "PayplugPluginCore\\Tests\\": "tests/" } }, "scripts": { "post-install-cmd": "vendor/bin/captainhook install --force --skip-existing", "post-update-cmd": "vendor/bin/captainhook install --force --skip-existing", - "test": "vendor/bin/phpunit", + "test": "vendor/bin/phpunit tests", + "test-unit": "vendor/bin/phpunit tests --group unit", + "test-inte": "vendor/bin/phpunit tests --group integration", "stan": "vendor/bin/phpstan analyse --configuration=phpstan.neon", - "lint": "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --dry-run --diff", - "fix": "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php", + "cs-lint": "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --dry-run --diff", + "cs-fix": "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php", "rector": "vendor/bin/rector process", "rector-dry": "vendor/bin/rector process --dry-run", "release": [ - "rm -rf payplug-core && cp -r src payplug-core && cp -r tests payplug-core", + "rm -rf payplug-core && mkdir payplug-core && cp -r src payplug-core/ && cp -r tests payplug-core/", "vendor/bin/rector process --config rector.php", "php scripts/generate-release-composer.php" ] diff --git a/composer.lock b/composer.lock index 19ca05f..5f30683 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bdd14120f415b9a164ea30c52b08fee1", + "content-hash": "ddd39cd74169a138281142f4e87ebe51", "packages": [ { "name": "captainhook/captainhook", - "version": "5.29.0", + "version": "5.29.2", "source": { "type": "git", "url": "https://github.com/captainhook-git/captainhook.git", - "reference": "ae6b2172e2865a572d6237235f66e652f05fe0f1" + "reference": "805d44b0de8ed143f4acfb8c6bcb788cdbc42963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/captainhook-git/captainhook/zipball/ae6b2172e2865a572d6237235f66e652f05fe0f1", - "reference": "ae6b2172e2865a572d6237235f66e652f05fe0f1", + "url": "https://api.github.com/repos/captainhook-git/captainhook/zipball/805d44b0de8ed143f4acfb8c6bcb788cdbc42963", + "reference": "805d44b0de8ed143f4acfb8c6bcb788cdbc42963", "shasum": "" }, "require": { @@ -80,7 +80,7 @@ ], "support": { "issues": "https://github.com/captainhook-git/captainhook/issues", - "source": "https://github.com/captainhook-git/captainhook/tree/5.29.0" + "source": "https://github.com/captainhook-git/captainhook/tree/5.29.2" }, "funding": [ { @@ -88,7 +88,7 @@ "type": "github" } ], - "time": "2026-03-22T09:20:04+00:00" + "time": "2026-03-25T19:32:25+00:00" }, { "name": "captainhook/secrets", @@ -428,39 +428,47 @@ }, { "name": "symfony/console", - "version": "v8.0.7", + "version": "v6.4.39", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a" + "reference": "c132f1215fe4aa45b70173cc00ce9a755dd31ec5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a", - "reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a", + "url": "https://api.github.com/repos/symfony/console/zipball/c132f1215fe4aa45b70173cc00ce9a755dd31ec5", + "reference": "c132f1215fe4aa45b70173cc00ce9a755dd31ec5", "shasum": "" }, "require": { - "php": ">=8.4", - "symfony/polyfill-mbstring": "^1.0", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^7.4|^8.0" + "symfony/string": "^5.4|^6.0|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^7.4|^8.0", - "symfony/dependency-injection": "^7.4|^8.0", - "symfony/event-dispatcher": "^7.4|^8.0", - "symfony/http-foundation": "^7.4|^8.0", - "symfony/http-kernel": "^7.4|^8.0", - "symfony/lock": "^7.4|^8.0", - "symfony/messenger": "^7.4|^8.0", - "symfony/process": "^7.4|^8.0", - "symfony/stopwatch": "^7.4|^8.0", - "symfony/var-dumper": "^7.4|^8.0" + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -494,7 +502,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v8.0.7" + "source": "https://github.com/symfony/console/tree/v6.4.39" }, "funding": [ { @@ -514,20 +522,20 @@ "type": "tidelift" } ], - "time": "2026-03-06T14:06:22+00:00" + "time": "2026-05-12T06:50:03+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.6.0", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b", + "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b", "shasum": "" }, "require": { @@ -540,7 +548,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -565,7 +573,7 @@ "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" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.0" }, "funding": [ { @@ -576,34 +584,38 @@ "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-25T14:21:43+00:00" + "time": "2026-04-13T15:52:40+00:00" }, { "name": "symfony/filesystem", - "version": "v8.0.6", + "version": "v6.4.39", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "7bf9162d7a0dff98d079b72948508fa48018a770" + "reference": "c507b077756b4e3e09adbbe7975fac81cd3722ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/7bf9162d7a0dff98d079b72948508fa48018a770", - "reference": "7bf9162d7a0dff98d079b72948508fa48018a770", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/c507b077756b4e3e09adbbe7975fac81cd3722ca", + "reference": "c507b077756b4e3e09adbbe7975fac81cd3722ca", "shasum": "" }, "require": { - "php": ">=8.4", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "symfony/process": "^7.4|^8.0" + "symfony/process": "^5.4|^6.4|^7.0" }, "type": "library", "autoload": { @@ -631,7 +643,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v8.0.6" + "source": "https://github.com/symfony/filesystem/tree/v6.4.39" }, "funding": [ { @@ -651,20 +663,20 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:59:43+00:00" + "time": "2026-05-07T13:11:42+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + "reference": "141046a8f9477948ff284fa65be2095baafb94f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2", + "reference": "141046a8f9477948ff284fa65be2095baafb94f2", "shasum": "" }, "require": { @@ -714,7 +726,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0" }, "funding": [ { @@ -734,20 +746,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + "reference": "4864388bfbd3001ce88e234fab652acd91fdc57e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/4864388bfbd3001ce88e234fab652acd91fdc57e", + "reference": "4864388bfbd3001ce88e234fab652acd91fdc57e", "shasum": "" }, "require": { @@ -796,7 +808,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.37.0" }, "funding": [ { @@ -816,11 +828,11 @@ "type": "tidelift" } ], - "time": "2025-06-27T09:58:17+00:00" + "time": "2026-04-26T13:13:48+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -881,7 +893,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.37.0" }, "funding": [ { @@ -905,16 +917,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6a21eb99c6973357967f6ce3708cd55a6bec6315", + "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315", "shasum": "" }, "require": { @@ -966,7 +978,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.37.0" }, "funding": [ { @@ -986,24 +998,24 @@ "type": "tidelift" } ], - "time": "2024-12-23T08:48:59+00:00" + "time": "2026-04-10T17:25:58+00:00" }, { "name": "symfony/process", - "version": "v8.0.5", + "version": "v6.4.39", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674" + "reference": "6c93071cb8c91dce5a41960d125e019e64ef6cb5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674", - "reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674", + "url": "https://api.github.com/repos/symfony/process/zipball/6c93071cb8c91dce5a41960d125e019e64ef6cb5", + "reference": "6c93071cb8c91dce5a41960d125e019e64ef6cb5", "shasum": "" }, "require": { - "php": ">=8.4" + "php": ">=8.1" }, "type": "library", "autoload": { @@ -1031,7 +1043,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v8.0.5" + "source": "https://github.com/symfony/process/tree/v6.4.39" }, "funding": [ { @@ -1051,20 +1063,20 @@ "type": "tidelift" } ], - "time": "2026-01-26T15:08:38+00:00" + "time": "2026-05-11T16:53:15+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.6.1", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" + "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d25d82433a80eba6aa0e6c24b61d7370d99e444a", + "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a", "shasum": "" }, "require": { @@ -1082,7 +1094,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -1118,7 +1130,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.7.0" }, "funding": [ { @@ -1138,38 +1150,37 @@ "type": "tidelift" } ], - "time": "2025-07-15T11:30:57+00:00" + "time": "2026-03-28T09:44:51+00:00" }, { "name": "symfony/string", - "version": "v8.0.6", + "version": "v6.4.39", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4" + "reference": "62e3c927de664edadb5bef260987eb047a17a113" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/6c9e1108041b5dce21a9a4984b531c4923aa9ec4", - "reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4", + "url": "https://api.github.com/repos/symfony/string/zipball/62e3c927de664edadb5bef260987eb047a17a113", + "reference": "62e3c927de664edadb5bef260987eb047a17a113", "shasum": "" }, "require": { - "php": ">=8.4", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-intl-grapheme": "^1.33", - "symfony/polyfill-intl-normalizer": "^1.0", - "symfony/polyfill-mbstring": "^1.0" + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/emoji": "^7.4|^8.0", - "symfony/http-client": "^7.4|^8.0", - "symfony/intl": "^7.4|^8.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/intl": "^6.2|^7.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^7.4|^8.0" + "symfony/var-exporter": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -1208,7 +1219,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v8.0.6" + "source": "https://github.com/symfony/string/tree/v6.4.39" }, "funding": [ { @@ -1228,7 +1239,7 @@ "type": "tidelift" } ], - "time": "2026-02-09T10:14:57+00:00" + "time": "2026-05-12T11:44:19+00:00" } ], "packages-dev": [ @@ -1518,6 +1529,75 @@ ], "time": "2024-05-06T16:37:16+00:00" }, + { + "name": "ergebnis/agent-detector", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/agent-detector.git", + "reference": "e211f17928c8b95a51e06040792d57f5462fb271" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/agent-detector/zipball/e211f17928c8b95a51e06040792d57f5462fb271", + "reference": "e211f17928c8b95a51e06040792d57f5462fb271", + "shasum": "" + }, + "require": { + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0 || ~8.6.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.51.0", + "ergebnis/license": "^2.7.0", + "ergebnis/php-cs-fixer-config": "^6.60.2", + "ergebnis/phpstan-rules": "^2.13.1", + "ergebnis/phpunit-slow-test-detector": "^2.24.0", + "ergebnis/rector-rules": "^1.18.1", + "fakerphp/faker": "^1.24.1", + "infection/infection": "^0.26.6", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.54", + "phpstan/phpstan-deprecation-rules": "^2.0.4", + "phpstan/phpstan-phpunit": "^2.0.16", + "phpstan/phpstan-strict-rules": "^2.0.10", + "phpunit/phpunit": "^9.6.34", + "rector/rector": "^2.4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + }, + "composer-normalize": { + "indent-size": 2, + "indent-style": "space" + } + }, + "autoload": { + "psr-4": { + "Ergebnis\\AgentDetector\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com" + } + ], + "description": "Provides a detector for detecting the presence of an agent.", + "homepage": "https://github.com/ergebnis/agent-detector", + "support": { + "issues": "https://github.com/ergebnis/agent-detector/issues", + "security": "https://github.com/ergebnis/agent-detector/blob/main/.github/SECURITY.md", + "source": "https://github.com/ergebnis/agent-detector" + }, + "time": "2026-05-07T08:19:07+00:00" + }, { "name": "evenement/evenement", "version": "v3.0.2", @@ -1628,22 +1708,23 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.94.2", + "version": "v3.95.2", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "7787ceff91365ba7d623ec410b8f429cdebb4f63" + "reference": "a28d88a5e172b27e78d0816992b15a9df3da20f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7787ceff91365ba7d623ec410b8f429cdebb4f63", - "reference": "7787ceff91365ba7d623ec410b8f429cdebb4f63", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/a28d88a5e172b27e78d0816992b15a9df3da20f1", + "reference": "a28d88a5e172b27e78d0816992b15a9df3da20f1", "shasum": "" }, "require": { "clue/ndjson-react": "^1.3", "composer/semver": "^3.4", "composer/xdebug-handler": "^3.0.5", + "ergebnis/agent-detector": "^1.1.1", "ext-filter": "*", "ext-hash": "*", "ext-json": "*", @@ -1668,18 +1749,18 @@ "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0" }, "require-dev": { - "facile-it/paraunit": "^1.3.1 || ^2.7.1", - "infection/infection": "^0.32.3", - "justinrainbow/json-schema": "^6.6.4", + "facile-it/paraunit": "^1.3.1 || ^2.11.0", + "infection/infection": "^0.32.7", + "justinrainbow/json-schema": "^6.8.0", "keradus/cli-executor": "^2.3", "mikey179/vfsstream": "^1.6.12", "php-coveralls/php-coveralls": "^2.9.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.7", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.7", - "phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.51", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.8", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.8", + "phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.55", "symfony/polyfill-php85": "^1.33", - "symfony/var-dumper": "^5.4.48 || ^6.4.32 || ^7.4.4 || ^8.0.4", - "symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0.1" + "symfony/var-dumper": "^5.4.48 || ^6.4.32 || ^7.4.4 || ^8.0.8", + "symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0.8" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -1720,7 +1801,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.94.2" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.95.2" }, "funding": [ { @@ -1728,7 +1809,141 @@ "type": "github" } ], - "time": "2026-02-20T16:13:53+00:00" + "time": "2026-05-15T09:20:44+00:00" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "^1.4 || ^2.0 || ^3.0", + "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "hamcrest" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "support": { + "issues": "https://github.com/hamcrest/hamcrest-php/issues", + "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.1.1" + }, + "time": "2025-04-30T06:54:44+00:00" + }, + { + "name": "mockery/mockery", + "version": "1.6.12", + "source": { + "type": "git", + "url": "https://github.com/mockery/mockery.git", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "^2.0.1", + "lib-pcre": ">=7.0", + "php": ">=7.3" + }, + "conflict": { + "phpunit/phpunit": "<8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.5 || ^9.6.17", + "symplify/easy-coding-standard": "^12.1.14" + }, + "type": "library", + "autoload": { + "files": [ + "library/helpers.php", + "library/Mockery.php" + ], + "psr-4": { + "Mockery\\": "library/Mockery" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "https://github.com/padraic", + "role": "Author" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "https://davedevelopment.co.uk", + "role": "Developer" + }, + { + "name": "Nathanael Esayeas", + "email": "nathanael.esayeas@protonmail.com", + "homepage": "https://github.com/ghostwriter", + "role": "Lead Developer" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework", + "homepage": "https://github.com/mockery/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "docs": "https://docs.mockery.io/", + "issues": "https://github.com/mockery/mockery/issues", + "rss": "https://github.com/mockery/mockery/releases.atom", + "security": "https://github.com/mockery/mockery/security/advisories", + "source": "https://github.com/mockery/mockery" + }, + "time": "2024-05-16T03:13:13+00:00" }, { "name": "myclabs/deep-copy", @@ -1968,11 +2183,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.42", + "version": "2.1.55", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1279e1ce86ba768f0780c9d889852b4e02ff40d0", - "reference": "1279e1ce86ba768f0780c9d889852b4e02ff40d0", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9eaac3826ed5e9b8427350a43cac825eeca3f566", + "reference": "9eaac3826ed5e9b8427350a43cac825eeca3f566", "shasum": "" }, "require": { @@ -2017,39 +2232,144 @@ "type": "github" } ], - "time": "2026-03-17T14:58:32+00:00" + "time": "2026-05-18T11:57:34+00:00" + }, + { + "name": "phpstan/phpstan-mockery", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-mockery.git", + "reference": "89a949d0ac64298e88b7c7fa00caee565c198394" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-mockery/zipball/89a949d0ac64298e88b7c7fa00caee565c198394", + "reference": "89a949d0ac64298e88b7c7fa00caee565c198394", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0" + }, + "require-dev": { + "mockery/mockery": "^1.6.11", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan Mockery extension", + "support": { + "issues": "https://github.com/phpstan/phpstan-mockery/issues", + "source": "https://github.com/phpstan/phpstan-mockery/tree/2.0.0" + }, + "time": "2024-10-14T03:18:12+00:00" + }, + { + "name": "phpstan/phpstan-phpunit", + "version": "2.0.16", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-phpunit.git", + "reference": "6ab598e1bc106e6827fd346ae4a12b4a5d634c32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/6ab598e1bc106e6827fd346ae4a12b4a5d634c32", + "reference": "6ab598e1bc106e6827fd346ae4a12b4a5d634c32", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.32" + }, + "conflict": { + "phpunit/phpunit": "<7.0" + }, + "require-dev": { + "nikic/php-parser": "^5", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPUnit extensions and rules for PHPStan", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/phpstan-phpunit/issues", + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.16" + }, + "time": "2026-02-14T09:05:21+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "11.0.12", + "version": "10.1.16", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56" + "reference": "7e308268858ed6baedc8704a304727d20bc07c77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", - "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", + "reference": "7e308268858ed6baedc8704a304727d20bc07c77", "shasum": "" }, "require": { "ext-dom": "*", "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" + "nikic/php-parser": "^4.19.1 || ^5.1.0", + "php": ">=8.1", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-text-template": "^3.0.1", + "sebastian/code-unit-reverse-lookup": "^3.0.0", + "sebastian/complexity": "^3.2.0", + "sebastian/environment": "^6.1.0", + "sebastian/lines-of-code": "^2.0.2", + "sebastian/version": "^4.0.1", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^11.5.46" + "phpunit/phpunit": "^10.1" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -2058,7 +2378,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "11.0.x-dev" + "dev-main": "10.1.x-dev" } }, "autoload": { @@ -2087,52 +2407,40 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.12" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16" }, "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" + "time": "2024-08-22T04:31:57+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "5.1.1", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", - "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.1-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -2160,48 +2468,36 @@ "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" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" }, "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" + "time": "2023-08-31T06:24:48+00:00" }, { "name": "phpunit/php-invoker", - "version": "5.0.1", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", - "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "suggest": { "ext-pcntl": "*" @@ -2209,7 +2505,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -2235,8 +2531,7 @@ ], "support": { "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" + "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" }, "funding": [ { @@ -2244,32 +2539,32 @@ "type": "github" } ], - "time": "2024-07-03T05:07:44+00:00" + "time": "2023-02-03T06:56:09+00:00" }, { "name": "phpunit/php-text-template", - "version": "4.0.1", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", - "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -2296,7 +2591,7 @@ "support": { "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" + "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" }, "funding": [ { @@ -2304,32 +2599,32 @@ "type": "github" } ], - "time": "2024-07-03T05:08:43+00:00" + "time": "2023-08-31T14:07:24+00:00" }, { "name": "phpunit/php-timer", - "version": "7.0.1", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", - "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "7.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -2355,8 +2650,7 @@ ], "support": { "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" + "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" }, "funding": [ { @@ -2364,20 +2658,20 @@ "type": "github" } ], - "time": "2024-07-03T05:09:35+00:00" + "time": "2023-02-03T06:57:52+00:00" }, { "name": "phpunit/phpunit", - "version": "11.5.55", + "version": "10.5.63", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00" + "reference": "33198268dad71e926626b618f3ec3966661e4d90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00", - "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/33198268dad71e926626b618f3ec3966661e4d90", + "reference": "33198268dad71e926626b618f3ec3966661e4d90", "shasum": "" }, "require": { @@ -2390,24 +2684,23 @@ "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" + "php": ">=8.1", + "phpunit/php-code-coverage": "^10.1.16", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-invoker": "^4.0.0", + "phpunit/php-text-template": "^3.0.1", + "phpunit/php-timer": "^6.0.0", + "sebastian/cli-parser": "^2.0.1", + "sebastian/code-unit": "^2.0.0", + "sebastian/comparator": "^5.0.5", + "sebastian/diff": "^5.1.1", + "sebastian/environment": "^6.1.0", + "sebastian/exporter": "^5.1.4", + "sebastian/global-state": "^6.0.2", + "sebastian/object-enumerator": "^5.0.0", + "sebastian/recursion-context": "^5.0.1", + "sebastian/type": "^4.0.0", + "sebastian/version": "^4.0.1" }, "suggest": { "ext-soap": "To be able to generate mocks based on WSDL files" @@ -2418,7 +2711,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "11.5-dev" + "dev-main": "10.5-dev" } }, "autoload": { @@ -2450,7 +2743,7 @@ "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" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.63" }, "funding": [ { @@ -2474,7 +2767,7 @@ "type": "tidelift" } ], - "time": "2026-02-18T12:37:06+00:00" + "time": "2026-01-27T05:48:37+00:00" }, { "name": "psr/event-dispatcher", @@ -3104,21 +3397,21 @@ }, { "name": "rector/rector", - "version": "2.3.9", + "version": "2.4.4", "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "917842143fd9f5331a2adefc214b8d7143bd32c4" + "reference": "4661c582a20f03df585d2e3fdc4af1b83d67a091" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/917842143fd9f5331a2adefc214b8d7143bd32c4", - "reference": "917842143fd9f5331a2adefc214b8d7143bd32c4", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/4661c582a20f03df585d2e3fdc4af1b83d67a091", + "reference": "4661c582a20f03df585d2e3fdc4af1b83d67a091", "shasum": "" }, "require": { "php": "^7.4|^8.0", - "phpstan/phpstan": "^2.1.40" + "phpstan/phpstan": "^2.1.48" }, "conflict": { "rector/rector-doctrine": "*", @@ -3152,7 +3445,7 @@ ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/2.3.9" + "source": "https://github.com/rectorphp/rector/tree/2.4.4" }, "funding": [ { @@ -3160,32 +3453,32 @@ "type": "github" } ], - "time": "2026-03-16T09:43:55+00:00" + "time": "2026-05-20T19:30:21+00:00" }, { "name": "sebastian/cli-parser", - "version": "3.0.2", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", - "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084", + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -3209,7 +3502,7 @@ "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" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1" }, "funding": [ { @@ -3217,32 +3510,32 @@ "type": "github" } ], - "time": "2024-07-03T04:41:36+00:00" + "time": "2024-03-02T07:12:49+00:00" }, { "name": "sebastian/code-unit", - "version": "3.0.3", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", - "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.5" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -3265,8 +3558,7 @@ "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" + "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" }, "funding": [ { @@ -3274,32 +3566,32 @@ "type": "github" } ], - "time": "2025-03-19T07:56:08+00:00" + "time": "2023-02-03T06:58:43+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "4.0.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", - "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -3321,8 +3613,7 @@ "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" + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" }, "funding": [ { @@ -3330,39 +3621,36 @@ "type": "github" } ], - "time": "2024-07-03T04:45:54+00:00" + "time": "2023-02-03T06:59:15+00:00" }, { "name": "sebastian/comparator", - "version": "6.3.3", + "version": "5.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" + "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", - "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55dfef806eb7dfeb6e7a6935601fef866f8ca48d", + "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d", "shasum": "" }, "require": { "ext-dom": "*", "ext-mbstring": "*", - "php": ">=8.2", - "sebastian/diff": "^6.0", - "sebastian/exporter": "^6.0" + "php": ">=8.1", + "sebastian/diff": "^5.0", + "sebastian/exporter": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^11.4" - }, - "suggest": { - "ext-bcmath": "For comparing BcMath\\Number objects" + "phpunit/phpunit": "^10.5" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.3-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -3402,7 +3690,7 @@ "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" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.5" }, "funding": [ { @@ -3422,33 +3710,33 @@ "type": "tidelift" } ], - "time": "2026-01-24T09:26:40+00:00" + "time": "2026-01-24T09:25:16+00:00" }, { "name": "sebastian/complexity", - "version": "4.0.1", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + "reference": "68ff824baeae169ec9f2137158ee529584553799" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", - "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", + "reference": "68ff824baeae169ec9f2137158ee529584553799", "shasum": "" }, "require": { - "nikic/php-parser": "^5.0", - "php": ">=8.2" + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "3.2-dev" } }, "autoload": { @@ -3472,7 +3760,7 @@ "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" + "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" }, "funding": [ { @@ -3480,33 +3768,33 @@ "type": "github" } ], - "time": "2024-07-03T04:49:50+00:00" + "time": "2023-12-21T08:37:17+00:00" }, { "name": "sebastian/diff", - "version": "6.0.2", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", - "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^10.0", + "symfony/process": "^6.4" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -3539,7 +3827,7 @@ "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" + "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" }, "funding": [ { @@ -3547,27 +3835,27 @@ "type": "github" } ], - "time": "2024-07-03T04:53:05+00:00" + "time": "2024-03-02T07:15:17+00:00" }, { "name": "sebastian/environment", - "version": "7.2.1", + "version": "6.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", - "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^10.0" }, "suggest": { "ext-posix": "*" @@ -3575,7 +3863,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "7.2-dev" + "dev-main": "6.1-dev" } }, "autoload": { @@ -3603,54 +3891,42 @@ "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" + "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0" }, "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" + "time": "2024-03-23T08:47:14+00:00" }, { "name": "sebastian/exporter", - "version": "6.3.2", + "version": "5.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" + "reference": "0735b90f4da94969541dac1da743446e276defa6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", - "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0735b90f4da94969541dac1da743446e276defa6", + "reference": "0735b90f4da94969541dac1da743446e276defa6", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": ">=8.2", - "sebastian/recursion-context": "^6.0" + "php": ">=8.1", + "sebastian/recursion-context": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^10.5" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.3-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -3693,7 +3969,7 @@ "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" + "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.4" }, "funding": [ { @@ -3713,35 +3989,35 @@ "type": "tidelift" } ], - "time": "2025-09-24T06:12:51+00:00" + "time": "2025-09-24T06:09:11+00:00" }, { "name": "sebastian/global-state", - "version": "7.0.2", + "version": "6.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", - "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", "shasum": "" }, "require": { - "php": ">=8.2", - "sebastian/object-reflector": "^4.0", - "sebastian/recursion-context": "^6.0" + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "7.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -3767,7 +4043,7 @@ "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" + "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2" }, "funding": [ { @@ -3775,33 +4051,33 @@ "type": "github" } ], - "time": "2024-07-03T04:57:36+00:00" + "time": "2024-03-02T07:19:19+00:00" }, { "name": "sebastian/lines-of-code", - "version": "3.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", - "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", "shasum": "" }, "require": { - "nikic/php-parser": "^5.0", - "php": ">=8.2" + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -3825,7 +4101,7 @@ "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" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" }, "funding": [ { @@ -3833,34 +4109,34 @@ "type": "github" } ], - "time": "2024-07-03T04:58:38+00:00" + "time": "2023-12-21T08:38:20+00:00" }, { "name": "sebastian/object-enumerator", - "version": "6.0.1", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", - "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", "shasum": "" }, "require": { - "php": ">=8.2", - "sebastian/object-reflector": "^4.0", - "sebastian/recursion-context": "^6.0" + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -3882,8 +4158,7 @@ "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" + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" }, "funding": [ { @@ -3891,32 +4166,32 @@ "type": "github" } ], - "time": "2024-07-03T05:00:13+00:00" + "time": "2023-02-03T07:08:32+00:00" }, { "name": "sebastian/object-reflector", - "version": "4.0.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", - "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -3938,8 +4213,7 @@ "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" + "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" }, "funding": [ { @@ -3947,32 +4221,32 @@ "type": "github" } ], - "time": "2024-07-03T05:01:32+00:00" + "time": "2023-02-03T07:06:18+00:00" }, { "name": "sebastian/recursion-context", - "version": "6.0.3", + "version": "5.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc" + "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc", - "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/47e34210757a2f37a97dcd207d032e1b01e64c7a", + "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^10.5" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -4003,7 +4277,7 @@ "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" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.1" }, "funding": [ { @@ -4023,32 +4297,32 @@ "type": "tidelift" } ], - "time": "2025-08-13T04:42:22+00:00" + "time": "2025-08-10T07:50:56+00:00" }, { "name": "sebastian/type", - "version": "5.1.3", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", - "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.1-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -4071,50 +4345,37 @@ "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" + "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" }, "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" + "time": "2023-02-03T07:10:45+00:00" }, { "name": "sebastian/version", - "version": "5.0.2", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", - "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -4137,8 +4398,7 @@ "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" + "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" }, "funding": [ { @@ -4146,80 +4406,28 @@ "type": "github" } ], - "time": "2024-10-09T05:16:32+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" + "time": "2023-02-07T11:34:05+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v8.0.4", + "version": "v6.4.37", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "99301401da182b6cfaa4700dbe9987bb75474b47" + "reference": "2e3bf817ba9347341ab15926700fb6320367c0e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/99301401da182b6cfaa4700dbe9987bb75474b47", - "reference": "99301401da182b6cfaa4700dbe9987bb75474b47", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2e3bf817ba9347341ab15926700fb6320367c0e1", + "reference": "2e3bf817ba9347341ab15926700fb6320367c0e1", "shasum": "" }, "require": { - "php": ">=8.4", + "php": ">=8.1", "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/security-http": "<7.4", + "symfony/dependency-injection": "<5.4", "symfony/service-contracts": "<2.5" }, "provide": { @@ -4228,14 +4436,13 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^7.4|^8.0", - "symfony/dependency-injection": "^7.4|^8.0", - "symfony/error-handler": "^7.4|^8.0", - "symfony/expression-language": "^7.4|^8.0", - "symfony/framework-bundle": "^7.4|^8.0", - "symfony/http-foundation": "^7.4|^8.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^7.4|^8.0" + "symfony/stopwatch": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -4263,7 +4470,7 @@ "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/v8.0.4" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.37" }, "funding": [ { @@ -4283,20 +4490,20 @@ "type": "tidelift" } ], - "time": "2026-01-05T11:45:55+00:00" + "time": "2026-04-13T14:11:12+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.6.0", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586" + "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/ccba7060602b7fed0b03c85bf025257f76d9ef32", + "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32", "shasum": "" }, "require": { @@ -4310,7 +4517,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -4343,7 +4550,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.0" }, "funding": [ { @@ -4354,32 +4561,36 @@ "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-25T14:21:43+00:00" + "time": "2026-01-05T13:30:16+00:00" }, { "name": "symfony/finder", - "version": "v8.0.6", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "441404f09a54de6d1bd6ad219e088cdf4c91f97c" + "reference": "9590e86be1d1c57bfbb16d0dd040345378c20896" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/441404f09a54de6d1bd6ad219e088cdf4c91f97c", - "reference": "441404f09a54de6d1bd6ad219e088cdf4c91f97c", + "url": "https://api.github.com/repos/symfony/finder/zipball/9590e86be1d1c57bfbb16d0dd040345378c20896", + "reference": "9590e86be1d1c57bfbb16d0dd040345378c20896", "shasum": "" }, "require": { - "php": ">=8.4" + "php": ">=8.1" }, "require-dev": { - "symfony/filesystem": "^7.4|^8.0" + "symfony/filesystem": "^6.0|^7.0" }, "type": "library", "autoload": { @@ -4407,7 +4618,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v8.0.6" + "source": "https://github.com/symfony/finder/tree/v6.4.34" }, "funding": [ { @@ -4427,24 +4638,24 @@ "type": "tidelift" } ], - "time": "2026-01-29T09:41:02+00:00" + "time": "2026-01-28T15:16:37+00:00" }, { "name": "symfony/options-resolver", - "version": "v8.0.0", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7" + "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/d2b592535ffa6600c265a3893a7f7fd2bad82dd7", - "reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", + "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", "shasum": "" }, "require": { - "php": ">=8.4", + "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3" }, "type": "library", @@ -4478,7 +4689,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v8.0.0" + "source": "https://github.com/symfony/options-resolver/tree/v6.4.30" }, "funding": [ { @@ -4498,20 +4709,20 @@ "type": "tidelift" } ], - "time": "2025-11-12T15:55:31+00:00" + "time": "2025-11-12T13:06:53+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411", + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411", "shasum": "" }, "require": { @@ -4562,7 +4773,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0" }, "funding": [ { @@ -4582,11 +4793,11 @@ "type": "tidelift" } ], - "time": "2025-01-02T08:10:11+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", @@ -4642,7 +4853,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.37.0" }, "funding": [ { @@ -4666,16 +4877,16 @@ }, { "name": "symfony/polyfill-php84", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" + "reference": "88486db2c389b290bf87ff1de7ebc1e13e42bb06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/88486db2c389b290bf87ff1de7ebc1e13e42bb06", + "reference": "88486db2c389b290bf87ff1de7ebc1e13e42bb06", "shasum": "" }, "require": { @@ -4722,7 +4933,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.37.0" }, "funding": [ { @@ -4742,24 +4953,24 @@ "type": "tidelift" } ], - "time": "2025-06-24T13:30:11+00:00" + "time": "2026-04-10T18:47:49+00:00" }, { "name": "symfony/stopwatch", - "version": "v8.0.0", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "67df1914c6ccd2d7b52f70d40cf2aea02159d942" + "reference": "b67e94e06a05d9572c2fa354483b3e13e3cb1898" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/67df1914c6ccd2d7b52f70d40cf2aea02159d942", - "reference": "67df1914c6ccd2d7b52f70d40cf2aea02159d942", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b67e94e06a05d9572c2fa354483b3e13e3cb1898", + "reference": "b67e94e06a05d9572c2fa354483b3e13e3cb1898", "shasum": "" }, "require": { - "php": ">=8.4", + "php": ">=8.1", "symfony/service-contracts": "^2.5|^3" }, "type": "library", @@ -4788,7 +4999,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v8.0.0" + "source": "https://github.com/symfony/stopwatch/tree/v6.4.24" }, "funding": [ { @@ -4808,7 +5019,7 @@ "type": "tidelift" } ], - "time": "2025-08-04T07:36:47+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "theseer/tokenizer", @@ -4867,7 +5078,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=8.4" + "php": ">=8.1" }, "platform-dev": {}, "plugin-api-version": "2.9.0" diff --git a/phpstan.neon b/phpstan.neon index e05ca18..bd382ff 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,10 @@ +includes: + - vendor/phpstan/phpstan-mockery/extension.neon + - vendor/phpstan/phpstan-phpunit/extension.neon + parameters: level: 8 phpVersion: 80400 paths: - src + - tests diff --git a/scripts/generate-release-composer.php b/scripts/generate-release-composer.php index 5c7e050..72c0100 100644 --- a/scripts/generate-release-composer.php +++ b/scripts/generate-release-composer.php @@ -8,8 +8,8 @@ * Changes applied: * - php requirement → ^7.2 * - captainhook removed from require (dev-only tool) - * - require-dev, autoload-dev, and scripts sections stripped - * - autoload psr-4 path changed from src/ to "" (release/ is the package root) + * - require-dev replaced with PHP 7.2-compatible versions (phpunit ^8.5, mockery ^1.3) + * - autoload psr-4: PayplugPluginCore\ → src/; tests/ added so class resolution works with --no-dev */ $root = dirname(__DIR__); @@ -41,13 +41,26 @@ // Downgrade PHP requirement $data['require']['php'] = '^7.2'; -// Remove dev-only dependencies from require -unset($data['require']['captainhook/captainhook'], $data['require-dev'], $data['autoload-dev'], $data['scripts']); +// Remove dev-only tools from require and scripts +unset($data['require']['captainhook/captainhook'], $data['scripts']); -// Strip dev-only sections +// Replace require-dev with PHP 7.2-compatible test dependencies +// (phpunit ^11 requires PHP >=8.2; mockery ^1.6 requires PHP >=7.3) +$data['require-dev'] = [ + 'phpunit/phpunit' => '^8.5', // PHPUnit 8.x requires PHP >=7.2 + 'mockery/mockery' => '^1.3', // Mockery 1.3.x requires PHP >=5.4 +]; -// Fix autoload: release/ is the package root, not src/ -$data['autoload']['psr-4'] = ['PayplugPluginCore\\' => '']; +// Fix autoload: src/ is now a proper subdirectory of the package root. +// The Tests\ prefix is more specific and must be declared before PayplugPluginCore\ so that +// PSR-4 resolves test classes to tests/ regardless of whether composer install runs with --no-dev. +$data['autoload']['psr-4'] = [ + 'PayplugPluginCore\\Tests\\' => 'tests/', + 'PayplugPluginCore\\' => 'src/', +]; + +// Mirror in autoload-dev for tools that rely on it +// $data['autoload-dev'] = ['psr-4' => ['PayplugPluginCore\\Tests\\' => 'tests/']]; $json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n"; diff --git a/src/Actions/PaymentAction.php b/src/Actions/PaymentAction.php index f8063c2..71904ab 100644 --- a/src/Actions/PaymentAction.php +++ b/src/Actions/PaymentAction.php @@ -13,12 +13,20 @@ class PaymentAction { use DependenciesLoader; + public function __construct() + { + $this->allowed_gateways = ['payment']; + $this->allowed_services = ['api']; + } + /** * @param PaymentInputDTO $payment_inputDTO - * @return PaymentOutputDTO - * @throws \Exception + * + * @return ?PaymentOutputDTO + *@throws \Exception + * */ - public function createAction(PaymentInputDTO $payment_inputDTO): PaymentOutputDTO + public function createAction(PaymentInputDTO $payment_inputDTO): ?PaymentOutputDTO { // todo: add a validator to check if the given paymentDTO is usable @@ -39,12 +47,8 @@ public function createAction(PaymentInputDTO $payment_inputDTO): PaymentOutputDT $api_service = $this->get_service('api'); $api = $api_service->load((string) $payment_inputDTO->getApiBearer()); $resource = $api->createPaymentResource($formated_attributes); - $output = PaymentOutputDTO::create($resource); - if ($output === null) { - throw new \Exception('Failed to build PaymentOutputDTO from API response.'); - } - return $output; + return PaymentOutputDTO::create($resource); } /** diff --git a/src/Gateways/AbstractPaymentGateway.php b/src/Gateways/AbstractPaymentGateway.php index 4eb483c..acfb576 100644 --- a/src/Gateways/AbstractPaymentGateway.php +++ b/src/Gateways/AbstractPaymentGateway.php @@ -25,7 +25,7 @@ abstract public function formatPaymentAttributes(PaymentInputDTO $payment_inputD public function getDefaultAttributeFromDTO(PaymentInputDTO $payment_inputDTO): array { $customer = $payment_inputDTO->getCustomer() ?? []; - $urls = $payment_inputDTO->getReturnUrls() ?? []; + $urls = $payment_inputDTO->getUrls() ?? []; return [ 'amount' => $payment_inputDTO->getAmount(), diff --git a/src/Gateways/Payment/StandardPaymentGateway.php b/src/Gateways/Payment/StandardPaymentGateway.php index 4164b11..1609f36 100644 --- a/src/Gateways/Payment/StandardPaymentGateway.php +++ b/src/Gateways/Payment/StandardPaymentGateway.php @@ -28,12 +28,13 @@ public function formatPaymentAttributes(PaymentInputDTO $payment_inputDTO): arra { $attributes = $this->getDefaultAttributeFromDTO($payment_inputDTO); if (empty($attributes)) { - throw new \Exception('Can\'t generate default Payment attributes'); + throw new \Exception('Can\'t generate default payment attributes'); } // todo : Set validator to check this point // Vérification des clés attendues dans $context $context = $payment_inputDTO->getContext() ?? []; + foreach ($this->expected_context as $key) { if (!\array_key_exists($key, $context)) { //@TODO: Create Exception System for the Library to avoid trigerring basic Exception all the time @@ -55,7 +56,7 @@ public function formatPaymentAttributes(PaymentInputDTO $payment_inputDTO): arra // Update Payment card could be saved $is_guest = isset($context['is_guest']) && $context['is_guest']; - $attributes['allow_save_card'] = !(bool)$is_guest; + $attributes['allow_save_card'] = !(bool) $is_guest; return $attributes; } diff --git a/src/Gateways/PaymentGatewayManager.php b/src/Gateways/PaymentGatewayManager.php index 9320c1d..fe78bab 100644 --- a/src/Gateways/PaymentGatewayManager.php +++ b/src/Gateways/PaymentGatewayManager.php @@ -17,7 +17,7 @@ public function load(string $payment_method_name): AbstractPaymentGateway $class = '\PayplugPluginCore\Gateways\Payment\\' . str_replace('_', '', ucwords($payment_method_name, '_')) - . 'PaymentGatewayManager'; + . 'PaymentGateway'; if (!class_exists($class)) { throw new \Exception('Payment method can\'t be found.'); diff --git a/src/Models/Entities/PaymentInputDTO.php b/src/Models/Entities/PaymentInputDTO.php index 902fbac..1f6b27e 100644 --- a/src/Models/Entities/PaymentInputDTO.php +++ b/src/Models/Entities/PaymentInputDTO.php @@ -55,7 +55,7 @@ public function hydrate(array $props): ?self continue; } - if (!\array_key_exists($key, $props) || $props[$key] === null) { + if (!\array_key_exists($key, $props) || null === $props[$key]) { $this->resetProperties(); throw new Exception('PaymentInputDTO can\'t be hydrated, required field is invalid.'); } @@ -66,7 +66,7 @@ public function hydrate(array $props): ?self $this->setAmount((int) $props['amount']); $this->setCurrencyIsoCode((string) $props['currency_iso_code']); $this->setCustomer((array) $props['customer']); - $this->setReturnUrls((array) $props['urls']); + $this->setUrls((array) $props['urls']); $this->setMetadata((array) $props['metadata']); $this->setContext((array) $props['context']); @@ -134,7 +134,7 @@ public function getPaymentMethod(): ?string /** * @return array|null */ - public function getReturnUrls(): ?array + public function getUrls(): ?array { return $this->urls; } @@ -196,7 +196,7 @@ public function setPaymentMethod(string $payment_method): void /** * @param array $urls */ - public function setReturnUrls(array $urls): void + public function setUrls(array $urls): void { $this->urls = $urls; } diff --git a/src/Models/Entities/PaymentOutputDTO.php b/src/Models/Entities/PaymentOutputDTO.php index 9b421e0..804a6d7 100644 --- a/src/Models/Entities/PaymentOutputDTO.php +++ b/src/Models/Entities/PaymentOutputDTO.php @@ -4,20 +4,34 @@ namespace PayplugPluginCore\Models\Entities; +use Payplug\Resource\Payment; + class PaymentOutputDTO { - public ?bool $result = null; + /** + * @var bool|null + */ + public $result; - public ?string $code = null; + /** + * @var string|null + */ + public $code; - public ?string $message = null; + /** + * @var string|null + */ + public $message; - public ?object $resource = null; + /** + * @var Payment|null + */ + public $resource; /** * @var array */ - private array $definitions = [ + private $definitions = [ 'result' => ['type' => 'boolean', 'required' => true], 'code' => ['type' => 'string', 'required' => true], 'message' => ['type' => 'string', 'required' => false], @@ -36,7 +50,7 @@ public function hydrate(array $props): ?self continue; } - if (!\array_key_exists($key, $props) || $props[$key] === null) { + if (!\array_key_exists($key, $props) || null === $props[$key]) { $this->resetProperties(); throw new \Exception('PaymentOutputDTO can\'t be hydrated, required field is invalid.'); } @@ -44,7 +58,7 @@ public function hydrate(array $props): ?self $this->setResult((bool) $props['result']); $this->setCode((string) $props['code']); - $this->setMessage((string) $props['message']); + $this->setMessage(isset($props['message']) ? (string) $props['message'] : ''); $this->setResource($props['resource']); return $this; @@ -83,7 +97,7 @@ public function getDefinitions(): array return $this->definitions; } - public function getResource(): ?object + public function getResource(): ?Payment { return $this->resource; } @@ -105,9 +119,9 @@ public function setMessage(string $message): void $this->message = $message; } - public function setResource(mixed $resource): void + public function setResource(?Payment $resource): void { - $this->resource = \is_object($resource) ? $resource : null; + $this->resource = $resource; } /** diff --git a/src/Utilities/Services/Api.php b/src/Utilities/Services/Api.php index cfecff2..50941d6 100644 --- a/src/Utilities/Services/Api.php +++ b/src/Utilities/Services/Api.php @@ -4,15 +4,15 @@ namespace PayplugPluginCore\Utilities\Services; +use http\Exception\RuntimeException; use Payplug\Payment; use Payplug\Payplug; class Api { - private string $bearer_token; + private ?Payplug $payplug_api = null; - /** @var array{0: class-string, 1: string} */ - private const array PAYMENT_CREATE = [Payment::class, 'create']; + private string $bearer_token; /** * @param array $datas @@ -20,7 +20,26 @@ class Api */ public function createPaymentResource(array $datas): array { - return $this->doRequest(self::PAYMENT_CREATE, $datas); + try { + if (null === $this->payplug_api) { + throw new RuntimeException('API Payplug must be initialized.'); + } + $response = [ + 'code' => 200, + 'message' => 'OK', + 'resource' => Payment::create($datas, $this->payplug_api), + 'result' => true, + ]; + } catch (\Exception $e) { + $response = [ + 'code' => $e->getCode(), + 'message' => $e->getMessage(), + 'resource' => null, + 'result' => false, + ]; + } + + return $response; } public function getBearerToken(): string @@ -45,36 +64,13 @@ public function load(string $bearer_token): self return $this; } - /** - * @param array $params - * @return array - */ - protected function doRequest(callable $callback, array $params): array - { - try { - $response = [ - 'result' => true, - 'response' => \call_user_func_array($callback, $params), - 'code' => 200, - ]; - } catch (\Exception $e) { - $response = [ - 'result' => false, - 'response' => null, - 'code' => $e->getCode(), - ]; - } - - return $response; - } - /** * @throws \Exception */ private function initialize(): void { try { - Payplug::init([ + $this->payplug_api = Payplug::init([ 'secretKey' => $this->getBearerToken(), 'apiVersion' => '2019-08-06', ]); diff --git a/src/Utilities/Traits/DependenciesLoader.php b/src/Utilities/Traits/DependenciesLoader.php index 4c992b5..462c524 100644 --- a/src/Utilities/Traits/DependenciesLoader.php +++ b/src/Utilities/Traits/DependenciesLoader.php @@ -61,9 +61,6 @@ public function get_gateway(string $name = ''): object public function get_payment_gateway(): PaymentGatewayManager { - /** @var PaymentGatewayManager $gateway */ - $gateway = $this->get_gateway('payment'); - - return $gateway; + return new PaymentGatewayManager(); } } diff --git a/tests/Integration/PaymentAction/createActionTest.php b/tests/Integration/PaymentAction/createActionTest.php new file mode 100644 index 0000000..ec6a87f --- /dev/null +++ b/tests/Integration/PaymentAction/createActionTest.php @@ -0,0 +1,82 @@ +action = Mockery::mock(PaymentAction::class, [])->makePartial(); + $this->payment_api = \Mockery::mock('alias:Payplug\Payment'); + $this->default_payment_input_DTO = PaymentInputDTOMock::get([ + 'payment_method' => 'standard', + 'context' => [ + 'is_deferred' => false, + 'is_integrated' => false, + 'is_guest' => false, + ], + ]); + } + + public function tearDown(): void + { + Mockery::close(); + } + + public function testWhenResourceCantBeCreated(): void + { + $error_msg = 'An error occurred during the process'; + $error_code = 500; + $this->payment_api + ->shouldReceive('create') + ->once() + ->andThrow(new \Exception($error_msg, $error_code)); + + $error_output_props = [ + 'code' => $error_code, + 'message' => $error_msg, + 'result' => false, + 'resource' => null, + ]; + $this->assertEquals( + PaymentOutputDTOMock::get($error_output_props), + $this->action->createAction($this->default_payment_input_DTO) + ); + } + + public function testWhenResourceIsCreated(): void + { + + $resource = PaymentMock::getStandard(); + $this->payment_api + ->shouldReceive('create') + ->once() + ->andReturn($resource); + + $success_output_props = [ + 'resource' => $resource, + ]; + $payment_output_DTO = PaymentOutputDTOMock::get($success_output_props); + $return = $this->action->createAction($this->default_payment_input_DTO); + + $this->assertEquals($payment_output_DTO, $return); + } +} diff --git a/tests/Mock/PaymentInputDTOMock.php b/tests/Mock/PaymentInputDTOMock.php new file mode 100644 index 0000000..5c926ce --- /dev/null +++ b/tests/Mock/PaymentInputDTOMock.php @@ -0,0 +1,81 @@ +|null $custom_props + * @throws \Exception + */ + public static function get(?array $custom_props): PaymentInputDTO + { + // get default + $props = [ + 'api_bearer' => 'token_bearer', + 'payment_method' => 'payment method', + 'amount' => 4242, + 'currency_iso_code' => 'EUR', + 'customer' => [ + 'identifier' => 42, + 'billing' => [ + 'title' => 'mr', + 'first_name' => 'John', + 'last_name' => 'Watson', + 'mobile_phone_number' => '+33612345678', + 'email' => 'john.watson@example.net', + 'address1' => '221B Baker Street', + 'postcode' => 'NW16XE', + 'city' => 'London', + 'country' => 'GB', + 'language' => 'en', + ], + 'shipping' => [ + 'title' => 'mr', + 'first_name' => 'John', + 'last_name' => 'Watson', + 'mobile_phone_number' => '+33612345678', + 'email' => 'john.watson@example.net', + 'address1' => '221B Baker Street', + 'postcode' => 'NW16XE', + 'city' => 'London', + 'country' => 'GB', + 'language' => 'en', + ], + ], + 'urls' => [ + 'return' => 'https://example.net/success?id=42', + 'cancel' => 'https://example.net/cancel?id=42', + 'notification' => 'https://example.net/notifications?id=42', + ], + 'metadata' => [ + 'cart ID' => '42', + 'custom data' => 'lorem ipsum', + ], + 'context' => [], + ]; + + // set custom props + if (!empty($custom_props)) { + foreach ($custom_props as $prop => $value) { + $props[$prop] = $value; + } + } + + // + $paymentInputDTO = new PaymentInputDTO(); + $result = $paymentInputDTO->hydrate($props); + if ($result === null) { + throw new \RuntimeException('PaymentInputDTOMock failed to hydrate DTO.'); + } + + return $result; + } +} diff --git a/tests/Mock/PaymentMock.php b/tests/Mock/PaymentMock.php new file mode 100644 index 0000000..fde49c1 --- /dev/null +++ b/tests/Mock/PaymentMock.php @@ -0,0 +1,143 @@ +> */ + public static array $payment_parameters = [ + 'oneclick' => [ + 'is_paid' => true, + 'paid_at' => 1614949567, + 'is_3ds' => false, + 'is_live' => true, + 'card' => [ + 'last4' => '0001', + 'country' => 'FR', + 'exp_year' => 2030, + 'exp_month' => 9, + 'brand' => 'CB', + 'id' => 'card_3EOJHyQXNCG8gZ452cUA0y', + 'metadata' => null, + ], + 'hosted_payment' => [ + 'paid_at' => 1614949567, + ], + 'refundable_after' => 1614949567, + 'refundable_until' => 1630501567, + 'metadata' => [ + 'ID Client' => 4, + 'ID Cart' => 17, + 'Website' => 'http://localhost', + ], + ], + ]; + + /** + * @param array $parameters + */ + public static function getStandard(array $parameters = []): Payment + { + $resource = self::get($parameters); + + return Payment::fromAttributes($resource); + } + + /** + * @param array $parameters + * @return array + */ + public static function get(array $parameters): array + { + $defaultConfiguration = [ + 'id' => 'pay_azerty', + 'object' => 'payment', + 'is_live' => true, + 'amount' => 42420, + 'amount_refunded' => 0, + 'currency' => 'EUR', + 'created_at' => time(), + 'description' => null, + 'is_paid' => false, + 'paid_at' => null, + 'is_refunded' => false, + 'is_3ds' => null, + 'save_card' => false, + 'card' => [ + 'last4' => null, + 'country' => null, + 'exp_year' => null, + 'exp_month' => null, + 'brand' => null, + 'id' => null, + 'metadata' => null, + ], + 'hosted_payment' => [ + 'payment_url' => 'payment_url', + 'return_url' => 'return_url', + 'cancel_url' => 'cancel_url', + 'paid_at' => null, + 'sent_by' => null, + ], + 'notification' => [ + 'url' => 'notification_url', + 'response_code' => null, + ], + 'metadata' => [ + 'ID Client' => 1, + 'ID Cart' => 1, + 'Website' => 'http://my.localhost.com', + ], + 'failure' => null, + 'installment_plan_id' => null, + 'authorization' => null, + 'refundable_after' => null, + 'refundable_until' => null, + 'billing' => [ + 'title' => null, + 'first_name' => 'John', + 'last_name' => 'Doe', + 'address1' => 'my address mock', + 'address2' => null, + 'company_name' => 'Mock Inc.', + 'postcode' => '75000', + 'city' => 'Paris', + 'state' => null, + 'country' => 'FR', + 'email' => 'jdoe@payplug.com', + 'mobile_phone_number' => '+33612345678', + 'landline_phone_number' => '+33112345678', + 'language' => 'fr', + ], + 'shipping' => [ + 'title' => null, + 'first_name' => 'John', + 'last_name' => 'Doe', + 'address1' => 'my address mock', + 'address2' => null, + 'company_name' => 'Mock Inc.', + 'postcode' => '75000', + 'city' => 'Paris', + 'state' => null, + 'country' => 'FR', + 'email' => 'jdoe@payplug.com', + 'mobile_phone_number' => '+33612345678', + 'landline_phone_number' => '+33112345678', + 'language' => 'fr', + 'delivery_type' => 'BILLING', + ], + ]; + + if (!empty($parameters)) { + foreach ($parameters as $key => $value) { + $defaultConfiguration[$key] = $value; + } + } + + return $defaultConfiguration; + } +} diff --git a/tests/mock/PaymentOutputDTOMock.php b/tests/Mock/PaymentOutputDTOMock.php similarity index 70% rename from tests/mock/PaymentOutputDTOMock.php rename to tests/Mock/PaymentOutputDTOMock.php index 63e5a69..0e26358 100644 --- a/tests/mock/PaymentOutputDTOMock.php +++ b/tests/Mock/PaymentOutputDTOMock.php @@ -2,32 +2,28 @@ declare(strict_types=1); -namespace PayplugPluginCore\tests\mock; +namespace PayplugPluginCore\Tests\Mock; use Payplug\Resource\Payment; +use PayplugPluginCore\Models\Entities\PaymentOutputDTO; class PaymentOutputDTOMock { - /** @var boolean */ - public $result; - /** @var string */ - public $code; - /** @var string */ - public $message; - /** @var object */ - public $resource; + public bool $result; + public string $code; + public string $message; + public object $resource; - public static function get() + /** + * @param array|null $custom_props + * @throws \Exception + */ + public static function get(?array $custom_props): PaymentOutputDTO { - $paymentOutputDTO = new \stdClass(); - - $paymentOutputDTO->result = true; - $paymentOutputDTO->code = 200; - $paymentOutputDTO->message = ''; - + // get default $payment_attributes = [ 'id' => 'pay_id', - 'object' => 'Payment', + 'object' => 'payment', 'is_live' => true, 'amount' => 4200, 'amount_refunded' => 0, @@ -94,8 +90,27 @@ public static function get() 'delivery_type' => 'BILLING', ], ]; - $paymentOutputDTO->resource = Payment::fromAttributes($payment_attributes); + $props = [ + 'result' => true, + 'code' => 200, + 'message' => 'OK', + 'resource' => Payment::fromAttributes($payment_attributes), + ]; + + // set custom props + if ($custom_props !== null) { + foreach ($custom_props as $prop => $value) { + $props[$prop] = $value; + } + } + + // + $paymentOutputDTO = new PaymentOutputDTO(); + $result = $paymentOutputDTO->hydrate($props); + if ($result === null) { + throw new \RuntimeException('PaymentOutputDTOMock failed to hydrate DTO.'); + } - return $paymentOutputDTO; + return $result; } } diff --git a/tests/Traits/FormatDataProvider.php b/tests/Traits/FormatDataProvider.php new file mode 100644 index 0000000..2e8e4a1 --- /dev/null +++ b/tests/Traits/FormatDataProvider.php @@ -0,0 +1,120 @@ + 'value']]; + + yield [null]; + } + + public function invalidIntegerFormatDataProvider(): \Generator + { + yield [null]; + + yield [['key' => 'value']]; + + yield [true]; + + yield ['lorem ipsum']; + } + + public function invalidFloatFormatDataProvider(): \Generator + { + yield [null]; + + yield [['key' => 'value']]; + + yield [true]; + + yield ['lorem ipsum']; + + yield [42]; + } + + public function invalidNumericFormatDataProvider(): \Generator + { + yield [null]; + + yield [['key' => 'value']]; + + yield [true]; + + yield ['lorem ipsum']; + + yield ['123abc']; + } + + public function invalidJSONFormatDataProvider(): \Generator + { + yield ['']; + + yield ['{"feature": \'value\'}']; + + yield ['{"feature": "value", }']; + + yield ['{{}}']; + } + + public function invalidObjectFormatDataProvider(): \Generator + { + yield [42]; + + yield [['key' => 'value']]; + + yield [true]; + + yield ['lorem ipsum']; + } + + public function invalidStringFormatDataProvider(): \Generator + { + yield [42]; + + yield [['key' => 'value']]; + + yield [false]; + + yield [null]; + } + + public function invalidEmailFormatDataProvider(): \Generator + { + yield ['@test.com']; + + yield ['email@test']; + + yield ['emailtest.com']; + } + + public function invalidPhoneFormatDataProvider(): \Generator + { + yield [42]; + + yield ['invalid phone number']; + + yield [false]; + + yield [null]; + } +} diff --git a/tests/Traits/TestingTools.php b/tests/Traits/TestingTools.php new file mode 100644 index 0000000..37e61cf --- /dev/null +++ b/tests/Traits/TestingTools.php @@ -0,0 +1,34 @@ +{$name})) { + return $this->{$name}; + } + + $mock = '\\PayplugPluginCore\\Tests\\Mock\\' . str_replace('_', '', ucwords($name, '_')) . 'Mock'; + if (!class_exists($mock)) { + throw new \Exception('Mock can\'t be found. Given: ' . $mock); + } + + $this->{$name} = new $mock(); + + return $this->{$name}; + } +} diff --git a/tests/Units/Actions/PaymentAction/createActionTest.php b/tests/Units/Actions/PaymentAction/createActionTest.php new file mode 100644 index 0000000..b289fec --- /dev/null +++ b/tests/Units/Actions/PaymentAction/createActionTest.php @@ -0,0 +1,212 @@ + */ + private array $payment_attributes = []; + + public function setUp(): void + { + parent::setUp(); + $this->input_dto = PaymentInputDTOMock::get([]); + + $this->gateway_loader = \Mockery::mock(PaymentGatewayManager::class); + $this->action->shouldReceive('get_payment_gateway') + ->andReturn($this->gateway_loader); + + $this->service_loader = \Mockery::mock('ServiceLoader'); + $this->action->shouldReceive('get_service') + ->with('api') + ->andReturn($this->service_loader); + + $this->api_service = \Mockery::mock('ApiService'); + $this->payment_gateway = \Mockery::mock(AbstractPaymentGateway::class); + + $customer = $this->input_dto->getCustomer() ?? []; + $urls = $this->input_dto->getUrls() ?? []; + $this->payment_attributes = [ + 'amount' => $this->input_dto->getAmount(), + 'currency' => $this->input_dto->getCurrencyIsoCode(), + 'billing' => $customer['billing'] ?? null, + 'shipping' => ($customer['shipping'] ?? []) + ['delivery_type' => 'BILLING'], + 'hosted_payment' => [ + 'return_url' => $urls['return'] ?? null, + 'cancel_url' => $urls['cancel'] ?? null, + ], + 'notification_url' => $urls['notification'] ?? null, + 'metadata' => $this->input_dto->getMetadata(), + 'allow_save_card' => false, + 'force_3ds' => false, + ]; + } + + public function testWhenGivenDTOIsInvalid(): void + { + $this->expectException(\TypeError::class); + new \ReflectionMethod($this->action, 'createAction')->invoke($this->action, null); + } + + public function testWhenPaymentGatewayLoadingThrowsException(): void + { + $exception_msg = 'Payment Gateway can\'t be found.'; + $this->gateway_loader + ->shouldReceive('load') + ->once() + ->with($this->input_dto->getPaymentMethod()) + ->andThrow(new \Exception($exception_msg)); + + // Le flux doit s'arrêter avant tout appel API + $this->action->shouldNotReceive('get_service'); + + $this->expectException(\Exception::class); + $this->expectExceptionMessage($exception_msg); + + $this->action->createAction($this->input_dto); + } + + public function testWhenContextInDTOIsMissing(): void + { + $this->gateway_loader + ->shouldReceive('load') + ->once() + ->with($this->input_dto->getPaymentMethod()) + ->andReturn($this->payment_gateway); + + $exception_msg = 'Resource attribe can\'t be formated, excepted parameter is missing.'; + $this->payment_gateway + ->shouldReceive('formatPaymentAttributes') + ->once() + ->andThrow(new \Exception($exception_msg)); + + // Le flux doit s'arrêter avant tout appel API + $this->action->shouldNotReceive('get_service'); + + $this->expectException(\Exception::class); + $this->expectExceptionMessage($exception_msg); + + $this->action->createAction($this->input_dto); + } + + public function testWhenApiServiceLoadingThrowsException(): void + { + $this->gateway_loader + ->shouldReceive('load') + ->once() + ->with($this->input_dto->getPaymentMethod()) + ->andReturn($this->payment_gateway); + + $this->payment_gateway + ->shouldReceive('formatPaymentAttributes') + ->once() + ->andReturn($this->payment_attributes); + + $exception_msg = 'Payplug API can\'t be initialized.'; + $this->service_loader + ->shouldReceive('load') + ->once() + ->with($this->input_dto->getApiBearer()) + ->andThrow(new \Exception($exception_msg)); + + $this->expectException(\Exception::class); + $this->expectExceptionMessage($exception_msg); + + $this->action->createAction($this->input_dto); + } + + public function testWhenPaymentResourceCantBeCreated(): void + { + $this->gateway_loader + ->shouldReceive('load') + ->once() + ->with($this->input_dto->getPaymentMethod()) + ->andReturn($this->payment_gateway); + + $this->payment_gateway + ->shouldReceive('formatPaymentAttributes') + ->once() + ->andReturn($this->payment_attributes); + + $this->service_loader + ->shouldReceive('load') + ->once() + ->with($this->input_dto->getApiBearer()) + ->andReturn($this->api_service); + + $error_code = 500; + $error_msg = 'An error occurred during payment creation.'; + $api_return = [ + 'code' => $error_code, + 'message' => $error_msg, + 'resource' => null, + 'result' => false, + ]; + $this->api_service + ->shouldReceive('createPaymentResource') + ->once() + ->andReturn($api_return); + $this->assertEquals( + PaymentOutputDTOMock::get($api_return), + $this->action->createAction($this->input_dto) + ); + } + + public function testWhenPaymentOutputDTOIsReturnWithSuccess(): void + { + $this->gateway_loader + ->shouldReceive('load') + ->once() + ->with($this->input_dto->getPaymentMethod()) + ->andReturn($this->payment_gateway); + + $this->payment_gateway + ->shouldReceive('formatPaymentAttributes') + ->once() + ->andReturn($this->payment_attributes); + + $this->service_loader + ->shouldReceive('load') + ->once() + ->with($this->input_dto->getApiBearer()) + ->andReturn($this->api_service); + + $api_return = [ + 'code' => 200, + 'message' => 'OK', + 'resource' => PaymentMock::getStandard(), + 'result' => true, + ]; + $this->api_service + ->shouldReceive('createPaymentResource') + ->once() + ->andReturn($api_return); + $this->assertEquals( + PaymentOutputDTOMock::get([ + 'resource' => PaymentMock::getStandard(), + ]), + $this->action->createAction($this->input_dto) + ); + } +} diff --git a/tests/Units/Actions/PaymentAction/paymentActionBase.php b/tests/Units/Actions/PaymentAction/paymentActionBase.php new file mode 100644 index 0000000..89e90a6 --- /dev/null +++ b/tests/Units/Actions/PaymentAction/paymentActionBase.php @@ -0,0 +1,24 @@ +action = Mockery::mock(PaymentAction::class, [])->makePartial(); + } + + protected function tearDown(): void + { + Mockery::close(); + } +} diff --git a/tests/Units/Gateways/Payment/StandardPaymentGateway/formatPaymentAttributesTest.php b/tests/Units/Gateways/Payment/StandardPaymentGateway/formatPaymentAttributesTest.php new file mode 100644 index 0000000..578417b --- /dev/null +++ b/tests/Units/Gateways/Payment/StandardPaymentGateway/formatPaymentAttributesTest.php @@ -0,0 +1,142 @@ +expectException(\TypeError::class); + new \ReflectionMethod($this->gateway, 'formatPaymentAttributes')->invoke($this->gateway, null); + } + + public function testWhenDefaultAttributesCanBeSet(): void + { + $exception_msg = 'Can\'t generate default payment attributes'; + $this->expectException(\Exception::class); + $this->expectExceptionMessage($exception_msg); + $this->gateway + ->shouldReceive('getDefaultAttributeFromDTO') + ->once() + ->andReturn([]); + $this->gateway->formatPaymentAttributes(PaymentInputDTOMock::get([])); + } + + public static function StandardPaymentRequiredContext(): \Generator + { + yield ['is_deferred']; + yield ['is_integrated']; + yield ['is_guest']; + } + /** + * @dataProvider StandardPaymentRequiredContext + * + * @param mixed $key + */ + public function testWhenRequiredContextIsMissing($key): void + { + $exception_msg = 'Resource attribe can\'t be formated, excepted parameter " ' . $key . '" is missing.'; + $this->expectException(\Exception::class); + $this->expectExceptionMessage($exception_msg); + $this->gateway + ->shouldReceive('getDefaultAttributeFromDTO') + ->once() + ->andReturn([ + 'amount' => 4242, + 'currency' => 'EUR', + ]); + + $context = [ + 'is_deferred' => false, + 'is_integrated' => false, + 'is_guest' => false, + ]; + unset($context[$key]); + $this->gateway->formatPaymentAttributes(PaymentInputDTOMock::get([ + 'context' => $context, + ])); + } + + /** + * @dataProvider StandardPaymentRequiredContext + * + * @param mixed $key + */ + public function testWhenPaymentAttributesIsReturned($key): void + { + $this->gateway + ->shouldReceive('getDefaultAttributeFromDTO') + ->once() + ->andReturn([ + 'amount' => 4242, + 'currency' => 'EUR', + 'hosted_payment' => [ + 'cancel_url' => 'cancel_url', + ], + 'allow_save_card' => true, + ]); + + $context = [ + 'is_deferred' => false, + 'is_integrated' => false, + 'is_guest' => false, + ]; + $context[$key] = true; + $expected = []; + switch ($key) { + case 'is_deferred': + $expected = [ + 'authorized_amount' => 4242, + 'currency' => 'EUR', + 'hosted_payment' => [ + 'cancel_url' => 'cancel_url', + ], + 'allow_save_card' => true, + ]; + break; + case 'is_integrated': + $expected = [ + 'amount' => 4242, + 'currency' => 'EUR', + 'hosted_payment' => [], + 'integration' => 'INTEGRATED_PAYMENT', + 'allow_save_card' => true, + ]; + break; + case 'is_guest': + $expected = [ + 'amount' => 4242, + 'currency' => 'EUR', + 'hosted_payment' => [ + 'cancel_url' => 'cancel_url', + ], + 'allow_save_card' => false, + ]; + break; + } + $this->assertEquals( + $expected, + $this->gateway->formatPaymentAttributes(PaymentInputDTOMock::get([ + 'context' => $context, + ])) + ); + } +} diff --git a/tests/Units/Gateways/Payment/StandardPaymentGateway/standardPaymentGatewayBase.php b/tests/Units/Gateways/Payment/StandardPaymentGateway/standardPaymentGatewayBase.php new file mode 100644 index 0000000..10ee162 --- /dev/null +++ b/tests/Units/Gateways/Payment/StandardPaymentGateway/standardPaymentGatewayBase.php @@ -0,0 +1,24 @@ +gateway = Mockery::mock(StandardPaymentGateway::class, [])->makePartial(); + } + + protected function tearDown(): void + { + Mockery::close(); + } +} diff --git a/tests/Units/Gateways/PaymentGateway.php b/tests/Units/Gateways/PaymentGateway.php new file mode 100644 index 0000000..5aca3d5 --- /dev/null +++ b/tests/Units/Gateways/PaymentGateway.php @@ -0,0 +1,66 @@ + */ + protected array $expected_context; + + /** + * @param string $payment_gateway_name + * + * @throws \Exception + */ + public function load(string $payment_gateway_name): self + { + if (empty($payment_gateway_name)) { + throw new \Exception('Invalid parameter, $payment_gateway_name given should be a non empty string.'); + } + + $payment_gateway_path = '\PayplugPluginCore\gateways\payment\\' + . str_replace('_', '', ucwords($payment_gateway_name, '_')) + . 'PaymentGateway'; + if (!class_exists($payment_gateway_path)) { + throw new \Exception('Payment Gateway can\'t be found.'); + } + + $instance = new $payment_gateway_path(); + if (!$instance instanceof self) { + throw new \Exception('Payment Gateway class does not extend PaymentGateway.'); + } + + return $instance; + } + + /** + * @param PaymentInputDTO $payment_inputDTO + * + * @return array + */ + public function getDefaultAttributeFromDTO(PaymentInputDTO $payment_inputDTO): array + { + $customer = $payment_inputDTO->getCustomer() ?? []; + $urls = $payment_inputDTO->getUrls() ?? []; + + return [ + 'amount' => $payment_inputDTO->getAmount(), + 'currency' => $payment_inputDTO->getCurrencyIsoCode(), + 'billing' => $customer['billing'] ?? null, + 'shipping' => ($customer['shipping'] ?? []) + ['delivery_type' => 'BILLING'], + 'hosted_payment' => [ + 'return_url' => $urls['return'] ?? null, + 'cancel_url' => $urls['cancel'] ?? null, + ], + 'notification_url' => $urls['notification'] ?? null, + 'metadata' => $payment_inputDTO->getMetadata(), + 'allow_save_card' => false, + 'force_3ds' => false, + ]; + } +} diff --git a/tests/mock/PaymentInputDTOMock.php b/tests/mock/PaymentInputDTOMock.php deleted file mode 100644 index efda218..0000000 --- a/tests/mock/PaymentInputDTOMock.php +++ /dev/null @@ -1,57 +0,0 @@ -api_bearer = 'token_bearer'; - $paymentInputDTO->payment_method = 'Payment method'; - $paymentInputDTO->amount = 4242; - $paymentInputDTO->currency_iso_code = 'EUR'; - $paymentInputDTO->customer = [ - 'identifier' => 42, - 'billing' => [ - 'title' => 'mr', - 'first_name' => 'John', - 'last_name' => 'Watson', - 'mobile_phone_number' => '+33612345678', - 'email' => 'john.watson@example.net', - 'address1' => '221B Baker Street', - 'postcode' => 'NW16XE', - 'city' => 'London', - 'country' => 'GB', - 'language' => 'en', - ], - 'shipping' => [ - 'title' => 'mr', - 'first_name' => 'John', - 'last_name' => 'Watson', - 'mobile_phone_number' => '+33612345678', - 'email' => 'john.watson@example.net', - 'address1' => '221B Baker Street', - 'postcode' => 'NW16XE', - 'city' => 'London', - 'country' => 'GB', - 'language' => 'en', - ], - ]; - $paymentInputDTO->urls = [ - 'return' => 'https://example.net/success?id=42', - 'cancel' => 'https://example.net/cancel?id=42', - 'notification' => 'https://example.net/notifications?id=42', - ]; - $paymentInputDTO->metadata = [ - 'cart ID' => '42', - 'custom data' => 'lorem ipsum', - ]; - $paymentInputDTO->context = []; - - return $paymentInputDTO; - } -}