From 3e36038731eae2b5bb52e0eedbca3f8f48d3d0ce Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 7 Dec 2025 20:30:33 +0000 Subject: [PATCH 01/24] Update dependency pymdown-extensions to v10.18 | datasource | package | from | to | | ---------- | ------------------ | ------- | ----- | | pypi | pymdown-extensions | 10.17.2 | 10.18 | Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 50cbcae5..c9525c05 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -5,7 +5,7 @@ mkdocs-material==9.7.0 # Markdown extensions Pygments==2.19.2 -pymdown-extensions==10.17.2 +pymdown-extensions==10.18 # MkDocs plugins mkdocs-material-extensions==1.3.1 From f95b0137007908c8e4f7499da6d910e325601260 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 20:55:08 +0000 Subject: [PATCH 02/24] Update dependency pymdown-extensions to v10.19 | datasource | package | from | to | | ---------- | ------------------ | ----- | ----- | | pypi | pymdown-extensions | 10.18 | 10.19 | Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index c9525c05..8f752ca8 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -5,7 +5,7 @@ mkdocs-material==9.7.0 # Markdown extensions Pygments==2.19.2 -pymdown-extensions==10.18 +pymdown-extensions==10.19 # MkDocs plugins mkdocs-material-extensions==1.3.1 From b671bbb04dddbdabd5928d4084c11d6d91f20be5 Mon Sep 17 00:00:00 2001 From: Daniel Badura Date: Fri, 12 Dec 2025 14:22:29 +0100 Subject: [PATCH 03/24] Add QueryBus integration test which was missing, also add "full cycle" bench which dispatches a command and then query the name. Fix a deprecation notice regarding `SplObjectStorage` --- phpstan-baseline.neon | 36 ++++- .../Engine/SubscriptionManager.php | 14 +- .../Command/ChangeProfileName.php | 18 +++ .../Command/CreateProfile.php | 16 +++ .../Events/NameChanged.php | 4 +- .../Benchmark/BasicImplementation/Profile.php | 2 +- .../ProfileWithCommands.php | 68 ++++++++++ .../Projection/BatchProfileProjector.php | 5 +- .../Projection/ProfileProjector.php | 16 ++- .../Query/QueryProfileName.php | 14 ++ tests/Benchmark/CommandToQueryBench.php | 128 ++++++++++++++++++ .../BasicIntegrationTest.php | 68 ++++++++++ .../Projection/ProfileProjector.php | 11 ++ .../Query/QueryProfileName.php | 14 ++ 14 files changed, 393 insertions(+), 21 deletions(-) create mode 100644 tests/Benchmark/BasicImplementation/Command/ChangeProfileName.php create mode 100644 tests/Benchmark/BasicImplementation/Command/CreateProfile.php create mode 100644 tests/Benchmark/BasicImplementation/ProfileWithCommands.php create mode 100644 tests/Benchmark/BasicImplementation/Query/QueryProfileName.php create mode 100644 tests/Benchmark/CommandToQueryBench.php create mode 100644 tests/Integration/BasicImplementation/Query/QueryProfileName.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 514dfbe7..2ee97190 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -42,12 +42,6 @@ parameters: count: 1 path: src/Message/Serializer/DefaultHeadersSerializer.php - - - message: '#^Call to an undefined method Patchlevel\\EventSourcing\\Store\\Store\:\:archive\(\)\.$#' - identifier: method.notFound - count: 1 - path: src/Repository/DefaultRepository.php - - message: '#^Parameter \#1 \.\.\.\$streamName of class Patchlevel\\EventSourcing\\Store\\Criteria\\StreamCriterion constructor expects string, string\|null given\.$#' identifier: argument.type @@ -168,6 +162,24 @@ parameters: count: 3 path: src/Subscription/ThrowableToErrorContextTransformer.php + - + message: '#^Property Patchlevel\\EventSourcing\\Tests\\Benchmark\\BasicImplementation\\ProfileWithCommands\:\:\$id is never read, only written\.$#' + identifier: property.onlyWritten + count: 1 + path: tests/Benchmark/BasicImplementation/ProfileWithCommands.php + + - + message: '#^Cannot access offset ''name'' on array\\|false\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: tests/Benchmark/BasicImplementation/Projection/ProfileProjector.php + + - + message: '#^Method Patchlevel\\EventSourcing\\Tests\\Benchmark\\BasicImplementation\\Projection\\ProfileProjector\:\:getProfileName\(\) should return string but returns mixed\.$#' + identifier: return.type + count: 1 + path: tests/Benchmark/BasicImplementation/Projection/ProfileProjector.php + - message: '#^Parameter \#1 \$id of static method Patchlevel\\EventSourcing\\Tests\\Benchmark\\BasicImplementation\\Profile\:\:create\(\) expects Patchlevel\\EventSourcing\\Tests\\Benchmark\\BasicImplementation\\ProfileId, Patchlevel\\EventSourcing\\Aggregate\\AggregateRootId given\.$#' identifier: argument.type @@ -234,6 +246,18 @@ parameters: count: 1 path: tests/Integration/BasicImplementation/ProfileWithCommands.php + - + message: '#^Cannot access offset ''name'' on array\\|false\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: tests/Integration/BasicImplementation/Projection/ProfileProjector.php + + - + message: '#^Method Patchlevel\\EventSourcing\\Tests\\Integration\\BasicImplementation\\Projection\\ProfileProjector\:\:getProfileName\(\) should return string but returns mixed\.$#' + identifier: return.type + count: 1 + path: tests/Integration/BasicImplementation/Projection/ProfileProjector.php + - message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertInstanceOf\(\) with ''Patchlevel\\\\EventSourcing\\\\Tests\\\\Integration\\\\ChildAggregate\\\\Profile'' and Patchlevel\\EventSourcing\\Tests\\Integration\\ChildAggregate\\Profile will always evaluate to true\.$#' identifier: staticMethod.alreadyNarrowedType diff --git a/src/Subscription/Engine/SubscriptionManager.php b/src/Subscription/Engine/SubscriptionManager.php index 96a36f9b..1350a13d 100644 --- a/src/Subscription/Engine/SubscriptionManager.php +++ b/src/Subscription/Engine/SubscriptionManager.php @@ -77,28 +77,28 @@ public function find(SubscriptionCriteria $criteria): array public function add(Subscription ...$subscriptions): void { foreach ($subscriptions as $sub) { - $this->forAdd->attach($sub); + $this->forAdd->offsetSet($sub); } } public function update(Subscription ...$subscriptions): void { foreach ($subscriptions as $sub) { - $this->forUpdate->attach($sub); + $this->forUpdate->offsetSet($sub); } } public function remove(Subscription ...$subscriptions): void { foreach ($subscriptions as $sub) { - $this->forRemove->attach($sub); + $this->forRemove->offsetSet($sub); } } public function flush(): void { foreach ($this->forAdd as $subscription) { - if ($this->forRemove->contains($subscription)) { + if ($this->forRemove->offsetExists($subscription)) { continue; } @@ -106,11 +106,11 @@ public function flush(): void } foreach ($this->forUpdate as $subscription) { - if ($this->forAdd->contains($subscription)) { + if ($this->forAdd->offsetExists($subscription)) { continue; } - if ($this->forRemove->contains($subscription)) { + if ($this->forRemove->offsetExists($subscription)) { continue; } @@ -118,7 +118,7 @@ public function flush(): void } foreach ($this->forRemove as $subscription) { - if ($this->forAdd->contains($subscription)) { + if ($this->forAdd->offsetExists($subscription)) { continue; } diff --git a/tests/Benchmark/BasicImplementation/Command/ChangeProfileName.php b/tests/Benchmark/BasicImplementation/Command/ChangeProfileName.php new file mode 100644 index 00000000..f8f9521a --- /dev/null +++ b/tests/Benchmark/BasicImplementation/Command/ChangeProfileName.php @@ -0,0 +1,18 @@ +recordThat(new NameChanged($name)); + $this->recordThat(new NameChanged($this->id, $name)); } public function changeEmail(string $email): void diff --git a/tests/Benchmark/BasicImplementation/ProfileWithCommands.php b/tests/Benchmark/BasicImplementation/ProfileWithCommands.php new file mode 100644 index 00000000..a448f05a --- /dev/null +++ b/tests/Benchmark/BasicImplementation/ProfileWithCommands.php @@ -0,0 +1,68 @@ +recordThat(new ProfileCreated($command->id, $command->name, null)); + + return $self; + } + + #[Handle] + public function changeName( + ChangeProfileName $command, + ClockInterface $clock, + #[Inject('env')] + string $env, + ): void { + $this->recordThat(new NameChanged($this->id, $command->name)); + } + + #[Apply] + protected function applyProfileCreated(ProfileCreated $event): void + { + $this->id = $event->profileId; + $this->name = $event->name; + } + + #[Apply] + protected function applyNameChanged(NameChanged $event): void + { + $this->name = $event->name; + } + + public function name(): string + { + return $this->name; + } +} diff --git a/tests/Benchmark/BasicImplementation/Projection/BatchProfileProjector.php b/tests/Benchmark/BasicImplementation/Projection/BatchProfileProjector.php index 1669225c..8896906f 100644 --- a/tests/Benchmark/BasicImplementation/Projection/BatchProfileProjector.php +++ b/tests/Benchmark/BasicImplementation/Projection/BatchProfileProjector.php @@ -13,7 +13,6 @@ use Patchlevel\EventSourcing\Subscription\Subscriber\SubscriberUtil; use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Events\NameChanged; use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Events\ProfileCreated; -use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\ProfileId; #[Projector('profile')] final class BatchProfileProjector implements BatchableSubscriber @@ -53,9 +52,9 @@ public function onProfileCreated(ProfileCreated $profileCreated): void } #[Subscribe(NameChanged::class)] - public function onNameChanged(NameChanged $nameChanged, ProfileId $profileId): void + public function onNameChanged(NameChanged $nameChanged): void { - $this->nameChanged[$profileId->toString()] = $nameChanged->name; + $this->nameChanged[$nameChanged->profileId->toString()] = $nameChanged->name; } public function table(): string diff --git a/tests/Benchmark/BasicImplementation/Projection/ProfileProjector.php b/tests/Benchmark/BasicImplementation/Projection/ProfileProjector.php index ef100be3..98f16b3c 100644 --- a/tests/Benchmark/BasicImplementation/Projection/ProfileProjector.php +++ b/tests/Benchmark/BasicImplementation/Projection/ProfileProjector.php @@ -5,6 +5,7 @@ namespace Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Projection; use Doctrine\DBAL\Connection; +use Patchlevel\EventSourcing\Attribute\Answer; use Patchlevel\EventSourcing\Attribute\Projector; use Patchlevel\EventSourcing\Attribute\Setup; use Patchlevel\EventSourcing\Attribute\Subscribe; @@ -12,7 +13,7 @@ use Patchlevel\EventSourcing\Subscription\Subscriber\SubscriberUtil; use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Events\NameChanged; use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Events\ProfileCreated; -use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\ProfileId; +use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Query\QueryProfileName; #[Projector('profile')] final class ProfileProjector @@ -49,15 +50,24 @@ public function onProfileCreated(ProfileCreated $profileCreated): void } #[Subscribe(NameChanged::class)] - public function onNameChanged(NameChanged $nameChanged, ProfileId $profileId): void + public function onNameChanged(NameChanged $nameChanged): void { $this->connection->update( $this->table(), ['name' => $nameChanged->name], - ['id' => $profileId->toString()], + ['id' => $nameChanged->profileId->toString()], ); } + #[Answer] + public function getProfileName(QueryProfileName $queryProfileName): string + { + return $this->connection->fetchAssociative( + "SELECT name FROM {$this->table()} WHERE id = :id;", + ['id' => $queryProfileName->id->toString()], + )['name']; + } + public function table(): string { return 'projection_' . $this->subscriberId(); diff --git a/tests/Benchmark/BasicImplementation/Query/QueryProfileName.php b/tests/Benchmark/BasicImplementation/Query/QueryProfileName.php new file mode 100644 index 00000000..a26ecad9 --- /dev/null +++ b/tests/Benchmark/BasicImplementation/Query/QueryProfileName.php @@ -0,0 +1,14 @@ + ProfileWithCommands::class]); + + $manager = new DefaultRepositoryManager( + $aggregateRootRegistry, + $store, + null, + new DefaultSnapshotStore(['default' => new InMemorySnapshotAdapter()]), + ); + + $projectionConnection = DbalManager::createConnection(); + $profileProjection = new ProfileProjector($projectionConnection); + + $engine = new DefaultSubscriptionEngine( + $store, + new InMemorySubscriptionStore(), + new MetadataSubscriberAccessorRepository([ + $profileProjection, + new SendEmailProcessor(), + ]), + ); + + $manager = new RunSubscriptionEngineRepositoryManager($manager, $engine); + + $this->commandBus = SyncCommandBus::createForAggregateHandlers( + $aggregateRootRegistry, + $manager, + new ServiceLocator([ + ClockInterface::class => new SystemClock(), + 'env' => 'test', + ]), + ); + + $this->queryBus = new SyncQueryBus(new ServiceHandlerProvider([$profileProjection])); + + $schemaDirector = new DoctrineSchemaDirector($connection, $store); + + $schemaDirector->create(); + $engine->setup(skipBooting: true); + + $this->updateId = ProfileId::generate(); + $this->commandBus->dispatch(new CreateProfile($this->updateId, 'Peter')); + } + + #[Bench\Revs(10)] + public function benchCreate(): void + { + $id = ProfileId::generate(); + $this->commandBus->dispatch(new CreateProfile($id, 'James')); + $result = $this->queryBus->dispatch(new QueryProfileName($id)); + + assert($result === 'James'); + } + + #[Bench\Revs(10)] + public function benchUpdate(): void + { + $this->commandBus->dispatch(new ChangeProfileName($this->updateId, 'James Doe')); + $result = $this->queryBus->dispatch(new QueryProfileName($this->updateId)); + + assert($result === 'James Doe'); + } + + #[Bench\Revs(10)] + public function benchBoth(): void + { + $id = ProfileId::generate(); + $this->commandBus->dispatch(new CreateProfile($id, 'James')); + $result = $this->queryBus->dispatch(new QueryProfileName($id)); + assert($result === 'James'); + + $this->commandBus->dispatch(new ChangeProfileName($id, 'James Doe')); + $result = $this->queryBus->dispatch(new QueryProfileName($id)); + assert($result === 'James Doe'); + } +} diff --git a/tests/Integration/BasicImplementation/BasicIntegrationTest.php b/tests/Integration/BasicImplementation/BasicIntegrationTest.php index 6b0a05ad..19c11d0d 100644 --- a/tests/Integration/BasicImplementation/BasicIntegrationTest.php +++ b/tests/Integration/BasicImplementation/BasicIntegrationTest.php @@ -15,6 +15,8 @@ use Patchlevel\EventSourcing\Message\Serializer\DefaultHeadersSerializer; use Patchlevel\EventSourcing\Message\Translator\UntilEventTranslator; use Patchlevel\EventSourcing\Metadata\AggregateRoot\AggregateRootRegistry; +use Patchlevel\EventSourcing\QueryBus\ServiceHandlerProvider; +use Patchlevel\EventSourcing\QueryBus\SyncQueryBus; use Patchlevel\EventSourcing\Repository\DefaultRepositoryManager; use Patchlevel\EventSourcing\Schema\DoctrineSchemaDirector; use Patchlevel\EventSourcing\Serializer\DefaultEventSerializer; @@ -36,6 +38,7 @@ use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\MessageDecorator\FooMessageDecorator; use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\Processor\SendEmailProcessor; use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\Projection\ProfileProjector; +use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\Query\QueryProfileName; use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\TestCase; use Psr\Clock\ClockInterface; @@ -324,4 +327,69 @@ public function testCommandBus(): void self::assertSame('John Doe', $profile->name()); self::assertSame(1, SendEmailMock::count()); } + + public function testQueryBus(): void + { + $store = new DoctrineDbalStore( + $this->connection, + DefaultEventSerializer::createFromPaths([__DIR__ . '/Events']), + DefaultHeadersSerializer::createFromPaths([ + __DIR__ . '/Header', + ]), + ); + + $aggregateRootRegistry = new AggregateRootRegistry(['profile_with_commands' => ProfileWithCommands::class]); + + $manager = new DefaultRepositoryManager( + new AggregateRootRegistry(['profile_with_commands' => ProfileWithCommands::class]), + $store, + null, + new DefaultSnapshotStore(['default' => new InMemorySnapshotAdapter()]), + new FooMessageDecorator(), + ); + + $profileProjection = new ProfileProjector($this->connection); + + $engine = new DefaultSubscriptionEngine( + $store, + new InMemorySubscriptionStore(), + new MetadataSubscriberAccessorRepository([ + $profileProjection, + new SendEmailProcessor(), + ]), + ); + + $manager = new RunSubscriptionEngineRepositoryManager( + $manager, + $engine, + ); + + $commandBus = SyncCommandBus::createForAggregateHandlers( + $aggregateRootRegistry, + $manager, + new ServiceLocator([ + ClockInterface::class => new SystemClock(), + 'env' => 'test', + ]), + ); + + $queryBus = new SyncQueryBus(new ServiceHandlerProvider([$profileProjection])); + + $schemaDirector = new DoctrineSchemaDirector( + $this->connection, + $store, + ); + + $schemaDirector->create(); + $engine->setup(skipBooting: true); + + $profileId = ProfileId::generate(); + + $commandBus->dispatch(new CreateProfile($profileId, 'John')); + $commandBus->dispatch(new ChangeProfileName($profileId, 'John Doe')); + + $result = $queryBus->dispatch(new QueryProfileName($profileId)); + + self::assertSame('John Doe', $result); + } } diff --git a/tests/Integration/BasicImplementation/Projection/ProfileProjector.php b/tests/Integration/BasicImplementation/Projection/ProfileProjector.php index 1e33973f..f83ca17f 100644 --- a/tests/Integration/BasicImplementation/Projection/ProfileProjector.php +++ b/tests/Integration/BasicImplementation/Projection/ProfileProjector.php @@ -6,6 +6,7 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Schema\Table; +use Patchlevel\EventSourcing\Attribute\Answer; use Patchlevel\EventSourcing\Attribute\Projector; use Patchlevel\EventSourcing\Attribute\Setup; use Patchlevel\EventSourcing\Attribute\Subscribe; @@ -13,6 +14,7 @@ use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\Events\NameChanged; use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\Events\ProfileCreated; use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\ProfileId; +use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\Query\QueryProfileName; #[Projector('profile-1')] final class ProfileProjector @@ -62,4 +64,13 @@ public function handleNameChanged(NameChanged $nameChanged, ProfileId $profileId ], ); } + + #[Answer] + public function getProfileName(QueryProfileName $queryProfileName): string + { + return $this->connection->fetchAssociative( + 'SELECT name FROM projection_profile WHERE id = :id', + ['id' => $queryProfileName->id->toString()], + )['name']; + } } diff --git a/tests/Integration/BasicImplementation/Query/QueryProfileName.php b/tests/Integration/BasicImplementation/Query/QueryProfileName.php new file mode 100644 index 00000000..607db501 --- /dev/null +++ b/tests/Integration/BasicImplementation/Query/QueryProfileName.php @@ -0,0 +1,14 @@ + Date: Sun, 14 Dec 2025 22:14:13 +0000 Subject: [PATCH 04/24] Update dependency pymdown-extensions to v10.19.1 | datasource | package | from | to | | ---------- | ------------------ | ----- | ------- | | pypi | pymdown-extensions | 10.19 | 10.19.1 | Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 8f752ca8..a5b9b926 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -5,7 +5,7 @@ mkdocs-material==9.7.0 # Markdown extensions Pygments==2.19.2 -pymdown-extensions==10.19 +pymdown-extensions==10.19.1 # MkDocs plugins mkdocs-material-extensions==1.3.1 From 36d8d3f28832ed5eb4f639634ef9b14c45ab0b70 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 03:32:57 +0000 Subject: [PATCH 05/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- composer.lock | 180 ++++++++++++++++++++++---------------------- tools/composer.lock | 168 +++++++++++++++++++++++++++-------------- 2 files changed, 200 insertions(+), 148 deletions(-) diff --git a/composer.lock b/composer.lock index 136ea3f4..67ed8f23 100644 --- a/composer.lock +++ b/composer.lock @@ -68,16 +68,16 @@ }, { "name": "doctrine/dbal", - "version": "4.3.4", + "version": "4.4.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "1a2fbd0e93b8dec7c3d1ac2b6396a7b929b130dc" + "reference": "3d544473fb93f5c25b483ea4f4ce99f8c4d9d44c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/1a2fbd0e93b8dec7c3d1ac2b6396a7b929b130dc", - "reference": "1a2fbd0e93b8dec7c3d1ac2b6396a7b929b130dc", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/3d544473fb93f5c25b483ea4f4ce99f8c4d9d44c", + "reference": "3d544473fb93f5c25b483ea4f4ce99f8c4d9d44c", "shasum": "" }, "require": { @@ -96,8 +96,8 @@ "phpunit/phpunit": "11.5.23", "slevomat/coding-standard": "8.24.0", "squizlabs/php_codesniffer": "4.0.0", - "symfony/cache": "^6.3.8|^7.0", - "symfony/console": "^5.4|^6.3|^7.0" + "symfony/cache": "^6.3.8|^7.0|^8.0", + "symfony/console": "^5.4|^6.3|^7.0|^8.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -154,7 +154,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/4.3.4" + "source": "https://github.com/doctrine/dbal/tree/4.4.1" }, "funding": [ { @@ -170,7 +170,7 @@ "type": "tidelift" } ], - "time": "2025-10-09T09:11:36+00:00" + "time": "2025-12-04T10:11:03+00:00" }, { "name": "doctrine/deprecations", @@ -917,20 +917,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" }, @@ -989,22 +989,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/console", - "version": "v7.4.0", + "version": "v7.4.1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8" + "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8", - "reference": "0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8", + "url": "https://api.github.com/repos/symfony/console/zipball/6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e", + "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e", "shasum": "" }, "require": { @@ -1069,7 +1069,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.0" + "source": "https://github.com/symfony/console/tree/v7.4.1" }, "funding": [ { @@ -1089,7 +1089,7 @@ "type": "tidelift" } ], - "time": "2025-11-27T13:27:24+00:00" + "time": "2025-12-05T15:23:39+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1877,16 +1877,16 @@ }, { "name": "symfony/string", - "version": "v8.0.0", + "version": "v8.0.1", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f929eccf09531078c243df72398560e32fa4cf4f" + "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f929eccf09531078c243df72398560e32fa4cf4f", - "reference": "f929eccf09531078c243df72398560e32fa4cf4f", + "url": "https://api.github.com/repos/symfony/string/zipball/ba65a969ac918ce0cc3edfac6cdde847eba231dc", + "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc", "shasum": "" }, "require": { @@ -1943,7 +1943,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v8.0.0" + "source": "https://github.com/symfony/string/tree/v8.0.1" }, "funding": [ { @@ -1963,20 +1963,20 @@ "type": "tidelift" } ], - "time": "2025-09-11T14:37:55+00:00" + "time": "2025-12-01T09:13:36+00:00" }, { "name": "symfony/type-info", - "version": "v8.0.0", + "version": "v8.0.1", "source": { "type": "git", "url": "https://github.com/symfony/type-info.git", - "reference": "9de828eae6aeb33806f8f2fec161a8f8e79338d0" + "reference": "bb091cec1f70383538c7d000699781813f8d1a6a" }, "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/bb091cec1f70383538c7d000699781813f8d1a6a", + "reference": "bb091cec1f70383538c7d000699781813f8d1a6a", "shasum": "" }, "require": { @@ -2025,7 +2025,7 @@ "type" ], "support": { - "source": "https://github.com/symfony/type-info/tree/v8.0.0" + "source": "https://github.com/symfony/type-info/tree/v8.0.1" }, "funding": [ { @@ -2045,30 +2045,29 @@ "type": "tidelift" } ], - "time": "2025-11-08T16:30:39+00:00" + "time": "2025-12-05T14:08:45+00:00" }, { "name": "symfony/var-exporter", - "version": "v7.4.0", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "03a60f169c79a28513a78c967316fbc8bf17816f" + "reference": "7345f46c251f2eb27c7b3ebdb5bb076b3ffcae04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/03a60f169c79a28513a78c967316fbc8bf17816f", - "reference": "03a60f169c79a28513a78c967316fbc8bf17816f", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/7345f46c251f2eb27c7b3ebdb5bb076b3ffcae04", + "reference": "7345f46c251f2eb27c7b3ebdb5bb076b3ffcae04", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3" + "php": ">=8.4" }, "require-dev": { - "symfony/property-access": "^6.4|^7.0|^8.0", - "symfony/serializer": "^6.4|^7.0|^8.0", - "symfony/var-dumper": "^6.4|^7.0|^8.0" + "symfony/property-access": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -2106,7 +2105,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.4.0" + "source": "https://github.com/symfony/var-exporter/tree/v8.0.0" }, "funding": [ { @@ -2126,7 +2125,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:15:23+00:00" + "time": "2025-11-05T18:53:00+00:00" } ], "packages-dev": [ @@ -2936,16 +2935,16 @@ }, { "name": "doctrine/orm", - "version": "3.5.7", + "version": "3.5.8", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "f18de9d569f00ed6eb9dac4b33c7844d705d17da" + "reference": "78dd074266e8b47a83bcf60ab5fe06c91a639168" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/f18de9d569f00ed6eb9dac4b33c7844d705d17da", - "reference": "f18de9d569f00ed6eb9dac4b33c7844d705d17da", + "url": "https://api.github.com/repos/doctrine/orm/zipball/78dd074266e8b47a83bcf60ab5fe06c91a639168", + "reference": "78dd074266e8b47a83bcf60ab5fe06c91a639168", "shasum": "" }, "require": { @@ -2961,19 +2960,18 @@ "ext-ctype": "*", "php": "^8.1", "psr/cache": "^1 || ^2 || ^3", - "symfony/console": "^5.4 || ^6.0 || ^7.0", - "symfony/var-exporter": "^6.3.9 || ^7.0" + "symfony/console": "^5.4 || ^6.0 || ^7.0 || ^8.0", + "symfony/var-exporter": "^6.3.9 || ^7.0 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^14.0", "phpbench/phpbench": "^1.0", - "phpdocumentor/guides-cli": "^1.4", "phpstan/extension-installer": "^1.4", "phpstan/phpstan": "2.1.23", "phpstan/phpstan-deprecation-rules": "^2", "phpunit/phpunit": "^10.5.0 || ^11.5", "psr/log": "^1 || ^2 || ^3", - "symfony/cache": "^5.4 || ^6.2 || ^7.0" + "symfony/cache": "^5.4 || ^6.2 || ^7.0 || ^8.0" }, "suggest": { "ext-dom": "Provides support for XSD validation for XML mapping files", @@ -3019,9 +3017,9 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/3.5.7" + "source": "https://github.com/doctrine/orm/tree/3.5.8" }, - "time": "2025-11-11T18:27:40+00:00" + "time": "2025-11-29T23:11:02+00:00" }, { "name": "doctrine/persistence", @@ -3540,21 +3538,21 @@ }, { "name": "justinrainbow/json-schema", - "version": "6.6.1", + "version": "6.6.3", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "fd8e5c6b1badb998844ad34ce0abcd71a0aeb396" + "reference": "134e98916fa2f663afa623970af345cd788e8967" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/fd8e5c6b1badb998844ad34ce0abcd71a0aeb396", - "reference": "fd8e5c6b1badb998844ad34ce0abcd71a0aeb396", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/134e98916fa2f663afa623970af345cd788e8967", + "reference": "134e98916fa2f663afa623970af345cd788e8967", "shasum": "" }, "require": { "ext-json": "*", - "marc-mabe/php-enum": "^4.0", + "marc-mabe/php-enum": "^4.4", "php": "^7.2 || ^8.0" }, "require-dev": { @@ -3609,9 +3607,9 @@ ], "support": { "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.1" + "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.3" }, - "time": "2025-11-07T18:30:29+00:00" + "time": "2025-12-02T10:21:33+00:00" }, { "name": "league/commonmark", @@ -4002,20 +4000,20 @@ }, { "name": "nette/utils", - "version": "v4.0.9", + "version": "v4.1.0", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "505a30ad386daa5211f08a318e47015b501cad30" + "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/505a30ad386daa5211f08a318e47015b501cad30", - "reference": "505a30ad386daa5211f08a318e47015b501cad30", + "url": "https://api.github.com/repos/nette/utils/zipball/fa1f0b8261ed150447979eb22e373b7b7ad5a8e0", + "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0", "shasum": "" }, "require": { - "php": "8.0 - 8.5" + "php": "8.2 - 8.5" }, "conflict": { "nette/finder": "<3", @@ -4038,7 +4036,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -4085,22 +4083,22 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.9" + "source": "https://github.com/nette/utils/tree/v4.1.0" }, - "time": "2025-10-31T00:45:47+00:00" + "time": "2025-12-01T17:49:23+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": { @@ -4143,9 +4141,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", @@ -4653,11 +4651,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.32", + "version": "2.1.33", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e126cad1e30a99b137b8ed75a85a676450ebb227", - "reference": "e126cad1e30a99b137b8ed75a85a676450ebb227", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9e800e6bee7d5bd02784d4c6069b48032d16224f", + "reference": "9e800e6bee7d5bd02784d4c6069b48032d16224f", "shasum": "" }, "require": { @@ -4702,20 +4700,20 @@ "type": "github" } ], - "time": "2025-11-11T15:18:17+00:00" + "time": "2025-12-05T10:24:31+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "2.0.8", + "version": "2.0.10", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "2fe9fbeceaf76dd1ebaa7bbbb25e2fb5e59db2fe" + "reference": "8d61a5854e7497d95bc85188e13537e99bd7aae7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/2fe9fbeceaf76dd1ebaa7bbbb25e2fb5e59db2fe", - "reference": "2fe9fbeceaf76dd1ebaa7bbbb25e2fb5e59db2fe", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/8d61a5854e7497d95bc85188e13537e99bd7aae7", + "reference": "8d61a5854e7497d95bc85188e13537e99bd7aae7", "shasum": "" }, "require": { @@ -4753,9 +4751,9 @@ "description": "PHPUnit extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.8" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.10" }, - "time": "2025-11-11T07:55:22+00:00" + "time": "2025-12-06T11:15:39+00:00" }, { "name": "phpunit/php-code-coverage", @@ -5094,16 +5092,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.44", + "version": "11.5.46", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c346885c95423eda3f65d85a194aaa24873cda82" + "reference": "75dfe79a2aa30085b7132bb84377c24062193f33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c346885c95423eda3f65d85a194aaa24873cda82", - "reference": "c346885c95423eda3f65d85a194aaa24873cda82", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/75dfe79a2aa30085b7132bb84377c24062193f33", + "reference": "75dfe79a2aa30085b7132bb84377c24062193f33", "shasum": "" }, "require": { @@ -5175,7 +5173,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.44" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.46" }, "funding": [ { @@ -5199,7 +5197,7 @@ "type": "tidelift" } ], - "time": "2025-11-13T07:17:35+00:00" + "time": "2025-12-06T08:01:15+00:00" }, { "name": "sanmai/di-container", diff --git a/tools/composer.lock b/tools/composer.lock index 61cff083..1ed91da7 100644 --- a/tools/composer.lock +++ b/tools/composer.lock @@ -151,16 +151,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.5.9", + "version": "1.5.10", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "1905981ee626e6f852448b7aaa978f8666c5bc54" + "reference": "961a5e4056dd2e4a2eedcac7576075947c28bf63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/1905981ee626e6f852448b7aaa978f8666c5bc54", - "reference": "1905981ee626e6f852448b7aaa978f8666c5bc54", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/961a5e4056dd2e4a2eedcac7576075947c28bf63", + "reference": "961a5e4056dd2e4a2eedcac7576075947c28bf63", "shasum": "" }, "require": { @@ -207,7 +207,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.5.9" + "source": "https://github.com/composer/ca-bundle/tree/1.5.10" }, "funding": [ { @@ -219,7 +219,7 @@ "type": "github" } ], - "time": "2025-11-06T11:46:17+00:00" + "time": "2025-12-08T15:06:51+00:00" }, { "name": "composer/class-map-generator", @@ -776,16 +776,16 @@ }, { "name": "deptrac/deptrac", - "version": "4.2.1", + "version": "4.4.0", "source": { "type": "git", "url": "https://github.com/deptrac/deptrac.git", - "reference": "232eeb7e99fd287a5a3c4f79efc34a025fc81957" + "reference": "3058cb1b5908a25711ccc0f4c96b64e6fd704114" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/deptrac/deptrac/zipball/232eeb7e99fd287a5a3c4f79efc34a025fc81957", - "reference": "232eeb7e99fd287a5a3c4f79efc34a025fc81957", + "url": "https://api.github.com/repos/deptrac/deptrac/zipball/3058cb1b5908a25711ccc0f4c96b64e6fd704114", + "reference": "3058cb1b5908a25711ccc0f4c96b64e6fd704114", "shasum": "" }, "require": { @@ -794,8 +794,9 @@ "nikic/php-parser": "^5", "php": "^8.1", "phpdocumentor/graphviz": "^2.1", - "phpdocumentor/type-resolver": "^1.6", - "phpstan/phpdoc-parser": "^2.0", + "phpdocumentor/type-resolver": "^1.9.0", + "phpstan/phpdoc-parser": "^1.5.0|^2.1.0", + "phpstan/phpstan": "^2.0", "psr/container": "^2.0", "psr/event-dispatcher": "^1.0", "symfony/config": "^6.4|^7.0", @@ -854,9 +855,9 @@ ], "support": { "issues": "https://github.com/deptrac/deptrac/issues", - "source": "https://github.com/deptrac/deptrac/tree/4.2.1" + "source": "https://github.com/deptrac/deptrac/tree/4.4.0" }, - "time": "2025-09-29T13:03:57+00:00" + "time": "2025-12-08T08:14:18+00:00" }, { "name": "doctrine/deprecations", @@ -955,21 +956,21 @@ }, { "name": "justinrainbow/json-schema", - "version": "6.6.2", + "version": "6.6.3", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "3c25fe750c1599716ef26aa997f7c026cee8c4b7" + "reference": "134e98916fa2f663afa623970af345cd788e8967" }, "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/134e98916fa2f663afa623970af345cd788e8967", + "reference": "134e98916fa2f663afa623970af345cd788e8967", "shasum": "" }, "require": { "ext-json": "*", - "marc-mabe/php-enum": "^4.0", + "marc-mabe/php-enum": "^4.4", "php": "^7.2 || ^8.0" }, "require-dev": { @@ -1024,9 +1025,9 @@ ], "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/6.6.3" }, - "time": "2025-11-28T15:24:03+00:00" + "time": "2025-12-02T10:21:33+00:00" }, { "name": "marc-mabe/php-enum", @@ -1103,16 +1104,16 @@ }, { "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": { @@ -1155,9 +1156,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": "nikolaposa/version", @@ -1494,6 +1495,59 @@ }, "time": "2025-08-30T15:50:23+00:00" }, + { + "name": "phpstan/phpstan", + "version": "2.1.33", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9e800e6bee7d5bd02784d4c6069b48032d16224f", + "reference": "9e800e6bee7d5bd02784d4c6069b48032d16224f", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2025-12-05T10:24:31+00:00" + }, { "name": "psr/container", "version": "2.0.2", @@ -2110,16 +2164,16 @@ }, { "name": "symfony/config", - "version": "v7.4.0", + "version": "v7.4.1", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "f76c74e93bce2b9285f2dad7fbd06fa8182a7a41" + "reference": "2c323304c354a43a48b61c5fa760fc4ed60ce495" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/f76c74e93bce2b9285f2dad7fbd06fa8182a7a41", - "reference": "f76c74e93bce2b9285f2dad7fbd06fa8182a7a41", + "url": "https://api.github.com/repos/symfony/config/zipball/2c323304c354a43a48b61c5fa760fc4ed60ce495", + "reference": "2c323304c354a43a48b61c5fa760fc4ed60ce495", "shasum": "" }, "require": { @@ -2165,7 +2219,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/v7.4.0" + "source": "https://github.com/symfony/config/tree/v7.4.1" }, "funding": [ { @@ -2185,20 +2239,20 @@ "type": "tidelift" } ], - "time": "2025-11-27T13:27:24+00:00" + "time": "2025-12-05T07:52:08+00:00" }, { "name": "symfony/console", - "version": "v7.4.0", + "version": "v7.4.1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8" + "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8", - "reference": "0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8", + "url": "https://api.github.com/repos/symfony/console/zipball/6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e", + "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e", "shasum": "" }, "require": { @@ -2263,7 +2317,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.0" + "source": "https://github.com/symfony/console/tree/v7.4.1" }, "funding": [ { @@ -2283,20 +2337,20 @@ "type": "tidelift" } ], - "time": "2025-11-27T13:27:24+00:00" + "time": "2025-12-05T15:23:39+00:00" }, { "name": "symfony/dependency-injection", - "version": "v7.4.0", + "version": "v7.4.2", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "3972ca7bbd649467b21a54870721b9e9f3652f9b" + "reference": "baf614f7c15b30ba6762d4b1ddabdf83dbf0d29b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/3972ca7bbd649467b21a54870721b9e9f3652f9b", - "reference": "3972ca7bbd649467b21a54870721b9e9f3652f9b", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/baf614f7c15b30ba6762d4b1ddabdf83dbf0d29b", + "reference": "baf614f7c15b30ba6762d4b1ddabdf83dbf0d29b", "shasum": "" }, "require": { @@ -2347,7 +2401,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/v7.4.0" + "source": "https://github.com/symfony/dependency-injection/tree/v7.4.2" }, "funding": [ { @@ -2367,7 +2421,7 @@ "type": "tidelift" } ], - "time": "2025-11-27T13:27:24+00:00" + "time": "2025-12-08T06:57:04+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3548,16 +3602,16 @@ }, { "name": "symfony/string", - "version": "v8.0.0", + "version": "v8.0.1", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f929eccf09531078c243df72398560e32fa4cf4f" + "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f929eccf09531078c243df72398560e32fa4cf4f", - "reference": "f929eccf09531078c243df72398560e32fa4cf4f", + "url": "https://api.github.com/repos/symfony/string/zipball/ba65a969ac918ce0cc3edfac6cdde847eba231dc", + "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc", "shasum": "" }, "require": { @@ -3614,7 +3668,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v8.0.0" + "source": "https://github.com/symfony/string/tree/v8.0.1" }, "funding": [ { @@ -3634,7 +3688,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T14:37:55+00:00" + "time": "2025-12-01T09:13:36+00:00" }, { "name": "symfony/var-exporter", @@ -3718,16 +3772,16 @@ }, { "name": "symfony/yaml", - "version": "v7.4.0", + "version": "v7.4.1", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "6c84a4b55aee4cd02034d1c528e83f69ddf63810" + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/6c84a4b55aee4cd02034d1c528e83f69ddf63810", - "reference": "6c84a4b55aee4cd02034d1c528e83f69ddf63810", + "url": "https://api.github.com/repos/symfony/yaml/zipball/24dd4de28d2e3988b311751ac49e684d783e2345", + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345", "shasum": "" }, "require": { @@ -3770,7 +3824,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.4.0" + "source": "https://github.com/symfony/yaml/tree/v7.4.1" }, "funding": [ { @@ -3790,7 +3844,7 @@ "type": "tidelift" } ], - "time": "2025-11-16T10:14:42+00:00" + "time": "2025-12-04T18:11:45+00:00" } ], "packages-dev": [], From e488b56eded5eb02d77eeed89888004c0b02432b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Dec 2025 10:30:51 +0000 Subject: [PATCH 06/24] Update dependency mkdocs-material to v9.7.1 | datasource | package | from | to | | ---------- | --------------- | ----- | ----- | | pypi | mkdocs-material | 9.7.0 | 9.7.1 | Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index a5b9b926..34832beb 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,7 +1,7 @@ mkdocs==1.6.1 mike==2.1.3 markdown==3.10 -mkdocs-material==9.7.0 +mkdocs-material==9.7.1 # Markdown extensions Pygments==2.19.2 From 024ba26f959947541c3480c1d210ce042ab0a329 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 20 Dec 2025 01:04:11 +0000 Subject: [PATCH 07/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- composer.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index 67ed8f23..2c5abdca 100644 --- a/composer.lock +++ b/composer.lock @@ -2935,16 +2935,16 @@ }, { "name": "doctrine/orm", - "version": "3.5.8", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "78dd074266e8b47a83bcf60ab5fe06c91a639168" + "reference": "d4e9276e79602b1eb4c4029c6c999b0d93478e2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/78dd074266e8b47a83bcf60ab5fe06c91a639168", - "reference": "78dd074266e8b47a83bcf60ab5fe06c91a639168", + "url": "https://api.github.com/repos/doctrine/orm/zipball/d4e9276e79602b1eb4c4029c6c999b0d93478e2f", + "reference": "d4e9276e79602b1eb4c4029c6c999b0d93478e2f", "shasum": "" }, "require": { @@ -3017,9 +3017,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.0" }, - "time": "2025-11-29T23:11:02+00:00" + "time": "2025-12-19T20:36:14+00:00" }, { "name": "doctrine/persistence", @@ -4704,16 +4704,16 @@ }, { "name": "phpstan/phpstan-phpunit", - "version": "2.0.10", + "version": "2.0.11", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "8d61a5854e7497d95bc85188e13537e99bd7aae7" + "reference": "5e30669bef866eff70db8b58d72a5c185aa82414" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/8d61a5854e7497d95bc85188e13537e99bd7aae7", - "reference": "8d61a5854e7497d95bc85188e13537e99bd7aae7", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/5e30669bef866eff70db8b58d72a5c185aa82414", + "reference": "5e30669bef866eff70db8b58d72a5c185aa82414", "shasum": "" }, "require": { @@ -4751,9 +4751,9 @@ "description": "PHPUnit extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.10" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.11" }, - "time": "2025-12-06T11:15:39+00:00" + "time": "2025-12-19T09:05:35+00:00" }, { "name": "phpunit/php-code-coverage", From 24527270bd20e11699eb3a564e35b812c4cb7972 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Dec 2025 02:52:23 +0000 Subject: [PATCH 08/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 2c5abdca..621c0673 100644 --- a/composer.lock +++ b/composer.lock @@ -5404,16 +5404,16 @@ }, { "name": "sanmai/pipeline", - "version": "7.5", + "version": "7.6", "source": { "type": "git", "url": "https://github.com/sanmai/pipeline.git", - "reference": "c3b87db671ee0bc286860bd13bdb7cfc108b7d7e" + "reference": "f7aeb6e1c9572f366c6035c79d715a2a73eeb1c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sanmai/pipeline/zipball/c3b87db671ee0bc286860bd13bdb7cfc108b7d7e", - "reference": "c3b87db671ee0bc286860bd13bdb7cfc108b7d7e", + "url": "https://api.github.com/repos/sanmai/pipeline/zipball/f7aeb6e1c9572f366c6035c79d715a2a73eeb1c9", + "reference": "f7aeb6e1c9572f366c6035c79d715a2a73eeb1c9", "shasum": "" }, "require": { @@ -5460,7 +5460,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.6" }, "funding": [ { @@ -5468,7 +5468,7 @@ "type": "github" } ], - "time": "2025-11-05T10:54:07+00:00" + "time": "2025-12-20T07:22:08+00:00" }, { "name": "sebastian/cli-parser", From 1e0365c1412458599bb1423670918e03c61e3a87 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 23 Dec 2025 00:49:46 +0000 Subject: [PATCH 09/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 621c0673..5deffe49 100644 --- a/composer.lock +++ b/composer.lock @@ -4000,16 +4000,16 @@ }, { "name": "nette/utils", - "version": "v4.1.0", + "version": "v4.1.1", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0" + "reference": "c99059c0315591f1a0db7ad6002000288ab8dc72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/fa1f0b8261ed150447979eb22e373b7b7ad5a8e0", - "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0", + "url": "https://api.github.com/repos/nette/utils/zipball/c99059c0315591f1a0db7ad6002000288ab8dc72", + "reference": "c99059c0315591f1a0db7ad6002000288ab8dc72", "shasum": "" }, "require": { @@ -4083,9 +4083,9 @@ ], "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.1" }, - "time": "2025-12-01T17:49:23+00:00" + "time": "2025-12-22T12:14:32+00:00" }, { "name": "nikic/php-parser", From c0aed5dbc78551afcfda0a9c2fe3620ef6985b44 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Dec 2025 02:09:58 +0000 Subject: [PATCH 10/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- composer.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/composer.lock b/composer.lock index 5deffe49..29cd23a2 100644 --- a/composer.lock +++ b/composer.lock @@ -4757,35 +4757,35 @@ }, { "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", @@ -4823,7 +4823,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": [ { @@ -4843,7 +4843,7 @@ "type": "tidelift" } ], - "time": "2025-08-27T14:37:49+00:00" + "time": "2025-12-24T07:01:01+00:00" }, { "name": "phpunit/php-file-iterator", From d69b1153aad0a40770947bac09dec5ad5e32f89c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Dec 2025 16:49:18 +0000 Subject: [PATCH 11/24] Update dependency infection/infection to ^0.32.0 | datasource | package | from | to | | ---------- | ------------------- | ------ | ------ | | packagist | infection/infection | 0.31.9 | 0.32.0 | Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- composer.json | 2 +- composer.lock | 132 +++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 104 insertions(+), 30 deletions(-) diff --git a/composer.json b/composer.json index ef610885..89b479ea 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "require-dev": { "ext-pdo_sqlite": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", "doctrine/orm": "^2.18.0 || ^3.0.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", diff --git a/composer.lock b/composer.lock index 29cd23a2..a2f82ce4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "89b1cd6613866204168f1dfda93dcfb8", + "content-hash": "eaaa35929b4073dbe5946b8486ca1a64", "packages": [ { "name": "brick/math", @@ -3354,16 +3354,16 @@ }, { "name": "infection/infection", - "version": "0.31.9", + "version": "0.32.0", "source": { "type": "git", - "url": "https://github.com/infection/infection.git", - "reference": "f9628fcd7f76eadf24726e57a81937c42458232b" + "url": "https://github.com/infection/infection", + "reference": "71d4a12cbe62d79c06dce628b8a5fe234636424c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/infection/infection/zipball/f9628fcd7f76eadf24726e57a81937c42458232b", - "reference": "f9628fcd7f76eadf24726e57a81937c42458232b", + "url": "https://api.github.com/repos/infection/infection/zipball/71d4a12cbe62d79c06dce628b8a5fe234636424c", + "reference": "71d4a12cbe62d79c06dce628b8a5fe234636424c", "shasum": "" }, "require": { @@ -3380,20 +3380,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", + "psr/log": "^2.0 || ^3.0", "sanmai/di-container": "^0.1.4", "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", + "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", @@ -3402,18 +3404,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" @@ -3468,20 +3473,9 @@ "unit testing" ], "support": { - "issues": "https://github.com/infection/infection/issues", - "source": "https://github.com/infection/infection/tree/0.31.9" + "issues": "https://github.com/infection/infection/issues" }, - "funding": [ - { - "url": "https://github.com/infection", - "type": "github" - }, - { - "url": "https://opencollective.com/infection", - "type": "open_collective" - } - ], - "time": "2025-10-27T12:00:54+00:00" + "time": "2025-12-24T13:55:03+00:00" }, { "name": "infection/mutator", @@ -7186,6 +7180,86 @@ ], "time": "2025-06-24T13:30:11+00:00" }, + { + "name": "symfony/polyfill-php85", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php85\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-23T16:12:55+00:00" + }, { "name": "symfony/process", "version": "v7.4.0", From 62d0aeae7f8d7aa52a510853da53694e7dc6e755 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Dec 2025 01:46:38 +0000 Subject: [PATCH 12/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- composer.lock | 124 ++++++++++++++++++++++++-------------------------- 1 file changed, 60 insertions(+), 64 deletions(-) diff --git a/composer.lock b/composer.lock index a2f82ce4..7771d747 100644 --- a/composer.lock +++ b/composer.lock @@ -995,47 +995,39 @@ }, { "name": "symfony/console", - "version": "v7.4.1", + "version": "v8.0.1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e" + "reference": "fcb73f69d655b48fcb894a262f074218df08bd58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e", - "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e", + "url": "https://api.github.com/repos/symfony/console/zipball/fcb73f69d655b48fcb894a262f074218df08bd58", + "reference": "fcb73f69d655b48fcb894a262f074218df08bd58", "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": { @@ -1069,7 +1061,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.1" + "source": "https://github.com/symfony/console/tree/v8.0.1" }, "funding": [ { @@ -1089,7 +1081,7 @@ "type": "tidelift" } ], - "time": "2025-12-05T15:23:39+00:00" + "time": "2025-12-05T15:25:33+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1321,23 +1313,23 @@ }, { "name": "symfony/finder", - "version": "v7.4.0", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "340b9ed7320570f319028a2cbec46d40535e94bd" + "reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/340b9ed7320570f319028a2cbec46d40535e94bd", - "reference": "340b9ed7320570f319028a2cbec46d40535e94bd", + "url": "https://api.github.com/repos/symfony/finder/zipball/7598dd5770580fa3517ec83e8da0c9b9e01f4291", + "reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291", "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": { @@ -1365,7 +1357,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.0" }, "funding": [ { @@ -1385,7 +1377,7 @@ "type": "tidelift" } ], - "time": "2025-11-05T05:42:40+00:00" + "time": "2025-11-05T14:36:47+00:00" }, { "name": "symfony/polyfill-ctype", @@ -4392,16 +4384,16 @@ }, { "name": "phpat/phpat", - "version": "0.12.0", + "version": "0.12.1", "source": { "type": "git", "url": "https://github.com/carlosas/phpat.git", - "reference": "f1d0eccdba0a6862b7a639cbd020147c35b63763" + "reference": "67b9e179757fbaa8b87e1469a66f103725858ee0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/carlosas/phpat/zipball/f1d0eccdba0a6862b7a639cbd020147c35b63763", - "reference": "f1d0eccdba0a6862b7a639cbd020147c35b63763", + "url": "https://api.github.com/repos/carlosas/phpat/zipball/67b9e179757fbaa8b87e1469a66f103725858ee0", + "reference": "67b9e179757fbaa8b87e1469a66f103725858ee0", "shasum": "" }, "require": { @@ -4443,9 +4435,9 @@ "description": "PHP Architecture Tester", "support": { "issues": "https://github.com/carlosas/phpat/issues", - "source": "https://github.com/carlosas/phpat/tree/0.12.0" + "source": "https://github.com/carlosas/phpat/tree/0.12.1" }, - "time": "2025-09-11T19:00:27+00:00" + "time": "2025-12-25T17:53:07+00:00" }, { "name": "phpbench/container", @@ -6789,25 +6781,25 @@ }, { "name": "symfony/filesystem", - "version": "v7.4.0", + "version": "v8.0.1", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "d551b38811096d0be9c4691d406991b47c0c630a" + "reference": "d937d400b980523dc9ee946bb69972b5e619058d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/d551b38811096d0be9c4691d406991b47c0c630a", - "reference": "d551b38811096d0be9c4691d406991b47c0c630a", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d", + "reference": "d937d400b980523dc9ee946bb69972b5e619058d", "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": { @@ -6835,7 +6827,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.1" }, "funding": [ { @@ -6855,7 +6847,7 @@ "type": "tidelift" } ], - "time": "2025-11-27T13:27:24+00:00" + "time": "2025-12-01T09:13:36+00:00" }, { "name": "symfony/messenger", @@ -7262,20 +7254,20 @@ }, { "name": "symfony/process", - "version": "v7.4.0", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "7ca8dc2d0dcf4882658313aba8be5d9fd01026c8" + "reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/7ca8dc2d0dcf4882658313aba8be5d9fd01026c8", - "reference": "7ca8dc2d0dcf4882658313aba8be5d9fd01026c8", + "url": "https://api.github.com/repos/symfony/process/zipball/a0a750500c4ce900d69ba4e9faf16f82c10ee149", + "reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "type": "library", "autoload": { @@ -7303,7 +7295,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.0" }, "funding": [ { @@ -7323,7 +7315,7 @@ "type": "tidelift" } ], - "time": "2025-10-16T11:21:06+00:00" + "time": "2025-10-16T16:25:44+00:00" }, { "name": "symfony/var-dumper", @@ -7603,23 +7595,23 @@ }, { "name": "webmozart/assert", - "version": "1.12.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" + "reference": "1b34b004e35a164bc5bb6ebd33c844b2d8069a54" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", - "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/1b34b004e35a164bc5bb6ebd33c844b2d8069a54", + "reference": "1b34b004e35a164bc5bb6ebd33c844b2d8069a54", "shasum": "" }, "require": { "ext-ctype": "*", "ext-date": "*", "ext-filter": "*", - "php": "^7.2 || ^8.0" + "php": "^8.2" }, "suggest": { "ext-intl": "", @@ -7629,7 +7621,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.10-dev" + "dev-feature/2-0": "2.0-dev" } }, "autoload": { @@ -7645,6 +7637,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.", @@ -7655,9 +7651,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.0.0" }, - "time": "2025-10-29T15:56:20+00:00" + "time": "2025-12-16T21:36:00+00:00" }, { "name": "webmozart/glob", From 46126cb2b4376c053c821b0ed74ff5a2af09442d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 27 Dec 2025 01:35:10 +0000 Subject: [PATCH 13/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- composer.lock | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/composer.lock b/composer.lock index 7771d747..a734399c 100644 --- a/composer.lock +++ b/composer.lock @@ -5262,16 +5262,16 @@ }, { "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": { @@ -5289,8 +5289,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": { @@ -5314,7 +5313,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": [ { @@ -5322,7 +5321,7 @@ "type": "github" } ], - "time": "2025-07-28T02:17:28+00:00" + "time": "2025-12-26T06:12:34+00:00" }, { "name": "sanmai/later", From a935088216a45b72f73eadd1d520e3c8b23f20a0 Mon Sep 17 00:00:00 2001 From: Daniel Badura Date: Mon, 29 Dec 2025 09:23:21 +0100 Subject: [PATCH 14/24] Add `StoreMigrateCommand` from integration repos to ease maintainance --- src/Console/Command/StoreMigrateCommand.php | 88 +++++ .../Command/StoreMigrateCommandTest.php | 330 ++++++++++++++++++ 2 files changed, 418 insertions(+) create mode 100644 src/Console/Command/StoreMigrateCommand.php create mode 100644 tests/Unit/Console/Command/StoreMigrateCommandTest.php diff --git a/src/Console/Command/StoreMigrateCommand.php b/src/Console/Command/StoreMigrateCommand.php new file mode 100644 index 00000000..b91daa3d --- /dev/null +++ b/src/Console/Command/StoreMigrateCommand.php @@ -0,0 +1,88 @@ + $translators */ + public function __construct( + private readonly Store $store, + private readonly Store $newStore, + private readonly iterable $translators = [], + ) { + parent::__construct(); + } + + protected function configure(): void + { + $this + ->addOption( + 'buffer', + null, + InputOption::VALUE_REQUIRED, + 'How many messages should be buffered', + 1_000, + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $buffer = InputHelper::positiveIntOrZero($input->getOption('buffer')); + $style = new OutputStyle($input, $output); + + $style->info('Migration initialization...'); + + $count = $this->store->count(); + $messages = $this->store->load(); + + $style->progressStart($count); + + $bufferedMessages = []; + + $pipe = new Pipe( + $messages, + ...$this->translators, + ); + + foreach ($pipe as $message) { + $bufferedMessages[] = $message; + + if (count($bufferedMessages) < $buffer) { + continue; + } + + $this->newStore->save(...$bufferedMessages); + $bufferedMessages = []; + $style->progressAdvance($buffer); + } + + if (count($bufferedMessages) !== 0) { + $this->newStore->save(...$bufferedMessages); + $style->progressAdvance(count($bufferedMessages)); + } + + $style->progressFinish(); + $style->success('Migration finished'); + + return 0; + } +} diff --git a/tests/Unit/Console/Command/StoreMigrateCommandTest.php b/tests/Unit/Console/Command/StoreMigrateCommandTest.php new file mode 100644 index 00000000..15e497f6 --- /dev/null +++ b/tests/Unit/Console/Command/StoreMigrateCommandTest.php @@ -0,0 +1,330 @@ +run($input, $output); + + self::assertSame(0, $exitCode); + + $content = $output->fetch(); + + self::assertStringContainsString('Migration initialization...', $content); + self::assertStringContainsString('0', $content); + self::assertStringContainsString('Migration finished', $content); + } + + public function testOneMessage(): void + { + $fromStore = new InMemoryStore([ + new Message( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('info@patchlevel.de'), + ), + ), + ]); + $toStore = new InMemoryStore(); + + $command = new StoreMigrateCommand($fromStore, $toStore, []); + + $input = new ArrayInput([]); + $output = new BufferedOutput(); + + $exitCode = $command->run($input, $output); + + self::assertSame(0, $exitCode); + + $content = $output->fetch(); + + self::assertStringContainsString('Migration initialization...', $content); + self::assertStringContainsString('1', $content); + self::assertStringContainsString('Migration finished', $content); + + self::assertCount(1, iterator_to_array($toStore->load()->getIterator())); + } + + public function testTenMessages(): void + { + $fromStore = new InMemoryStore([ + new Message( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('2'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('3'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('4'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('5'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('6'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('7'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('8'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('9'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('10'), + Email::fromString('info@patchlevel.de'), + ), + ), + ]); + $toStore = new InMemoryStore(); + + $command = new StoreMigrateCommand($fromStore, $toStore, []); + + $input = new ArrayInput([]); + $output = new BufferedOutput(); + + $exitCode = $command->run($input, $output); + + self::assertSame(0, $exitCode); + + $content = $output->fetch(); + + self::assertStringContainsString('Migration initialization...', $content); + self::assertStringContainsString('10', $content); + self::assertStringContainsString('Migration finished', $content); + + self::assertCount(10, iterator_to_array($toStore->load()->getIterator())); + } + + public function testTenMessagesWithBufferAt2(): void + { + $fromStore = new InMemoryStore([ + new Message( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('2'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('3'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('4'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('5'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('6'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('7'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('8'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('9'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('10'), + Email::fromString('info@patchlevel.de'), + ), + ), + ]); + $toStore = new InMemoryStore(); + + $command = new StoreMigrateCommand($fromStore, $toStore, []); + + $input = new ArrayInput(['--buffer' => 10]); + $output = new BufferedOutput(); + + $exitCode = $command->run($input, $output); + + self::assertSame(0, $exitCode); + + $content = $output->fetch(); + + self::assertStringContainsString('Migration initialization...', $content); + self::assertStringContainsString('10', $content); + self::assertStringContainsString('Migration finished', $content); + + self::assertCount(10, iterator_to_array($toStore->load()->getIterator())); + } + + public function testTenMessagesWithDroppingTranslator(): void + { + $fromStore = new InMemoryStore([ + new Message( + new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('2'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('3'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('4'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('5'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('6'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('7'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('8'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileCreated( + ProfileId::fromString('9'), + Email::fromString('info@patchlevel.de'), + ), + ), + new Message( + new ProfileVisited( + ProfileId::fromString('1'), + ), + ), + ]); + $toStore = new InMemoryStore(); + + $command = new StoreMigrateCommand( + $fromStore, + $toStore, + [new ExcludeEventTranslator([ProfileCreated::class])], + ); + + $input = new ArrayInput([]); + $output = new BufferedOutput(); + + $exitCode = $command->run($input, $output); + + self::assertSame(0, $exitCode); + + $content = $output->fetch(); + + self::assertStringContainsString('Migration initialization...', $content); + self::assertStringContainsString('10', $content); + self::assertStringContainsString('Migration finished', $content); + + self::assertCount(1, iterator_to_array($toStore->load()->getIterator())); + } +} From 6dc8a9f141b61cd414a7832574db0aa6d588388f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 30 Dec 2025 01:27:56 +0000 Subject: [PATCH 15/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- tools/composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/composer.lock b/tools/composer.lock index 1ed91da7..9d15a808 100644 --- a/tools/composer.lock +++ b/tools/composer.lock @@ -223,16 +223,16 @@ }, { "name": "composer/class-map-generator", - "version": "1.7.0", + "version": "1.7.1", "source": { "type": "git", "url": "https://github.com/composer/class-map-generator.git", - "reference": "2373419b7709815ed323ebf18c3c72d03ff4a8a6" + "reference": "8f5fa3cc214230e71f54924bd0197a3bcc705eb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/class-map-generator/zipball/2373419b7709815ed323ebf18c3c72d03ff4a8a6", - "reference": "2373419b7709815ed323ebf18c3c72d03ff4a8a6", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/8f5fa3cc214230e71f54924bd0197a3bcc705eb1", + "reference": "8f5fa3cc214230e71f54924bd0197a3bcc705eb1", "shasum": "" }, "require": { @@ -276,7 +276,7 @@ ], "support": { "issues": "https://github.com/composer/class-map-generator/issues", - "source": "https://github.com/composer/class-map-generator/tree/1.7.0" + "source": "https://github.com/composer/class-map-generator/tree/1.7.1" }, "funding": [ { @@ -288,7 +288,7 @@ "type": "github" } ], - "time": "2025-11-19T10:41:15+00:00" + "time": "2025-12-29T13:15:25+00:00" }, { "name": "composer/composer", From fd74b0889633f33d539a9cba39e2e41d4742e8f5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 31 Dec 2025 02:01:41 +0000 Subject: [PATCH 16/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- tools/composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/composer.lock b/tools/composer.lock index 9d15a808..1a8d6280 100644 --- a/tools/composer.lock +++ b/tools/composer.lock @@ -292,16 +292,16 @@ }, { "name": "composer/composer", - "version": "2.9.2", + "version": "2.9.3", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "8d5358f147c63a3a681b002076deff8c90e0b19d" + "reference": "fb3bee27676fd852a8a11ebbb1de19b4dada5aba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/8d5358f147c63a3a681b002076deff8c90e0b19d", - "reference": "8d5358f147c63a3a681b002076deff8c90e0b19d", + "url": "https://api.github.com/repos/composer/composer/zipball/fb3bee27676fd852a8a11ebbb1de19b4dada5aba", + "reference": "fb3bee27676fd852a8a11ebbb1de19b4dada5aba", "shasum": "" }, "require": { @@ -389,7 +389,7 @@ "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/composer/issues", "security": "https://github.com/composer/composer/security/policy", - "source": "https://github.com/composer/composer/tree/2.9.2" + "source": "https://github.com/composer/composer/tree/2.9.3" }, "funding": [ { @@ -401,7 +401,7 @@ "type": "github" } ], - "time": "2025-11-19T20:57:25+00:00" + "time": "2025-12-30T12:40:17+00:00" }, { "name": "composer/metadata-minifier", From 705afc38b828ab79d8b01cf973133c6d0ad62990 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 31 Dec 2025 21:52:39 +0000 Subject: [PATCH 17/24] Update dependency pymdown-extensions to v10.20 | datasource | package | from | to | | ---------- | ------------------ | ------- | ----- | | pypi | pymdown-extensions | 10.19.1 | 10.20 | Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 34832beb..effa5a13 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -5,7 +5,7 @@ mkdocs-material==9.7.1 # Markdown extensions Pygments==2.19.2 -pymdown-extensions==10.19.1 +pymdown-extensions==10.20 # MkDocs plugins mkdocs-material-extensions==1.3.1 From f37304a12397fb8051e3b036290485f0da9da975 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Jan 2026 02:11:02 +0000 Subject: [PATCH 18/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- composer.lock | 60 ++++++++++++++++++++++----------------------- tools/composer.lock | 60 ++++++++++++++++++++++----------------------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/composer.lock b/composer.lock index a734399c..bd7b5e04 100644 --- a/composer.lock +++ b/composer.lock @@ -995,16 +995,16 @@ }, { "name": "symfony/console", - "version": "v8.0.1", + "version": "v8.0.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "fcb73f69d655b48fcb894a262f074218df08bd58" + "reference": "6145b304a5c1ea0bdbd0b04d297a5864f9a7d587" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/fcb73f69d655b48fcb894a262f074218df08bd58", - "reference": "fcb73f69d655b48fcb894a262f074218df08bd58", + "url": "https://api.github.com/repos/symfony/console/zipball/6145b304a5c1ea0bdbd0b04d297a5864f9a7d587", + "reference": "6145b304a5c1ea0bdbd0b04d297a5864f9a7d587", "shasum": "" }, "require": { @@ -1061,7 +1061,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v8.0.1" + "source": "https://github.com/symfony/console/tree/v8.0.3" }, "funding": [ { @@ -1081,7 +1081,7 @@ "type": "tidelift" } ], - "time": "2025-12-05T15:25:33+00:00" + "time": "2025-12-23T14:52:06+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1313,16 +1313,16 @@ }, { "name": "symfony/finder", - "version": "v8.0.0", + "version": "v8.0.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291" + "reference": "dd3a2953570a283a2ba4e17063bb98c734cf5b12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/7598dd5770580fa3517ec83e8da0c9b9e01f4291", - "reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291", + "url": "https://api.github.com/repos/symfony/finder/zipball/dd3a2953570a283a2ba4e17063bb98c734cf5b12", + "reference": "dd3a2953570a283a2ba4e17063bb98c734cf5b12", "shasum": "" }, "require": { @@ -1357,7 +1357,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v8.0.0" + "source": "https://github.com/symfony/finder/tree/v8.0.3" }, "funding": [ { @@ -1377,7 +1377,7 @@ "type": "tidelift" } ], - "time": "2025-11-05T14:36:47+00:00" + "time": "2025-12-23T14:52:06+00:00" }, { "name": "symfony/polyfill-ctype", @@ -6850,16 +6850,16 @@ }, { "name": "symfony/messenger", - "version": "v8.0.0", + "version": "v8.0.3", "source": { "type": "git", "url": "https://github.com/symfony/messenger.git", - "reference": "c37b86c313e26291c5defe9194bcf31cbe630fbc" + "reference": "b56b89aee16ceb623f76c8739ab62202ec198190" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/messenger/zipball/c37b86c313e26291c5defe9194bcf31cbe630fbc", - "reference": "c37b86c313e26291c5defe9194bcf31cbe630fbc", + "url": "https://api.github.com/repos/symfony/messenger/zipball/b56b89aee16ceb623f76c8739ab62202ec198190", + "reference": "b56b89aee16ceb623f76c8739ab62202ec198190", "shasum": "" }, "require": { @@ -6914,7 +6914,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.3" }, "funding": [ { @@ -6934,7 +6934,7 @@ "type": "tidelift" } ], - "time": "2025-11-06T11:20:17+00:00" + "time": "2025-12-23T14:52:06+00:00" }, { "name": "symfony/options-resolver", @@ -7253,16 +7253,16 @@ }, { "name": "symfony/process", - "version": "v8.0.0", + "version": "v8.0.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149" + "reference": "0cbbd88ec836f8757641c651bb995335846abb78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/a0a750500c4ce900d69ba4e9faf16f82c10ee149", - "reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149", + "url": "https://api.github.com/repos/symfony/process/zipball/0cbbd88ec836f8757641c651bb995335846abb78", + "reference": "0cbbd88ec836f8757641c651bb995335846abb78", "shasum": "" }, "require": { @@ -7294,7 +7294,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v8.0.0" + "source": "https://github.com/symfony/process/tree/v8.0.3" }, "funding": [ { @@ -7314,20 +7314,20 @@ "type": "tidelift" } ], - "time": "2025-10-16T16:25:44+00:00" + "time": "2025-12-19T10:01:18+00:00" }, { "name": "symfony/var-dumper", - "version": "v8.0.0", + "version": "v8.0.3", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "d2a2476c93b58ac5292145e9fac1ff76a21d1ce2" + "reference": "3bc368228532ad538cc216768caa8968be95a8d6" }, "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/3bc368228532ad538cc216768caa8968be95a8d6", + "reference": "3bc368228532ad538cc216768caa8968be95a8d6", "shasum": "" }, "require": { @@ -7381,7 +7381,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v8.0.0" + "source": "https://github.com/symfony/var-dumper/tree/v8.0.3" }, "funding": [ { @@ -7401,7 +7401,7 @@ "type": "tidelift" } ], - "time": "2025-10-28T09:34:19+00:00" + "time": "2025-12-18T11:23:51+00:00" }, { "name": "thecodingmachine/safe", diff --git a/tools/composer.lock b/tools/composer.lock index 1a8d6280..7a147ca8 100644 --- a/tools/composer.lock +++ b/tools/composer.lock @@ -2164,16 +2164,16 @@ }, { "name": "symfony/config", - "version": "v7.4.1", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "2c323304c354a43a48b61c5fa760fc4ed60ce495" + "reference": "800ce889e358a53a9678b3212b0c8cecd8c6aace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/2c323304c354a43a48b61c5fa760fc4ed60ce495", - "reference": "2c323304c354a43a48b61c5fa760fc4ed60ce495", + "url": "https://api.github.com/repos/symfony/config/zipball/800ce889e358a53a9678b3212b0c8cecd8c6aace", + "reference": "800ce889e358a53a9678b3212b0c8cecd8c6aace", "shasum": "" }, "require": { @@ -2219,7 +2219,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/v7.4.1" + "source": "https://github.com/symfony/config/tree/v7.4.3" }, "funding": [ { @@ -2239,20 +2239,20 @@ "type": "tidelift" } ], - "time": "2025-12-05T07:52:08+00:00" + "time": "2025-12-23T14:24:27+00:00" }, { "name": "symfony/console", - "version": "v7.4.1", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e" + "reference": "732a9ca6cd9dfd940c639062d5edbde2f6727fb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e", - "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e", + "url": "https://api.github.com/repos/symfony/console/zipball/732a9ca6cd9dfd940c639062d5edbde2f6727fb6", + "reference": "732a9ca6cd9dfd940c639062d5edbde2f6727fb6", "shasum": "" }, "require": { @@ -2317,7 +2317,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.1" + "source": "https://github.com/symfony/console/tree/v7.4.3" }, "funding": [ { @@ -2337,20 +2337,20 @@ "type": "tidelift" } ], - "time": "2025-12-05T15:23:39+00:00" + "time": "2025-12-23T14:50:43+00:00" }, { "name": "symfony/dependency-injection", - "version": "v7.4.2", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "baf614f7c15b30ba6762d4b1ddabdf83dbf0d29b" + "reference": "54122901b6d772e94f1e71a75e0533bc16563499" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/baf614f7c15b30ba6762d4b1ddabdf83dbf0d29b", - "reference": "baf614f7c15b30ba6762d4b1ddabdf83dbf0d29b", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/54122901b6d772e94f1e71a75e0533bc16563499", + "reference": "54122901b6d772e94f1e71a75e0533bc16563499", "shasum": "" }, "require": { @@ -2401,7 +2401,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/v7.4.2" + "source": "https://github.com/symfony/dependency-injection/tree/v7.4.3" }, "funding": [ { @@ -2421,7 +2421,7 @@ "type": "tidelift" } ], - "time": "2025-12-08T06:57:04+00:00" + "time": "2025-12-28T10:55:46+00:00" }, { "name": "symfony/deprecation-contracts", @@ -2723,16 +2723,16 @@ }, { "name": "symfony/finder", - "version": "v7.4.0", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "340b9ed7320570f319028a2cbec46d40535e94bd" + "reference": "fffe05569336549b20a1be64250b40516d6e8d06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/340b9ed7320570f319028a2cbec46d40535e94bd", - "reference": "340b9ed7320570f319028a2cbec46d40535e94bd", + "url": "https://api.github.com/repos/symfony/finder/zipball/fffe05569336549b20a1be64250b40516d6e8d06", + "reference": "fffe05569336549b20a1be64250b40516d6e8d06", "shasum": "" }, "require": { @@ -2767,7 +2767,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/v7.4.3" }, "funding": [ { @@ -2787,7 +2787,7 @@ "type": "tidelift" } ], - "time": "2025-11-05T05:42:40+00:00" + "time": "2025-12-23T14:50:43+00:00" }, { "name": "symfony/polyfill-ctype", @@ -3450,16 +3450,16 @@ }, { "name": "symfony/process", - "version": "v8.0.0", + "version": "v8.0.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149" + "reference": "0cbbd88ec836f8757641c651bb995335846abb78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/a0a750500c4ce900d69ba4e9faf16f82c10ee149", - "reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149", + "url": "https://api.github.com/repos/symfony/process/zipball/0cbbd88ec836f8757641c651bb995335846abb78", + "reference": "0cbbd88ec836f8757641c651bb995335846abb78", "shasum": "" }, "require": { @@ -3491,7 +3491,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v8.0.0" + "source": "https://github.com/symfony/process/tree/v8.0.3" }, "funding": [ { @@ -3511,7 +3511,7 @@ "type": "tidelift" } ], - "time": "2025-10-16T16:25:44+00:00" + "time": "2025-12-19T10:01:18+00:00" }, { "name": "symfony/service-contracts", From 7fab24b83e74c63bbf49305d475f36d3e8b0cd4c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Jan 2026 00:35:02 +0000 Subject: [PATCH 19/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- composer.lock | 24 ++++++++++++------------ tools/composer.lock | 12 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/composer.lock b/composer.lock index bd7b5e04..025952d8 100644 --- a/composer.lock +++ b/composer.lock @@ -3524,16 +3524,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "6.6.3", + "version": "6.6.4", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "134e98916fa2f663afa623970af345cd788e8967" + "reference": "2eeb75d21cf73211335888e7f5e6fd7440723ec7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/134e98916fa2f663afa623970af345cd788e8967", - "reference": "134e98916fa2f663afa623970af345cd788e8967", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/2eeb75d21cf73211335888e7f5e6fd7440723ec7", + "reference": "2eeb75d21cf73211335888e7f5e6fd7440723ec7", "shasum": "" }, "require": { @@ -3593,9 +3593,9 @@ ], "support": { "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.3" + "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.4" }, - "time": "2025-12-02T10:21:33+00:00" + "time": "2025-12-19T15:01:32+00:00" }, { "name": "league/commonmark", @@ -5187,16 +5187,16 @@ }, { "name": "sanmai/di-container", - "version": "0.1.5", + "version": "0.1.6", "source": { "type": "git", "url": "https://github.com/sanmai/di-container.git", - "reference": "355534ad7970fc7dab4211ecaf2da5c546855ee8" + "reference": "e57d6de5309be56ca3a810987bf8279d69ce4661" }, "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/e57d6de5309be56ca3a810987bf8279d69ce4661", + "reference": "e57d6de5309be56ca3a810987bf8279d69ce4661", "shasum": "" }, "require": { @@ -5250,7 +5250,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.6" }, "funding": [ { @@ -5258,7 +5258,7 @@ "type": "github" } ], - "time": "2025-08-04T09:43:58+00:00" + "time": "2026-01-02T09:35:43+00:00" }, { "name": "sanmai/duoclock", diff --git a/tools/composer.lock b/tools/composer.lock index 7a147ca8..bbb6f9d3 100644 --- a/tools/composer.lock +++ b/tools/composer.lock @@ -956,16 +956,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "6.6.3", + "version": "6.6.4", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "134e98916fa2f663afa623970af345cd788e8967" + "reference": "2eeb75d21cf73211335888e7f5e6fd7440723ec7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/134e98916fa2f663afa623970af345cd788e8967", - "reference": "134e98916fa2f663afa623970af345cd788e8967", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/2eeb75d21cf73211335888e7f5e6fd7440723ec7", + "reference": "2eeb75d21cf73211335888e7f5e6fd7440723ec7", "shasum": "" }, "require": { @@ -1025,9 +1025,9 @@ ], "support": { "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.3" + "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.4" }, - "time": "2025-12-02T10:21:33+00:00" + "time": "2025-12-19T15:01:32+00:00" }, { "name": "marc-mabe/php-enum", From 183a44ce065b249fae92725ba5af56f01335ac88 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 4 Jan 2026 00:41:28 +0000 Subject: [PATCH 20/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 025952d8..780966e9 100644 --- a/composer.lock +++ b/composer.lock @@ -5187,16 +5187,16 @@ }, { "name": "sanmai/di-container", - "version": "0.1.6", + "version": "0.1.8", "source": { "type": "git", "url": "https://github.com/sanmai/di-container.git", - "reference": "e57d6de5309be56ca3a810987bf8279d69ce4661" + "reference": "f7ea6a00692608f785fc0eabb1c54f5349d973e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sanmai/di-container/zipball/e57d6de5309be56ca3a810987bf8279d69ce4661", - "reference": "e57d6de5309be56ca3a810987bf8279d69ce4661", + "url": "https://api.github.com/repos/sanmai/di-container/zipball/f7ea6a00692608f785fc0eabb1c54f5349d973e9", + "reference": "f7ea6a00692608f785fc0eabb1c54f5349d973e9", "shasum": "" }, "require": { @@ -5250,7 +5250,7 @@ ], "support": { "issues": "https://github.com/sanmai/di-container/issues", - "source": "https://github.com/sanmai/di-container/tree/0.1.6" + "source": "https://github.com/sanmai/di-container/tree/0.1.8" }, "funding": [ { @@ -5258,7 +5258,7 @@ "type": "github" } ], - "time": "2026-01-02T09:35:43+00:00" + "time": "2026-01-03T14:10:40+00:00" }, { "name": "sanmai/duoclock", From 97171488f3935973d2da22a8d9e3909265d6da6d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 01:45:06 +0000 Subject: [PATCH 21/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- composer.lock | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/composer.lock b/composer.lock index 780966e9..fe9eac29 100644 --- a/composer.lock +++ b/composer.lock @@ -3346,16 +3346,16 @@ }, { "name": "infection/infection", - "version": "0.32.0", + "version": "0.32.1", "source": { "type": "git", - "url": "https://github.com/infection/infection", - "reference": "71d4a12cbe62d79c06dce628b8a5fe234636424c" + "url": "https://github.com/infection/infection.git", + "reference": "b5c2dc7dd7615c90edf56924df09d39170c2817d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/infection/infection/zipball/71d4a12cbe62d79c06dce628b8a5fe234636424c", - "reference": "71d4a12cbe62d79c06dce628b8a5fe234636424c", + "url": "https://api.github.com/repos/infection/infection/zipball/b5c2dc7dd7615c90edf56924df09d39170c2817d", + "reference": "b5c2dc7dd7615c90edf56924df09d39170c2817d", "shasum": "" }, "require": { @@ -3465,9 +3465,20 @@ "unit testing" ], "support": { - "issues": "https://github.com/infection/infection/issues" + "issues": "https://github.com/infection/infection/issues", + "source": "https://github.com/infection/infection/tree/0.32.1" }, - "time": "2025-12-24T13:55:03+00:00" + "funding": [ + { + "url": "https://github.com/infection", + "type": "github" + }, + { + "url": "https://opencollective.com/infection", + "type": "open_collective" + } + ], + "time": "2026-01-05T18:10:44+00:00" }, { "name": "infection/mutator", From 33a513456799786c2a9eca98ed9da15db756a9c9 Mon Sep 17 00:00:00 2001 From: Daniel Badura Date: Tue, 6 Jan 2026 13:19:17 +0100 Subject: [PATCH 22/24] Deprecate `SubscriberHelper` and `SubscriberUtil` and update docs to use a CONST instead --- docs/pages/getting_started.md | 23 ++++++++----------- docs/pages/subscription.md | 17 ++++---------- .../Subscriber/SubscriberHelper.php | 1 + .../Subscriber/SubscriberUtil.php | 1 + 4 files changed, 15 insertions(+), 27 deletions(-) diff --git a/docs/pages/getting_started.md b/docs/pages/getting_started.md index dd0ed4db..1e7fb6c9 100644 --- a/docs/pages/getting_started.md +++ b/docs/pages/getting_started.md @@ -163,12 +163,12 @@ use Patchlevel\EventSourcing\Attribute\Projector; use Patchlevel\EventSourcing\Attribute\Setup; use Patchlevel\EventSourcing\Attribute\Subscribe; use Patchlevel\EventSourcing\Attribute\Teardown; -use Patchlevel\EventSourcing\Subscription\Subscriber\SubscriberUtil; -#[Projector('hotel')] +#[Projector(self::TABLE)] final class HotelProjector { - use SubscriberUtil; + // use a const for easier access in the projector & to keep projector id and table name in sync + private const TABLE = 'hotel'; public function __construct( private readonly Connection $db, @@ -178,14 +178,14 @@ final class HotelProjector /** @return list */ public function getHotels(): array { - return $this->db->fetchAllAssociative("SELECT id, name, guests FROM {$this->table()};"); + return $this->db->fetchAllAssociative(sprintf('SELECT id, name, guests FROM %s;'), self::TABLE); } #[Subscribe(HotelCreated::class)] public function handleHotelCreated(HotelCreated $event): void { $this->db->insert( - $this->table(), + self::TABLE, [ 'id' => $event->hotelId->toString(), 'name' => $event->hotelName, @@ -198,7 +198,7 @@ final class HotelProjector public function handleGuestIsCheckedIn(GuestIsCheckedIn $event): void { $this->db->executeStatement( - "UPDATE {$this->table()} SET guests = guests + 1 WHERE id = ?;", + sprintf('UPDATE %s SET guests = guests + 1 WHERE id = ?;', self::TABLE), [$event->hotelId->toString()], ); } @@ -207,7 +207,7 @@ final class HotelProjector public function handleGuestIsCheckedOut(GuestIsCheckedOut $event): void { $this->db->executeStatement( - "UPDATE {$this->table()} SET guests = guests - 1 WHERE id = ?;", + sprintf('UPDATE %s SET guests = guests - 1 WHERE id = ?;', self::TABLE), [$event->hotelId->toString()], ); } @@ -215,18 +215,13 @@ final class HotelProjector #[Setup] public function create(): void { - $this->db->executeStatement("CREATE TABLE IF NOT EXISTS {$this->table()} (id VARCHAR PRIMARY KEY, name VARCHAR, guests INTEGER);"); + $this->db->executeStatement(sprintf('CREATE TABLE IF NOT EXISTS %s (id VARCHAR PRIMARY KEY, name VARCHAR, guests INTEGER);', self::TABLE)); } #[Teardown] public function drop(): void { - $this->db->executeStatement("DROP TABLE IF EXISTS {$this->table()};"); - } - - private function table(): string - { - return 'projection_' . $this->subscriberId(); + $this->db->executeStatement(sprintf('DROP TABLE IF EXISTS %s;', self::TABLE)); } } ``` diff --git a/docs/pages/subscription.md b/docs/pages/subscription.md index 94a4457d..19e5a980 100644 --- a/docs/pages/subscription.md +++ b/docs/pages/subscription.md @@ -231,8 +231,6 @@ use Patchlevel\EventSourcing\Subscription\Lookup; #[Projector('public_profile')] final class PublicProfileProjection { - use SubscriberUtil; - // ... constructor #[Subscribe(Published::class)] @@ -306,12 +304,11 @@ use Doctrine\DBAL\Connection; use Patchlevel\EventSourcing\Attribute\Projector; use Patchlevel\EventSourcing\Attribute\Setup; use Patchlevel\EventSourcing\Attribute\Teardown; -use Patchlevel\EventSourcing\Subscription\Subscriber\SubscriberUtil; -#[Projector('profile_1')] +#[Projector(self::TABLE)] final class ProfileProjector { - use SubscriberUtil; + private const TABLE = 'profile_v1'; private Connection $connection; @@ -319,19 +316,14 @@ final class ProfileProjector public function create(): void { $this->connection->executeStatement( - "CREATE TABLE IF NOT EXISTS {$this->table()} (id VARCHAR PRIMARY KEY, name VARCHAR NOT NULL);", + sprintf('CREATE TABLE IF NOT EXISTS %s (id VARCHAR PRIMARY KEY, name VARCHAR NOT NULL);', self::TABLE), ); } #[Teardown] public function drop(): void { - $this->connection->executeStatement("DROP TABLE IF EXISTS {$this->table()};"); - } - - private function table(): string - { - return 'projection_' . $this->subscriberId(); + $this->connection->executeStatement(sprintf('DROP TABLE IF EXISTS %s;', self::TABLE)); } } ``` @@ -346,7 +338,6 @@ final class ProfileProjector If you change the subscriber id, you must also change the table/collection name. The subscription engine will create a new subscription with the new subscriber id. That means the setup method will be called again and the table/collection will conflict with the old existing projection. - You can use the `SubscriberUtil` to build the table/collection name. !!! note diff --git a/src/Subscription/Subscriber/SubscriberHelper.php b/src/Subscription/Subscriber/SubscriberHelper.php index 3243ac8f..733a4ffc 100644 --- a/src/Subscription/Subscriber/SubscriberHelper.php +++ b/src/Subscription/Subscriber/SubscriberHelper.php @@ -8,6 +8,7 @@ use Patchlevel\EventSourcing\Metadata\Subscriber\SubscriberMetadata; use Patchlevel\EventSourcing\Metadata\Subscriber\SubscriberMetadataFactory; +/** @deprecated since 3.15.0 will be removed with 4.0.0 */ final class SubscriberHelper { public function __construct( diff --git a/src/Subscription/Subscriber/SubscriberUtil.php b/src/Subscription/Subscriber/SubscriberUtil.php index b73ad0a8..01592494 100644 --- a/src/Subscription/Subscriber/SubscriberUtil.php +++ b/src/Subscription/Subscriber/SubscriberUtil.php @@ -7,6 +7,7 @@ use Patchlevel\EventSourcing\Metadata\Subscriber\AttributeSubscriberMetadataFactory; use Patchlevel\EventSourcing\Metadata\Subscriber\SubscriberMetadataFactory; +/** @deprecated since 3.15.0 will be removed with 4.0.0 */ trait SubscriberUtil { private static SubscriberMetadataFactory|null $metadataFactory = null; From 71cb083baf3d9b5e80a12e646dc788b02b2d170a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 00:39:09 +0000 Subject: [PATCH 23/24] Lock file maintenance Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- composer.lock | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index fe9eac29..6fe346a9 100644 --- a/composer.lock +++ b/composer.lock @@ -2780,30 +2780,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": { @@ -2830,7 +2829,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": [ { @@ -2846,7 +2845,7 @@ "type": "tidelift" } ], - "time": "2022-12-30T00:23:10+00:00" + "time": "2026-01-05T06:47:08+00:00" }, { "name": "doctrine/lexer", From bf535b959e0d02d7481d43aabc22be98a21ddb29 Mon Sep 17 00:00:00 2001 From: Daniel Badura Date: Thu, 8 Jan 2026 15:47:03 +0100 Subject: [PATCH 24/24] Use StreamStore and message loader, fix cs --- tests/Benchmark/CommandToQueryBench.php | 3 ++- .../Integration/BasicImplementation/BasicIntegrationTest.php | 4 ++-- .../BasicImplementation/Projection/ProfileProjector.php | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Benchmark/CommandToQueryBench.php b/tests/Benchmark/CommandToQueryBench.php index 008950fb..e6695a4e 100644 --- a/tests/Benchmark/CommandToQueryBench.php +++ b/tests/Benchmark/CommandToQueryBench.php @@ -19,6 +19,7 @@ use Patchlevel\EventSourcing\Snapshot\DefaultSnapshotStore; use Patchlevel\EventSourcing\Store\StreamDoctrineDbalStore; use Patchlevel\EventSourcing\Subscription\Engine\DefaultSubscriptionEngine; +use Patchlevel\EventSourcing\Subscription\Engine\StoreMessageLoader; use Patchlevel\EventSourcing\Subscription\Repository\RunSubscriptionEngineRepositoryManager; use Patchlevel\EventSourcing\Subscription\Store\InMemorySubscriptionStore; use Patchlevel\EventSourcing\Subscription\Subscriber\MetadataSubscriberAccessorRepository; @@ -64,7 +65,7 @@ public function setUp(): void $profileProjection = new ProfileProjector($projectionConnection); $engine = new DefaultSubscriptionEngine( - $store, + new StoreMessageLoader($store), new InMemorySubscriptionStore(), new MetadataSubscriberAccessorRepository([ $profileProjection, diff --git a/tests/Integration/BasicImplementation/BasicIntegrationTest.php b/tests/Integration/BasicImplementation/BasicIntegrationTest.php index bb3b1d1d..0cabaad6 100644 --- a/tests/Integration/BasicImplementation/BasicIntegrationTest.php +++ b/tests/Integration/BasicImplementation/BasicIntegrationTest.php @@ -329,7 +329,7 @@ public function testCommandBus(): void public function testQueryBus(): void { - $store = new DoctrineDbalStore( + $store = new StreamDoctrineDbalStore( $this->connection, DefaultEventSerializer::createFromPaths([__DIR__ . '/Events']), DefaultHeadersSerializer::createFromPaths([ @@ -350,7 +350,7 @@ public function testQueryBus(): void $profileProjection = new ProfileProjector($this->connection); $engine = new DefaultSubscriptionEngine( - $store, + new StoreMessageLoader($store), new InMemorySubscriptionStore(), new MetadataSubscriberAccessorRepository([ $profileProjection, diff --git a/tests/Integration/BasicImplementation/Projection/ProfileProjector.php b/tests/Integration/BasicImplementation/Projection/ProfileProjector.php index 38e7cc80..164d9d1a 100644 --- a/tests/Integration/BasicImplementation/Projection/ProfileProjector.php +++ b/tests/Integration/BasicImplementation/Projection/ProfileProjector.php @@ -13,7 +13,6 @@ use Patchlevel\EventSourcing\Attribute\Teardown; use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\Events\NameChanged; use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\Events\ProfileCreated; -use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\ProfileId; use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\Query\QueryProfileName; #[Projector('profile-1')]