diff --git a/.github/workflows/coding-standard.yml b/.github/workflows/coding-standard.yml index eb95d6b2..0834f336 100644 --- a/.github/workflows/coding-standard.yml +++ b/.github/workflows/coding-standard.yml @@ -29,13 +29,13 @@ jobs: uses: actions/checkout@v6 - name: "Install PHP" - uses: "shivammathur/setup-php@2.36.0" + uses: "shivammathur/setup-php@2.37.0" with: coverage: "pcov" php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1 - - uses: ramsey/composer-install@3.1.1 + - uses: ramsey/composer-install@4.0.0 with: dependency-versions: ${{ matrix.dependencies }} diff --git a/.github/workflows/docs-check.yml b/.github/workflows/docs-check.yml index ed78b7e1..6951b621 100644 --- a/.github/workflows/docs-check.yml +++ b/.github/workflows/docs-check.yml @@ -28,13 +28,13 @@ jobs: uses: actions/checkout@v6 - name: "Install PHP" - uses: "shivammathur/setup-php@2.36.0" + uses: "shivammathur/setup-php@2.37.0" with: coverage: none php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1, opcache.enable_cli=1 - - uses: ramsey/composer-install@3.1.1 + - uses: ramsey/composer-install@4.0.0 with: dependency-versions: ${{ matrix.dependencies }} diff --git a/.github/workflows/mutation-tests-diff.yml b/.github/workflows/mutation-tests-diff.yml index d01b57fe..a76343c8 100644 --- a/.github/workflows/mutation-tests-diff.yml +++ b/.github/workflows/mutation-tests-diff.yml @@ -27,14 +27,14 @@ jobs: fetch-depth: 0 - name: "Install PHP" - uses: "shivammathur/setup-php@2.36.0" + uses: "shivammathur/setup-php@2.37.0" with: coverage: "pcov" php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1 extensions: pdo_sqlite - - uses: ramsey/composer-install@3.1.1 + - uses: ramsey/composer-install@4.0.0 with: dependency-versions: ${{ matrix.dependencies }} diff --git a/.github/workflows/mutation-tests.yml b/.github/workflows/mutation-tests.yml index 379d868f..8e6f3f0a 100644 --- a/.github/workflows/mutation-tests.yml +++ b/.github/workflows/mutation-tests.yml @@ -29,14 +29,14 @@ jobs: uses: actions/checkout@v6 - name: "Install PHP" - uses: "shivammathur/setup-php@2.36.0" + uses: "shivammathur/setup-php@2.37.0" with: coverage: "pcov" php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1 extensions: pdo_sqlite - - uses: ramsey/composer-install@3.1.1 + - uses: ramsey/composer-install@4.0.0 with: dependency-versions: ${{ matrix.dependencies }} diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 1691d500..d88b7ed3 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -29,13 +29,13 @@ jobs: uses: actions/checkout@v6 - name: "Install PHP" - uses: "shivammathur/setup-php@2.36.0" + uses: "shivammathur/setup-php@2.37.0" with: coverage: "pcov" php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1 - - uses: ramsey/composer-install@3.1.1 + - uses: ramsey/composer-install@4.0.0 with: dependency-versions: ${{ matrix.dependencies }} diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index adc97a75..15fe285e 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -40,14 +40,14 @@ jobs: uses: actions/checkout@v6 - name: "Install PHP" - uses: "shivammathur/setup-php@2.36.0" + uses: "shivammathur/setup-php@2.37.0" with: coverage: "pcov" php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1 extensions: pdo_sqlite - - uses: ramsey/composer-install@3.1.1 + - uses: ramsey/composer-install@4.0.0 with: dependency-versions: ${{ matrix.dependencies }} diff --git a/.gitignore b/.gitignore index 41248c4c..22a0e157 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ phpunit.xml phpstan.neon infection.html infection.log +/docs_php diff --git a/composer.json b/composer.json index caeed2e3..b5e5cb9a 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,8 @@ ], "require": { "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", - "patchlevel/event-sourcing": "^3.13.0", + "patchlevel/event-sourcing": "^3.18.0", + "patchlevel/hydrator": "^1.18.0", "symfony/cache": "^6.4.0 || ^7.0.0 || ^8.0.0", "symfony/config": "^6.4.0 || ^7.0.0 || ^8.0.0", "symfony/console": "^6.4.1 || ^7.0.1 || ^8.0.0", @@ -33,13 +34,14 @@ "ext-pdo_sqlite": "*", "doctrine/migrations": "^3.3.2", "doctrine/orm": "^2.19.4 || ^3.1.2", - "infection/infection": "^0.31.9", + "infection/infection": "^0.32.0", "league/commonmark": "^2.4", "patchlevel/coding-standard": "^1.3.0", "phpstan/phpstan": "^2.1.32", "phpstan/phpstan-symfony": "^2.0.8", "phpunit/phpunit": "^11.5.45", "roave/security-advisories": "dev-master", + "symfony/clock": "^6.4.0 || ^7.0.0 || ^8.0.0", "symfony/uid": "^6.4.0 || ^7.0.0 || ^8.0.0", "symfony/var-dumper": "^6.4.0 || ^7.0.0 || ^8.0.0", "symfony/web-profiler-bundle": "^6.4.0 || ^7.0.0 || ^8.0.0", diff --git a/composer.lock b/composer.lock index 500667a7..7fddbad9 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": "1c75d38e785534064af75151cb317294", + "content-hash": "fd9dadf670426ef444497d6f5e2d4959", "packages": [ { "name": "brick/math", - "version": "0.14.1", + "version": "0.14.8", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "f05858549e5f9d7bb45875a75583240a38a281d0" + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/f05858549e5f9d7bb45875a75583240a38a281d0", - "reference": "f05858549e5f9d7bb45875a75583240a38a281d0", + "url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629", + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629", "shasum": "" }, "require": { @@ -56,7 +56,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.14.1" + "source": "https://github.com/brick/math/tree/0.14.8" }, "funding": [ { @@ -64,20 +64,20 @@ "type": "github" } ], - "time": "2025-11-24T14:40:29+00:00" + "time": "2026-02-10T14:33:43+00:00" }, { "name": "doctrine/dbal", - "version": "4.4.0", + "version": "4.4.3", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "e8c5163fbec0f34e357431bd1e5fc4056cdf4fdc" + "reference": "61e730f1658814821a85f2402c945f3883407dec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/e8c5163fbec0f34e357431bd1e5fc4056cdf4fdc", - "reference": "e8c5163fbec0f34e357431bd1e5fc4056cdf4fdc", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/61e730f1658814821a85f2402c945f3883407dec", + "reference": "61e730f1658814821a85f2402c945f3883407dec", "shasum": "" }, "require": { @@ -93,9 +93,9 @@ "phpstan/phpstan": "2.1.30", "phpstan/phpstan-phpunit": "2.0.7", "phpstan/phpstan-strict-rules": "^2", - "phpunit/phpunit": "11.5.23", - "slevomat/coding-standard": "8.24.0", - "squizlabs/php_codesniffer": "4.0.0", + "phpunit/phpunit": "11.5.50", + "slevomat/coding-standard": "8.27.1", + "squizlabs/php_codesniffer": "4.0.1", "symfony/cache": "^6.3.8|^7.0|^8.0", "symfony/console": "^5.4|^6.3|^7.0|^8.0" }, @@ -154,7 +154,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/4.4.0" + "source": "https://github.com/doctrine/dbal/tree/4.4.3" }, "funding": [ { @@ -170,33 +170,33 @@ "type": "tidelift" } ], - "time": "2025-11-29T12:17:09+00:00" + "time": "2026-03-20T08:52:12+00:00" }, { "name": "doctrine/deprecations", - "version": "1.1.5", + "version": "1.1.6", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "conflict": { - "phpunit/phpunit": "<=7.5 || >=13" + "phpunit/phpunit": "<=7.5 || >=14" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^12 || ^13", - "phpstan/phpstan": "1.4.10 || 2.1.11", + "doctrine/coding-standard": "^9 || ^12 || ^14", + "phpstan/phpstan": "1.4.10 || 2.1.30", "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0", "psr/log": "^1 || ^2 || ^3" }, "suggest": { @@ -216,22 +216,22 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.5" + "source": "https://github.com/doctrine/deprecations/tree/1.1.6" }, - "time": "2025-04-07T20:06:18+00:00" + "time": "2026-02-07T07:09:04+00:00" }, { "name": "doctrine/event-manager", - "version": "2.0.1", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e" + "reference": "dda33921b198841ca8dbad2eaa5d4d34769d18cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/b680156fa328f1dfd874fd48c7026c41570b9c6e", - "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/dda33921b198841ca8dbad2eaa5d4d34769d18cf", + "reference": "dda33921b198841ca8dbad2eaa5d4d34769d18cf", "shasum": "" }, "require": { @@ -241,10 +241,10 @@ "doctrine/common": "<2.9" }, "require-dev": { - "doctrine/coding-standard": "^12", - "phpstan/phpstan": "^1.8.8", - "phpunit/phpunit": "^10.5", - "vimeo/psalm": "^5.24" + "doctrine/coding-standard": "^14", + "phpdocumentor/guides-cli": "^1.4", + "phpstan/phpstan": "^2.1.32", + "phpunit/phpunit": "^10.5.58" }, "type": "library", "autoload": { @@ -293,7 +293,7 @@ ], "support": { "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/2.0.1" + "source": "https://github.com/doctrine/event-manager/tree/2.1.1" }, "funding": [ { @@ -309,20 +309,20 @@ "type": "tidelift" } ], - "time": "2024-05-22T20:47:39+00:00" + "time": "2026-01-29T07:11:08+00:00" }, { "name": "doctrine/migrations", - "version": "3.9.5", + "version": "3.9.6", "source": { "type": "git", "url": "https://github.com/doctrine/migrations.git", - "reference": "1b823afbc40f932dae8272574faee53f2755eac5" + "reference": "ffd8355cdd8505fc650d9604f058bf62aedd80a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/migrations/zipball/1b823afbc40f932dae8272574faee53f2755eac5", - "reference": "1b823afbc40f932dae8272574faee53f2755eac5", + "url": "https://api.github.com/repos/doctrine/migrations/zipball/ffd8355cdd8505fc650d9604f058bf62aedd80a1", + "reference": "ffd8355cdd8505fc650d9604f058bf62aedd80a1", "shasum": "" }, "require": { @@ -396,7 +396,7 @@ ], "support": { "issues": "https://github.com/doctrine/migrations/issues", - "source": "https://github.com/doctrine/migrations/tree/3.9.5" + "source": "https://github.com/doctrine/migrations/tree/3.9.6" }, "funding": [ { @@ -412,20 +412,20 @@ "type": "tidelift" } ], - "time": "2025-11-20T11:15:36+00:00" + "time": "2026-02-11T06:46:11+00:00" }, { "name": "patchlevel/event-sourcing", - "version": "3.14.0", + "version": "3.18.0", "source": { "type": "git", "url": "https://github.com/patchlevel/event-sourcing.git", - "reference": "c14a953147050d1c6e2b45bbeb9566206915d771" + "reference": "d17688b827baaa87626fb5fc3f9d58faa47a13d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/patchlevel/event-sourcing/zipball/c14a953147050d1c6e2b45bbeb9566206915d771", - "reference": "c14a953147050d1c6e2b45bbeb9566206915d771", + "url": "https://api.github.com/repos/patchlevel/event-sourcing/zipball/d17688b827baaa87626fb5fc3f9d58faa47a13d2", + "reference": "d17688b827baaa87626fb5fc3f9d58faa47a13d2", "shasum": "" }, "require": { @@ -448,7 +448,7 @@ "require-dev": { "doctrine/orm": "^2.18.0 || ^3.0.0", "ext-pdo_sqlite": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", - "infection/infection": "^0.31.9", + "infection/infection": "^0.32.0", "league/commonmark": "^2.6.1", "patchlevel/coding-standard": "^1.3.0", "phpat/phpat": "^0.12.0", @@ -491,22 +491,22 @@ ], "support": { "issues": "https://github.com/patchlevel/event-sourcing/issues", - "source": "https://github.com/patchlevel/event-sourcing/tree/3.14.0" + "source": "https://github.com/patchlevel/event-sourcing/tree/3.18.0" }, - "time": "2025-11-29T19:12:18+00:00" + "time": "2026-02-23T09:53:37+00:00" }, { "name": "patchlevel/hydrator", - "version": "1.13.0", + "version": "1.18.0", "source": { "type": "git", "url": "https://github.com/patchlevel/hydrator.git", - "reference": "dc6fe9a835edaa2d6972ad148738eaeb95a6cb35" + "reference": "fb802134da1eb6294a4358b1f55dbe3621104d80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/patchlevel/hydrator/zipball/dc6fe9a835edaa2d6972ad148738eaeb95a6cb35", - "reference": "dc6fe9a835edaa2d6972ad148738eaeb95a6cb35", + "url": "https://api.github.com/repos/patchlevel/hydrator/zipball/fb802134da1eb6294a4358b1f55dbe3621104d80", + "reference": "fb802134da1eb6294a4358b1f55dbe3621104d80", "shasum": "" }, "require": { @@ -518,13 +518,13 @@ "symfony/type-info": "^7.3.0 || ^8.0.0" }, "require-dev": { - "infection/infection": "^0.31.9", + "infection/infection": "^0.32.4", "patchlevel/coding-standard": "^1.3.0", - "phpat/phpat": "^0.12.0", - "phpbench/phpbench": "^1.2.15", - "phpstan/phpstan": "^2.1.32", - "phpstan/phpstan-phpunit": "^2.0.8", - "phpunit/phpunit": "^11.5.17", + "phpat/phpat": "^0.12.2", + "phpbench/phpbench": "^1.4.3", + "phpstan/phpstan": "^2.1.39", + "phpstan/phpstan-phpunit": "^2.0.15", + "phpunit/phpunit": "^11.5.53", "symfony/var-dumper": "^5.4.29 || ^6.4.0 || ^7.0.0 || ^8.0.0" }, "type": "library", @@ -555,9 +555,9 @@ ], "support": { "issues": "https://github.com/patchlevel/hydrator/issues", - "source": "https://github.com/patchlevel/hydrator/tree/1.13.0" + "source": "https://github.com/patchlevel/hydrator/tree/1.18.0" }, - "time": "2025-11-27T16:58:40+00:00" + "time": "2026-03-13T17:09:15+00:00" }, { "name": "patchlevel/worker", @@ -998,20 +998,20 @@ }, { "name": "ramsey/uuid", - "version": "4.9.1", + "version": "4.9.2", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440" + "reference": "8429c78ca35a09f27565311b98101e2826affde0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/81f941f6f729b1e3ceea61d9d014f8b6c6800440", - "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0", + "reference": "8429c78ca35a09f27565311b98101e2826affde0", "shasum": "" }, "require": { - "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", + "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" }, @@ -1070,22 +1070,22 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.9.1" + "source": "https://github.com/ramsey/uuid/tree/4.9.2" }, - "time": "2025-09-04T20:59:21+00:00" + "time": "2025-12-14T04:43:48+00:00" }, { "name": "symfony/cache", - "version": "v8.0.0", + "version": "v8.0.7", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "1005fe1988f719db8e0c6db5b8ce24284336530f" + "reference": "b7b0f4ce5fb57a8dc061d494639e44e2cf7aa30f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/1005fe1988f719db8e0c6db5b8ce24284336530f", - "reference": "1005fe1988f719db8e0c6db5b8ce24284336530f", + "url": "https://api.github.com/repos/symfony/cache/zipball/b7b0f4ce5fb57a8dc061d494639e44e2cf7aa30f", + "reference": "b7b0f4ce5fb57a8dc061d494639e44e2cf7aa30f", "shasum": "" }, "require": { @@ -1152,7 +1152,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v8.0.0" + "source": "https://github.com/symfony/cache/tree/v8.0.7" }, "funding": [ { @@ -1172,7 +1172,7 @@ "type": "tidelift" } ], - "time": "2025-11-16T10:17:21+00:00" + "time": "2026-03-06T13:17:40+00:00" }, { "name": "symfony/cache-contracts", @@ -1329,16 +1329,16 @@ }, { "name": "symfony/config", - "version": "v8.0.0", + "version": "v8.0.7", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "12d43bf5ebe79ab96da294f468c38794e1a2c98b" + "reference": "9a34c52187112503d02903ab35e6e3783f580c29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/12d43bf5ebe79ab96da294f468c38794e1a2c98b", - "reference": "12d43bf5ebe79ab96da294f468c38794e1a2c98b", + "url": "https://api.github.com/repos/symfony/config/zipball/9a34c52187112503d02903ab35e6e3783f580c29", + "reference": "9a34c52187112503d02903ab35e6e3783f580c29", "shasum": "" }, "require": { @@ -1383,7 +1383,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v8.0.0" + "source": "https://github.com/symfony/config/tree/v8.0.7" }, "funding": [ { @@ -1403,51 +1403,43 @@ "type": "tidelift" } ], - "time": "2025-11-02T08:10:27+00:00" + "time": "2026-03-06T13:17:40+00:00" }, { "name": "symfony/console", - "version": "v7.4.0", + "version": "v8.0.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8" + "reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8", - "reference": "0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8", + "url": "https://api.github.com/repos/symfony/console/zipball/15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a", + "reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0", + "php": ">=8.4", + "symfony/polyfill-mbstring": "^1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^7.2|^8.0" - }, - "conflict": { - "symfony/dependency-injection": "<6.4", - "symfony/dotenv": "<6.4", - "symfony/event-dispatcher": "<6.4", - "symfony/lock": "<6.4", - "symfony/process": "<6.4" + "symfony/string": "^7.4|^8.0" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/event-dispatcher": "^6.4|^7.0|^8.0", - "symfony/http-foundation": "^6.4|^7.0|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0", - "symfony/lock": "^6.4|^7.0|^8.0", - "symfony/messenger": "^6.4|^7.0|^8.0", - "symfony/process": "^6.4|^7.0|^8.0", - "symfony/stopwatch": "^6.4|^7.0|^8.0", - "symfony/var-dumper": "^6.4|^7.0|^8.0" + "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" }, "type": "library", "autoload": { @@ -1481,7 +1473,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.0" + "source": "https://github.com/symfony/console/tree/v8.0.7" }, "funding": [ { @@ -1501,20 +1493,20 @@ "type": "tidelift" } ], - "time": "2025-11-27T13:27:24+00:00" + "time": "2026-03-06T14:06:22+00:00" }, { "name": "symfony/dependency-injection", - "version": "v8.0.0", + "version": "v8.0.7", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "8b61252a5e897809ebbe9c7856aa7738830e6002" + "reference": "1faaac6dbfe069a92ab9e5c270fa43fc4e1761da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8b61252a5e897809ebbe9c7856aa7738830e6002", - "reference": "8b61252a5e897809ebbe9c7856aa7738830e6002", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/1faaac6dbfe069a92ab9e5c270fa43fc4e1761da", + "reference": "1faaac6dbfe069a92ab9e5c270fa43fc4e1761da", "shasum": "" }, "require": { @@ -1562,7 +1554,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v8.0.0" + "source": "https://github.com/symfony/dependency-injection/tree/v8.0.7" }, "funding": [ { @@ -1582,7 +1574,7 @@ "type": "tidelift" } ], - "time": "2025-11-27T08:09:45+00:00" + "time": "2026-03-03T07:49:33+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1653,16 +1645,16 @@ }, { "name": "symfony/error-handler", - "version": "v8.0.0", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "d77ec7dda0c274178745d152e82baf7ea827fd73" + "reference": "7620b97ec0ab1d2d6c7fb737aa55da411bea776a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/d77ec7dda0c274178745d152e82baf7ea827fd73", - "reference": "d77ec7dda0c274178745d152e82baf7ea827fd73", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/7620b97ec0ab1d2d6c7fb737aa55da411bea776a", + "reference": "7620b97ec0ab1d2d6c7fb737aa55da411bea776a", "shasum": "" }, "require": { @@ -1710,7 +1702,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v8.0.0" + "source": "https://github.com/symfony/error-handler/tree/v8.0.4" }, "funding": [ { @@ -1730,20 +1722,20 @@ "type": "tidelift" } ], - "time": "2025-11-05T14:36:47+00:00" + "time": "2026-01-23T11:07:10+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v8.0.0", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "573f95783a2ec6e38752979db139f09fec033f03" + "reference": "99301401da182b6cfaa4700dbe9987bb75474b47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/573f95783a2ec6e38752979db139f09fec033f03", - "reference": "573f95783a2ec6e38752979db139f09fec033f03", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/99301401da182b6cfaa4700dbe9987bb75474b47", + "reference": "99301401da182b6cfaa4700dbe9987bb75474b47", "shasum": "" }, "require": { @@ -1795,7 +1787,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.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v8.0.4" }, "funding": [ { @@ -1815,7 +1807,7 @@ "type": "tidelift" } ], - "time": "2025-10-30T14:17:19+00:00" + "time": "2026-01-05T11:45:55+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -1895,25 +1887,25 @@ }, { "name": "symfony/filesystem", - "version": "v7.4.0", + "version": "v8.0.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "d551b38811096d0be9c4691d406991b47c0c630a" + "reference": "7bf9162d7a0dff98d079b72948508fa48018a770" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/d551b38811096d0be9c4691d406991b47c0c630a", - "reference": "d551b38811096d0be9c4691d406991b47c0c630a", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/7bf9162d7a0dff98d079b72948508fa48018a770", + "reference": "7bf9162d7a0dff98d079b72948508fa48018a770", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "symfony/process": "^6.4|^7.0|^8.0" + "symfony/process": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -1941,7 +1933,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.4.0" + "source": "https://github.com/symfony/filesystem/tree/v8.0.6" }, "funding": [ { @@ -1961,27 +1953,27 @@ "type": "tidelift" } ], - "time": "2025-11-27T13:27:24+00:00" + "time": "2026-02-25T16:59:43+00:00" }, { "name": "symfony/finder", - "version": "v7.4.0", + "version": "v8.0.6", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "340b9ed7320570f319028a2cbec46d40535e94bd" + "reference": "441404f09a54de6d1bd6ad219e088cdf4c91f97c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/340b9ed7320570f319028a2cbec46d40535e94bd", - "reference": "340b9ed7320570f319028a2cbec46d40535e94bd", + "url": "https://api.github.com/repos/symfony/finder/zipball/441404f09a54de6d1bd6ad219e088cdf4c91f97c", + "reference": "441404f09a54de6d1bd6ad219e088cdf4c91f97c", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { - "symfony/filesystem": "^6.4|^7.0|^8.0" + "symfony/filesystem": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -2009,7 +2001,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.4.0" + "source": "https://github.com/symfony/finder/tree/v8.0.6" }, "funding": [ { @@ -2029,20 +2021,20 @@ "type": "tidelift" } ], - "time": "2025-11-05T05:42:40+00:00" + "time": "2026-01-29T09:41:02+00:00" }, { "name": "symfony/http-foundation", - "version": "v8.0.0", + "version": "v8.0.7", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "19f925ff62437970e56fcdf793aa93607622d8be" + "reference": "c5ecf7b07408dbc4a87482634307654190954ae8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/19f925ff62437970e56fcdf793aa93607622d8be", - "reference": "19f925ff62437970e56fcdf793aa93607622d8be", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/c5ecf7b07408dbc4a87482634307654190954ae8", + "reference": "c5ecf7b07408dbc4a87482634307654190954ae8", "shasum": "" }, "require": { @@ -2089,7 +2081,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v8.0.0" + "source": "https://github.com/symfony/http-foundation/tree/v8.0.7" }, "funding": [ { @@ -2109,20 +2101,20 @@ "type": "tidelift" } ], - "time": "2025-11-13T08:54:25+00:00" + "time": "2026-03-06T13:17:40+00:00" }, { "name": "symfony/http-kernel", - "version": "v8.0.0", + "version": "v8.0.7", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "33a41d7f17dfb65519670e7f9c2813896ae2a2aa" + "reference": "c04721f45723d8ce049fa3eee378b5a505272ac7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/33a41d7f17dfb65519670e7f9c2813896ae2a2aa", - "reference": "33a41d7f17dfb65519670e7f9c2813896ae2a2aa", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/c04721f45723d8ce049fa3eee378b5a505272ac7", + "reference": "c04721f45723d8ce049fa3eee378b5a505272ac7", "shasum": "" }, "require": { @@ -2193,7 +2185,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v8.0.0" + "source": "https://github.com/symfony/http-kernel/tree/v8.0.7" }, "funding": [ { @@ -2213,20 +2205,20 @@ "type": "tidelift" } ], - "time": "2025-11-27T08:33:14+00:00" + "time": "2026-03-06T16:58:46+00:00" }, { "name": "symfony/messenger", - "version": "v8.0.0", + "version": "v8.0.7", "source": { "type": "git", "url": "https://github.com/symfony/messenger.git", - "reference": "c37b86c313e26291c5defe9194bcf31cbe630fbc" + "reference": "6ba5f08c156cfc95911dbb0da01a9bc390a70fd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/messenger/zipball/c37b86c313e26291c5defe9194bcf31cbe630fbc", - "reference": "c37b86c313e26291c5defe9194bcf31cbe630fbc", + "url": "https://api.github.com/repos/symfony/messenger/zipball/6ba5f08c156cfc95911dbb0da01a9bc390a70fd1", + "reference": "6ba5f08c156cfc95911dbb0da01a9bc390a70fd1", "shasum": "" }, "require": { @@ -2236,7 +2228,9 @@ }, "conflict": { "symfony/console": "<7.4", - "symfony/event-dispatcher-contracts": "<2.5" + "symfony/event-dispatcher-contracts": "<2.5", + "symfony/lock": "<7.4", + "symfony/serializer": "<7.4.4|>=8.0,<8.0.4" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", @@ -2249,7 +2243,7 @@ "symfony/property-access": "^7.4|^8.0", "symfony/rate-limiter": "^7.4|^8.0", "symfony/routing": "^7.4|^8.0", - "symfony/serializer": "^7.4|^8.0", + "symfony/serializer": "^7.4.4|^8.0.4", "symfony/service-contracts": "^2.5|^3", "symfony/stopwatch": "^7.4|^8.0", "symfony/validator": "^7.4|^8.0", @@ -2281,7 +2275,7 @@ "description": "Helps applications send and receive messages to/from other applications or via message queues", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/messenger/tree/v8.0.0" + "source": "https://github.com/symfony/messenger/tree/v8.0.7" }, "funding": [ { @@ -2301,7 +2295,7 @@ "type": "tidelift" } ], - "time": "2025-11-06T11:20:17+00:00" + "time": "2026-03-04T13:55:34+00:00" }, { "name": "symfony/polyfill-ctype", @@ -2873,16 +2867,16 @@ }, { "name": "symfony/string", - "version": "v8.0.0", + "version": "v8.0.6", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f929eccf09531078c243df72398560e32fa4cf4f" + "reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f929eccf09531078c243df72398560e32fa4cf4f", - "reference": "f929eccf09531078c243df72398560e32fa4cf4f", + "url": "https://api.github.com/repos/symfony/string/zipball/6c9e1108041b5dce21a9a4984b531c4923aa9ec4", + "reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4", "shasum": "" }, "require": { @@ -2939,7 +2933,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v8.0.0" + "source": "https://github.com/symfony/string/tree/v8.0.6" }, "funding": [ { @@ -2959,20 +2953,20 @@ "type": "tidelift" } ], - "time": "2025-09-11T14:37:55+00:00" + "time": "2026-02-09T10:14:57+00:00" }, { "name": "symfony/type-info", - "version": "v8.0.0", + "version": "v8.0.7", "source": { "type": "git", "url": "https://github.com/symfony/type-info.git", - "reference": "9de828eae6aeb33806f8f2fec161a8f8e79338d0" + "reference": "3c7de103dd6cb68be24e155838a64ef4a70ae195" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/type-info/zipball/9de828eae6aeb33806f8f2fec161a8f8e79338d0", - "reference": "9de828eae6aeb33806f8f2fec161a8f8e79338d0", + "url": "https://api.github.com/repos/symfony/type-info/zipball/3c7de103dd6cb68be24e155838a64ef4a70ae195", + "reference": "3c7de103dd6cb68be24e155838a64ef4a70ae195", "shasum": "" }, "require": { @@ -3021,7 +3015,7 @@ "type" ], "support": { - "source": "https://github.com/symfony/type-info/tree/v8.0.0" + "source": "https://github.com/symfony/type-info/tree/v8.0.7" }, "funding": [ { @@ -3041,20 +3035,20 @@ "type": "tidelift" } ], - "time": "2025-11-08T16:30:39+00:00" + "time": "2026-03-04T13:55:34+00:00" }, { "name": "symfony/var-dumper", - "version": "v8.0.0", + "version": "v8.0.6", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "d2a2476c93b58ac5292145e9fac1ff76a21d1ce2" + "reference": "2e14f7e0bf5ff02c6e63bd31cb8e4855a13d6209" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/d2a2476c93b58ac5292145e9fac1ff76a21d1ce2", - "reference": "d2a2476c93b58ac5292145e9fac1ff76a21d1ce2", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2e14f7e0bf5ff02c6e63bd31cb8e4855a13d6209", + "reference": "2e14f7e0bf5ff02c6e63bd31cb8e4855a13d6209", "shasum": "" }, "require": { @@ -3108,7 +3102,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v8.0.0" + "source": "https://github.com/symfony/var-dumper/tree/v8.0.6" }, "funding": [ { @@ -3128,7 +3122,7 @@ "type": "tidelift" } ], - "time": "2025-10-28T09:34:19+00:00" + "time": "2026-02-15T10:53:29+00:00" }, { "name": "symfony/var-exporter", @@ -3618,16 +3612,16 @@ }, { "name": "doctrine/collections", - "version": "2.4.0", + "version": "2.6.0", "source": { "type": "git", "url": "https://github.com/doctrine/collections.git", - "reference": "9acfeea2e8666536edff3d77c531261c63680160" + "reference": "7713da39d8e237f28411d6a616a3dce5e20d5de2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/9acfeea2e8666536edff3d77c531261c63680160", - "reference": "9acfeea2e8666536edff3d77c531261c63680160", + "url": "https://api.github.com/repos/doctrine/collections/zipball/7713da39d8e237f28411d6a616a3dce5e20d5de2", + "reference": "7713da39d8e237f28411d6a616a3dce5e20d5de2", "shasum": "" }, "require": { @@ -3684,7 +3678,7 @@ ], "support": { "issues": "https://github.com/doctrine/collections/issues", - "source": "https://github.com/doctrine/collections/tree/2.4.0" + "source": "https://github.com/doctrine/collections/tree/2.6.0" }, "funding": [ { @@ -3700,7 +3694,7 @@ "type": "tidelift" } ], - "time": "2025-10-25T09:18:13+00:00" + "time": "2026-01-15T10:01:58+00:00" }, { "name": "doctrine/inflector", @@ -3794,30 +3788,29 @@ }, { "name": "doctrine/instantiator", - "version": "2.0.0", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + "reference": "23da848e1a2308728fe5fdddabf4be17ff9720c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/23da848e1a2308728fe5fdddabf4be17ff9720c7", + "reference": "23da848e1a2308728fe5fdddabf4be17ff9720c7", "shasum": "" }, "require": { - "php": "^8.1" + "php": "^8.4" }, "require-dev": { - "doctrine/coding-standard": "^11", + "doctrine/coding-standard": "^14", "ext-pdo": "*", "ext-phar": "*", "phpbench/phpbench": "^1.2", - "phpstan/phpstan": "^1.9.4", - "phpstan/phpstan-phpunit": "^1.3", - "phpunit/phpunit": "^9.5.27", - "vimeo/psalm": "^5.4" + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5.58" }, "type": "library", "autoload": { @@ -3844,7 +3837,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + "source": "https://github.com/doctrine/instantiator/tree/2.1.0" }, "funding": [ { @@ -3860,7 +3853,7 @@ "type": "tidelift" } ], - "time": "2022-12-30T00:23:10+00:00" + "time": "2026-01-05T06:47:08+00:00" }, { "name": "doctrine/lexer", @@ -3941,16 +3934,16 @@ }, { "name": "doctrine/orm", - "version": "3.5.8", + "version": "3.6.2", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "78dd074266e8b47a83bcf60ab5fe06c91a639168" + "reference": "4262eb495b4d2a53b45de1ac58881e0091f2970f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/78dd074266e8b47a83bcf60ab5fe06c91a639168", - "reference": "78dd074266e8b47a83bcf60ab5fe06c91a639168", + "url": "https://api.github.com/repos/doctrine/orm/zipball/4262eb495b4d2a53b45de1ac58881e0091f2970f", + "reference": "4262eb495b4d2a53b45de1ac58881e0091f2970f", "shasum": "" }, "require": { @@ -4023,9 +4016,9 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/3.5.8" + "source": "https://github.com/doctrine/orm/tree/3.6.2" }, - "time": "2025-11-29T23:11:02+00:00" + "time": "2026-01-30T21:41:41+00:00" }, { "name": "doctrine/persistence", @@ -4360,16 +4353,16 @@ }, { "name": "infection/infection", - "version": "0.31.9", + "version": "0.32.6", "source": { "type": "git", "url": "https://github.com/infection/infection.git", - "reference": "f9628fcd7f76eadf24726e57a81937c42458232b" + "reference": "4ed769947eaf2ecf42203027301bad2bedf037e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/infection/infection/zipball/f9628fcd7f76eadf24726e57a81937c42458232b", - "reference": "f9628fcd7f76eadf24726e57a81937c42458232b", + "url": "https://api.github.com/repos/infection/infection/zipball/4ed769947eaf2ecf42203027301bad2bedf037e5", + "reference": "4ed769947eaf2ecf42203027301bad2bedf037e5", "shasum": "" }, "require": { @@ -4386,20 +4379,22 @@ "infection/include-interceptor": "^0.2.5", "infection/mutator": "^0.4", "justinrainbow/json-schema": "^6.0", - "nikic/php-parser": "^5.3", + "nikic/php-parser": "^5.6.2", "ondram/ci-detector": "^4.1.0", "php": "^8.2", - "sanmai/di-container": "^0.1.4", + "psr/log": "^2.0 || ^3.0", + "sanmai/di-container": "^0.1.12", "sanmai/duoclock": "^0.1.0", "sanmai/later": "^0.1.7", - "sanmai/pipeline": "^7.0", - "sebastian/diff": "^4.0 || ^5.0 || ^6.0 || ^7.0", - "symfony/console": "^6.4 || ^7.0", - "symfony/filesystem": "^6.4 || ^7.0", - "symfony/finder": "^6.4 || ^7.0", - "symfony/process": "^6.4 || ^7.0", + "sanmai/pipeline": "^7.2", + "sebastian/diff": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0", + "symfony/console": "^6.4 || ^7.0 || ^8.0", + "symfony/filesystem": "^6.4 || ^7.0 || ^8.0", + "symfony/finder": "^6.4 || ^7.0 || ^8.0", + "symfony/polyfill-php85": "^1.33", + "symfony/process": "^6.4 || ^7.0 || ^8.0", "thecodingmachine/safe": "^v3.0", - "webmozart/assert": "^1.11" + "webmozart/assert": "^1.11 || ^2.0" }, "conflict": { "antecedent/patchwork": "<2.1.25", @@ -4408,18 +4403,21 @@ "require-dev": { "ext-simplexml": "*", "fidry/makefile": "^1.0", + "fig/log-test": "^1.2", + "phpbench/phpbench": "^1.4", "phpstan/extension-installer": "^1.4", "phpstan/phpstan": "^2.1", "phpstan/phpstan-phpunit": "^2.0", "phpstan/phpstan-strict-rules": "^2.0", "phpstan/phpstan-webmozart-assert": "^2.0", "phpunit/phpunit": "^11.5.27", - "rector/rector": "^2.0", - "shipmonk/dead-code-detector": "^0.12.0", + "rector/rector": "^2.2.4", + "shipmonk/dead-code-detector": "^0.14.0", "shipmonk/name-collision-detector": "^2.1", "sidz/phpstan-rules": "^0.5.1", - "symfony/yaml": "^6.4 || ^7.0", - "thecodingmachine/phpstan-safe-rule": "^1.4" + "symfony/yaml": "^6.4 || ^7.0 || ^8.0", + "thecodingmachine/phpstan-safe-rule": "^1.4", + "webmozarts/strict-phpunit": "^7.15" }, "bin": [ "bin/infection" @@ -4475,7 +4473,7 @@ ], "support": { "issues": "https://github.com/infection/infection/issues", - "source": "https://github.com/infection/infection/tree/0.31.9" + "source": "https://github.com/infection/infection/tree/0.32.6" }, "funding": [ { @@ -4487,7 +4485,7 @@ "type": "open_collective" } ], - "time": "2025-10-27T12:00:54+00:00" + "time": "2026-02-26T14:34:26+00:00" }, { "name": "infection/mutator", @@ -4544,21 +4542,21 @@ }, { "name": "justinrainbow/json-schema", - "version": "6.6.2", + "version": "v6.7.2", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "3c25fe750c1599716ef26aa997f7c026cee8c4b7" + "reference": "6fea66c7204683af437864e7c4e7abf383d14bc0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/3c25fe750c1599716ef26aa997f7c026cee8c4b7", - "reference": "3c25fe750c1599716ef26aa997f7c026cee8c4b7", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/6fea66c7204683af437864e7c4e7abf383d14bc0", + "reference": "6fea66c7204683af437864e7c4e7abf383d14bc0", "shasum": "" }, "require": { "ext-json": "*", - "marc-mabe/php-enum": "^4.0", + "marc-mabe/php-enum": "^4.4", "php": "^7.2 || ^8.0" }, "require-dev": { @@ -4613,22 +4611,22 @@ ], "support": { "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.2" + "source": "https://github.com/jsonrainbow/json-schema/tree/v6.7.2" }, - "time": "2025-11-28T15:24:03+00:00" + "time": "2026-02-15T15:06:22+00:00" }, { "name": "league/commonmark", - "version": "2.8.0", + "version": "2.8.2", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb" + "reference": "59fb075d2101740c337c7216e3f32b36c204218b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/4efa10c1e56488e658d10adf7b7b7dcd19940bfb", - "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/59fb075d2101740c337c7216e3f32b36c204218b", + "reference": "59fb075d2101740c337c7216e3f32b36c204218b", "shasum": "" }, "require": { @@ -4653,9 +4651,9 @@ "phpstan/phpstan": "^1.8.2", "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", "scrutinizer/ocular": "^1.8.1", - "symfony/finder": "^5.3 | ^6.0 | ^7.0", - "symfony/process": "^5.4 | ^6.0 | ^7.0", - "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", + "symfony/finder": "^5.3 | ^6.0 | ^7.0 || ^8.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0 || ^8.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0 || ^8.0", "unleashedtech/php-coding-standard": "^3.1.1", "vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0" }, @@ -4722,7 +4720,7 @@ "type": "tidelift" } ], - "time": "2025-11-26T21:48:24+00:00" + "time": "2026-03-19T13:16:38+00:00" }, { "name": "league/config", @@ -4941,16 +4939,16 @@ }, { "name": "nette/schema", - "version": "v1.3.3", + "version": "v1.3.5", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004" + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/2befc2f42d7c715fd9d95efc31b1081e5d765004", - "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004", + "url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002", + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002", "shasum": "" }, "require": { @@ -4958,8 +4956,10 @@ "php": "8.1 - 8.5" }, "require-dev": { - "nette/tester": "^2.5.2", - "phpstan/phpstan-nette": "^2.0@stable", + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.6", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1.39@stable", "tracy/tracy": "^2.8" }, "type": "library", @@ -5000,22 +5000,22 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.3.3" + "source": "https://github.com/nette/schema/tree/v1.3.5" }, - "time": "2025-10-30T22:57:59+00:00" + "time": "2026-02-23T03:47:12+00:00" }, { "name": "nette/utils", - "version": "v4.1.0", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0" + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/fa1f0b8261ed150447979eb22e373b7b7ad5a8e0", - "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0", + "url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe", + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe", "shasum": "" }, "require": { @@ -5027,8 +5027,10 @@ }, "require-dev": { "jetbrains/phpstorm-attributes": "^1.2", + "nette/phpstan-rules": "^1.0", "nette/tester": "^2.5", - "phpstan/phpstan-nette": "^2.0@stable", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1@stable", "tracy/tracy": "^2.9" }, "suggest": { @@ -5089,22 +5091,22 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.1.0" + "source": "https://github.com/nette/utils/tree/v4.1.3" }, - "time": "2025-12-01T17:49:23+00:00" + "time": "2026-02-13T03:05:33+00:00" }, { "name": "nikic/php-parser", - "version": "v5.6.2", + "version": "v5.7.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb" + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", "shasum": "" }, "require": { @@ -5147,9 +5149,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" }, - "time": "2025-10-21T19:32:17+00:00" + "time": "2025-12-06T11:56:16+00:00" }, { "name": "ondram/ci-detector", @@ -5404,16 +5406,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "2.3.0", + "version": "2.3.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", "shasum": "" }, "require": { @@ -5445,17 +5447,17 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" }, - "time": "2025-08-30T15:50:23+00:00" + "time": "2026-01-25T14:56:51+00:00" }, { "name": "phpstan/phpstan", - "version": "2.1.32", + "version": "2.1.44", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e126cad1e30a99b137b8ed75a85a676450ebb227", - "reference": "e126cad1e30a99b137b8ed75a85a676450ebb227", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/4a88c083c668b2c364a425c9b3171b2d9ea5d218", + "reference": "4a88c083c668b2c364a425c9b3171b2d9ea5d218", "shasum": "" }, "require": { @@ -5500,20 +5502,20 @@ "type": "github" } ], - "time": "2025-11-11T15:18:17+00:00" + "time": "2026-03-25T17:34:21+00:00" }, { "name": "phpstan/phpstan-symfony", - "version": "2.0.9", + "version": "2.0.15", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-symfony.git", - "reference": "24d8c157aa483141b0579d705ef0aac9e1b95436" + "reference": "9b85ab476969b87bbe2253b69e265a9359b2f395" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/24d8c157aa483141b0579d705ef0aac9e1b95436", - "reference": "24d8c157aa483141b0579d705ef0aac9e1b95436", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/9b85ab476969b87bbe2253b69e265a9359b2f395", + "reference": "9b85ab476969b87bbe2253b69e265a9359b2f395", "shasum": "" }, "require": { @@ -5567,43 +5569,46 @@ } ], "description": "Symfony Framework extensions and rules for PHPStan", + "keywords": [ + "static analysis" + ], "support": { "issues": "https://github.com/phpstan/phpstan-symfony/issues", - "source": "https://github.com/phpstan/phpstan-symfony/tree/2.0.9" + "source": "https://github.com/phpstan/phpstan-symfony/tree/2.0.15" }, - "time": "2025-11-29T11:17:28+00:00" + "time": "2026-02-26T10:15:59+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "11.0.11", + "version": "11.0.12", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4" + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4", - "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^5.4.0", + "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.0", + "sebastian/environment": "^7.2.1", "sebastian/lines-of-code": "^3.0.1", "sebastian/version": "^5.0.2", - "theseer/tokenizer": "^1.2.3" + "theseer/tokenizer": "^1.3.1" }, "require-dev": { - "phpunit/phpunit": "^11.5.2" + "phpunit/phpunit": "^11.5.46" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -5641,7 +5646,7 @@ "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.11" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.12" }, "funding": [ { @@ -5661,32 +5666,32 @@ "type": "tidelift" } ], - "time": "2025-08-27T14:37:49+00:00" + "time": "2025-12-24T07:01:01+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "5.1.0", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -5714,15 +5719,27 @@ "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.0" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" } ], - "time": "2024-08-27T05:02:59+00:00" + "time": "2026-02-02T13:52:54+00:00" }, { "name": "phpunit/php-invoker", @@ -5910,16 +5927,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.45", + "version": "11.5.55", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "faf5fff4fb9beb290affa53f812b05380819c51a" + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/faf5fff4fb9beb290affa53f812b05380819c51a", - "reference": "faf5fff4fb9beb290affa53f812b05380819c51a", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00", + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00", "shasum": "" }, "require": { @@ -5933,19 +5950,20 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.11", - "phpunit/php-file-iterator": "^5.1.0", + "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.2", + "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" @@ -5991,7 +6009,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.45" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.55" }, "funding": [ { @@ -6015,7 +6033,7 @@ "type": "tidelift" } ], - "time": "2025-12-01T07:38:43+00:00" + "time": "2026-02-18T12:37:06+00:00" }, { "name": "roave/security-advisories", @@ -6023,18 +6041,18 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "4400137eb61cd0db3192a409353ae83e811395fe" + "reference": "8522ed5a1cbb7828ed9bb1b3c12053f79da78155" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/4400137eb61cd0db3192a409353ae83e811395fe", - "reference": "4400137eb61cd0db3192a409353ae83e811395fe", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/8522ed5a1cbb7828ed9bb1b3c12053f79da78155", + "reference": "8522ed5a1cbb7828ed9bb1b3c12053f79da78155", "shasum": "" }, "conflict": { "3f/pygmentize": "<1.2", "adaptcms/adaptcms": "<=1.3", - "admidio/admidio": "<=4.3.16", + "admidio/admidio": "<=5.0.6", "adodb/adodb-php": "<=5.22.9", "aheinze/cockpit": "<2.2", "aimeos/ai-admin-graphql": ">=2022.04.1,<2022.10.10|>=2023.04.1,<2023.10.6|>=2024.04.1,<2024.07.2", @@ -6043,19 +6061,23 @@ "aimeos/ai-cms-grapesjs": ">=2021.04.1,<2021.10.8|>=2022.04.1,<2022.10.9|>=2023.04.1,<2023.10.15|>=2024.04.1,<2024.10.8|>=2025.04.1,<2025.10.2", "aimeos/ai-controller-frontend": "<2020.10.15|>=2021.04.1,<2021.10.8|>=2022.04.1,<2022.10.8|>=2023.04.1,<2023.10.9|==2024.04.1", "aimeos/aimeos-core": ">=2022.04.1,<2022.10.17|>=2023.04.1,<2023.10.17|>=2024.04.1,<2024.04.7", + "aimeos/aimeos-laravel": "==2021.10", "aimeos/aimeos-typo3": "<19.10.12|>=20,<20.10.5", "airesvsg/acf-to-rest-api": "<=3.1", "akaunting/akaunting": "<2.1.13", "akeneo/pim-community-dev": "<5.0.119|>=6,<6.0.53", - "alextselegidis/easyappointments": "<1.5.2.0-beta1", + "alextselegidis/easyappointments": "<=1.5.2", "alexusmai/laravel-file-manager": "<=3.3.1", + "algolia/algoliasearch-magento-2": "<=3.16.1|>=3.17.0.0-beta1,<=3.17.1", "alt-design/alt-redirect": "<1.6.4", + "altcha-org/altcha": "<1.3.1", "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", "amazing/media2click": ">=1,<1.3.3", "ameos/ameos_tarteaucitron": "<1.2.23", "amphp/artax": "<1.0.6|>=2,<2.0.6", "amphp/http": "<=1.7.2|>=2,<=2.1", "amphp/http-client": ">=4,<4.4", + "amphp/http-server": ">=2.0.0.0-RC1-dev,<2.1.10|>=3.0.0.0-beta1,<3.4.4", "anchorcms/anchor-cms": "<=0.12.7", "andreapollastri/cipi": "<=3.1.15", "andrewhaine/silverstripe-form-capture": ">=0.2,<=0.2.3|>=1,<1.0.2|>=2,<2.2.5", @@ -6072,23 +6094,26 @@ "athlon1600/php-proxy": "<=5.1", "athlon1600/php-proxy-app": "<=3", "athlon1600/youtube-downloader": "<=4", + "aureuserp/aureuserp": "<1.3.0.0-beta1", "austintoddj/canvas": "<=3.4.2", - "auth0/auth0-php": ">=3.3,<=8.16", - "auth0/login": "<=7.18", - "auth0/symfony": "<=5.4.1", - "auth0/wordpress": "<=5.3", + "auth0/auth0-php": ">=3.3,<8.18", + "auth0/login": "<7.20", + "auth0/symfony": "<=5.5", + "auth0/wordpress": "<=5.4", "automad/automad": "<2.0.0.0-alpha5", "automattic/jetpack": "<9.8", + "avideo/avideo": "<=26", "awesome-support/awesome-support": "<=6.0.7", - "aws/aws-sdk-php": "<3.288.1", - "azuracast/azuracast": "<0.18.3", + "aws/aws-sdk-php": "<3.368", + "ayacoo/redirect-tab": "<2.1.2|>=3,<3.1.7|>=4,<4.0.5", + "azuracast/azuracast": "<=0.23.3", "b13/seo_basics": "<0.8.2", "backdrop/backdrop": "<=1.32", "backpack/crud": "<3.4.9", "backpack/filemanager": "<2.0.2|>=3,<3.0.9", "bacula-web/bacula-web": "<9.7.1", "badaso/core": "<=2.9.11", - "bagisto/bagisto": "<=2.3.7", + "bagisto/bagisto": "<2.3.10", "barrelstrength/sprout-base-email": "<1.2.7", "barrelstrength/sprout-forms": "<3.9", "barryvdh/laravel-translation-manager": "<0.6.8", @@ -6120,7 +6145,8 @@ "bvbmedia/multishop": "<2.0.39", "bytefury/crater": "<6.0.2", "cachethq/cachet": "<2.5.1", - "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.1,<4.1.4|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", + "cadmium-org/cadmium-cms": "<=0.4.9", + "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.1,<4.1.4|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10|>=5.2.10,<5.2.12|==5.3", "cakephp/database": ">=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", "cardgate/magento2": "<2.0.33", "cardgate/woocommerce": "<=3.1.15", @@ -6131,15 +6157,17 @@ "causal/oidc": "<4", "cecil/cecil": "<7.47.1", "centreon/centreon": "<22.10.15", + "cesargb/laravel-magiclink": ">=2,<2.25.1", "cesnet/simplesamlphp-module-proxystatistics": "<3.1", "chriskacerguis/codeigniter-restserver": "<=2.7.1", "chrome-php/chrome": "<1.14", + "ci4-cms-erp/ci4ms": "<0.28.5", "civicrm/civicrm-core": ">=4.2,<4.2.9|>=4.3,<4.3.3", "ckeditor/ckeditor": "<4.25", "clickstorm/cs-seo": ">=6,<6.8|>=7,<7.5|>=8,<8.4|>=9,<9.3", "co-stack/fal_sftp": "<0.2.6", - "cockpit-hq/cockpit": "<2.11.4", - "code16/sharp": "<9.11.1", + "cockpit-hq/cockpit": "<2.13.5", + "code16/sharp": "<9.20", "codeception/codeception": "<3.1.3|>=4,<4.1.22", "codeigniter/framework": "<3.1.10", "codeigniter4/framework": "<4.6.2", @@ -6149,8 +6177,8 @@ "codingms/modules": "<4.3.11|>=5,<5.7.4|>=6,<6.4.2|>=7,<7.5.5", "commerceteam/commerce": ">=0.9.6,<0.9.9", "components/jquery": ">=1.0.3,<3.5", - "composer/composer": "<1.10.27|>=2,<2.2.24|>=2.3,<2.7.7", - "concrete5/concrete5": "<9.4.3", + "composer/composer": "<1.10.27|>=2,<2.2.26|>=2.3,<2.9.3", + "concrete5/concrete5": "<9.4.8", "concrete5/core": "<8.5.8|>=9,<9.1", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4", @@ -6159,11 +6187,20 @@ "contao/core-bundle": "<4.13.57|>=5,<5.3.42|>=5.4,<5.6.5", "contao/listing-bundle": ">=3,<=3.5.30|>=4,<4.4.8", "contao/managed-edition": "<=1.5", + "coreshop/core-shop": "<4.1.9", "corveda/phpsandbox": "<1.3.5", "cosenary/instagram": "<=2.3", "couleurcitron/tarteaucitron-wp": "<0.3", - "craftcms/cms": "<=4.16.5|>=5,<=5.8.6", - "croogo/croogo": "<4", + "cpsit/typo3-mailqueue": "<0.4.5|>=0.5,<0.5.2", + "craftcms/aws-s3": ">=2.0.2,<=2.2.4", + "craftcms/azure-blob": ">=2.0.0.0-beta1,<=2.1", + "craftcms/cms": "<=4.17.7|>=5,<=5.9.13", + "craftcms/commerce": ">=4,<4.11|>=5,<5.6", + "craftcms/composer": ">=4.0.0.0-RC1-dev,<=4.10|>=5.0.0.0-RC1-dev,<=5.5.1", + "craftcms/craft": ">=3.5,<=4.16.17|>=5.0.0.0-RC1-dev,<=5.8.21", + "craftcms/google-cloud": ">=2.0.0.0-beta1,<=2.2", + "craftcms/webhooks": ">=3,<3.2", + "croogo/croogo": "<=4.0.7", "cuyz/valinor": "<0.12", "czim/file-handling": "<1.5|>=2,<2.3", "czproject/git-php": "<4.0.3", @@ -6180,10 +6217,11 @@ "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1|>=7,<7.4", "desperado/xml-bundle": "<=0.1.7", "dev-lancer/minecraft-motd-parser": "<=1.0.5", - "devcode-it/openstamanager": "<=2.9.4", + "devcode-it/openstamanager": "<=2.9.8", "devgroup/dotplant": "<2020.09.14-dev", "digimix/wp-svg-upload": "<=1", "directmailteam/direct-mail": "<6.0.3|>=7,<7.0.3|>=8,<9.5.2", + "directorytree/imapengine": "<1.22.3", "dl/yag": "<3.0.1", "dmk/webkitpdf": "<1.1.4", "dnadesign/silverstripe-elemental": "<5.3.12", @@ -6199,6 +6237,7 @@ "dolibarr/dolibarr": "<21.0.3", "dompdf/dompdf": "<2.0.4", "doublethreedigital/guest-entries": "<3.1.2", + "dreamfactory/df-core": "<1.0.4", "drupal-pattern-lab/unified-twig-extensions": "<=0.1", "drupal/access_code": "<2.0.5", "drupal/acquia_dam": "<1.1.5", @@ -6210,7 +6249,7 @@ "drupal/commerce_alphabank_redirect": "<1.0.3", "drupal/commerce_eurobank_redirect": "<2.1.1", "drupal/config_split": "<1.10|>=2,<2.0.2", - "drupal/core": ">=6,<6.38|>=7,<7.102|>=8,<10.4.9|>=10.5,<10.5.6|>=11,<11.1.9|>=11.2,<11.2.8", + "drupal/core": ">=6,<6.38|>=7,<7.103|>=8,<10.4.9|>=10.5,<10.5.6|>=11,<11.1.9|>=11.2,<11.2.8", "drupal/core-recommended": ">=7,<7.102|>=8,<10.2.11|>=10.3,<10.3.9|>=11,<11.0.8", "drupal/currency": "<3.5", "drupal/drupal": ">=5,<5.11|>=6,<6.38|>=7,<7.102|>=8,<10.2.11|>=10.3,<10.3.9|>=11,<11.0.8", @@ -6237,10 +6276,10 @@ "drupal/umami_analytics": "<1.0.1", "duncanmcclean/guest-entries": "<3.1.2", "dweeves/magmi": "<=0.7.24", - "ec-cube/ec-cube": "<2.4.4|>=2.11,<=2.17.1|>=3,<=3.0.18.0-patch4|>=4,<=4.1.2", + "ec-cube/ec-cube": "<2.4.4|>=2.11,<=2.17.1|>=3,<=3.0.18.0-patch4|>=4,<=4.3.1", "ecodev/newsletter": "<=4", "ectouch/ectouch": "<=2.7.2", - "egroupware/egroupware": "<23.1.20240624", + "egroupware/egroupware": "<23.1.20260113|>=26.0.20251208,<26.0.20260113", "elefant/cms": "<2.0.7", "elgg/elgg": "<3.3.24|>=4,<4.0.5", "elijaa/phpmemcacheadmin": "<=1.3", @@ -6263,18 +6302,18 @@ "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1|>=5.3.0.0-beta1,<5.3.5", "ezsystems/ezplatform-graphql": ">=1.0.0.0-RC1-dev,<1.0.13|>=2.0.0.0-beta1,<2.3.12", "ezsystems/ezplatform-http-cache": "<2.3.16", - "ezsystems/ezplatform-kernel": "<1.2.5.1-dev|>=1.3,<1.3.35", + "ezsystems/ezplatform-kernel": "<=1.2.5|>=1.3,<1.3.35", "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<1.3.8", "ezsystems/ezplatform-richtext": ">=2.3,<2.3.26|>=3.3,<3.3.40", "ezsystems/ezplatform-solr-search-engine": ">=1.7,<1.7.12|>=2,<2.0.2|>=3.3,<3.3.15", "ezsystems/ezplatform-user": ">=1,<1.0.1", - "ezsystems/ezpublish-kernel": "<6.13.8.2-dev|>=7,<7.5.31", + "ezsystems/ezpublish-kernel": "<=6.13.8.1|>=7,<7.5.31", "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.6,<=2019.03.5.1", "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", "ezsystems/repository-forms": ">=2.3,<2.3.2.1-dev|>=2.5,<2.5.15", "ezyang/htmlpurifier": "<=4.2", "facade/ignition": "<1.16.15|>=2,<2.4.2|>=2.5,<2.5.2", - "facturascripts/facturascripts": "<=2022.08", + "facturascripts/facturascripts": "<2025.81", "fastly/magento2": "<1.2.26", "feehi/cms": "<=2.1.1", "feehi/feehicms": "<=2.1.1", @@ -6282,11 +6321,11 @@ "filament/actions": ">=3.2,<3.2.123", "filament/filament": ">=4,<4.3.1", "filament/infolists": ">=3,<3.2.115", - "filament/tables": ">=3,<3.2.115", + "filament/tables": ">=3,<3.2.115|>=4,<4.8.5|>=5,<5.3.5", "filegator/filegator": "<7.8", "filp/whoops": "<2.1.13", "fineuploader/php-traditional-server": "<=1.2.2", - "firebase/php-jwt": "<6", + "firebase/php-jwt": "<7", "fisharebest/webtrees": "<=2.1.18", "fixpunkt/fp-masterquiz": "<2.2.1|>=3,<3.5.2", "fixpunkt/fp-newsletter": "<1.1.1|>=1.2,<2.1.2|>=2.2,<3.2.6", @@ -6294,11 +6333,13 @@ "flarum/flarum": "<0.1.0.0-beta8", "flarum/framework": "<1.8.10", "flarum/mentions": "<1.6.3", + "flarum/nicknames": "<1.8.3", "flarum/sticky": ">=0.1.0.0-beta14,<=0.1.0.0-beta15", "flarum/tags": "<=0.1.0.0-beta13", "floriangaerber/magnesium": "<0.3.1", "fluidtypo3/vhs": "<5.1.1", "fof/byobu": ">=0.3.0.0-beta2,<1.1.7", + "fof/pretty-mail": "<=1.1.2", "fof/upload": "<1.2.3", "foodcoopshop/foodcoopshop": ">=3.2,<3.6.1", "fooman/tcpdf": "<6.2.22", @@ -6314,17 +6355,18 @@ "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", "friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6", "froala/wysiwyg-editor": "<=4.3", - "froxlor/froxlor": "<=2.2.5", + "frosh/adminer-platform": "<2.2.1", + "froxlor/froxlor": "<=2.3.4", "frozennode/administrator": "<=5.0.12", "fuel/core": "<1.8.1", - "funadmin/funadmin": "<=5.0.2", + "funadmin/funadmin": "<=7.1.0.0-RC4", "gaoming13/wechat-php-sdk": "<=1.10.2", "genix/cms": "<=1.1.11", "georgringer/news": "<1.3.3", "geshi/geshi": "<=1.0.9.1", - "getformwork/formwork": "<2.2", + "getformwork/formwork": "<=2.3.3", "getgrav/grav": "<1.11.0.0-beta1", - "getkirby/cms": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1|>=5,<5.1.4", + "getkirby/cms": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1|>=5,<=5.2.1", "getkirby/kirby": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1", "getkirby/panel": "<2.5.14", "getkirby/starterkit": "<=3.7.0.2", @@ -6333,12 +6375,12 @@ "globalpayments/php-sdk": "<2", "goalgorilla/open_social": "<12.3.11|>=12.4,<12.4.10|>=13.0.0.0-alpha1,<13.0.0.0-alpha11", "gogentooss/samlbase": "<1.2.7", - "google/protobuf": "<3.4", + "google/protobuf": "<4.33.6", "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", "gp247/core": "<1.1.24", "gree/jose": "<2.2.1", "gregwar/rst": "<1.0.3", - "grumpydictator/firefly-iii": "<6.1.17", + "grumpydictator/firefly-iii": "<6.1.17|>=6.4.23,<=6.5", "gugoan/economizzer": "<=0.9.0.0-beta1", "guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5", "guzzlehttp/oauth-subscriber": "<0.8.1", @@ -6364,7 +6406,7 @@ "ibexa/solr": ">=4.5,<4.5.4", "ibexa/user": ">=4,<4.4.3|>=5,<5.0.4", "icecoder/icecoder": "<=8.1", - "idno/known": "<=1.3.1", + "idno/known": "<1.6.4", "ilicmiljan/secure-props": ">=1.2,<1.2.2", "illuminate/auth": "<5.5.10", "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<6.18.31|>=7,<7.22.4", @@ -6381,6 +6423,7 @@ "innologi/typo3-appointments": "<2.0.6", "intelliants/subrion": "<4.2.2", "inter-mediator/inter-mediator": "==5.5", + "invoiceninja/invoiceninja": "<5.13.4", "ipl/web": "<0.10.1", "islandora/crayfish": "<4.1", "islandora/islandora": ">=2,<2.4.1", @@ -6393,6 +6436,7 @@ "jbartels/wec-map": "<3.0.3", "jcbrand/converse.js": "<3.3.3", "joelbutcher/socialstream": "<5.6|>=6,<6.2", + "johnbillion/query-monitor": "<3.20.4", "johnbillion/wp-crontrol": "<1.16.2|>=1.17,<1.19.2", "joomla/application": "<1.0.13", "joomla/archive": "<1.1.12|>=2,<2.0.1", @@ -6411,10 +6455,11 @@ "jweiland/events2": "<8.3.8|>=9,<9.0.6", "jweiland/kk-downloader": "<1.2.2", "kazist/phpwhois": "<=4.2.6", + "kelvinmo/simplejwt": "<=1.1", "kelvinmo/simplexrd": "<3.1.1", "kevinpapst/kimai2": "<1.16.7", "khodakhah/nodcms": "<=3", - "kimai/kimai": "<=2.20.1", + "kimai/kimai": "<=2.50", "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", "klaviyo/magento2-extension": ">=1,<3", "knplabs/knp-snappy": "<=1.4.2", @@ -6433,23 +6478,24 @@ "laravel/framework": "<10.48.29|>=11,<11.44.1|>=12,<12.1.1", "laravel/laravel": ">=5.4,<5.4.22", "laravel/pulse": "<1.3.1", - "laravel/reverb": "<1.4", + "laravel/reverb": "<1.7", "laravel/socialite": ">=1,<2.0.10", "latte/latte": "<2.10.8", - "lavalite/cms": "<=9|==10.1", + "lavalite/cms": "<=10.1", "lavitto/typo3-form-to-database": "<2.2.5|>=3,<3.2.2|>=4,<4.2.3|>=5,<5.0.2", "lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5", - "league/commonmark": "<2.7", + "league/commonmark": "<=2.8.1", "league/flysystem": "<1.1.4|>=2,<2.1.1", "league/oauth2-server": ">=8.3.2,<8.4.2|>=8.5,<8.5.3", "leantime/leantime": "<3.3", "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", "libreform/libreform": ">=2,<=2.0.8", - "librenms/librenms": "<25.11", + "librenms/librenms": "<26.2", "liftkit/database": "<2.13.2", "lightsaml/lightsaml": "<1.3.5", - "limesurvey/limesurvey": "<6.5.12", + "limesurvey/limesurvey": "<6.15.4", "livehelperchat/livehelperchat": "<=3.91", + "livewire-filemanager/filemanager": "<=1.0.4", "livewire/livewire": "<2.12.7|>=3.0.0.0-beta1,<3.6.4", "livewire/volt": "<1.7", "lms/routes": "<2.1.1", @@ -6470,12 +6516,12 @@ "maikuolan/phpmussel": ">=1,<1.6", "mainwp/mainwp": "<=4.4.3.3", "manogi/nova-tiptap": "<=3.2.6", - "mantisbt/mantisbt": "<2.27.2", + "mantisbt/mantisbt": "<2.28.1", "marcwillmann/turn": "<0.3.3", "marshmallow/nova-tiptap": "<5.7", "matomo/matomo": "<1.11", "matyhtf/framework": "<3.0.6", - "mautic/core": "<5.2.9|>=6,<6.0.7", + "mautic/core": "<5.2.10|>=6,<6.0.8|>=7.0.0.0-alpha,<7.0.1", "mautic/core-lib": ">=1.0.0.0-beta,<4.4.13|>=5.0.0.0-alpha,<5.1.1", "mautic/grapes-js-builder-bundle": ">=4,<4.4.18|>=5,<5.2.9|>=6,<6.0.7", "maximebf/debugbar": "<1.19", @@ -6497,8 +6543,9 @@ "microsoft/microsoft-graph": ">=1.16,<1.109.1|>=2,<2.0.1", "microsoft/microsoft-graph-beta": "<2.0.1", "microsoft/microsoft-graph-core": "<2.0.2", - "microweber/microweber": "<=2.0.19", + "microweber/microweber": "<2.0.20", "mikehaertl/php-shellcommand": "<1.6.1", + "mineadmin/mineadmin": "<=3.0.9", "miniorange/miniorange-saml": "<1.4.3", "mittwald/typo3_forum": "<1.2.1", "mobiledetect/mobiledetectlib": "<2.8.32", @@ -6507,7 +6554,7 @@ "mongodb/mongodb": ">=1,<1.9.2", "mongodb/mongodb-extension": "<1.21.2", "monolog/monolog": ">=1.8,<1.12", - "moodle/moodle": "<4.4.11|>=4.5.0.0-beta,<4.5.7|>=5.0.0.0-beta,<5.0.3", + "moodle/moodle": "<4.5.9|>=5.0.0.0-beta,<5.0.5|>=5.1.0.0-beta,<5.1.2", "moonshine/moonshine": "<=3.12.5", "mos/cimage": "<0.7.19", "movim/moxl": ">=0.8,<=0.10", @@ -6552,7 +6599,7 @@ "october/cms": "<1.0.469|==1.0.469|==1.0.471|==1.1.1", "october/october": "<3.7.5", "october/rain": "<1.0.472|>=1.1,<1.1.2", - "october/system": "<3.7.5", + "october/system": "<=3.7.12|>=4,<=4.0.11", "oliverklee/phpunit": "<3.5.15", "omeka/omeka-s": "<4.0.3", "onelogin/php-saml": "<2.21.1|>=3,<3.8.1|>=4,<4.3.1", @@ -6560,9 +6607,9 @@ "open-web-analytics/open-web-analytics": "<1.8.1", "opencart/opencart": ">=0", "openid/php-openid": "<2.3", - "openmage/magento-lts": "<20.16", + "openmage/magento-lts": "<20.16.1", "opensolutions/vimbadmin": "<=3.0.15", - "opensource-workshop/connect-cms": "<1.8.7|>=2,<2.4.7", + "opensource-workshop/connect-cms": "<1.41.1|>=2,<2.41.1", "orchid/platform": ">=8,<14.43", "oro/calendar-bundle": ">=4.2,<=4.2.6|>=5,<=5.0.6|>=5.1,<5.1.1", "oro/commerce": ">=4.1,<5.0.11|>=5.1,<5.1.1", @@ -6579,6 +6626,7 @@ "pagekit/pagekit": "<=1.0.18", "paragonie/ecc": "<2.0.1", "paragonie/random_compat": "<2", + "paragonie/sodium_compat": "<1.24|>=2,<2.5", "passbolt/passbolt_api": "<4.6.2", "paypal/adaptivepayments-sdk-php": "<=3.9.2", "paypal/invoice-sdk-php": "<=3.9", @@ -6591,6 +6639,7 @@ "pear/pear": "<=1.10.1", "pegasus/google-for-jobs": "<1.5.1|>=2,<2.1.1", "personnummer/personnummer": "<3.0.2", + "ph7software/ph7builder": "<=17.9.1", "phanan/koel": "<5.1.4", "phenx/php-svg-lib": "<0.5.2", "php-censor/php-censor": "<2.0.13|>=2.1,<2.1.5", @@ -6601,28 +6650,30 @@ "phpmailer/phpmailer": "<6.5", "phpmussel/phpmussel": ">=1,<1.6", "phpmyadmin/phpmyadmin": "<5.2.2", - "phpmyfaq/phpmyfaq": "<=4.0.13", + "phpmyfaq/phpmyfaq": "<=4.0.16", "phpoffice/common": "<0.2.9", "phpoffice/math": "<=0.2", "phpoffice/phpexcel": "<=1.8.2", "phpoffice/phpspreadsheet": "<1.30|>=2,<2.1.12|>=2.2,<2.4|>=3,<3.10|>=4,<5", "phppgadmin/phppgadmin": "<=7.13", - "phpseclib/phpseclib": "<2.0.47|>=3,<3.0.36", + "phpseclib/phpseclib": "<=2.0.51|>=3,<=3.0.49", "phpservermon/phpservermon": "<3.6", "phpsysinfo/phpsysinfo": "<3.4.3", - "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", + "phpunit/phpunit": "<8.5.52|>=9,<9.6.33|>=10,<10.5.62|>=11,<11.5.50|>=12,<12.5.8", "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", "phpxmlrpc/phpxmlrpc": "<4.9.2", + "phraseanet/phraseanet": "==4.0.3", "pi/pi": "<=2.5", - "pimcore/admin-ui-classic-bundle": "<1.7.6", + "pimcore/admin-ui-classic-bundle": "<=1.7.15|>=2.0.0.0-RC1-dev,<=2.2.2", "pimcore/customer-management-framework-bundle": "<4.2.1", "pimcore/data-hub": "<1.2.4", "pimcore/data-importer": "<1.8.9|>=1.9,<1.9.3", "pimcore/demo": "<10.3", "pimcore/ecommerce-framework-bundle": "<1.0.10", "pimcore/perspective-editor": "<1.5.1", - "pimcore/pimcore": "<11.5.4", + "pimcore/pimcore": "<=11.5.14.1|>=12,<12.3.3", + "pimcore/web2print-tools-bundle": "<=5.2.1|>=6.0.0.0-RC1-dev,<=6.1", "piwik/piwik": "<1.11", "pixelfed/pixelfed": "<0.12.5", "plotly/plotly.js": "<2.25.2", @@ -6635,7 +6686,7 @@ "prestashop/blockwishlist": ">=2,<2.1.1", "prestashop/contactform": ">=1.0.1,<4.3", "prestashop/gamification": "<2.3.2", - "prestashop/prestashop": "<8.2.3", + "prestashop/prestashop": "<8.2.5|>=9.0.0.0-alpha1,<9.1", "prestashop/productcomments": "<5.0.2", "prestashop/ps_checkout": "<4.4.1|>=5,<5.0.5", "prestashop/ps_contactinfo": "<=3.3.2", @@ -6646,12 +6697,14 @@ "processwire/processwire": "<=3.0.246", "propel/propel": ">=2.0.0.0-alpha1,<=2.0.0.0-alpha7", "propel/propel1": ">=1,<=1.7.1", - "pterodactyl/panel": "<=1.11.10", + "psy/psysh": "<=0.11.22|>=0.12,<=0.12.18", + "pterodactyl/panel": "<1.12.1", "ptheofan/yii2-statemachine": ">=2.0.0.0-RC1-dev,<=2", "ptrofimov/beanstalk_console": "<1.7.14", "pubnub/pubnub": "<6.1", "punktde/pt_extbase": "<1.5.1", "pusher/pusher-php-server": "<2.2.1", + "putyourlightson/craft-sprig": ">=2,<2.15.2|>=3,<3.7.2", "pwweb/laravel-core": "<=0.3.6.0-beta", "pxlrbt/filament-excel": "<1.1.14|>=2.0.0.0-alpha,<2.3.3", "pyrocms/pyrocms": "<=3.9.1", @@ -6660,17 +6713,19 @@ "rainlab/blog-plugin": "<1.4.1", "rainlab/debugbar-plugin": "<3.1", "rainlab/user-plugin": "<=1.4.5", + "ralffreit/mfa-email": "<1.0.7|==2", "rankmath/seo-by-rank-math": "<=1.0.95", "rap2hpoutre/laravel-log-viewer": "<0.13", "react/http": ">=0.7,<1.9", "really-simple-plugins/complianz-gdpr": "<6.4.2", - "redaxo/source": "<5.20.1", + "redaxo/source": "<=5.20.1", "remdex/livehelperchat": "<4.29", "renolit/reint-downloadmanager": "<4.0.2|>=5,<5.0.1", "reportico-web/reportico": "<=8.1", "rhukster/dom-sanitizer": "<1.0.7", "rmccue/requests": ">=1.6,<1.8", - "robrichards/xmlseclibs": "<=3.1.3", + "roadiz/documents": "<2.3.42|>=2.4,<2.5.44|>=2.6,<2.6.28|>=2.7,<2.7.9", + "robrichards/xmlseclibs": "<3.1.5", "roots/soil": "<4.1", "roundcube/roundcubemail": "<1.5.10|>=1.6,<1.6.11", "rudloff/alltube": "<3.0.3", @@ -6679,6 +6734,7 @@ "s-cart/s-cart": "<6.9", "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", "sabre/dav": ">=1.6,<1.7.11|>=1.8,<1.8.9", + "saloonphp/saloon": "<4", "samwilson/unlinked-wikibase": "<1.42", "scheb/two-factor-bundle": "<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", @@ -6686,10 +6742,10 @@ "setasign/fpdi": "<2.6.4", "sfroemken/url_redirect": "<=1.2.1", "sheng/yiicms": "<1.2.1", - "shopware/core": "<6.6.10.9-dev|>=6.7,<6.7.4.1-dev", - "shopware/platform": "<6.6.10.7-dev|>=6.7,<6.7.3.1-dev", + "shopware/core": "<6.6.10.15-dev|>=6.7,<6.7.8.1-dev", + "shopware/platform": "<6.6.10.15-dev|>=6.7,<6.7.8.1-dev", "shopware/production": "<=6.3.5.2", - "shopware/shopware": "<=5.7.17|>=6.4.6,<6.6.10.10-dev|>=6.7,<6.7.5.1-dev", + "shopware/shopware": "<=5.7.17|>=6.4.6,<6.6.10.10-dev|>=6.7,<6.7.6.1-dev", "shopware/storefront": "<6.6.10.10-dev|>=6.7,<6.7.5.1-dev", "shopxo/shopxo": "<=6.4", "showdoc/showdoc": "<2.10.4", @@ -6721,7 +6777,7 @@ "simplesamlphp/simplesamlphp-module-openid": "<1", "simplesamlphp/simplesamlphp-module-openidprovider": "<0.9", "simplesamlphp/xml-common": "<1.20", - "simplesamlphp/xml-security": "==1.6.11", + "simplesamlphp/xml-security": "<1.13.9|>=2,<2.3.1", "simplito/elliptic-php": "<1.0.6", "sitegeist/fluid-components": "<3.5", "sjbr/sr-feuser-register": "<2.6.2|>=5.1,<12.5", @@ -6731,10 +6787,10 @@ "slim/slim": "<2.6", "slub/slub-events": "<3.0.3", "smarty/smarty": "<4.5.3|>=5,<5.1.1", - "snipe/snipe-it": "<=8.3.4", + "snipe/snipe-it": "<8.3.7", "socalnick/scn-social-auth": "<1.15.2", "socialiteproviders/steam": "<1.1", - "solspace/craft-freeform": ">=5,<5.10.16", + "solspace/craft-freeform": "<4.1.29|>=5,<=5.14.6", "soosyze/soosyze": "<=2", "spatie/browsershot": "<5.0.5", "spatie/image-optimizer": "<1.7.3", @@ -6749,7 +6805,7 @@ "starcitizentools/short-description": ">=4,<4.0.1", "starcitizentools/tabber-neue": ">=1.9.1,<2.7.2|>=3,<3.1.1", "starcitizenwiki/embedvideo": "<=4", - "statamic/cms": "<=5.22", + "statamic/cms": "<5.73.16|>=6,<6.7.2", "stormpath/sdk": "<9.9.99", "studio-42/elfinder": "<=2.1.64", "studiomitte/friendlycaptcha": "<0.1.4", @@ -6768,7 +6824,7 @@ "sylius/grid-bundle": "<1.10.1", "sylius/paypal-plugin": "<1.6.2|>=1.7,<1.7.2|>=2,<2.0.2", "sylius/resource-bundle": ">=1,<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", - "sylius/sylius": "<1.12.19|>=1.13.0.0-alpha1,<1.13.4", + "sylius/sylius": "<1.9.12|>=1.10,<1.10.16|>=1.11,<1.11.17|>=1.12,<=1.12.22|>=1.13,<=1.13.14|>=1.14,<=1.14.17|>=2,<=2.0.15|>=2.1,<=2.1.11|>=2.2,<=2.2.2", "symbiote/silverstripe-multivaluefield": ">=3,<3.1", "symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4", "symbiote/silverstripe-seed": "<6.0.3", @@ -6788,7 +6844,7 @@ "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/polyfill": ">=1,<1.10", "symfony/polyfill-php55": ">=1,<1.10", - "symfony/process": "<5.4.46|>=6,<6.4.14|>=7,<7.1.7", + "symfony/process": "<5.4.51|>=6,<6.4.33|>=7,<7.1.7|>=7.3,<7.3.11|>=7.4,<7.4.5|>=8,<8.0.5", "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/routing": ">=2,<2.0.19", "symfony/runtime": ">=5.3,<5.4.46|>=6,<6.4.14|>=7,<7.1.7", @@ -6799,7 +6855,7 @@ "symfony/security-guard": ">=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7|>=5.1,<5.2.8|>=5.3,<5.4.47|>=6,<6.4.15|>=7,<7.1.8", "symfony/serializer": ">=2,<2.0.11|>=4.1,<4.4.35|>=5,<5.3.12", - "symfony/symfony": "<5.4.50|>=6,<6.4.29|>=7,<7.3.7", + "symfony/symfony": "<5.4.51|>=6,<6.4.33|>=7,<7.3.11|>=7.4,<7.4.5|>=8,<8.0.5", "symfony/translation": ">=2,<2.0.17", "symfony/twig-bridge": ">=2,<4.4.51|>=5,<5.4.31|>=6,<6.3.8", "symfony/ux-autocomplete": "<2.11.2", @@ -6823,7 +6879,7 @@ "thelia/thelia": ">=2.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "thinkcmf/thinkcmf": "<6.0.8", - "thorsten/phpmyfaq": "<=4.0.13", + "thorsten/phpmyfaq": "<4.0.18|>=4.1.0.0-alpha,<=4.1.0.0-beta2", "tikiwiki/tiki-manager": "<=17.1", "timber/timber": ">=0.16.6,<1.23.1|>=1.24,<1.24.1|>=2,<2.1", "tinymce/tinymce": "<7.2", @@ -6841,11 +6897,12 @@ "ttskch/pagination-service-provider": "<1", "twbs/bootstrap": "<3.4.1|>=4,<4.3.1", "twig/twig": "<3.11.2|>=3.12,<3.14.1|>=3.16,<3.19", + "typicms/core": "<16.1.7", "typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", - "typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.55|>=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", + "typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", "typo3/cms-belog": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", "typo3/cms-beuser": ">=9,<9.5.55|>=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", - "typo3/cms-core": "<=8.7.56|>=9,<9.5.55|>=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", + "typo3/cms-core": "<=8.7.56|>=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", "typo3/cms-dashboard": ">=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", "typo3/cms-extbase": "<6.2.24|>=7,<7.6.8|==8.1.1", "typo3/cms-extensionmanager": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", @@ -6857,7 +6914,8 @@ "typo3/cms-install": "<4.1.14|>=4.2,<4.2.16|>=4.3,<4.3.9|>=4.4,<4.4.5|>=12.2,<12.4.8|==13.4.2", "typo3/cms-lowlevel": ">=11,<=11.5.41", "typo3/cms-recordlist": ">=11,<11.5.48", - "typo3/cms-recycler": ">=9,<9.5.55|>=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", + "typo3/cms-recycler": ">=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", + "typo3/cms-redirects": ">=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", "typo3/cms-rte-ckeditor": ">=9.5,<9.5.42|>=10,<10.4.39|>=11,<11.5.30", "typo3/cms-scheduler": ">=11,<=11.5.41", "typo3/cms-setup": ">=9,<=9.5.50|>=10,<=10.4.49|>=11,<=11.5.43|>=12,<=12.4.30|>=13,<=13.4.11", @@ -6887,15 +6945,16 @@ "vertexvaar/falsftp": "<0.2.6", "villagedefrance/opencart-overclocked": "<=1.11.1", "vova07/yii2-fileapi-widget": "<0.1.9", - "vrana/adminer": "<=4.8.1", + "vrana/adminer": "<5.4.2", "vufind/vufind": ">=2,<9.1.1", "waldhacker/hcaptcha": "<2.1.2", "wallabag/tcpdf": "<6.2.22", "wallabag/wallabag": "<2.6.11", "wanglelecc/laracms": "<=1.0.3", "wapplersystems/a21glossary": "<=0.4.10", - "web-auth/webauthn-framework": ">=3.3,<3.3.4|>=4.5,<4.9", - "web-auth/webauthn-lib": ">=4.5,<4.9", + "web-auth/webauthn-framework": ">=3.3,<3.3.4|>=4.5,<4.9|>=5.2,<5.2.4", + "web-auth/webauthn-lib": ">=4.5,<4.9|>=5.2,<5.2.4", + "web-auth/webauthn-symfony-bundle": ">=5.2,<5.2.4", "web-feet/coastercms": "==5.5", "web-tp3/wec_map": "<3.0.3", "webbuilders-group/silverstripe-kapost-bridge": "<0.4", @@ -6907,8 +6966,8 @@ "wikibase/wikibase": "<=1.39.3", "wikimedia/parsoid": "<0.12.2", "willdurand/js-translation-bundle": "<2.1.1", - "winter/wn-backend-module": "<1.2.4", - "winter/wn-cms-module": "<1.0.476|>=1.1,<1.1.11|>=1.2,<1.2.7", + "winter/wn-backend-module": "<1.2.12", + "winter/wn-cms-module": "<=1.2.9", "winter/wn-dusk-plugin": "<2.1", "winter/wn-system-module": "<1.2.4", "wintercms/winter": "<=1.2.3", @@ -6920,10 +6979,12 @@ "wpanel/wpanel4-cms": "<=4.3.1", "wpcloud/wp-stateless": "<3.2", "wpglobus/wpglobus": "<=1.9.6", - "wwbn/avideo": "<14.3", + "wpmetabox/meta-box": "<5.11.2", + "wwbn/avideo": "<=26", "xataface/xataface": "<3", "xpressengine/xpressengine": "<3.0.15", "yab/quarx": "<2.4.5", + "yansongda/pay": "<=3.7.19", "yeswiki/yeswiki": "<=4.5.4", "yetiforce/yetiforce-crm": "<6.5", "yidashi/yii2cmf": "<=2", @@ -6939,7 +7000,8 @@ "yiisoft/yii2-redis": "<2.0.20", "yikesinc/yikes-inc-easy-mailchimp-extender": "<6.8.6", "yoast-seo-for-typo3/yoast_seo": "<7.2.3", - "yourls/yourls": "<=1.8.2", + "yoast/duplicate-post": "<=4.5", + "yourls/yourls": "<=1.10.2", "yuan1994/tpadmin": "<=1.3.12", "yungifez/skuul": "<=2.6.5", "z-push/z-push-dev": "<2.7.6", @@ -6979,7 +7041,8 @@ "zf-commons/zfc-user": "<1.2.2", "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", "zfr/zfr-oauth2-server-module": "<0.1.2", - "zoujingli/thinkadmin": "<=6.1.53" + "zoujingli/thinkadmin": "<=6.1.53", + "zumba/json-serializer": "<3.2.3" }, "type": "metapackage", "notification-url": "https://packagist.org/downloads/", @@ -7016,20 +7079,20 @@ "type": "tidelift" } ], - "time": "2025-12-10T19:05:59+00:00" + "time": "2026-03-25T22:13:18+00:00" }, { "name": "sanmai/di-container", - "version": "0.1.5", + "version": "0.1.12", "source": { "type": "git", "url": "https://github.com/sanmai/di-container.git", - "reference": "355534ad7970fc7dab4211ecaf2da5c546855ee8" + "reference": "8b9ad72f6ac1f9e185e5bd060dc9479cb5191d8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sanmai/di-container/zipball/355534ad7970fc7dab4211ecaf2da5c546855ee8", - "reference": "355534ad7970fc7dab4211ecaf2da5c546855ee8", + "url": "https://api.github.com/repos/sanmai/di-container/zipball/8b9ad72f6ac1f9e185e5bd060dc9479cb5191d8b", + "reference": "8b9ad72f6ac1f9e185e5bd060dc9479cb5191d8b", "shasum": "" }, "require": { @@ -7040,14 +7103,18 @@ "require-dev": { "ergebnis/composer-normalize": "^2.8", "friendsofphp/php-cs-fixer": "^3.17", - "infection/infection": ">=0.29", + "infection/infection": ">=0.31", "php-coveralls/php-coveralls": "^2.4.1", + "phpbench/phpbench": "^1.4", "phpstan/extension-installer": "^1.4", "phpunit/phpunit": "^11.5.25", "sanmai/phpstan-rules": "^0.3.10" }, "type": "library", "extra": { + "branch-alias": { + "dev-main": "0.1.x-dev" + }, "preferred-install": "dist" }, "autoload": { @@ -7083,7 +7150,7 @@ ], "support": { "issues": "https://github.com/sanmai/di-container/issues", - "source": "https://github.com/sanmai/di-container/tree/0.1.5" + "source": "https://github.com/sanmai/di-container/tree/0.1.12" }, "funding": [ { @@ -7091,20 +7158,20 @@ "type": "github" } ], - "time": "2025-08-04T09:43:58+00:00" + "time": "2026-01-27T08:25:46+00:00" }, { "name": "sanmai/duoclock", - "version": "0.1.1", + "version": "0.1.3", "source": { "type": "git", "url": "https://github.com/sanmai/DuoClock.git", - "reference": "30aa40092396dc96b68c8e8d49162619574477e2" + "reference": "47461e3ff65b7308635047831a55615652e7be1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sanmai/DuoClock/zipball/30aa40092396dc96b68c8e8d49162619574477e2", - "reference": "30aa40092396dc96b68c8e8d49162619574477e2", + "url": "https://api.github.com/repos/sanmai/DuoClock/zipball/47461e3ff65b7308635047831a55615652e7be1a", + "reference": "47461e3ff65b7308635047831a55615652e7be1a", "shasum": "" }, "require": { @@ -7122,8 +7189,7 @@ "phpstan/extension-installer": "^1.4", "phpstan/phpstan": "^2", "phpunit/phpunit": "^11.5.25", - "sanmai/phpstan-rules": "^0.3.1", - "vimeo/psalm": "^6.12" + "sanmai/phpstan-rules": "^0.3.1" }, "type": "library", "extra": { @@ -7147,7 +7213,7 @@ "description": "PHP time mocking for tests - PSR-20 clock with mockable sleep(), time(), and TimeSpy for PHPUnit testing", "support": { "issues": "https://github.com/sanmai/DuoClock/issues", - "source": "https://github.com/sanmai/DuoClock/tree/0.1.1" + "source": "https://github.com/sanmai/DuoClock/tree/0.1.3" }, "funding": [ { @@ -7155,7 +7221,7 @@ "type": "github" } ], - "time": "2025-07-28T02:17:28+00:00" + "time": "2025-12-26T06:12:34+00:00" }, { "name": "sanmai/later", @@ -7223,16 +7289,16 @@ }, { "name": "sanmai/pipeline", - "version": "7.5", + "version": "7.9", "source": { "type": "git", "url": "https://github.com/sanmai/pipeline.git", - "reference": "c3b87db671ee0bc286860bd13bdb7cfc108b7d7e" + "reference": "d7046ecce91ae57fca403be694888371a21250eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sanmai/pipeline/zipball/c3b87db671ee0bc286860bd13bdb7cfc108b7d7e", - "reference": "c3b87db671ee0bc286860bd13bdb7cfc108b7d7e", + "url": "https://api.github.com/repos/sanmai/pipeline/zipball/d7046ecce91ae57fca403be694888371a21250eb", + "reference": "d7046ecce91ae57fca403be694888371a21250eb", "shasum": "" }, "require": { @@ -7242,7 +7308,7 @@ "ergebnis/composer-normalize": "^2.8", "esi/phpunit-coverage-check": ">2", "friendsofphp/php-cs-fixer": "^3.17", - "infection/infection": ">=0.30.3", + "infection/infection": ">=0.32.3", "league/pipeline": "^0.3 || ^1.0", "php-coveralls/php-coveralls": "^2.4.1", "phpstan/extension-installer": "^1.4", @@ -7255,7 +7321,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "v6.x-dev" + "dev-main": "7.x-dev" } }, "autoload": { @@ -7279,7 +7345,7 @@ "description": "General-purpose collections pipeline", "support": { "issues": "https://github.com/sanmai/pipeline/issues", - "source": "https://github.com/sanmai/pipeline/tree/7.5" + "source": "https://github.com/sanmai/pipeline/tree/7.9" }, "funding": [ { @@ -7287,7 +7353,7 @@ "type": "github" } ], - "time": "2025-11-05T10:54:07+00:00" + "time": "2026-01-16T11:54:05+00:00" }, { "name": "sebastian/cli-parser", @@ -7461,16 +7527,16 @@ }, { "name": "sebastian/comparator", - "version": "6.3.2", + "version": "6.3.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8" + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85c77556683e6eee4323e4c5468641ca0237e2e8", - "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", "shasum": "" }, "require": { @@ -7529,7 +7595,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.2" + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.3" }, "funding": [ { @@ -7549,7 +7615,7 @@ "type": "tidelift" } ], - "time": "2025-08-10T08:07:46+00:00" + "time": "2026-01-24T09:26:40+00:00" }, { "name": "sebastian/complexity", @@ -8473,16 +8539,16 @@ }, { "name": "symfony/framework-bundle", - "version": "v8.0.0", + "version": "v8.0.7", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "01cdaf3f26e981c3d9dc87a13cdf7352a8cf6ef8" + "reference": "6a43d76538d52d4b7660f07054a07f8346f73eae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/01cdaf3f26e981c3d9dc87a13cdf7352a8cf6ef8", - "reference": "01cdaf3f26e981c3d9dc87a13cdf7352a8cf6ef8", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/6a43d76538d52d4b7660f07054a07f8346f73eae", + "reference": "6a43d76538d52d4b7660f07054a07f8346f73eae", "shasum": "" }, "require": { @@ -8490,8 +8556,8 @@ "ext-xml": "*", "php": ">=8.4", "symfony/cache": "^7.4|^8.0", - "symfony/config": "^7.4|^8.0", - "symfony/dependency-injection": "^7.4|^8.0", + "symfony/config": "^7.4.4|^8.0.4", + "symfony/dependency-injection": "^7.4.4|^8.0.4", "symfony/deprecation-contracts": "^2.5|^3", "symfony/error-handler": "^7.4|^8.0", "symfony/event-dispatcher": "^7.4|^8.0", @@ -8505,8 +8571,8 @@ }, "conflict": { "doctrine/persistence": "<1.3", - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", + "phpdocumentor/reflection-docblock": "<5.2|>=7", + "phpdocumentor/type-resolver": "<1.5.1", "symfony/console": "<7.4", "symfony/form": "<7.4", "symfony/json-streamer": "<7.4", @@ -8520,7 +8586,8 @@ "require-dev": { "doctrine/persistence": "^1.3|^2|^3", "dragonmantank/cron-expression": "^3.1", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "phpdocumentor/reflection-docblock": "^5.2|^6.0", + "phpstan/phpdoc-parser": "^1.0|^2.0", "seld/jsonlint": "^1.10", "symfony/asset": "^7.4|^8.0", "symfony/asset-mapper": "^7.4|^8.0", @@ -8554,7 +8621,7 @@ "symfony/string": "^7.4|^8.0", "symfony/translation": "^7.4|^8.0", "symfony/twig-bundle": "^7.4|^8.0", - "symfony/type-info": "^7.4|^8.0", + "symfony/type-info": "^7.4.1|^8.0.1", "symfony/uid": "^7.4|^8.0", "symfony/validator": "^7.4|^8.0", "symfony/web-link": "^7.4|^8.0", @@ -8588,7 +8655,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v8.0.0" + "source": "https://github.com/symfony/framework-bundle/tree/v8.0.7" }, "funding": [ { @@ -8608,7 +8675,7 @@ "type": "tidelift" } ], - "time": "2025-11-21T13:19:49+00:00" + "time": "2026-03-06T15:40:00+00:00" }, { "name": "symfony/polyfill-php80", @@ -8859,20 +8926,20 @@ }, { "name": "symfony/process", - "version": "v7.4.0", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "7ca8dc2d0dcf4882658313aba8be5d9fd01026c8" + "reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/7ca8dc2d0dcf4882658313aba8be5d9fd01026c8", - "reference": "7ca8dc2d0dcf4882658313aba8be5d9fd01026c8", + "url": "https://api.github.com/repos/symfony/process/zipball/b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674", + "reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "type": "library", "autoload": { @@ -8900,7 +8967,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.4.0" + "source": "https://github.com/symfony/process/tree/v8.0.5" }, "funding": [ { @@ -8920,20 +8987,20 @@ "type": "tidelift" } ], - "time": "2025-10-16T11:21:06+00:00" + "time": "2026-01-26T15:08:38+00:00" }, { "name": "symfony/routing", - "version": "v8.0.0", + "version": "v8.0.6", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "8da1cf2796c9cef09b170208ddb9bc00d997502e" + "reference": "053c40fd46e1d19c5c5a94cada93ce6c3facdd55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/8da1cf2796c9cef09b170208ddb9bc00d997502e", - "reference": "8da1cf2796c9cef09b170208ddb9bc00d997502e", + "url": "https://api.github.com/repos/symfony/routing/zipball/053c40fd46e1d19c5c5a94cada93ce6c3facdd55", + "reference": "053c40fd46e1d19c5c5a94cada93ce6c3facdd55", "shasum": "" }, "require": { @@ -8980,7 +9047,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v8.0.0" + "source": "https://github.com/symfony/routing/tree/v8.0.6" }, "funding": [ { @@ -9000,7 +9067,7 @@ "type": "tidelift" } ], - "time": "2025-11-27T08:09:45+00:00" + "time": "2026-02-25T16:59:43+00:00" }, { "name": "symfony/translation-contracts", @@ -9086,16 +9153,16 @@ }, { "name": "symfony/twig-bridge", - "version": "v8.0.0", + "version": "v8.0.7", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "6fd7fdb536c0c7b6bd54080f0785841ff794c1fd" + "reference": "e0539400f53d8305945c06eba7e8df007402f5e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/6fd7fdb536c0c7b6bd54080f0785841ff794c1fd", - "reference": "6fd7fdb536c0c7b6bd54080f0785841ff794c1fd", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/e0539400f53d8305945c06eba7e8df007402f5e2", + "reference": "e0539400f53d8305945c06eba7e8df007402f5e2", "shasum": "" }, "require": { @@ -9104,13 +9171,14 @@ "twig/twig": "^3.21" }, "conflict": { - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0" + "phpdocumentor/reflection-docblock": "<5.2|>=7", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/form": "<7.4.4|>8.0,<8.0.4" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3|^4", "league/html-to-markdown": "^5.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "phpdocumentor/reflection-docblock": "^5.2|^6.0", "symfony/asset": "^7.4|^8.0", "symfony/asset-mapper": "^7.4|^8.0", "symfony/console": "^7.4|^8.0", @@ -9118,7 +9186,7 @@ "symfony/emoji": "^7.4|^8.0", "symfony/expression-language": "^7.4|^8.0", "symfony/finder": "^7.4|^8.0", - "symfony/form": "^7.4|^8.0", + "symfony/form": "^7.4.4|^8.0.4", "symfony/html-sanitizer": "^7.4|^8.0", "symfony/http-foundation": "^7.4|^8.0", "symfony/http-kernel": "^7.4|^8.0", @@ -9168,7 +9236,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v8.0.0" + "source": "https://github.com/symfony/twig-bridge/tree/v8.0.7" }, "funding": [ { @@ -9188,20 +9256,20 @@ "type": "tidelift" } ], - "time": "2025-11-05T14:36:47+00:00" + "time": "2026-03-04T15:37:12+00:00" }, { "name": "symfony/twig-bundle", - "version": "v8.0.0", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "4505b860fb07951521ae55eec43007eef67222a5" + "reference": "5a68f2e0e06996514bf04900c3982b93b42487af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/4505b860fb07951521ae55eec43007eef67222a5", - "reference": "4505b860fb07951521ae55eec43007eef67222a5", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/5a68f2e0e06996514bf04900c3982b93b42487af", + "reference": "5a68f2e0e06996514bf04900c3982b93b42487af", "shasum": "" }, "require": { @@ -9252,7 +9320,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v8.0.0" + "source": "https://github.com/symfony/twig-bundle/tree/v8.0.4" }, "funding": [ { @@ -9272,20 +9340,20 @@ "type": "tidelift" } ], - "time": "2025-10-07T12:38:08+00:00" + "time": "2026-01-06T12:43:21+00:00" }, { "name": "symfony/uid", - "version": "v8.0.0", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "8395a2cc2ed49aa68f602c5c489f60ab853893df" + "reference": "8b81bd3700f5c1913c22a3266a647aa1bb974435" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/8395a2cc2ed49aa68f602c5c489f60ab853893df", - "reference": "8395a2cc2ed49aa68f602c5c489f60ab853893df", + "url": "https://api.github.com/repos/symfony/uid/zipball/8b81bd3700f5c1913c22a3266a647aa1bb974435", + "reference": "8b81bd3700f5c1913c22a3266a647aa1bb974435", "shasum": "" }, "require": { @@ -9330,7 +9398,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v8.0.0" + "source": "https://github.com/symfony/uid/tree/v8.0.4" }, "funding": [ { @@ -9350,20 +9418,20 @@ "type": "tidelift" } ], - "time": "2025-09-26T07:52:19+00:00" + "time": "2026-01-03T23:40:55+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v8.0.0", + "version": "v8.0.7", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "82503c06aa67202092a3bc06c6ea6aaec53a2fd2" + "reference": "141336fd018b9ac77ba4910c04c2ca05c35e7ad2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/82503c06aa67202092a3bc06c6ea6aaec53a2fd2", - "reference": "82503c06aa67202092a3bc06c6ea6aaec53a2fd2", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/141336fd018b9ac77ba4910c04c2ca05c35e7ad2", + "reference": "141336fd018b9ac77ba4910c04c2ca05c35e7ad2", "shasum": "" }, "require": { @@ -9415,7 +9483,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v8.0.0" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v8.0.7" }, "funding": [ { @@ -9435,20 +9503,20 @@ "type": "tidelift" } ], - "time": "2025-11-20T12:42:53+00:00" + "time": "2026-03-04T08:20:53+00:00" }, { "name": "thecodingmachine/safe", - "version": "v3.3.0", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/thecodingmachine/safe.git", - "reference": "2cdd579eeaa2e78e51c7509b50cc9fb89a956236" + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/2cdd579eeaa2e78e51c7509b50cc9fb89a956236", - "reference": "2cdd579eeaa2e78e51c7509b50cc9fb89a956236", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19", + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19", "shasum": "" }, "require": { @@ -9558,7 +9626,7 @@ "description": "PHP core functions that throw exceptions instead of returning FALSE on error", "support": { "issues": "https://github.com/thecodingmachine/safe/issues", - "source": "https://github.com/thecodingmachine/safe/tree/v3.3.0" + "source": "https://github.com/thecodingmachine/safe/tree/v3.4.0" }, "funding": [ { @@ -9569,12 +9637,16 @@ "url": "https://github.com/shish", "type": "github" }, + { + "url": "https://github.com/silasjoisten", + "type": "github" + }, { "url": "https://github.com/staabm", "type": "github" } ], - "time": "2025-05-14T06:15:44+00:00" + "time": "2026-02-04T18:08:13+00:00" }, { "name": "theseer/tokenizer", @@ -9628,16 +9700,16 @@ }, { "name": "twig/twig", - "version": "v3.22.1", + "version": "v3.24.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "1de2ec1fc43ab58a4b7e80b214b96bfc895750f3" + "reference": "a6769aefb305efef849dc25c9fd1653358c148f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/1de2ec1fc43ab58a4b7e80b214b96bfc895750f3", - "reference": "1de2ec1fc43ab58a4b7e80b214b96bfc895750f3", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/a6769aefb305efef849dc25c9fd1653358c148f0", + "reference": "a6769aefb305efef849dc25c9fd1653358c148f0", "shasum": "" }, "require": { @@ -9647,7 +9719,8 @@ "symfony/polyfill-mbstring": "^1.3" }, "require-dev": { - "phpstan/phpstan": "^2.0", + "php-cs-fixer/shim": "^3.0@stable", + "phpstan/phpstan": "^2.0@stable", "psr/container": "^1.0|^2.0", "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, @@ -9691,7 +9764,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.22.1" + "source": "https://github.com/twigphp/Twig/tree/v3.24.0" }, "funding": [ { @@ -9703,27 +9776,27 @@ "type": "tidelift" } ], - "time": "2025-11-16T16:01:12+00:00" + "time": "2026-03-17T21:31:11+00:00" }, { "name": "webmozart/assert", - "version": "1.12.1", + "version": "2.1.6", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" + "reference": "ff31ad6efc62e66e518fbab1cde3453d389bcdc8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", - "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/ff31ad6efc62e66e518fbab1cde3453d389bcdc8", + "reference": "ff31ad6efc62e66e518fbab1cde3453d389bcdc8", "shasum": "" }, "require": { "ext-ctype": "*", "ext-date": "*", "ext-filter": "*", - "php": "^7.2 || ^8.0" + "php": "^8.2" }, "suggest": { "ext-intl": "", @@ -9733,7 +9806,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.10-dev" + "dev-feature/2-0": "2.0-dev" } }, "autoload": { @@ -9749,6 +9822,10 @@ { "name": "Bernhard Schussek", "email": "bschussek@gmail.com" + }, + { + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com" } ], "description": "Assertions to validate method input/output with nice error messages.", @@ -9759,9 +9836,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.12.1" + "source": "https://github.com/webmozarts/assert/tree/2.1.6" }, - "time": "2025-10-29T15:56:20+00:00" + "time": "2026-02-27T10:28:38+00:00" }, { "name": "wnx/commonmark-markdown-renderer", diff --git a/docs/pages/configuration.md b/docs/pages/configuration.md index df495fe5..019668ab 100644 --- a/docs/pages/configuration.md +++ b/docs/pages/configuration.md @@ -496,11 +496,10 @@ patchlevel_event_sourcing: default_exceptions: - Patchlevel\EventSourcing\Repository\AggregateOutdated ``` - !!! note You can find out more about instant retry [here](https://event-sourcing.patchlevel.io/latest/command_bus/#instant-retry). - + ## Query Bus You can enable the query bus integration to use queries to retrieve data from your system. For this bundle we provide @@ -570,6 +569,7 @@ We can then use this messenger or event bus in event sourcing: ```yaml patchlevel_event_sourcing: event_bus: + type: symfony service: event.bus ``` Since the event bus was replaced, event sourcing own attributes no longer work. @@ -674,13 +674,12 @@ patchlevel_event_sourcing: cryptography: use_encrypted_field_name: true ``` - !!! tip You should activate `use_encrypted_field_name` to mark the fields that are encrypted. That allows you later to migrate not encrypted fields to encrypted fields. If you have already encrypted fields, you can activate `fallback_to_field_name` to use the old field name as fallback. - + If you want to use another algorithm, you can specify this here: ```yaml diff --git a/docs/pages/usage.md b/docs/pages/usage.md index fa034b13..93b698cd 100644 --- a/docs/pages/usage.md +++ b/docs/pages/usage.md @@ -153,28 +153,48 @@ This bundle adds more Symfony specific normalizers in addition to the existing b You can find the other build-in normalizers [here](https://event-sourcing.patchlevel.io/latest/normalizer/#built-in-normalizer) -### Uuid +!!! tip + + The Hydrator can automatically determine the appropriate normalizer based on the data type and annotations. + You don't have to specify the normalizer manually like in the example below. + +### Uid -With the `Uuid` Normalizer, as the name suggests, you can convert Symfony Uuid objects to a string and back again. +With the `Uid` Normalizer, as the name suggests, you can convert Symfony Uuid and Ulid objects to a string and back again. ```php -use Patchlevel\EventSourcingBundle\Normalizer\SymfonyUuidNormalizer; +use Patchlevel\EventSourcingBundle\Normalizer\UidNormalizer; use Symfony\Component\Uid\Uuid; final class DTO { - #[SymfonyUuidNormalizer] + #[UidNormalizer] public Uuid $id; } ``` !!! warning - The symfony uuid don't implement the `AggregateId` interface, so it can be used as aggregate id. + The symfony uuid don't implement the `AggregateId` interface, so it can not be used as an aggregate id directly. + Use instead the `Patchlevel\EventSourcing\Aggregate\Uuid` class. !!! tip Use the `Uuid` implementation and `IdNormalizer` from the library to use it as an aggregate id. +### DatePoint + +With the `DatePoint` Normalizer, you can convert a `DatePoint` object to a string and back again. + +```php +use Patchlevel\EventSourcingBundle\Normalizer\DatePointNormalizer; +use Symfony\Component\Clock\DatePoint; + +final class DTO +{ + #[DatePointNormalizer] + public DatePoint $createdAt; +} +``` ## Upcasting ```php diff --git a/docs/requirements.txt b/docs/requirements.txt index 83a01a64..e4bf8371 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,11 +1,11 @@ mkdocs==1.6.1 -mike==2.1.3 -markdown==3.10 -mkdocs-material==9.7.0 +mike==2.1.4 +markdown==3.10.2 +mkdocs-material==9.7.6 # Markdown extensions Pygments==2.19.2 -pymdown-extensions==10.18 +pymdown-extensions==10.21 # MkDocs plugins mkdocs-material-extensions==1.3.1 \ No newline at end of file diff --git a/phpcs.xml.dist b/phpcs.xml.dist index b2ebef97..5feb11b4 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -6,6 +6,7 @@ src + tests diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 2a5fff41..e9cf1917 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -18,6 +18,30 @@ parameters: count: 1 path: src/DependencyInjection/QueryHandlerCompilerPass.php + - + message: '#^Method Patchlevel\\EventSourcingBundle\\Normalizer\\SymfonyGuesser\:\:guess\(\) has parameter \$type with generic class Symfony\\Component\\TypeInfo\\Type\\ObjectType but does not specify its types\: T$#' + identifier: missingType.generics + count: 1 + path: src/Normalizer/SymfonyGuesser.php + + - + message: '#^Parameter \#1 \$uidClass of class Patchlevel\\EventSourcingBundle\\Normalizer\\UidNormalizer constructor expects class\-string\\|null, string given\.$#' + identifier: argument.type + count: 1 + path: src/Normalizer/SymfonyGuesser.php + + - + message: '#^Property Patchlevel\\EventSourcingBundle\\Normalizer\\UidNormalizer\:\:\$uidClass \(class\-string\\|null\) does not accept string\.$#' + identifier: assign.propertyType + count: 1 + path: src/Normalizer/UidNormalizer.php + + - + message: '#^Method Fixtures\\DummyGuesser\:\:guess\(\) has parameter \$type with generic class Symfony\\Component\\TypeInfo\\Type\\ObjectType but does not specify its types\: T$#' + identifier: missingType.generics + count: 1 + path: tests/Fixtures/DummyGuesser.php + - message: '#^Property Patchlevel\\EventSourcingBundle\\Tests\\Fixtures\\Profile\:\:\$id is never read, only written\.$#' identifier: property.onlyWritten diff --git a/src/Command/StoreMigrateCommand.php b/src/Command/StoreMigrateCommand.php index cbd7a2c4..a9342d89 100644 --- a/src/Command/StoreMigrateCommand.php +++ b/src/Command/StoreMigrateCommand.php @@ -17,6 +17,7 @@ use function count; +/** @deprecated since version 3.15.0, to be removed in 4.0.0. Use the StoreMigrateCommand from the patchlevel/event-sourcing package instead. */ #[AsCommand( 'event-sourcing:store:migrate', 'migrate events from one store to another', diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 001b3b9b..b6fb37a4 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -42,8 +42,13 @@ * enabled: bool, * ids: list, * groups: list, + * exclude_url: string|null * }, - * rebuild_after_file_change: array{enabled: bool, cache_pool: string}, + * rebuild_after_file_change: array{ + * enabled: bool, + * cache_pool: string, + * exclude_url: string|null + * }, * gap_detection: array{ * enabled: bool, * retries_in_ms: list, @@ -277,6 +282,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->children() ->arrayNode('ids')->scalarPrototype()->end()->end() ->arrayNode('groups')->scalarPrototype()->end()->end() + ->scalarNode('exclude_url')->defaultValue('^/_(wdt|profiler|error)')->end() ->end() ->end() @@ -285,6 +291,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->addDefaultsIfNotSet() ->children() ->scalarNode('cache_pool')->defaultValue('cache.app')->end() + ->scalarNode('exclude_url')->defaultValue('^/_(wdt|profiler|error)')->end() ->end() ->end() diff --git a/src/DependencyInjection/DoctrineCleanupCompilerPass.php b/src/DependencyInjection/DoctrineCleanupCompilerPass.php new file mode 100644 index 00000000..7e82bc55 --- /dev/null +++ b/src/DependencyInjection/DoctrineCleanupCompilerPass.php @@ -0,0 +1,30 @@ +has('doctrine')) { + $container->register(DbalCleanupTaskHandler::class, DbalCleanupTaskHandler::class) + ->setArguments([ + new Reference('doctrine'), + ]) + ->addTag('event_sourcing.cleanup_task_handler'); + } elseif ($container->has('event_sourcing.dbal_public_connection')) { + $container->register(DbalCleanupTaskHandler::class, DbalCleanupTaskHandler::class) + ->setArguments([ + new Reference('event_sourcing.dbal_public_connection'), + ]) + ->addTag('event_sourcing.cleanup_task_handler'); + } + } +} diff --git a/src/DependencyInjection/PatchlevelEventSourcingExtension.php b/src/DependencyInjection/PatchlevelEventSourcingExtension.php index 4f8d6bf3..bf88497e 100644 --- a/src/DependencyInjection/PatchlevelEventSourcingExtension.php +++ b/src/DependencyInjection/PatchlevelEventSourcingExtension.php @@ -32,9 +32,11 @@ use Patchlevel\EventSourcing\Console\Command\SchemaUpdateCommand; use Patchlevel\EventSourcing\Console\Command\ShowAggregateCommand; use Patchlevel\EventSourcing\Console\Command\ShowCommand; +use Patchlevel\EventSourcing\Console\Command\StoreMigrateCommand; use Patchlevel\EventSourcing\Console\Command\SubscriptionBootCommand; use Patchlevel\EventSourcing\Console\Command\SubscriptionPauseCommand; use Patchlevel\EventSourcing\Console\Command\SubscriptionReactivateCommand; +use Patchlevel\EventSourcing\Console\Command\SubscriptionRefreshCommand; use Patchlevel\EventSourcing\Console\Command\SubscriptionRemoveCommand; use Patchlevel\EventSourcing\Console\Command\SubscriptionRunCommand; use Patchlevel\EventSourcing\Console\Command\SubscriptionSetupCommand; @@ -94,6 +96,9 @@ use Patchlevel\EventSourcing\Store\Store; use Patchlevel\EventSourcing\Store\StreamDoctrineDbalStore; use Patchlevel\EventSourcing\Store\StreamReadOnlyStore; +use Patchlevel\EventSourcing\Subscription\Cleanup\Cleaner; +use Patchlevel\EventSourcing\Subscription\Cleanup\CleanupTaskHandler; +use Patchlevel\EventSourcing\Subscription\Cleanup\DefaultCleaner; use Patchlevel\EventSourcing\Subscription\Engine\CatchUpSubscriptionEngine; use Patchlevel\EventSourcing\Subscription\Engine\DefaultSubscriptionEngine; use Patchlevel\EventSourcing\Subscription\Engine\GapResolverStoreMessageLoader; @@ -116,12 +121,12 @@ use Patchlevel\EventSourcing\Subscription\Subscriber\SubscriberHelper; use Patchlevel\EventSourcingBundle\Attribute\AsListener; use Patchlevel\EventSourcingBundle\Clock\FrozenClockFactory; -use Patchlevel\EventSourcingBundle\Command\StoreMigrateCommand; use Patchlevel\EventSourcingBundle\CommandBus\SymfonyCommandBus; use Patchlevel\EventSourcingBundle\DataCollector\EventSourcingCollector; use Patchlevel\EventSourcingBundle\DataCollector\MessageCollectorEventBus; use Patchlevel\EventSourcingBundle\Doctrine\DbalConnectionFactory; use Patchlevel\EventSourcingBundle\EventBus\SymfonyEventBus; +use Patchlevel\EventSourcingBundle\Normalizer\SymfonyGuesser; use Patchlevel\EventSourcingBundle\QueryBus\SymfonyQueryBus; use Patchlevel\EventSourcingBundle\RequestListener\AutoSetupListener; use Patchlevel\EventSourcingBundle\RequestListener\SubscriptionRebuildAfterFileChangeListener; @@ -136,6 +141,9 @@ use Patchlevel\Hydrator\Cryptography\PayloadCryptographer; use Patchlevel\Hydrator\Cryptography\PersonalDataPayloadCryptographer; use Patchlevel\Hydrator\Cryptography\Store\CipherKeyStore; +use Patchlevel\Hydrator\Guesser\BuiltInGuesser; +use Patchlevel\Hydrator\Guesser\ChainGuesser; +use Patchlevel\Hydrator\Guesser\Guesser; use Patchlevel\Hydrator\Hydrator; use Patchlevel\Hydrator\Metadata\AttributeMetadataFactory; use Patchlevel\Hydrator\Metadata\MetadataFactory; @@ -459,7 +467,10 @@ static function (ChildDefinition $definition): void { continue; } - throw new InvalidArgumentException(sprintf('Unknown retry strategy type "%s"', $strategyConfig['type'])); + throw new InvalidArgumentException(sprintf( + 'Unknown retry strategy type "%s"', + $strategyConfig['type'], + )); } } @@ -516,6 +527,16 @@ static function (ChildDefinition $definition): void { $container->setAlias(SubscriberAccessorRepository::class, MetadataSubscriberAccessorRepository::class); + $container->registerForAutoconfiguration(CleanupTaskHandler::class) + ->addTag('event_sourcing.cleanup_task_handler'); + + $container->register(DefaultCleaner::class) + ->setArguments([ + new TaggedIteratorArgument('event_sourcing.cleanup_task_handler'), + ]); + + $container->setAlias(Cleaner::class, DefaultCleaner::class); + $container->register(DefaultSubscriptionEngine::class) ->setArguments([ new Reference(MessageLoader::class), @@ -523,6 +544,7 @@ static function (ChildDefinition $definition): void { new Reference(SubscriberAccessorRepository::class), new Reference(RetryStrategyRepository::class), new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), + new Reference(Cleaner::class), ]) ->addTag('monolog.logger', ['channel' => 'event_sourcing']); @@ -572,6 +594,7 @@ static function (ChildDefinition $definition): void { new Reference(SubscriptionEngine::class), $config['subscription']['auto_setup']['ids'] ?: null, $config['subscription']['auto_setup']['groups'] ?: null, + $config['subscription']['auto_setup']['exclude_url'] ?: null, ]) ->addTag('kernel.event_listener', [ 'event' => 'kernel.request', @@ -590,6 +613,7 @@ static function (ChildDefinition $definition): void { new TaggedIteratorArgument('event_sourcing.subscriber'), new Reference($config['subscription']['rebuild_after_file_change']['cache_pool']), new Reference(SubscriberMetadataFactory::class), + $config['subscription']['rebuild_after_file_change']['exclude_url'] ?: null, ]) ->addTag('kernel.event_listener', [ 'event' => 'kernel.request', @@ -600,7 +624,24 @@ static function (ChildDefinition $definition): void { private function configureHydrator(ContainerBuilder $container): void { - $container->register(AttributeMetadataFactory::class); + $container->register(ChainGuesser::class) + ->setArguments([new TaggedIteratorArgument('event_sourcing.hydrator.guesser')]); + + $container->register(BuiltInGuesser::class) + ->addTag('event_sourcing.hydrator.guesser', ['priority' => -100]); + + $container->register(SymfonyGuesser::class) + ->addTag('event_sourcing.hydrator.guesser', ['priority' => -50]); + + $container->registerForAutoconfiguration(Guesser::class) + ->addTag('event_sourcing.hydrator.guesser'); + + $container->register(AttributeMetadataFactory::class) + ->setArguments([ + null, + new Reference(ChainGuesser::class), + ]); + $container->setAlias(MetadataFactory::class, AttributeMetadataFactory::class); $container->register(MetadataHydrator::class) @@ -981,6 +1022,12 @@ private function configureCommands(ContainerBuilder $container): void new Reference(SubscriptionEngine::class), ]) ->addTag('console.command'); + + $container->register(SubscriptionRefreshCommand::class) + ->setArguments([ + new Reference(SubscriptionEngine::class), + ]) + ->addTag('console.command'); } /** @param Config $config */ diff --git a/src/Normalizer/DatePointNormalizer.php b/src/Normalizer/DatePointNormalizer.php new file mode 100644 index 00000000..a30ab753 --- /dev/null +++ b/src/Normalizer/DatePointNormalizer.php @@ -0,0 +1,47 @@ +format($this->format); + } + + public function denormalize(mixed $value): DatePoint|null + { + if ($value === null) { + return null; + } + + if (!is_string($value)) { + throw InvalidArgument::withWrongType('string|null', $value); + } + + return DatePoint::createFromFormat($this->format, $value); + } +} diff --git a/src/Normalizer/SymfonyGuesser.php b/src/Normalizer/SymfonyGuesser.php new file mode 100644 index 00000000..68598570 --- /dev/null +++ b/src/Normalizer/SymfonyGuesser.php @@ -0,0 +1,27 @@ +isIdentifiedBy(AbstractUid::class)) { + return new UidNormalizer($type->getClassName()); + } + + if ($type->isIdentifiedBy(DatePoint::class)) { + return new DatePointNormalizer(); + } + + return null; + } +} diff --git a/src/Normalizer/SymfonyUuidNormalizer.php b/src/Normalizer/SymfonyUuidNormalizer.php index 4b168eea..12e59b16 100644 --- a/src/Normalizer/SymfonyUuidNormalizer.php +++ b/src/Normalizer/SymfonyUuidNormalizer.php @@ -11,6 +11,7 @@ use function is_string; +/** @deprecated Use SymfonyUidNormalizer instead, which supports all Uid types, not just Uuid. */ #[Attribute(Attribute::TARGET_PROPERTY)] final class SymfonyUuidNormalizer implements Normalizer { diff --git a/src/Normalizer/UidNormalizer.php b/src/Normalizer/UidNormalizer.php new file mode 100644 index 00000000..b22ff258 --- /dev/null +++ b/src/Normalizer/UidNormalizer.php @@ -0,0 +1,90 @@ +|null */ + private string|null $uidClass = null, + ) { + } + + public function normalize(mixed $value): string|null + { + if ($value === null) { + return null; + } + + if (!$value instanceof AbstractUid) { + throw InvalidArgument::withWrongType(AbstractUid::class . '|null', $value); + } + + return (string)$value; + } + + public function denormalize(mixed $value): Uuid|null + { + if ($value === null) { + return null; + } + + if (!is_string($value)) { + throw InvalidArgument::withWrongType('string|null', $value); + } + + return Uuid::fromString($value); + } + + public function handleType(Type|null $type): void + { + if ($type === null || $this->uidClass !== null) { + return; + } + + if ($type instanceof NullableType) { + $type = $type->getWrappedType(); + } + + if ($type instanceof GenericType) { + $type = $type->getWrappedType(); + } + + if ($type instanceof TemplateType) { + $type = $type->getWrappedType(); + } + + if (!$type instanceof ObjectType) { + return; + } + + $this->uidClass = $type->getClassName(); + } + + public function getClassName(): string + { + if ($this->uidClass === null) { + throw InvalidType::missingType(); + } + + return $this->uidClass; + } +} diff --git a/src/PatchlevelEventSourcingBundle.php b/src/PatchlevelEventSourcingBundle.php index 81c73768..40d129c9 100644 --- a/src/PatchlevelEventSourcingBundle.php +++ b/src/PatchlevelEventSourcingBundle.php @@ -5,6 +5,7 @@ namespace Patchlevel\EventSourcingBundle; use Patchlevel\EventSourcingBundle\DependencyInjection\CommandHandlerCompilerPass; +use Patchlevel\EventSourcingBundle\DependencyInjection\DoctrineCleanupCompilerPass; use Patchlevel\EventSourcingBundle\DependencyInjection\HandlerServiceLocatorCompilerPass; use Patchlevel\EventSourcingBundle\DependencyInjection\QueryHandlerCompilerPass; use Patchlevel\EventSourcingBundle\DependencyInjection\RepositoryCompilerPass; @@ -23,5 +24,6 @@ public function build(ContainerBuilder $container): void $container->addCompilerPass(new QueryHandlerCompilerPass(), priority: 100); $container->addCompilerPass(new HandlerServiceLocatorCompilerPass(), priority: -100); $container->addCompilerPass(new TranslatorCompilerPass()); + $container->addCompilerPass(new DoctrineCleanupCompilerPass()); } } diff --git a/src/RequestListener/AutoSetupListener.php b/src/RequestListener/AutoSetupListener.php index 19bdcf13..3e59fd2e 100644 --- a/src/RequestListener/AutoSetupListener.php +++ b/src/RequestListener/AutoSetupListener.php @@ -9,6 +9,8 @@ use Patchlevel\EventSourcing\Subscription\Status; use Symfony\Component\HttpKernel\Event\RequestEvent; +use function preg_match; + final class AutoSetupListener { /** @@ -19,6 +21,7 @@ public function __construct( private readonly SubscriptionEngine $subscriptionEngine, private readonly array|null $ids, private readonly array|null $groups, + private readonly string|null $excludeUrl = null, ) { } @@ -28,6 +31,13 @@ public function onKernelRequest(RequestEvent $event): void return; } + if ( + $this->excludeUrl !== null + && preg_match('#' . $this->excludeUrl . '#', $event->getRequest()->getRequestUri()) + ) { + return; + } + $subscriptions = $this->subscriptionEngine->subscriptions( new SubscriptionEngineCriteria( $this->ids, diff --git a/src/RequestListener/SubscriptionRebuildAfterFileChangeListener.php b/src/RequestListener/SubscriptionRebuildAfterFileChangeListener.php index 3fdbcb4d..df17f965 100644 --- a/src/RequestListener/SubscriptionRebuildAfterFileChangeListener.php +++ b/src/RequestListener/SubscriptionRebuildAfterFileChangeListener.php @@ -14,6 +14,7 @@ use Symfony\Component\HttpKernel\Event\RequestEvent; use function filemtime; +use function preg_match; final class SubscriptionRebuildAfterFileChangeListener { @@ -23,6 +24,7 @@ public function __construct( private readonly iterable $subscribers, private readonly CacheItemPoolInterface $cache, private readonly SubscriberMetadataFactory $metadataFactory = new AttributeSubscriberMetadataFactory(), + private readonly string|null $excludeUrl = null, ) { } @@ -32,6 +34,13 @@ public function onKernelRequest(RequestEvent $event): void return; } + if ( + $this->excludeUrl !== null + && preg_match('#' . $this->excludeUrl . '#', $event->getRequest()->getRequestUri()) + ) { + return; + } + $toRemove = []; $itemsToSave = []; diff --git a/tests/Fixtures/CreateProfile.php b/tests/Fixtures/CreateProfile.php index 6843e2ee..2e3dfc15 100644 --- a/tests/Fixtures/CreateProfile.php +++ b/tests/Fixtures/CreateProfile.php @@ -1,5 +1,7 @@ recordThat(new ProfileCreated($command->id)); diff --git a/tests/Fixtures/ProfileCreated.php b/tests/Fixtures/ProfileCreated.php index a68b091a..27e94239 100644 --- a/tests/Fixtures/ProfileCreated.php +++ b/tests/Fixtures/ProfileCreated.php @@ -1,5 +1,7 @@ dispatch($command); } - public function testRecursiveException(): void { $command = new CreateProfile( @@ -74,7 +73,7 @@ public function testRecursiveException(): void ->with($command) ->willThrowException(new HandlerFailedException( $envelope, - [new HandlerFailedException($envelope, [$internalException])] + [new HandlerFailedException($envelope, [$internalException])], )); $commandBus = new SymfonyCommandBus($messageBus); @@ -82,4 +81,4 @@ public function testRecursiveException(): void $commandBus->dispatch($command); } -} \ No newline at end of file +} diff --git a/tests/Unit/DataCollector/EventSourcingCollectorTest.php b/tests/Unit/DataCollector/EventSourcingCollectorTest.php index f7f24a57..240b5f6b 100644 --- a/tests/Unit/DataCollector/EventSourcingCollectorTest.php +++ b/tests/Unit/DataCollector/EventSourcingCollectorTest.php @@ -40,7 +40,7 @@ public function testCollectData(): void '1', 1, new DateTimeImmutable('2022-07-07T18:55:50+02:00'), - ) + ), ]); $collector = new EventSourcingCollector( @@ -53,7 +53,7 @@ public function testCollectData(): void $collector->collect( new Request(), - new Response() + new Response(), ); self::assertSame(['profile' => Profile::class], $collector->getAggregates()); diff --git a/tests/Unit/EventBus/SymfonyEventBusTest.php b/tests/Unit/EventBus/SymfonyEventBusTest.php index 6d8298c2..1b0220ec 100644 --- a/tests/Unit/EventBus/SymfonyEventBusTest.php +++ b/tests/Unit/EventBus/SymfonyEventBusTest.php @@ -50,4 +50,4 @@ public function testDispatchMultipleMessages(): void $eventBus = new SymfonyEventBus($messageBus); $eventBus->dispatch($message1, $message2); } -} \ No newline at end of file +} diff --git a/tests/Unit/Normalizer/DatePointNormalizerTest.php b/tests/Unit/Normalizer/DatePointNormalizerTest.php new file mode 100644 index 00000000..27b5eca9 --- /dev/null +++ b/tests/Unit/Normalizer/DatePointNormalizerTest.php @@ -0,0 +1,59 @@ +assertEquals(null, $normalizer->normalize(null)); + } + + public function testDenormalizeWithNull(): void + { + $normalizer = new DatePointNormalizer(); + + $this->assertEquals(null, $normalizer->denormalize(null)); + } + + public function testNormalizeWithInvalidArgument(): void + { + $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); + $this->expectExceptionMessage('type "Symfony\Component\Clock\DatePoint|null" was expected but "string" was passed.'); + + $normalizer = new DatePointNormalizer(); + $normalizer->normalize('foo'); + } + + public function testNormalizeWithValue(): void + { + $normalizer = new DatePointNormalizer(); + + self::assertEquals( + $normalizer->normalize(DatePoint::createFromFormat(DatePoint::ATOM, '2024-06-01T12:00:00+00:00')), + '2024-06-01T12:00:00+00:00', + ); + } + + public function testDenormalizeWithValue(): void + { + $normalizer = new DatePointNormalizer(); + + $this->assertEquals( + DatePoint::createFromFormat(DatePoint::ATOM, '2024-06-01T12:00:00+00:00'), + $normalizer->denormalize('2024-06-01T12:00:00+00:00'), + ); + } +} diff --git a/tests/Unit/Normalizer/SymfonyGuesserTest.php b/tests/Unit/Normalizer/SymfonyGuesserTest.php new file mode 100644 index 00000000..c06e803f --- /dev/null +++ b/tests/Unit/Normalizer/SymfonyGuesserTest.php @@ -0,0 +1,54 @@ +guess(new ObjectType($typeClass)); + + self::assertEquals($expectedNormalizer, $normalizer); + } + + /** @return iterable */ + public static function successfulGuessProvider(): iterable + { + yield [Uuid::class, new UidNormalizer(Uuid::class)]; + yield [UuidV4::class, new UidNormalizer(UuidV4::class)]; + yield [UuidV7::class, new UidNormalizer(UuidV7::class)]; + yield [Ulid::class, new UidNormalizer(Ulid::class)]; + yield [DatePoint::class, new DatePointNormalizer()]; + } + + public function testGuessReturnsNullForUnknownType(): void + { + $guesser = new SymfonyGuesser(); + + $normalizer = $guesser->guess(new ObjectType(stdClass::class)); + + self::assertNull($normalizer); + } +} diff --git a/tests/Unit/Normalizer/UidNormalizerTest.php b/tests/Unit/Normalizer/UidNormalizerTest.php new file mode 100644 index 00000000..d37e806e --- /dev/null +++ b/tests/Unit/Normalizer/UidNormalizerTest.php @@ -0,0 +1,113 @@ +assertEquals(null, $normalizer->normalize(null)); + } + + public function testDenormalizeWithNull(): void + { + $normalizer = new UidNormalizer(UuidV7::class); + + $this->assertEquals(null, $normalizer->denormalize(null)); + } + + public function testNormalizeWithInvalidArgument(): void + { + $this->expectException(InvalidArgument::class); + $this->expectExceptionCode(0); + $this->expectExceptionMessage('type "Symfony\Component\Uid\AbstractUid|null" was expected but "string" was passed.'); + + $normalizer = new UidNormalizer(UuidV7::class); + $normalizer->normalize('foo'); + } + + public function testNormalizeWithValue(): void + { + $normalizer = new UidNormalizer(UuidV7::class); + + self::assertEquals( + $normalizer->normalize(UuidV7::fromString('019d2984-ee8a-73a1-b9b6-3041d960ae9b')), + '019d2984-ee8a-73a1-b9b6-3041d960ae9b', + ); + } + + public function testDenormalizeWithValue(): void + { + $normalizer = new UidNormalizer(UuidV7::class); + + $this->assertEquals( + UuidV7::fromString('019d2984-ee8a-73a1-b9b6-3041d960ae9b'), + $normalizer->denormalize('019d2984-ee8a-73a1-b9b6-3041d960ae9b'), + ); + } + + public function testAutoDetect(): void + { + $normalizer = new UidNormalizer(); + $normalizer->handleType(Type::object(UuidV7::class)); + + self::assertEquals(UuidV7::class, $normalizer->getClassName()); + } + + public function testAutoDetectOverrideNotPossible(): void + { + $normalizer = new UidNormalizer(UuidV4::class); + $normalizer->handleType(Type::object(UuidV7::class)); + + self::assertEquals(UuidV4::class, $normalizer->getClassName()); + } + + public function testAutoDetectMissingType(): void + { + $this->expectException(InvalidType::class); + + $normalizer = new UidNormalizer(); + + $normalizer->getClassName(); + } + + public function testAutoDetectMissingTypeBecauseNull(): void + { + $this->expectException(InvalidType::class); + + $normalizer = new UidNormalizer(); + $normalizer->handleType(null); + + $normalizer->getClassName(); + } + + public function testGeneric(): void + { + $normalizer = new UidNormalizer(); + $normalizer->handleType(Type::generic(Type::object(UuidV7::class))); + + self::assertEquals(UuidV7::class, $normalizer->getClassName()); + } + + public function testTemplate(): void + { + $normalizer = new UidNormalizer(); + $normalizer->handleType(Type::template('T', Type::object(UuidV7::class))); + + self::assertEquals(UuidV7::class, $normalizer->getClassName()); + } +} diff --git a/tests/Unit/PatchlevelEventSourcingBundleTest.php b/tests/Unit/PatchlevelEventSourcingBundleTest.php index fd20caff..46e32589 100644 --- a/tests/Unit/PatchlevelEventSourcingBundleTest.php +++ b/tests/Unit/PatchlevelEventSourcingBundleTest.php @@ -1,5 +1,7 @@ [ - 'connection' => [ - 'url' => 'sqlite3:///:memory:', - ], + 'connection' => ['url' => 'sqlite3:///:memory:'], ], - ] + ], ); self::assertInstanceOf(Connection::class, $container->get('event_sourcing.dbal_connection')); @@ -172,7 +183,7 @@ public function testMinimalConfig(): void $this->assertSame( [['source' => sprintf('with #[%s] attribute', $class)]], - $definition->getTag('container.excluded') + $definition->getTag('container.excluded'), ); $this->assertTrue($definition->isAbstract()); } @@ -186,11 +197,9 @@ public function testMinimalConfigPreSymf8(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'url' => 'sqlite3:///:memory:', - ], + 'connection' => ['url' => 'sqlite3:///:memory:'], ], - ] + ], ); self::assertInstanceOf(Connection::class, $container->get('event_sourcing.dbal_connection')); @@ -210,7 +219,7 @@ public function testMinimalConfigPreSymf8(): void $this->assertSame( [['source' => sprintf('with #[%s] attribute', $class)]], - $definition->getTag('container.excluded') + $definition->getTag('container.excluded'), ); $this->assertTrue($definition->isAbstract()); } @@ -223,11 +232,9 @@ public function testConnectionService(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], ], - ] + ], ); self::assertInstanceOf(Connection::class, $container->get('event_sourcing.dbal_connection')); @@ -246,7 +253,7 @@ public function testProjectionConnection(): void 'provide_dedicated_connection' => true, ], ], - ] + ], ); $eventSourcingConnection = $container->get('event_sourcing.dbal_connection'); @@ -270,15 +277,13 @@ public function testCustomStore(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'store' => [ 'type' => 'custom', 'service' => 'my_store', - ] + ], ], - ] + ], ); self::assertSame($store, $container->get(Store::class)); @@ -298,14 +303,10 @@ public function testCustomStoreMissingService(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], - 'store' => [ - 'type' => 'custom', - ] + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], + 'store' => ['type' => 'custom'], ], - ] + ], ); } @@ -316,14 +317,10 @@ public function testStreamStore(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], - 'store' => [ - 'type' => 'dbal_stream', - ] + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], + 'store' => ['type' => 'dbal_stream'], ], - ] + ], ); self::assertInstanceOf(StreamStore::class, $container->get(Store::class)); @@ -336,14 +333,10 @@ public function testInMemoryStore(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], - 'store' => [ - 'type' => 'in_memory', - ] + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], + 'store' => ['type' => 'in_memory'], ], - ] + ], ); self::assertInstanceOf(InMemoryStore::class, $container->get(Store::class)); @@ -356,14 +349,10 @@ public function testReadOnlyStore(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], - 'store' => [ - 'read_only' => true, - ] + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], + 'store' => ['read_only' => true], ], - ] + ], ); self::assertInstanceOf(ReadOnlyStore::class, $container->get(Store::class)); @@ -380,9 +369,7 @@ public function testMigrateStore(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'store' => [ 'migrate_to_new_store' => [ 'type' => 'dbal_stream', @@ -392,9 +379,9 @@ public function testMigrateStore(): void AggregateToStreamHeaderTranslator::class, ], ], - ] + ], ], - ] + ], ); self::assertInstanceOf(DoctrineDbalStore::class, $container->get(Store::class)); @@ -413,7 +400,7 @@ public function testMigrateStore(): void ['priority' => -2], ], ], - $container->findTaggedServiceIds('event_sourcing.translator') + $container->findTaggedServiceIds('event_sourcing.translator'), ); } @@ -424,15 +411,13 @@ public function testStreamReadOnlyStore(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'store' => [ 'type' => 'dbal_stream', 'read_only' => true, - ] + ], ], - ] + ], ); self::assertInstanceOf(StreamReadOnlyStore::class, $container->get(Store::class)); @@ -449,15 +434,13 @@ public function testSymfonyEventBus(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'event_bus' => [ 'type' => 'symfony', 'service' => 'my_event_bus', ], ], - ] + ], ); self::assertEquals(new SymfonyEventBus($eventBus), $container->get(EventBus::class)); @@ -474,15 +457,13 @@ public function testPsr14EventBus(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'event_bus' => [ 'type' => 'psr14', 'service' => 'my_event_bus', ], ], - ] + ], ); self::assertEquals(new Psr14EventBus($eventBus), $container->get(EventBus::class)); @@ -499,15 +480,13 @@ public function testCustomEventBus(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'event_bus' => [ 'type' => 'custom', 'service' => 'my_event_bus', ], ], - ] + ], ); self::assertEquals($eventBus, $container->get(EventBus::class)); @@ -525,12 +504,10 @@ public function testListener(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'event_bus' => true, ], - ] + ], ); self::assertInstanceOf(DefaultEventBus::class, $container->get(EventBus::class)); @@ -543,7 +520,7 @@ public function testListener(): void [], ], ], - $container->findTaggedServiceIds('event_sourcing.listener') + $container->findTaggedServiceIds('event_sourcing.listener'), ); } @@ -559,24 +536,20 @@ public function testAutoconfigureListener(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], - 'event_bus' => true + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], + 'event_bus' => true, ], - ] + ], ); self::assertInstanceOf(DefaultEventBus::class, $container->get(EventBus::class)); self::assertEquals( [ 'Patchlevel\EventSourcingBundle\Tests\Fixtures\Listener1' => [ - [ - 'priority' => 0, - ], + ['priority' => 0], ], ], - $container->findTaggedServiceIds('event_sourcing.listener') + $container->findTaggedServiceIds('event_sourcing.listener'), ); } @@ -588,15 +561,11 @@ public function testCommandHandler(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'aggregates' => [__DIR__ . '/../Fixtures'], - 'aggregate_handlers' => [ - 'bus' => 'command.bus', - ], + 'aggregate_handlers' => ['bus' => 'command.bus'], ], - ] + ], ); $handler = $container->get('event_sourcing.handler.profile.create'); @@ -625,18 +594,12 @@ public function testCommandBusAndLegacyConfigurationNotAllowed(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'aggregates' => [__DIR__ . '/../Fixtures'], - 'aggregate_handlers' => [ - 'bus' => 'command.bus', - ], - 'command_bus' => [ - 'service' => 'command.bus', - ], + 'aggregate_handlers' => ['bus' => 'command.bus'], + 'command_bus' => ['service' => 'command.bus'], ], - ] + ], ); } @@ -648,15 +611,11 @@ public function testCommandBus(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'aggregates' => [__DIR__ . '/../Fixtures'], - 'command_bus' => [ - 'service' => 'command.bus', - ], + 'command_bus' => ['service' => 'command.bus'], ], - ] + ], ); $handler = $container->get('event_sourcing.handler.profile.create'); @@ -686,15 +645,11 @@ public function testQueryBus(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'aggregates' => [__DIR__ . '/../Fixtures'], - 'query_bus' => [ - 'service' => 'query.bus', - ], + 'query_bus' => ['service' => 'query.bus'], ], - ] + ], ); $definition = $container->getDefinition(ProfileProjector::class); @@ -722,11 +677,9 @@ public function testMessageLoader(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], ], - ] + ], ); $messageLoader = $container->get(MessageLoader::class); @@ -742,16 +695,12 @@ public function testGapDetection(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'subscription' => [ - 'gap_detection' => [ - 'enabled' => true, - ], + 'gap_detection' => ['enabled' => true], ], ], - ] + ], ); $messageLoader = $container->get(MessageLoader::class); @@ -767,9 +716,7 @@ public function testGapDetectionWithExplicitValues(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'subscription' => [ 'gap_detection' => [ 'enabled' => true, @@ -778,7 +725,7 @@ public function testGapDetectionWithExplicitValues(): void ], ], ], - ] + ], ); $messageLoader = $container->get(MessageLoader::class); @@ -786,24 +733,76 @@ public function testGapDetectionWithExplicitValues(): void self::assertInstanceOf(GapResolverStoreMessageLoader::class, $messageLoader); } - public function testSnapshotStore(): void + public function testSubscriptionCleanupWithDoctrine(): void { + $registry = $this->createMock(ManagerRegistry::class); + $container = new ContainerBuilder(); + $container->set('doctrine', $registry); + + $this->compileContainer( + $container, + [ + 'patchlevel_event_sourcing' => [ + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], + 'store' => ['merge_orm_schema' => true], + ], + ], + ); + + $definition = $container->getDefinition(DbalCleanupTaskHandler::class); + $tags = $definition->getTag('event_sourcing.cleanup_task_handler'); + self::assertCount(1, $tags); + + $cleaner = $container->get(Cleaner::class); + self::assertInstanceOf(DefaultCleaner::class, $cleaner); + + $cleanupTaskHandler = $container->get(DbalCleanupTaskHandler::class); + self::assertInstanceOf(DbalCleanupTaskHandler::class, $cleanupTaskHandler); + } + + public function testSubscriptionCleanupWithProjectionConnection(): void + { + $container = new ContainerBuilder(); $this->compileContainer( $container, [ 'patchlevel_event_sourcing' => [ 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', + 'url' => 'sqlite3:///:memory:', + 'provide_dedicated_connection' => true, ], + ], + ], + ); + + $definition = $container->getDefinition(DbalCleanupTaskHandler::class); + $tags = $definition->getTag('event_sourcing.cleanup_task_handler'); + + self::assertCount(1, $tags); + + $cleaner = $container->get(Cleaner::class); + self::assertInstanceOf(DefaultCleaner::class, $cleaner); + + $cleanupTaskHandler = $container->get(DbalCleanupTaskHandler::class); + self::assertInstanceOf(DbalCleanupTaskHandler::class, $cleanupTaskHandler); + } + + public function testSnapshotStore(): void + { + $container = new ContainerBuilder(); + + $this->compileContainer( + $container, + [ + 'patchlevel_event_sourcing' => [ + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'snapshot_stores' => [ - 'default' => [ - 'service' => 'cache.default', - ], + 'default' => ['service' => 'cache.default'], ], ], - ] + ], ); $snapshotStore = $container->get(SnapshotStore::class); @@ -823,20 +822,18 @@ public function testPsr6SnapshotAdapter(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'snapshot_stores' => [ - 'default' => [ - 'service' => 'cache.default', - ], + 'default' => ['service' => 'cache.default'], ], ], - ] + ], ); - self::assertInstanceOf(Psr6SnapshotAdapter::class, - $container->get('event_sourcing.snapshot_store.adapter.default')); + self::assertInstanceOf( + Psr6SnapshotAdapter::class, + $container->get('event_sourcing.snapshot_store.adapter.default'), + ); } public function testPsr16SnapshotAdapter(): void @@ -850,9 +847,7 @@ public function testPsr16SnapshotAdapter(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'snapshot_stores' => [ 'default' => [ 'type' => 'psr16', @@ -860,11 +855,13 @@ public function testPsr16SnapshotAdapter(): void ], ], ], - ] + ], ); - self::assertInstanceOf(Psr16SnapshotAdapter::class, - $container->get('event_sourcing.snapshot_store.adapter.default')); + self::assertInstanceOf( + Psr16SnapshotAdapter::class, + $container->get('event_sourcing.snapshot_store.adapter.default'), + ); } public function testCustomSnapshotAdapter(): void @@ -878,9 +875,7 @@ public function testCustomSnapshotAdapter(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'snapshot_stores' => [ 'default' => [ 'type' => 'custom', @@ -888,7 +883,7 @@ public function testCustomSnapshotAdapter(): void ], ], ], - ] + ], ); self::assertEquals($customSnapshotStore, $container->get('event_sourcing.snapshot_store.adapter.default')); @@ -902,12 +897,10 @@ public function testEventRegistry(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'events' => [__DIR__ . '/../Fixtures'], ], - ] + ], ); $eventRegistry = $container->get(EventRegistry::class); @@ -924,12 +917,10 @@ public function testAggregateRegistry(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'aggregates' => [__DIR__ . '/../Fixtures'], ], - ] + ], ); $aggregateRegistry = $container->get(AggregateRootRegistry::class); @@ -946,12 +937,10 @@ public function testMessageHeaderRegistry(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'headers' => [__DIR__ . '/../Fixtures'], ], - ] + ], ); /** @var MessageHeaderRegistry $messageHeaderRegistry */ @@ -969,12 +958,10 @@ public function testRepositoryManager(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'aggregates' => [__DIR__ . '/../Fixtures'], ], - ] + ], ); $repositoryManager = $container->get(RepositoryManager::class); @@ -994,11 +981,9 @@ public function testCommands(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], ], - ] + ], ); self::assertInstanceOf(DatabaseCreateCommand::class, $container->get(DatabaseCreateCommand::class)); @@ -1006,13 +991,16 @@ public function testCommands(): void self::assertInstanceOf(DebugCommand::class, $container->get(DebugCommand::class)); self::assertInstanceOf(SubscriptionBootCommand::class, $container->get(SubscriptionBootCommand::class)); self::assertInstanceOf(SubscriptionPauseCommand::class, $container->get(SubscriptionPauseCommand::class)); - self::assertInstanceOf(SubscriptionReactivateCommand::class, - $container->get(SubscriptionReactivateCommand::class)); + self::assertInstanceOf( + SubscriptionReactivateCommand::class, + $container->get(SubscriptionReactivateCommand::class), + ); self::assertInstanceOf(SubscriptionRemoveCommand::class, $container->get(SubscriptionRemoveCommand::class)); self::assertInstanceOf(SubscriptionRunCommand::class, $container->get(SubscriptionRunCommand::class)); self::assertInstanceOf(SubscriptionSetupCommand::class, $container->get(SubscriptionSetupCommand::class)); self::assertInstanceOf(SubscriptionStatusCommand::class, $container->get(SubscriptionStatusCommand::class)); self::assertInstanceOf(SubscriptionTeardownCommand::class, $container->get(SubscriptionTeardownCommand::class)); + self::assertInstanceOf(SubscriptionRefreshCommand::class, $container->get(SubscriptionRefreshCommand::class)); self::assertInstanceOf(SchemaCreateCommand::class, $container->get(SchemaCreateCommand::class)); self::assertInstanceOf(SchemaUpdateCommand::class, $container->get(SchemaUpdateCommand::class)); self::assertInstanceOf(SchemaDropCommand::class, $container->get(SchemaDropCommand::class)); @@ -1029,11 +1017,9 @@ public function testMigrations(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], ], - ] + ], ); self::assertInstanceOf(DiffCommand::class, $container->get('event_sourcing.command.migration_diff')); @@ -1051,11 +1037,9 @@ public function testDefaultClock(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], ], - ] + ], ); self::assertInstanceOf(SystemClock::class, $container->get('event_sourcing.clock')); @@ -1069,14 +1053,10 @@ public function testFrozenClock(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], - 'clock' => [ - 'freeze' => '2020-01-01 22:00:00', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], + 'clock' => ['freeze' => '2020-01-01 22:00:00'], ], - ] + ], ); $clock = $container->get('event_sourcing.clock'); @@ -1096,14 +1076,10 @@ public function testPsrClock(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], - 'clock' => [ - 'service' => 'clock', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], + 'clock' => ['service' => 'clock'], ], - ] + ], ); self::assertInstanceOf(ClockInterface::class, $container->get('event_sourcing.clock')); @@ -1117,11 +1093,9 @@ public function testDecorator(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], ], - ] + ], ); self::assertInstanceOf(ChainMessageDecorator::class, $container->get(MessageDecorator::class)); @@ -1136,9 +1110,7 @@ public function testRunSubscriptionEngineRepositoryManager(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'subscription' => [ 'run_after_aggregate_save' => [ 'ids' => ['a'], @@ -1147,11 +1119,13 @@ public function testRunSubscriptionEngineRepositoryManager(): void ], ], ], - ] + ], ); - self::assertInstanceOf(RunSubscriptionEngineRepositoryManager::class, - $container->get(RepositoryManager::class)); + self::assertInstanceOf( + RunSubscriptionEngineRepositoryManager::class, + $container->get(RepositoryManager::class), + ); } public function testSubscriptionEngineInMemoryStore(): void @@ -1162,16 +1136,12 @@ public function testSubscriptionEngineInMemoryStore(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'subscription' => [ - 'store' => [ - 'type' => 'in_memory' - ], + 'store' => ['type' => 'in_memory'], ], ], - ] + ], ); self::assertInstanceOf(InMemorySubscriptionStore::class, $container->get(SubscriptionStore::class)); @@ -1186,37 +1156,29 @@ public function testSubscriptionEngineStaticInMemoryStore(): void $containerA, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'subscription' => [ - 'store' => [ - 'type' => 'static_in_memory' - ], + 'store' => ['type' => 'static_in_memory'], ], ], - ] + ], ); $this->compileContainer( $containerB, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'subscription' => [ - 'store' => [ - 'type' => 'static_in_memory' - ], + 'store' => ['type' => 'static_in_memory'], ], ], - ] + ], ); self::assertSame( $containerA->get(SubscriptionStore::class), - $containerB->get(SubscriptionStore::class) + $containerB->get(SubscriptionStore::class), ); } @@ -1228,20 +1190,18 @@ public function testCatchUpSubscriptionEngine(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'subscription' => [ - 'catch_up' => [ - 'limit' => 10, - ], + 'catch_up' => ['limit' => 10], ], ], - ] + ], ); - self::assertInstanceOf(CatchUpSubscriptionEngine::class, - $container->get(SubscriptionEngine::class)); + self::assertInstanceOf( + CatchUpSubscriptionEngine::class, + $container->get(SubscriptionEngine::class), + ); } public function testSubscriberSameConnectionError(): void @@ -1250,7 +1210,7 @@ public function testSubscriberSameConnectionError(): void $container->setDefinition(ProfileProjector::class, new Definition( ProfileProjector::class, - [new Reference('doctrine.dbal.eventstore_connection')] + [new Reference('doctrine.dbal.eventstore_connection')], )) ->setAutoconfigured(true); @@ -1261,11 +1221,9 @@ public function testSubscriberSameConnectionError(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], ], - ] + ], ); } @@ -1286,11 +1244,9 @@ public function testAutoconfigureSubscriber(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], ], - ] + ], ); self::assertTrue($container->getDefinition(ProfileSubscriber::class)->hasTag('event_sourcing.subscriber')); @@ -1309,18 +1265,20 @@ public function testAutoconfigureArgumentResolver(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], ], - ] + ], ); self::assertTrue($container->getDefinition(DummyArgumentResolver::class)->hasTag('event_sourcing.argument_resolver')); - self::assertInstanceOf(TaggedIteratorArgument::class, - $container->getDefinition(MetadataSubscriberAccessorRepository::class)->getArgument(2)); - self::assertEquals('event_sourcing.argument_resolver', - $container->getDefinition(MetadataSubscriberAccessorRepository::class)->getArgument(2)->getTag()); + self::assertInstanceOf( + TaggedIteratorArgument::class, + $container->getDefinition(MetadataSubscriberAccessorRepository::class)->getArgument(2), + ); + self::assertEquals( + 'event_sourcing.argument_resolver', + $container->getDefinition(MetadataSubscriberAccessorRepository::class)->getArgument(2)->getTag(), + ); } public function testLegacyRetryStrategy(): void @@ -1331,9 +1289,7 @@ public function testLegacyRetryStrategy(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'subscription' => [ 'retry_strategy' => [ 'base_delay' => 10, @@ -1342,7 +1298,7 @@ public function testLegacyRetryStrategy(): void ], ], ], - ] + ], ); $repository = $container->get(RetryStrategyRepository::class); @@ -1361,9 +1317,7 @@ public function testRetryStrategy(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'subscription' => [ 'retry_strategies' => [ 'default' => [ @@ -1374,13 +1328,11 @@ public function testRetryStrategy(): void 'max_attempts' => 12, ], ], - 'no_retry' => [ - 'type' => 'no_retry', - ] - ] + 'no_retry' => ['type' => 'no_retry'], + ], ], ], - ] + ], ); $repository = $container->get(RetryStrategyRepository::class); @@ -1402,19 +1354,17 @@ public function testRetryStrategyCustom(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'subscription' => [ 'retry_strategies' => [ 'default' => [ 'type' => 'custom', - 'service' => 'my_retry_strategy' + 'service' => 'my_retry_strategy', ], - ] + ], ], ], - ] + ], ); $repository = $container->get(RetryStrategyRepository::class); @@ -1431,14 +1381,10 @@ public function testSchemaMerge(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], - 'store' => [ - 'merge_orm_schema' => true, - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], + 'store' => ['merge_orm_schema' => true], ], - ] + ], ); self::assertInstanceOf(DoctrineSchemaListener::class, $container->get(DoctrineSchemaListener::class)); @@ -1448,6 +1394,40 @@ public function testSchemaMerge(): void self::assertFalse($container->has('event_sourcing.command.migration_diff')); } + public function testHydrator(): void + { + $container = new ContainerBuilder(); + + $container->setDefinition(DummyGuesser::class, new Definition(DummyGuesser::class)) + ->setAutoconfigured(true); + + $this->compileContainer( + $container, + [ + 'patchlevel_event_sourcing' => [ + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], + ], + ], + ); + + self::assertInstanceOf(MetadataHydrator::class, $container->get(Hydrator::class)); + + self::assertEquals( + [ + BuiltInGuesser::class => [ + ['priority' => -100], + ], + SymfonyGuesser::class => [ + ['priority' => -50], + ], + DummyGuesser::class => [ + [], + ], + ], + $container->findTaggedServiceIds('event_sourcing.hydrator.guesser'), + ); + } + public function testCryptography(): void { $container = new ContainerBuilder(); @@ -1456,14 +1436,10 @@ public function testCryptography(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], - 'cryptography' => [ - 'algorithm' => 'aes256', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], + 'cryptography' => ['algorithm' => 'aes256'], ], - ] + ], ); self::assertInstanceOf(PersonalDataPayloadCryptographer::class, $container->get(PayloadCryptographer::class)); @@ -1480,20 +1456,12 @@ public function testFullBuild(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'store' => [ - 'options' => [ - 'table_name' => 'event_store', - ], - ], - 'clock' => [ - 'service' => 'clock', - ], - 'event_bus' => [ - 'type' => 'default', + 'options' => ['table_name' => 'event_store'], ], + 'clock' => ['service' => 'clock'], + 'event_bus' => ['type' => 'default'], 'aggregates' => [__DIR__ . '/../Fixtures'], 'migration' => [ 'namespace' => 'Foo', @@ -1505,17 +1473,13 @@ public function testFullBuild(): void 'service' => 'cache.default', ], ], - 'cryptography' => [ - 'algorithm' => 'aes256', - ], + 'cryptography' => ['algorithm' => 'aes256'], 'subscription' => [ - 'catch_up' => [ - 'limit' => 10, - ], + 'catch_up' => ['limit' => 10], 'throw_on_error' => true, - ] + ], ], - ] + ], ); self::assertInstanceOf(Connection::class, $container->get('event_sourcing.dbal_connection')); @@ -1536,12 +1500,10 @@ public function testNamedRepository(): void $container, [ 'patchlevel_event_sourcing' => [ - 'connection' => [ - 'service' => 'doctrine.dbal.eventstore_connection', - ], + 'connection' => ['service' => 'doctrine.dbal.eventstore_connection'], 'aggregates' => [__DIR__ . '/../Fixtures'], ], - ] + ], ); $profileRepository = $container->get('event_sourcing.profile.repository'); @@ -1553,9 +1515,7 @@ public function testNamedRepository(): void self::assertSame($profileRepository, $namedArgumentProfileRepository); } - /** - * @param array{patchlevel_event_sourcing: array} $config - */ + /** @param array{patchlevel_event_sourcing: array} $config */ private function compileContainer(ContainerBuilder $container, array $config): void { $bundle = new PatchlevelEventSourcingBundle(); diff --git a/tests/Unit/RequestListener/AutoSetupListenerTest.php b/tests/Unit/RequestListener/AutoSetupListenerTest.php new file mode 100644 index 00000000..6db0ae8c --- /dev/null +++ b/tests/Unit/RequestListener/AutoSetupListenerTest.php @@ -0,0 +1,82 @@ +createMock(SubscriptionEngine::class); + $subscriptionEngine->expects($this->never())->method('subscriptions'); + $subscriptionEngine->expects($this->never())->method('setup'); + + $listener = new AutoSetupListener($subscriptionEngine, null, null); + $listener->onKernelRequest($this->createRequestEvent('/foo', HttpKernelInterface::SUB_REQUEST)); + } + + public function testSkipExcludedUrl(): void + { + $subscriptionEngine = $this->createMock(SubscriptionEngine::class); + $subscriptionEngine->expects($this->never())->method('subscriptions'); + $subscriptionEngine->expects($this->never())->method('setup'); + + $listener = new AutoSetupListener($subscriptionEngine, null, null, '^/_profiler'); + $listener->onKernelRequest($this->createRequestEvent('/_profiler/test')); + } + + public function testSetupOnlyNewSubscriptions(): void + { + $subscriptionEngine = $this->createMock(SubscriptionEngine::class); + $subscriptionEngine + ->expects($this->once()) + ->method('subscriptions') + ->with($this->callback(static function (SubscriptionEngineCriteria|null $criteria): bool { + return $criteria instanceof SubscriptionEngineCriteria + && $criteria->ids === ['id-1'] + && $criteria->groups === ['group-1']; + })) + ->willReturn([ + new Subscription('new-1'), + new Subscription('active-1', status: Status::Active), + new Subscription('new-2'), + ]); + + $subscriptionEngine + ->expects($this->once()) + ->method('setup') + ->with($this->callback(static function (SubscriptionEngineCriteria|null $criteria): bool { + return $criteria instanceof SubscriptionEngineCriteria + && $criteria->ids === ['new-1', 'new-2'] + && $criteria->groups === null; + }), true) + ->willReturn(new Result()); + + $listener = new AutoSetupListener($subscriptionEngine, ['id-1'], ['group-1'], '^/_profiler'); + $listener->onKernelRequest($this->createRequestEvent('/app')); + } + + private function createRequestEvent( + string $uri, + int $requestType = HttpKernelInterface::MAIN_REQUEST, + ): RequestEvent { + return new RequestEvent( + $this->createMock(HttpKernelInterface::class), + Request::create($uri), + $requestType, + ); + } +} diff --git a/tests/Unit/RequestListener/SubscriptionRebuildAfterFileChangeListenerTest.php b/tests/Unit/RequestListener/SubscriptionRebuildAfterFileChangeListenerTest.php new file mode 100644 index 00000000..5821540a --- /dev/null +++ b/tests/Unit/RequestListener/SubscriptionRebuildAfterFileChangeListenerTest.php @@ -0,0 +1,135 @@ +createMock(SubscriptionEngine::class); + $subscriptionEngine->expects($this->never())->method('remove'); + $subscriptionEngine->expects($this->never())->method('setup'); + $subscriptionEngine->expects($this->never())->method('boot'); + + $cache = $this->createMock(CacheItemPoolInterface::class); + $cache->expects($this->never())->method('getItem'); + + $listener = new SubscriptionRebuildAfterFileChangeListener( + $subscriptionEngine, + [new FromBeginningSubscriber()], + $cache, + ); + + $listener->onKernelRequest($this->createRequestEvent('/app', HttpKernelInterface::SUB_REQUEST)); + } + + public function testSkipExcludedUrl(): void + { + $subscriptionEngine = $this->createMock(SubscriptionEngine::class); + $subscriptionEngine->expects($this->never())->method('remove'); + $subscriptionEngine->expects($this->never())->method('setup'); + $subscriptionEngine->expects($this->never())->method('boot'); + + $cache = $this->createMock(CacheItemPoolInterface::class); + $cache->expects($this->never())->method('getItem'); + + $listener = new SubscriptionRebuildAfterFileChangeListener( + $subscriptionEngine, + [new FromBeginningSubscriber()], + $cache, + excludeUrl: '^/_wdt', + ); + + $listener->onKernelRequest($this->createRequestEvent('/_wdt/abc')); + } + + public function testRebuildChangedFromBeginningSubscriptionsOnly(): void + { + $item = $this->createMock(CacheItemInterface::class); + $item->expects($this->once())->method('get')->willReturn(1); + $item->expects($this->once())->method('set')->with($this->isType('int'))->willReturnSelf(); + + $cache = $this->createMock(CacheItemPoolInterface::class); + $cache->expects($this->once())->method('getItem')->with('from-beginning')->willReturn($item); + $cache->expects($this->once())->method('save')->with($item)->willReturn(true); + + $subscriptionEngine = $this->createMock(SubscriptionEngine::class); + $criteriaMatcher = $this->callback(static fn (SubscriptionEngineCriteria|null $criteria): bool => $criteria instanceof SubscriptionEngineCriteria && $criteria->ids === ['from-beginning'] && $criteria->groups === null); + + $subscriptionEngine->expects($this->once())->method('remove')->with($criteriaMatcher)->willReturn(new Result()); + $subscriptionEngine->expects($this->once())->method('setup')->with($criteriaMatcher)->willReturn(new Result()); + $subscriptionEngine->expects($this->once())->method('boot')->with($criteriaMatcher)->willReturn(new ProcessedResult(0)); + + $listener = new SubscriptionRebuildAfterFileChangeListener( + $subscriptionEngine, + [new FromBeginningSubscriber(), new FromNowSubscriber()], + $cache, + ); + + $listener->onKernelRequest($this->createRequestEvent('/app')); + } + + public function testNoRebuildWhenFileDidNotChange(): void + { + $subscriberFile = (new ReflectionClass(FromBeginningSubscriber::class))->getFileName(); + self::assertIsString($subscriberFile); + + $currentModified = filemtime($subscriberFile); + self::assertIsInt($currentModified); + + $item = $this->createMock(CacheItemInterface::class); + $item->expects($this->once())->method('get')->willReturn($currentModified); + $item->expects($this->never())->method('set'); + + $cache = $this->createMock(CacheItemPoolInterface::class); + $cache->expects($this->once())->method('getItem')->with('from-beginning')->willReturn($item); + $cache->expects($this->never())->method('save'); + + $subscriptionEngine = $this->createMock(SubscriptionEngine::class); + $emptyCriteriaMatcher = $this->callback(static fn (SubscriptionEngineCriteria|null $criteria): bool => $criteria instanceof SubscriptionEngineCriteria && $criteria->ids === []); + + $subscriptionEngine->expects($this->once())->method('remove')->with($emptyCriteriaMatcher)->willReturn(new Result()); + $subscriptionEngine->expects($this->once())->method('setup')->with($emptyCriteriaMatcher)->willReturn(new Result()); + $subscriptionEngine->expects($this->once())->method('boot')->with($emptyCriteriaMatcher)->willReturn(new ProcessedResult(0)); + + $listener = new SubscriptionRebuildAfterFileChangeListener( + $subscriptionEngine, + [new FromBeginningSubscriber()], + $cache, + excludeUrl: '^/_profiler', + ); + + $listener->onKernelRequest($this->createRequestEvent('/app')); + } + + private function createRequestEvent( + string $uri, + int $requestType = HttpKernelInterface::MAIN_REQUEST, + ): RequestEvent { + return new RequestEvent( + $this->createMock(HttpKernelInterface::class), + Request::create($uri), + $requestType, + ); + } +} diff --git a/tests/Unit/TestCaseAllPublicCompilerPass.php b/tests/Unit/TestCaseAllPublicCompilerPass.php index cf579bd0..c9fbbafd 100644 --- a/tests/Unit/TestCaseAllPublicCompilerPass.php +++ b/tests/Unit/TestCaseAllPublicCompilerPass.php @@ -7,6 +7,8 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use function str_starts_with; + final class TestCaseAllPublicCompilerPass implements CompilerPassInterface { private const SERVICE_PREFIX = 'event_sourcing.'; @@ -15,15 +17,19 @@ final class TestCaseAllPublicCompilerPass implements CompilerPassInterface public function process(ContainerBuilder $container): void { foreach ($container->getDefinitions() as $id => $definition) { - if ($this->isOwnService($id)) { - $definition->setPublic(true); + if (!$this->isOwnService($id)) { + continue; } + + $definition->setPublic(true); } foreach ($container->getAliases() as $id => $alias) { - if ($this->isOwnService($id)) { - $alias->setPublic(true); + if (!$this->isOwnService($id)) { + continue; } + + $alias->setPublic(true); } } diff --git a/tests/Unit/ValueResolver/AggregateRootIdValueResolverTest.php b/tests/Unit/ValueResolver/AggregateRootIdValueResolverTest.php index 7d5fd596..ef3cf88a 100644 --- a/tests/Unit/ValueResolver/AggregateRootIdValueResolverTest.php +++ b/tests/Unit/ValueResolver/AggregateRootIdValueResolverTest.php @@ -1,5 +1,7 @@ resolve($request, $argument); @@ -45,7 +45,7 @@ public function testNoAggregateId(): void 'string', false, false, - null + null, ); $result = $valueResolver->resolve($request, $argument); @@ -65,11 +65,11 @@ public function testInvalidValue(): void CustomId::class, false, false, - null + null, ); $result = $valueResolver->resolve($request, $argument); self::assertEquals([], $result); } -} \ No newline at end of file +}