From b82ed3ce23300d82ab4c6c128e53377bf44f6654 Mon Sep 17 00:00:00 2001 From: David Badura Date: Fri, 13 Feb 2026 11:07:20 +0100 Subject: [PATCH] update --- composer.json | 2 +- composer.lock | 412 +++++++++--------- docs/index.md | 2 +- docs/normalizer.md | 4 +- docs/{personal-data.md => sensitive-data.md} | 35 +- docs/snapshots.md | 2 +- .../Serializer/DefaultHeadersSerializer.php | 6 +- src/Serializer/DefaultEventSerializer.php | 44 +- src/Serializer/Normalizer/IdNormalizer.php | 4 +- src/Serializer/Upcast/UpcastMiddleware.php | 35 ++ src/Snapshot/DefaultSnapshotStore.php | 16 +- .../Events/EmailChanged.php | 4 +- .../Events/ProfileCreated.php | 4 +- tests/Benchmark/PersonalDataBench.php | 4 +- .../Events/NameChanged.php | 8 +- .../Events/PersonalDataRemoved.php | 4 +- .../Events/ProfileCreated.php | 8 +- .../Processor/DeletePersonalDataProcessor.php | 4 +- .../Profile.php | 12 +- .../ProfileId.php | 2 +- .../SensitiveDataTest.php} | 31 +- .../Subscription/SubscriptionTest.php | 7 +- tests/Unit/Fixture/EmailNormalizer.php | 4 +- tests/Unit/Fixture/MessageNormalizer.php | 4 +- 24 files changed, 367 insertions(+), 291 deletions(-) rename docs/{personal-data.md => sensitive-data.md} (86%) create mode 100644 src/Serializer/Upcast/UpcastMiddleware.php rename tests/Integration/{PersonalData => SensitiveData}/Events/NameChanged.php (59%) rename tests/Integration/{PersonalData => SensitiveData}/Events/PersonalDataRemoved.php (63%) rename tests/Integration/{PersonalData => SensitiveData}/Events/ProfileCreated.php (57%) rename tests/Integration/{PersonalData => SensitiveData}/Processor/DeletePersonalDataProcessor.php (77%) rename tests/Integration/{PersonalData => SensitiveData}/Profile.php (78%) rename tests/Integration/{PersonalData => SensitiveData}/ProfileId.php (77%) rename tests/Integration/{PersonalData/PersonalDataTest.php => SensitiveData/SensitiveDataTest.php} (87%) diff --git a/composer.json b/composer.json index 87514ff3b..1d76859b2 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", "doctrine/dbal": "^4.0.0", "doctrine/migrations": "^3.3.2", - "patchlevel/hydrator": "^1.8.0", + "patchlevel/hydrator": "^2.0.x-dev", "patchlevel/worker": "^1.4.0", "psr/cache": "^2.0.0 || ^3.0.0", "psr/clock": "^1.0", diff --git a/composer.lock b/composer.lock index 0b288a230..d00d8af10 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0c3c161d87cdce3d1923690220fd6394", + "content-hash": "9bf1b1cf234fc1b36cbb452e1bed8edb", "packages": [ { "name": "brick/math", - "version": "0.14.1", + "version": "0.14.8", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "f05858549e5f9d7bb45875a75583240a38a281d0" + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/f05858549e5f9d7bb45875a75583240a38a281d0", - "reference": "f05858549e5f9d7bb45875a75583240a38a281d0", + "url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629", + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629", "shasum": "" }, "require": { @@ -56,7 +56,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.14.1" + "source": "https://github.com/brick/math/tree/0.14.8" }, "funding": [ { @@ -64,7 +64,7 @@ "type": "github" } ], - "time": "2025-11-24T14:40:29+00:00" + "time": "2026-02-10T14:33:43+00:00" }, { "name": "doctrine/dbal", @@ -174,29 +174,29 @@ }, { "name": "doctrine/deprecations", - "version": "1.1.5", + "version": "1.1.6", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "conflict": { - "phpunit/phpunit": "<=7.5 || >=13" + "phpunit/phpunit": "<=7.5 || >=14" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^12 || ^13", - "phpstan/phpstan": "1.4.10 || 2.1.11", + "doctrine/coding-standard": "^9 || ^12 || ^14", + "phpstan/phpstan": "1.4.10 || 2.1.30", "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0", "psr/log": "^1 || ^2 || ^3" }, "suggest": { @@ -216,22 +216,22 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.5" + "source": "https://github.com/doctrine/deprecations/tree/1.1.6" }, - "time": "2025-04-07T20:06:18+00:00" + "time": "2026-02-07T07:09:04+00:00" }, { "name": "doctrine/event-manager", - "version": "2.0.1", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e" + "reference": "dda33921b198841ca8dbad2eaa5d4d34769d18cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/b680156fa328f1dfd874fd48c7026c41570b9c6e", - "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/dda33921b198841ca8dbad2eaa5d4d34769d18cf", + "reference": "dda33921b198841ca8dbad2eaa5d4d34769d18cf", "shasum": "" }, "require": { @@ -241,10 +241,10 @@ "doctrine/common": "<2.9" }, "require-dev": { - "doctrine/coding-standard": "^12", - "phpstan/phpstan": "^1.8.8", - "phpunit/phpunit": "^10.5", - "vimeo/psalm": "^5.24" + "doctrine/coding-standard": "^14", + "phpdocumentor/guides-cli": "^1.4", + "phpstan/phpstan": "^2.1.32", + "phpunit/phpunit": "^10.5.58" }, "type": "library", "autoload": { @@ -293,7 +293,7 @@ ], "support": { "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/2.0.1" + "source": "https://github.com/doctrine/event-manager/tree/2.1.1" }, "funding": [ { @@ -309,20 +309,20 @@ "type": "tidelift" } ], - "time": "2024-05-22T20:47:39+00:00" + "time": "2026-01-29T07:11:08+00:00" }, { "name": "doctrine/migrations", - "version": "3.9.5", + "version": "3.9.6", "source": { "type": "git", "url": "https://github.com/doctrine/migrations.git", - "reference": "1b823afbc40f932dae8272574faee53f2755eac5" + "reference": "ffd8355cdd8505fc650d9604f058bf62aedd80a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/migrations/zipball/1b823afbc40f932dae8272574faee53f2755eac5", - "reference": "1b823afbc40f932dae8272574faee53f2755eac5", + "url": "https://api.github.com/repos/doctrine/migrations/zipball/ffd8355cdd8505fc650d9604f058bf62aedd80a1", + "reference": "ffd8355cdd8505fc650d9604f058bf62aedd80a1", "shasum": "" }, "require": { @@ -396,7 +396,7 @@ ], "support": { "issues": "https://github.com/doctrine/migrations/issues", - "source": "https://github.com/doctrine/migrations/tree/3.9.5" + "source": "https://github.com/doctrine/migrations/tree/3.9.6" }, "funding": [ { @@ -412,20 +412,20 @@ "type": "tidelift" } ], - "time": "2025-11-20T11:15:36+00:00" + "time": "2026-02-11T06:46:11+00:00" }, { "name": "patchlevel/hydrator", - "version": "1.13.0", + "version": "2.0.x-dev", "source": { "type": "git", "url": "https://github.com/patchlevel/hydrator.git", - "reference": "dc6fe9a835edaa2d6972ad148738eaeb95a6cb35" + "reference": "8e66530a726ee410c00ae6bb993ae984525d2dd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/patchlevel/hydrator/zipball/dc6fe9a835edaa2d6972ad148738eaeb95a6cb35", - "reference": "dc6fe9a835edaa2d6972ad148738eaeb95a6cb35", + "url": "https://api.github.com/repos/patchlevel/hydrator/zipball/8e66530a726ee410c00ae6bb993ae984525d2dd7", + "reference": "8e66530a726ee410c00ae6bb993ae984525d2dd7", "shasum": "" }, "require": { @@ -433,11 +433,10 @@ "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", "psr/cache": "^2.0.0 || ^3.0.0", "psr/simple-cache": "^2.0.0 || ^3.0.0", - "symfony/event-dispatcher": "^5.4.29 || ^6.4.0 || ^7.0.0 || ^8.0.0", "symfony/type-info": "^7.3.0 || ^8.0.0" }, "require-dev": { - "infection/infection": "^0.31.9", + "infection/infection": "^0.32.0", "patchlevel/coding-standard": "^1.3.0", "phpat/phpat": "^0.12.0", "phpbench/phpbench": "^1.2.15", @@ -474,9 +473,9 @@ ], "support": { "issues": "https://github.com/patchlevel/hydrator/issues", - "source": "https://github.com/patchlevel/hydrator/tree/1.13.0" + "source": "https://github.com/patchlevel/hydrator/tree/2.0.x" }, - "time": "2025-11-27T16:58:40+00:00" + "time": "2026-02-11T13:24:58+00:00" }, { "name": "patchlevel/worker", @@ -995,16 +994,16 @@ }, { "name": "symfony/console", - "version": "v8.0.3", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "6145b304a5c1ea0bdbd0b04d297a5864f9a7d587" + "reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/6145b304a5c1ea0bdbd0b04d297a5864f9a7d587", - "reference": "6145b304a5c1ea0bdbd0b04d297a5864f9a7d587", + "url": "https://api.github.com/repos/symfony/console/zipball/ace03c4cf9805080ff40cbeec69fca180c339a3b", + "reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b", "shasum": "" }, "require": { @@ -1061,7 +1060,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v8.0.3" + "source": "https://github.com/symfony/console/tree/v8.0.4" }, "funding": [ { @@ -1081,7 +1080,7 @@ "type": "tidelift" } ], - "time": "2025-12-23T14:52:06+00:00" + "time": "2026-01-13T13:06:50+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1152,16 +1151,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v8.0.0", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "573f95783a2ec6e38752979db139f09fec033f03" + "reference": "99301401da182b6cfaa4700dbe9987bb75474b47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/573f95783a2ec6e38752979db139f09fec033f03", - "reference": "573f95783a2ec6e38752979db139f09fec033f03", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/99301401da182b6cfaa4700dbe9987bb75474b47", + "reference": "99301401da182b6cfaa4700dbe9987bb75474b47", "shasum": "" }, "require": { @@ -1213,7 +1212,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v8.0.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v8.0.4" }, "funding": [ { @@ -1233,7 +1232,7 @@ "type": "tidelift" } ], - "time": "2025-10-30T14:17:19+00:00" + "time": "2026-01-05T11:45:55+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -1313,16 +1312,16 @@ }, { "name": "symfony/finder", - "version": "v8.0.3", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "dd3a2953570a283a2ba4e17063bb98c734cf5b12" + "reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/dd3a2953570a283a2ba4e17063bb98c734cf5b12", - "reference": "dd3a2953570a283a2ba4e17063bb98c734cf5b12", + "url": "https://api.github.com/repos/symfony/finder/zipball/8bd576e97c67d45941365bf824e18dc8538e6eb0", + "reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0", "shasum": "" }, "require": { @@ -1357,7 +1356,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.3" + "source": "https://github.com/symfony/finder/tree/v8.0.5" }, "funding": [ { @@ -1377,7 +1376,7 @@ "type": "tidelift" } ], - "time": "2025-12-23T14:52:06+00:00" + "time": "2026-01-26T15:08:38+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1869,16 +1868,16 @@ }, { "name": "symfony/string", - "version": "v8.0.1", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc" + "reference": "758b372d6882506821ed666032e43020c4f57194" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/ba65a969ac918ce0cc3edfac6cdde847eba231dc", - "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc", + "url": "https://api.github.com/repos/symfony/string/zipball/758b372d6882506821ed666032e43020c4f57194", + "reference": "758b372d6882506821ed666032e43020c4f57194", "shasum": "" }, "require": { @@ -1935,7 +1934,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v8.0.1" + "source": "https://github.com/symfony/string/tree/v8.0.4" }, "funding": [ { @@ -1955,20 +1954,20 @@ "type": "tidelift" } ], - "time": "2025-12-01T09:13:36+00:00" + "time": "2026-01-12T12:37:40+00:00" }, { "name": "symfony/type-info", - "version": "v8.0.1", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/type-info.git", - "reference": "bb091cec1f70383538c7d000699781813f8d1a6a" + "reference": "106a2d3bbf0d4576b2f70e6ca866fa420956ed0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/type-info/zipball/bb091cec1f70383538c7d000699781813f8d1a6a", - "reference": "bb091cec1f70383538c7d000699781813f8d1a6a", + "url": "https://api.github.com/repos/symfony/type-info/zipball/106a2d3bbf0d4576b2f70e6ca866fa420956ed0d", + "reference": "106a2d3bbf0d4576b2f70e6ca866fa420956ed0d", "shasum": "" }, "require": { @@ -2017,7 +2016,7 @@ "type" ], "support": { - "source": "https://github.com/symfony/type-info/tree/v8.0.1" + "source": "https://github.com/symfony/type-info/tree/v8.0.4" }, "funding": [ { @@ -2037,7 +2036,7 @@ "type": "tidelift" } ], - "time": "2025-12-05T14:08:45+00:00" + "time": "2026-01-09T12:15:10+00:00" }, { "name": "symfony/var-exporter", @@ -2604,16 +2603,16 @@ }, { "name": "doctrine/collections", - "version": "2.5.0", + "version": "2.6.0", "source": { "type": "git", "url": "https://github.com/doctrine/collections.git", - "reference": "6108e0cd57d7ef125fb84696346a68860403a25d" + "reference": "7713da39d8e237f28411d6a616a3dce5e20d5de2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/6108e0cd57d7ef125fb84696346a68860403a25d", - "reference": "6108e0cd57d7ef125fb84696346a68860403a25d", + "url": "https://api.github.com/repos/doctrine/collections/zipball/7713da39d8e237f28411d6a616a3dce5e20d5de2", + "reference": "7713da39d8e237f28411d6a616a3dce5e20d5de2", "shasum": "" }, "require": { @@ -2670,7 +2669,7 @@ ], "support": { "issues": "https://github.com/doctrine/collections/issues", - "source": "https://github.com/doctrine/collections/tree/2.5.0" + "source": "https://github.com/doctrine/collections/tree/2.6.0" }, "funding": [ { @@ -2686,7 +2685,7 @@ "type": "tidelift" } ], - "time": "2026-01-07T17:26:56+00:00" + "time": "2026-01-15T10:01:58+00:00" }, { "name": "doctrine/inflector", @@ -2926,16 +2925,16 @@ }, { "name": "doctrine/orm", - "version": "3.6.0", + "version": "3.6.2", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "d4e9276e79602b1eb4c4029c6c999b0d93478e2f" + "reference": "4262eb495b4d2a53b45de1ac58881e0091f2970f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/d4e9276e79602b1eb4c4029c6c999b0d93478e2f", - "reference": "d4e9276e79602b1eb4c4029c6c999b0d93478e2f", + "url": "https://api.github.com/repos/doctrine/orm/zipball/4262eb495b4d2a53b45de1ac58881e0091f2970f", + "reference": "4262eb495b4d2a53b45de1ac58881e0091f2970f", "shasum": "" }, "require": { @@ -3008,9 +3007,9 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/3.6.0" + "source": "https://github.com/doctrine/orm/tree/3.6.2" }, - "time": "2025-12-19T20:36:14+00:00" + "time": "2026-01-30T21:41:41+00:00" }, { "name": "doctrine/persistence", @@ -3345,16 +3344,16 @@ }, { "name": "infection/infection", - "version": "0.32.2", + "version": "0.32.4", "source": { "type": "git", "url": "https://github.com/infection/infection.git", - "reference": "df90353784ab0505f07502770f59f8fabef24d8c" + "reference": "a2b0a3e47b56bd2f27ca13caecae47baa7e5abe8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/infection/infection/zipball/df90353784ab0505f07502770f59f8fabef24d8c", - "reference": "df90353784ab0505f07502770f59f8fabef24d8c", + "url": "https://api.github.com/repos/infection/infection/zipball/a2b0a3e47b56bd2f27ca13caecae47baa7e5abe8", + "reference": "a2b0a3e47b56bd2f27ca13caecae47baa7e5abe8", "shasum": "" }, "require": { @@ -3375,11 +3374,11 @@ "ondram/ci-detector": "^4.1.0", "php": "^8.2", "psr/log": "^2.0 || ^3.0", - "sanmai/di-container": "^0.1.4", + "sanmai/di-container": "^0.1.12", "sanmai/duoclock": "^0.1.0", "sanmai/later": "^0.1.7", - "sanmai/pipeline": "^7.0", - "sebastian/diff": "^4.0 || ^5.0 || ^6.0 || ^7.0", + "sanmai/pipeline": "^7.2", + "sebastian/diff": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0", "symfony/console": "^6.4 || ^7.0 || ^8.0", "symfony/filesystem": "^6.4 || ^7.0 || ^8.0", "symfony/finder": "^6.4 || ^7.0 || ^8.0", @@ -3465,7 +3464,7 @@ ], "support": { "issues": "https://github.com/infection/infection/issues", - "source": "https://github.com/infection/infection/tree/0.32.2" + "source": "https://github.com/infection/infection/tree/0.32.4" }, "funding": [ { @@ -3477,7 +3476,7 @@ "type": "open_collective" } ], - "time": "2026-01-07T13:28:58+00:00" + "time": "2026-02-09T13:24:18+00:00" }, { "name": "infection/mutator", @@ -3931,16 +3930,16 @@ }, { "name": "nette/schema", - "version": "v1.3.3", + "version": "v1.3.4", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004" + "reference": "086497a2f34b82fede9b5a41cc8e131d087cd8f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/2befc2f42d7c715fd9d95efc31b1081e5d765004", - "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004", + "url": "https://api.github.com/repos/nette/schema/zipball/086497a2f34b82fede9b5a41cc8e131d087cd8f7", + "reference": "086497a2f34b82fede9b5a41cc8e131d087cd8f7", "shasum": "" }, "require": { @@ -3948,8 +3947,8 @@ "php": "8.1 - 8.5" }, "require-dev": { - "nette/tester": "^2.5.2", - "phpstan/phpstan-nette": "^2.0@stable", + "nette/tester": "^2.6", + "phpstan/phpstan": "^2.0@stable", "tracy/tracy": "^2.8" }, "type": "library", @@ -3990,22 +3989,22 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.3.3" + "source": "https://github.com/nette/schema/tree/v1.3.4" }, - "time": "2025-10-30T22:57:59+00:00" + "time": "2026-02-08T02:54:00+00:00" }, { "name": "nette/utils", - "version": "v4.1.1", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "c99059c0315591f1a0db7ad6002000288ab8dc72" + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/c99059c0315591f1a0db7ad6002000288ab8dc72", - "reference": "c99059c0315591f1a0db7ad6002000288ab8dc72", + "url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe", + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe", "shasum": "" }, "require": { @@ -4017,8 +4016,10 @@ }, "require-dev": { "jetbrains/phpstorm-attributes": "^1.2", + "nette/phpstan-rules": "^1.0", "nette/tester": "^2.5", - "phpstan/phpstan-nette": "^2.0@stable", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1@stable", "tracy/tracy": "^2.9" }, "suggest": { @@ -4079,9 +4080,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.1.1" + "source": "https://github.com/nette/utils/tree/v4.1.3" }, - "time": "2025-12-22T12:14:32+00:00" + "time": "2026-02-13T03:05:33+00:00" }, { "name": "nikic/php-parser", @@ -4451,16 +4452,16 @@ }, { "name": "phpat/phpat", - "version": "0.12.1", + "version": "0.12.2", "source": { "type": "git", "url": "https://github.com/carlosas/phpat.git", - "reference": "67b9e179757fbaa8b87e1469a66f103725858ee0" + "reference": "fe9caef4f8633a57c1d19643d37b58050b11806c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/carlosas/phpat/zipball/67b9e179757fbaa8b87e1469a66f103725858ee0", - "reference": "67b9e179757fbaa8b87e1469a66f103725858ee0", + "url": "https://api.github.com/repos/carlosas/phpat/zipball/fe9caef4f8633a57c1d19643d37b58050b11806c", + "reference": "fe9caef4f8633a57c1d19643d37b58050b11806c", "shasum": "" }, "require": { @@ -4502,9 +4503,9 @@ "description": "PHP Architecture Tester", "support": { "issues": "https://github.com/carlosas/phpat/issues", - "source": "https://github.com/carlosas/phpat/tree/0.12.1" + "source": "https://github.com/carlosas/phpat/tree/0.12.2" }, - "time": "2025-12-25T17:53:07+00:00" + "time": "2026-01-27T11:41:37+00:00" }, { "name": "phpbench/container", @@ -4657,16 +4658,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "2.3.0", + "version": "2.3.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", "shasum": "" }, "require": { @@ -4698,17 +4699,17 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" }, - "time": "2025-08-30T15:50:23+00:00" + "time": "2026-01-25T14:56:51+00:00" }, { "name": "phpstan/phpstan", - "version": "2.1.33", + "version": "2.1.39", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9e800e6bee7d5bd02784d4c6069b48032d16224f", - "reference": "9e800e6bee7d5bd02784d4c6069b48032d16224f", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224", + "reference": "c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224", "shasum": "" }, "require": { @@ -4753,20 +4754,20 @@ "type": "github" } ], - "time": "2025-12-05T10:24:31+00:00" + "time": "2026-02-11T14:48:56+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "2.0.11", + "version": "2.0.15", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "5e30669bef866eff70db8b58d72a5c185aa82414" + "reference": "0f6ba8e22a3e919353a8f4615ea3cd2e91626c7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/5e30669bef866eff70db8b58d72a5c185aa82414", - "reference": "5e30669bef866eff70db8b58d72a5c185aa82414", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/0f6ba8e22a3e919353a8f4615ea3cd2e91626c7f", + "reference": "0f6ba8e22a3e919353a8f4615ea3cd2e91626c7f", "shasum": "" }, "require": { @@ -4802,11 +4803,14 @@ "MIT" ], "description": "PHPUnit extensions and rules for PHPStan", + "keywords": [ + "static analysis" + ], "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.11" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.15" }, - "time": "2025-12-19T09:05:35+00:00" + "time": "2026-02-11T14:43:43+00:00" }, { "name": "phpunit/php-code-coverage", @@ -4900,28 +4904,28 @@ }, { "name": "phpunit/php-file-iterator", - "version": "5.1.0", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -4949,15 +4953,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" } ], - "time": "2024-08-27T05:02:59+00:00" + "time": "2026-02-02T13:52:54+00:00" }, { "name": "phpunit/php-invoker", @@ -5145,16 +5161,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.46", + "version": "11.5.53", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "75dfe79a2aa30085b7132bb84377c24062193f33" + "reference": "a997a653a82845f1240d73ee73a8a4e97e4b0607" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/75dfe79a2aa30085b7132bb84377c24062193f33", - "reference": "75dfe79a2aa30085b7132bb84377c24062193f33", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a997a653a82845f1240d73ee73a8a4e97e4b0607", + "reference": "a997a653a82845f1240d73ee73a8a4e97e4b0607", "shasum": "" }, "require": { @@ -5168,19 +5184,20 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.11", - "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-code-coverage": "^11.0.12", + "phpunit/php-file-iterator": "^5.1.1", "phpunit/php-invoker": "^5.0.1", "phpunit/php-text-template": "^4.0.1", "phpunit/php-timer": "^7.0.1", "sebastian/cli-parser": "^3.0.2", "sebastian/code-unit": "^3.0.3", - "sebastian/comparator": "^6.3.2", + "sebastian/comparator": "^6.3.3", "sebastian/diff": "^6.0.2", "sebastian/environment": "^7.2.1", "sebastian/exporter": "^6.3.2", "sebastian/global-state": "^7.0.2", "sebastian/object-enumerator": "^6.0.1", + "sebastian/recursion-context": "^6.0.3", "sebastian/type": "^5.1.3", "sebastian/version": "^5.0.2", "staabm/side-effects-detector": "^1.0.5" @@ -5226,7 +5243,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.46" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.53" }, "funding": [ { @@ -5250,20 +5267,20 @@ "type": "tidelift" } ], - "time": "2025-12-06T08:01:15+00:00" + "time": "2026-02-10T12:28:25+00:00" }, { "name": "sanmai/di-container", - "version": "0.1.8", + "version": "0.1.12", "source": { "type": "git", "url": "https://github.com/sanmai/di-container.git", - "reference": "f7ea6a00692608f785fc0eabb1c54f5349d973e9" + "reference": "8b9ad72f6ac1f9e185e5bd060dc9479cb5191d8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sanmai/di-container/zipball/f7ea6a00692608f785fc0eabb1c54f5349d973e9", - "reference": "f7ea6a00692608f785fc0eabb1c54f5349d973e9", + "url": "https://api.github.com/repos/sanmai/di-container/zipball/8b9ad72f6ac1f9e185e5bd060dc9479cb5191d8b", + "reference": "8b9ad72f6ac1f9e185e5bd060dc9479cb5191d8b", "shasum": "" }, "require": { @@ -5274,14 +5291,18 @@ "require-dev": { "ergebnis/composer-normalize": "^2.8", "friendsofphp/php-cs-fixer": "^3.17", - "infection/infection": ">=0.29", + "infection/infection": ">=0.31", "php-coveralls/php-coveralls": "^2.4.1", + "phpbench/phpbench": "^1.4", "phpstan/extension-installer": "^1.4", "phpunit/phpunit": "^11.5.25", "sanmai/phpstan-rules": "^0.3.10" }, "type": "library", "extra": { + "branch-alias": { + "dev-main": "0.1.x-dev" + }, "preferred-install": "dist" }, "autoload": { @@ -5317,7 +5338,7 @@ ], "support": { "issues": "https://github.com/sanmai/di-container/issues", - "source": "https://github.com/sanmai/di-container/tree/0.1.8" + "source": "https://github.com/sanmai/di-container/tree/0.1.12" }, "funding": [ { @@ -5325,7 +5346,7 @@ "type": "github" } ], - "time": "2026-01-03T14:10:40+00:00" + "time": "2026-01-27T08:25:46+00:00" }, { "name": "sanmai/duoclock", @@ -5456,16 +5477,16 @@ }, { "name": "sanmai/pipeline", - "version": "7.6", + "version": "7.9", "source": { "type": "git", "url": "https://github.com/sanmai/pipeline.git", - "reference": "f7aeb6e1c9572f366c6035c79d715a2a73eeb1c9" + "reference": "d7046ecce91ae57fca403be694888371a21250eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sanmai/pipeline/zipball/f7aeb6e1c9572f366c6035c79d715a2a73eeb1c9", - "reference": "f7aeb6e1c9572f366c6035c79d715a2a73eeb1c9", + "url": "https://api.github.com/repos/sanmai/pipeline/zipball/d7046ecce91ae57fca403be694888371a21250eb", + "reference": "d7046ecce91ae57fca403be694888371a21250eb", "shasum": "" }, "require": { @@ -5475,7 +5496,7 @@ "ergebnis/composer-normalize": "^2.8", "esi/phpunit-coverage-check": ">2", "friendsofphp/php-cs-fixer": "^3.17", - "infection/infection": ">=0.30.3", + "infection/infection": ">=0.32.3", "league/pipeline": "^0.3 || ^1.0", "php-coveralls/php-coveralls": "^2.4.1", "phpstan/extension-installer": "^1.4", @@ -5488,7 +5509,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "v6.x-dev" + "dev-main": "7.x-dev" } }, "autoload": { @@ -5512,7 +5533,7 @@ "description": "General-purpose collections pipeline", "support": { "issues": "https://github.com/sanmai/pipeline/issues", - "source": "https://github.com/sanmai/pipeline/tree/7.6" + "source": "https://github.com/sanmai/pipeline/tree/7.9" }, "funding": [ { @@ -5520,7 +5541,7 @@ "type": "github" } ], - "time": "2025-12-20T07:22:08+00:00" + "time": "2026-01-16T11:54:05+00:00" }, { "name": "sebastian/cli-parser", @@ -5694,16 +5715,16 @@ }, { "name": "sebastian/comparator", - "version": "6.3.2", + "version": "6.3.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8" + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85c77556683e6eee4323e4c5468641ca0237e2e8", - "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", "shasum": "" }, "require": { @@ -5762,7 +5783,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.2" + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.3" }, "funding": [ { @@ -5782,7 +5803,7 @@ "type": "tidelift" } ], - "time": "2025-08-10T08:07:46+00:00" + "time": "2026-01-24T09:26:40+00:00" }, { "name": "sebastian/complexity", @@ -6917,16 +6938,16 @@ }, { "name": "symfony/messenger", - "version": "v8.0.3", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/messenger.git", - "reference": "b56b89aee16ceb623f76c8739ab62202ec198190" + "reference": "3483db96bcc33310cd1807d2b962e7e01d9f41c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/messenger/zipball/b56b89aee16ceb623f76c8739ab62202ec198190", - "reference": "b56b89aee16ceb623f76c8739ab62202ec198190", + "url": "https://api.github.com/repos/symfony/messenger/zipball/3483db96bcc33310cd1807d2b962e7e01d9f41c2", + "reference": "3483db96bcc33310cd1807d2b962e7e01d9f41c2", "shasum": "" }, "require": { @@ -6936,7 +6957,9 @@ }, "conflict": { "symfony/console": "<7.4", - "symfony/event-dispatcher-contracts": "<2.5" + "symfony/event-dispatcher-contracts": "<2.5", + "symfony/lock": "<7.4", + "symfony/serializer": "<7.4.4|>=8.0,<8.0.4" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", @@ -6949,7 +6972,7 @@ "symfony/property-access": "^7.4|^8.0", "symfony/rate-limiter": "^7.4|^8.0", "symfony/routing": "^7.4|^8.0", - "symfony/serializer": "^7.4|^8.0", + "symfony/serializer": "^7.4.4|^8.0.4", "symfony/service-contracts": "^2.5|^3", "symfony/stopwatch": "^7.4|^8.0", "symfony/validator": "^7.4|^8.0", @@ -6981,7 +7004,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.3" + "source": "https://github.com/symfony/messenger/tree/v8.0.4" }, "funding": [ { @@ -7001,7 +7024,7 @@ "type": "tidelift" } ], - "time": "2025-12-23T14:52:06+00:00" + "time": "2026-01-08T22:36:47+00:00" }, { "name": "symfony/options-resolver", @@ -7320,16 +7343,16 @@ }, { "name": "symfony/process", - "version": "v8.0.3", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "0cbbd88ec836f8757641c651bb995335846abb78" + "reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/0cbbd88ec836f8757641c651bb995335846abb78", - "reference": "0cbbd88ec836f8757641c651bb995335846abb78", + "url": "https://api.github.com/repos/symfony/process/zipball/b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674", + "reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674", "shasum": "" }, "require": { @@ -7361,7 +7384,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v8.0.3" + "source": "https://github.com/symfony/process/tree/v8.0.5" }, "funding": [ { @@ -7381,20 +7404,20 @@ "type": "tidelift" } ], - "time": "2025-12-19T10:01:18+00:00" + "time": "2026-01-26T15:08:38+00:00" }, { "name": "symfony/var-dumper", - "version": "v8.0.3", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "3bc368228532ad538cc216768caa8968be95a8d6" + "reference": "326e0406fc315eca57ef5740fa4a280b7a068c82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3bc368228532ad538cc216768caa8968be95a8d6", - "reference": "3bc368228532ad538cc216768caa8968be95a8d6", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/326e0406fc315eca57ef5740fa4a280b7a068c82", + "reference": "326e0406fc315eca57ef5740fa4a280b7a068c82", "shasum": "" }, "require": { @@ -7448,7 +7471,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v8.0.3" + "source": "https://github.com/symfony/var-dumper/tree/v8.0.4" }, "funding": [ { @@ -7468,7 +7491,7 @@ "type": "tidelift" } ], - "time": "2025-12-18T11:23:51+00:00" + "time": "2026-01-01T23:07:29+00:00" }, { "name": "thecodingmachine/safe", @@ -7661,16 +7684,16 @@ }, { "name": "webmozart/assert", - "version": "2.1.1", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "bdbabc199a7ba9965484e4725d66170e5711323b" + "reference": "ce6a2f100c404b2d32a1dd1270f9b59ad4f57649" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/bdbabc199a7ba9965484e4725d66170e5711323b", - "reference": "bdbabc199a7ba9965484e4725d66170e5711323b", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/ce6a2f100c404b2d32a1dd1270f9b59ad4f57649", + "reference": "ce6a2f100c404b2d32a1dd1270f9b59ad4f57649", "shasum": "" }, "require": { @@ -7717,9 +7740,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/2.1.1" + "source": "https://github.com/webmozarts/assert/tree/2.1.2" }, - "time": "2026-01-08T11:28:40+00:00" + "time": "2026-01-13T14:02:24+00:00" }, { "name": "webmozart/glob", @@ -7835,7 +7858,8 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { - "patchlevel/event-sourcing-phpstan-extension": 20 + "patchlevel/event-sourcing-phpstan-extension": 20, + "patchlevel/hydrator": 20 }, "prefer-stable": false, "prefer-lowest": false, diff --git a/docs/index.md b/docs/index.md index 11a4c9918..8ee436999 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,7 +11,7 @@ powered by the reliable Doctrine ecosystem and focused on developer experience. * Automatic [snapshot](snapshots.md)-system to boost your performance * [Split](split-stream.md) big aggregates into multiple streams * Versioned and managed lifecycle of [subscriptions](subscription.md) like projections and processors -* Safe usage of [Personal Data](personal-data.md) with crypto-shredding +* Safe usage of [Personal Data](sensitive-data.md) with crypto-shredding * Smooth [upcasting](upcasting.md) of old events * Simple setup with [scheme management](store.md) and [doctrine migration](store.md) * Built in [cli commands](cli.md) with [symfony](https://symfony.com/) diff --git a/docs/normalizer.md b/docs/normalizer.md index 4701a3704..65c9ab656 100644 --- a/docs/normalizer.md +++ b/docs/normalizer.md @@ -101,7 +101,7 @@ final class CreateHotel ``` :::note -If you have personal data, you can use [crypto-shredding](personal-data.md). + If you have personal data, you can use [crypto-shredding](sensitive_data.md). ::: ### Aggregate @@ -472,4 +472,4 @@ final class DTO * [How to define aggregates](aggregate.md) * [How to define events](events.md) * [How to snapshot aggregates](snapshots.md) -* [How to work with personal data](personal-data.md) +* [How to work with personal data](sensitive-data.md) diff --git a/docs/personal-data.md b/docs/sensitive-data.md similarity index 86% rename from docs/personal-data.md rename to docs/sensitive-data.md index cb95cc3a2..60fccb6be 100644 --- a/docs/personal-data.md +++ b/docs/sensitive-data.md @@ -1,4 +1,4 @@ -# Personal Data (GDPR) +# Sensitive Data According to GDPR, personal data must be able to be deleted upon request. But here we have the problem that our events are immutable and we cannot easily manipulate the event store. @@ -42,23 +42,22 @@ final class EmailChanged :::tip You can use the `DataSubjectId` in aggregates for snapshots too. -::: - -### PersonalData +::: +### SensitiveData -Next, you have to mark the properties that should be encrypted with the `#[PersonalData]` attribute. +Next, you have to mark the properties that should be encrypted with the `#[SensitiveData]` attribute. ```php use Patchlevel\EventSourcing\Identifier\Uuid; use Patchlevel\Hydrator\Attribute\DataSubjectId; -use Patchlevel\Hydrator\Attribute\PersonalData; +use Patchlevel\Hydrator\Attribute\SensitiveData; final class EmailChanged { public function __construct( #[DataSubjectId] public readonly Uuid $profileId, - #[PersonalData] + #[SensitiveData] public readonly string|null $email, ) { } @@ -66,7 +65,7 @@ final class EmailChanged ``` :::tip -You can use the `PersonalData` in aggregates for snapshots too. +You can use the `SensitiveData` in aggregates for snapshots too. ::: If the information could not be decrypted, then a fallback value will be used. @@ -74,16 +73,16 @@ The default fallback value is `null`. You can change this by setting the `fallback` parameter or using the `fallbackCallable` parameter. ```php -use Patchlevel\Hydrator\Attribute\PersonalData; +use Patchlevel\Hydrator\Attribute\SensitiveData; final class ProfileChanged { public function __construct( #[DataSubjectId] public readonly Uuid $profileId, - #[PersonalData(fallback: 'unknown')] + #[SensitiveData(fallback: 'unknown')] public readonly string $name, - #[PersonalData(fallbackCallable: [self::class, 'createAnonymousEmail'])] + #[SensitiveData(fallbackCallable: [self::class, 'createAnonymousEmail'])] public readonly string $email, ) { } @@ -147,10 +146,10 @@ Now we have to put the whole thing together in a Personal Data Payload Cryptogra ```php use Patchlevel\EventSourcing\Cryptography\Store\CipherKeyStore; -use Patchlevel\Hydrator\Cryptography\PersonalDataPayloadCryptographer; +use Patchlevel\Hydrator\Cryptography\SensitiveDataPayloadCryptographer; /** @var CipherKeyStore $cipherKeyStore */ -$cryptographer = PersonalDataPayloadCryptographer::createWithDefaultSettings($cipherKeyStore); +$cryptographer = SensitiveDataPayloadCryptographer::createWithDefaultSettings($cipherKeyStore); ``` :::tip @@ -163,9 +162,9 @@ The last step is to integrate the cryptographer into the event store. ```php use Patchlevel\EventSourcing\Serializer\DefaultEventSerializer; -use Patchlevel\Hydrator\Cryptography\PersonalDataPayloadCryptographer; +use Patchlevel\Hydrator\Cryptography\SensitiveDataPayloadCryptographer; -/** @var PersonalDataPayloadCryptographer $cryptographer */ +/** @var SensitiveDataPayloadCryptographer $cryptographer */ DefaultEventSerializer::createFromPaths( [__DIR__ . '/Events'], cryptographer: $cryptographer, @@ -182,9 +181,9 @@ And for the snapshot store. ```php use Patchlevel\EventSourcing\Snapshot\DefaultSnapshotStore; -use Patchlevel\Hydrator\Cryptography\PersonalDataPayloadCryptographer; +use Patchlevel\Hydrator\Cryptography\SensitiveDataPayloadCryptographer; -/** @var PersonalDataPayloadCryptographer $cryptographer */ +/** @var SensitiveDataPayloadCryptographer $cryptographer */ $snapshotStore = DefaultSnapshotStore::createDefault( [ /* adapters... */ @@ -212,7 +211,7 @@ use Patchlevel\EventSourcing\Message\Message; use Patchlevel\Hydrator\Cryptography\Store\CipherKeyStore; #[Processor('delete_personal_data')] -final class DeletePersonalDataProcessor +final class DeleteSensitiveDataProcessor { public function __construct( private readonly CipherKeyStore $cipherKeyStore, diff --git a/docs/snapshots.md b/docs/snapshots.md index a8caa83b6..96447e3fe 100644 --- a/docs/snapshots.md +++ b/docs/snapshots.md @@ -265,4 +265,4 @@ You still have to bring the aggregate up to date by loading the missing events f * [How to define aggregates](aggregate.md) * [How to store and load aggregates](repository.md) * [How to split streams](split-stream.md) -* [How to work with personal data](personal-data.md) +* [How to work with personal data](sensitive-data.md) diff --git a/src/Message/Serializer/DefaultHeadersSerializer.php b/src/Message/Serializer/DefaultHeadersSerializer.php index 02addd9d5..09efe9d96 100644 --- a/src/Message/Serializer/DefaultHeadersSerializer.php +++ b/src/Message/Serializer/DefaultHeadersSerializer.php @@ -8,7 +8,9 @@ use Patchlevel\EventSourcing\Metadata\Message\MessageHeaderRegistry; use Patchlevel\EventSourcing\Serializer\Encoder\Encoder; use Patchlevel\EventSourcing\Serializer\Encoder\JsonEncoder; +use Patchlevel\Hydrator\CoreExtension; use Patchlevel\Hydrator\Hydrator; +use Patchlevel\Hydrator\HydratorBuilder; use Patchlevel\Hydrator\MetadataHydrator; use function is_array; @@ -65,7 +67,7 @@ public static function createFromPaths(array $paths): static { return new self( (new AttributeMessageHeaderRegistryFactory())->create($paths), - new MetadataHydrator(), + (new HydratorBuilder())->useExtension(new CoreExtension())->build(), new JsonEncoder(), ); } @@ -74,7 +76,7 @@ public static function createDefault(): static { return new self( MessageHeaderRegistry::createWithInternalHeaders(), - new MetadataHydrator(), + (new HydratorBuilder())->useExtension(new CoreExtension())->build(), new JsonEncoder(), ); } diff --git a/src/Serializer/DefaultEventSerializer.php b/src/Serializer/DefaultEventSerializer.php index 260098936..07af31b1c 100644 --- a/src/Serializer/DefaultEventSerializer.php +++ b/src/Serializer/DefaultEventSerializer.php @@ -8,19 +8,21 @@ use Patchlevel\EventSourcing\Metadata\Event\EventRegistry; use Patchlevel\EventSourcing\Serializer\Encoder\Encoder; use Patchlevel\EventSourcing\Serializer\Encoder\JsonEncoder; -use Patchlevel\EventSourcing\Serializer\Upcast\Upcast; -use Patchlevel\EventSourcing\Serializer\Upcast\Upcaster; +use Patchlevel\Hydrator\CoreExtension; +use Patchlevel\Hydrator\Cryptography\CryptographyExtension; use Patchlevel\Hydrator\Cryptography\PayloadCryptographer; use Patchlevel\Hydrator\Hydrator; -use Patchlevel\Hydrator\MetadataHydrator; +use Patchlevel\Hydrator\HydratorBuilder; final class DefaultEventSerializer implements EventSerializer { + public const CONTEXT_EVENT_NAME = 'event_name'; + public const CONTEXT_EVENT_CLASS = 'event_class'; + public function __construct( private EventRegistry $eventRegistry, - private Hydrator $hydrator = new MetadataHydrator(), + private Hydrator $hydrator, private Encoder $encoder = new JsonEncoder(), - private Upcaster|null $upcaster = null, ) { } @@ -28,7 +30,11 @@ public function __construct( public function serialize(object $event, array $options = []): SerializedEvent { $name = $this->eventRegistry->eventName($event::class); - $data = $this->hydrator->extract($event); + + $data = $this->hydrator->extract($event, [ + self::CONTEXT_EVENT_NAME => $name, + self::CONTEXT_EVENT_CLASS => $event::class, + ]); return new SerializedEvent( $name, @@ -40,30 +46,30 @@ public function serialize(object $event, array $options = []): SerializedEvent public function deserialize(SerializedEvent $data, array $options = []): object { $payload = $this->encoder->decode($data->payload, $options); + $class = $this->eventRegistry->eventClass($data->name); - $eventName = $data->name; - if ($this->upcaster) { - $upcast = ($this->upcaster)(new Upcast($data->name, $payload)); - $eventName = $upcast->eventName; - $payload = $upcast->payload; - } - - $class = $this->eventRegistry->eventClass($eventName); - - return $this->hydrator->hydrate($class, $payload); + return $this->hydrator->hydrate($class, $payload, [ + self::CONTEXT_EVENT_NAME => $data->name, + self::CONTEXT_EVENT_CLASS => $class, + ]); } /** @param list $paths */ public static function createFromPaths( array $paths, - Upcaster|null $upcaster = null, PayloadCryptographer|null $cryptographer = null, ): static { + $builder = (new HydratorBuilder()) + ->useExtension(new CoreExtension()); + + if ($cryptographer) { + $builder->useExtension(new CryptographyExtension($cryptographer)); + } + return new self( (new AttributeEventRegistryFactory())->create($paths), - new MetadataHydrator(cryptographer: $cryptographer), + $builder->build(), new JsonEncoder(), - $upcaster, ); } } diff --git a/src/Serializer/Normalizer/IdNormalizer.php b/src/Serializer/Normalizer/IdNormalizer.php index d65d903b2..422354097 100644 --- a/src/Serializer/Normalizer/IdNormalizer.php +++ b/src/Serializer/Normalizer/IdNormalizer.php @@ -25,7 +25,7 @@ public function __construct( ) { } - public function normalize(mixed $value): string|null + public function normalize(mixed $value, array $context): string|null { if ($value === null) { return null; @@ -40,7 +40,7 @@ public function normalize(mixed $value): string|null return $value->toString(); } - public function denormalize(mixed $value): Identifier|null + public function denormalize(mixed $value, array $context): Identifier|null { if ($value === null) { return null; diff --git a/src/Serializer/Upcast/UpcastMiddleware.php b/src/Serializer/Upcast/UpcastMiddleware.php new file mode 100644 index 000000000..c39cc94a9 --- /dev/null +++ b/src/Serializer/Upcast/UpcastMiddleware.php @@ -0,0 +1,35 @@ +className !== $eventClass) { + return $stack->next()->hydrate($metadata, $data, $context, $stack); + } + + $upcast = ($this->upcaster)(new Upcast($eventName, $data)); + + return $stack->next()->hydrate($metadata, $upcast->payload, $context, $stack); + } + + public function extract(ClassMetadata $metadata, object $object, array $context, Stack $stack): array + { + return $stack->next()->extract($metadata, $object, $context, $stack); + } +} \ No newline at end of file diff --git a/src/Snapshot/DefaultSnapshotStore.php b/src/Snapshot/DefaultSnapshotStore.php index 5bab975f6..8ef3fc444 100644 --- a/src/Snapshot/DefaultSnapshotStore.php +++ b/src/Snapshot/DefaultSnapshotStore.php @@ -9,11 +9,12 @@ use Patchlevel\EventSourcing\Metadata\AggregateRoot\AggregateRootMetadataAwareMetadataFactory; use Patchlevel\EventSourcing\Metadata\AggregateRoot\AggregateRootMetadataFactory; use Patchlevel\EventSourcing\Snapshot\Adapter\SnapshotAdapter; +use Patchlevel\Hydrator\CoreExtension; +use Patchlevel\Hydrator\Cryptography\CryptographyExtension; use Patchlevel\Hydrator\Cryptography\PayloadCryptographer; use Patchlevel\Hydrator\Hydrator; -use Patchlevel\Hydrator\MetadataHydrator; +use Patchlevel\Hydrator\HydratorBuilder; use Throwable; - use function array_key_exists; use function is_array; use function sprintf; @@ -38,7 +39,7 @@ public function __construct( $this->adapterRepository = $adapterRepository; } - $this->hydrator = $hydrator ?? new MetadataHydrator(); + $this->hydrator = $hydrator ?? (new HydratorBuilder())->useExtension(new CoreExtension())->build();; $this->metadataFactory = $metadataFactory ?? new AggregateRootMetadataAwareMetadataFactory(); } @@ -120,9 +121,16 @@ private function version(string $aggregateClass): string|null /** @param array $snapshotAdapters */ public static function createDefault(array $snapshotAdapters, PayloadCryptographer|null $cryptographer = null): self { + $builder = new HydratorBuilder(); + $builder->useExtension(new CoreExtension()); + + if ($cryptographer) { + $builder->useExtension(new CryptographyExtension($cryptographer)); + } + return new self( new ArrayAdapterRepository($snapshotAdapters), - new MetadataHydrator(cryptographer: $cryptographer), + $builder->build(), ); } } diff --git a/tests/Benchmark/BasicImplementation/Events/EmailChanged.php b/tests/Benchmark/BasicImplementation/Events/EmailChanged.php index a7c3743cc..757a3e5eb 100644 --- a/tests/Benchmark/BasicImplementation/Events/EmailChanged.php +++ b/tests/Benchmark/BasicImplementation/Events/EmailChanged.php @@ -7,7 +7,7 @@ use Patchlevel\EventSourcing\Attribute\Event; use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\ProfileId; use Patchlevel\Hydrator\Attribute\DataSubjectId; -use Patchlevel\Hydrator\Attribute\PersonalData; +use Patchlevel\Hydrator\Attribute\SensitiveData; #[Event('profile.email_changed')] final class EmailChanged @@ -15,7 +15,7 @@ final class EmailChanged public function __construct( #[DataSubjectId] public ProfileId $profileId, - #[PersonalData] + #[SensitiveData] public string|null $email, ) { } diff --git a/tests/Benchmark/BasicImplementation/Events/ProfileCreated.php b/tests/Benchmark/BasicImplementation/Events/ProfileCreated.php index 07adcaeee..656bd164d 100644 --- a/tests/Benchmark/BasicImplementation/Events/ProfileCreated.php +++ b/tests/Benchmark/BasicImplementation/Events/ProfileCreated.php @@ -8,7 +8,7 @@ use Patchlevel\EventSourcing\Attribute\EventTag; use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\ProfileId; use Patchlevel\Hydrator\Attribute\DataSubjectId; -use Patchlevel\Hydrator\Attribute\PersonalData; +use Patchlevel\Hydrator\Attribute\SensitiveData; #[Event('profile.created')] final class ProfileCreated @@ -18,7 +18,7 @@ public function __construct( #[EventTag(prefix: 'profile')] public ProfileId $profileId, public string $name, - #[PersonalData] + #[SensitiveData] public string|null $email, ) { } diff --git a/tests/Benchmark/PersonalDataBench.php b/tests/Benchmark/PersonalDataBench.php index 0e7b93a92..b5247bb3a 100644 --- a/tests/Benchmark/PersonalDataBench.php +++ b/tests/Benchmark/PersonalDataBench.php @@ -16,7 +16,7 @@ use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Profile; use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\ProfileId; use Patchlevel\EventSourcing\Tests\DbalManager; -use Patchlevel\Hydrator\Cryptography\PersonalDataPayloadCryptographer; +use Patchlevel\Hydrator\Cryptography\SensitiveDataPayloadCryptographer; use PhpBench\Attributes as Bench; #[Bench\BeforeMethods('setUp')] @@ -34,7 +34,7 @@ public function setUp(): void $cipherKeyStore = new DoctrineCipherKeyStore($connection); - $cryptographer = PersonalDataPayloadCryptographer::createWithOpenssl( + $cryptographer = SensitiveDataPayloadCryptographer::createWithOpenssl( $cipherKeyStore, ); diff --git a/tests/Integration/PersonalData/Events/NameChanged.php b/tests/Integration/SensitiveData/Events/NameChanged.php similarity index 59% rename from tests/Integration/PersonalData/Events/NameChanged.php rename to tests/Integration/SensitiveData/Events/NameChanged.php index 22c18482d..c747d1ceb 100644 --- a/tests/Integration/PersonalData/Events/NameChanged.php +++ b/tests/Integration/SensitiveData/Events/NameChanged.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Patchlevel\EventSourcing\Tests\Integration\PersonalData\Events; +namespace Patchlevel\EventSourcing\Tests\Integration\SensitiveData\Events; use Patchlevel\EventSourcing\Attribute\Event; -use Patchlevel\EventSourcing\Tests\Integration\PersonalData\ProfileId; +use Patchlevel\EventSourcing\Tests\Integration\SensitiveData\ProfileId; use Patchlevel\Hydrator\Attribute\DataSubjectId; -use Patchlevel\Hydrator\Attribute\PersonalData; +use Patchlevel\Hydrator\Attribute\SensitiveData; #[Event('profile.name_changed')] final class NameChanged @@ -15,7 +15,7 @@ final class NameChanged public function __construct( #[DataSubjectId] public readonly ProfileId $aggregateId, - #[PersonalData(fallback: 'unknown')] + #[SensitiveData(fallback: 'unknown')] public readonly string $name, ) { } diff --git a/tests/Integration/PersonalData/Events/PersonalDataRemoved.php b/tests/Integration/SensitiveData/Events/PersonalDataRemoved.php similarity index 63% rename from tests/Integration/PersonalData/Events/PersonalDataRemoved.php rename to tests/Integration/SensitiveData/Events/PersonalDataRemoved.php index 646b4a3f4..bff7d54c0 100644 --- a/tests/Integration/PersonalData/Events/PersonalDataRemoved.php +++ b/tests/Integration/SensitiveData/Events/PersonalDataRemoved.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Patchlevel\EventSourcing\Tests\Integration\PersonalData\Events; +namespace Patchlevel\EventSourcing\Tests\Integration\SensitiveData\Events; use Patchlevel\EventSourcing\Attribute\Event; -use Patchlevel\EventSourcing\Tests\Integration\PersonalData\ProfileId; +use Patchlevel\EventSourcing\Tests\Integration\SensitiveData\ProfileId; #[Event('profile.personal_data_removed')] final class PersonalDataRemoved diff --git a/tests/Integration/PersonalData/Events/ProfileCreated.php b/tests/Integration/SensitiveData/Events/ProfileCreated.php similarity index 57% rename from tests/Integration/PersonalData/Events/ProfileCreated.php rename to tests/Integration/SensitiveData/Events/ProfileCreated.php index 82b1dd0b8..5fc800b1a 100644 --- a/tests/Integration/PersonalData/Events/ProfileCreated.php +++ b/tests/Integration/SensitiveData/Events/ProfileCreated.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Patchlevel\EventSourcing\Tests\Integration\PersonalData\Events; +namespace Patchlevel\EventSourcing\Tests\Integration\SensitiveData\Events; use Patchlevel\EventSourcing\Attribute\Event; -use Patchlevel\EventSourcing\Tests\Integration\PersonalData\ProfileId; +use Patchlevel\EventSourcing\Tests\Integration\SensitiveData\ProfileId; use Patchlevel\Hydrator\Attribute\DataSubjectId; -use Patchlevel\Hydrator\Attribute\PersonalData; +use Patchlevel\Hydrator\Attribute\SensitiveData; #[Event('profile.created')] final class ProfileCreated @@ -15,7 +15,7 @@ final class ProfileCreated public function __construct( #[DataSubjectId] public ProfileId $profileId, - #[PersonalData(fallback: 'unknown')] + #[SensitiveData(fallback: 'unknown')] public string $name, ) { } diff --git a/tests/Integration/PersonalData/Processor/DeletePersonalDataProcessor.php b/tests/Integration/SensitiveData/Processor/DeletePersonalDataProcessor.php similarity index 77% rename from tests/Integration/PersonalData/Processor/DeletePersonalDataProcessor.php rename to tests/Integration/SensitiveData/Processor/DeletePersonalDataProcessor.php index ab07bcc9d..cf4ecad35 100644 --- a/tests/Integration/PersonalData/Processor/DeletePersonalDataProcessor.php +++ b/tests/Integration/SensitiveData/Processor/DeletePersonalDataProcessor.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Patchlevel\EventSourcing\Tests\Integration\PersonalData\Processor; +namespace Patchlevel\EventSourcing\Tests\Integration\SensitiveData\Processor; use Patchlevel\EventSourcing\Attribute\Processor; use Patchlevel\EventSourcing\Attribute\Subscribe; -use Patchlevel\EventSourcing\Tests\Integration\PersonalData\Events\PersonalDataRemoved; +use Patchlevel\EventSourcing\Tests\Integration\SensitiveData\Events\PersonalDataRemoved; use Patchlevel\Hydrator\Cryptography\Store\CipherKeyStore; #[Processor('delete_personal_data')] diff --git a/tests/Integration/PersonalData/Profile.php b/tests/Integration/SensitiveData/Profile.php similarity index 78% rename from tests/Integration/PersonalData/Profile.php rename to tests/Integration/SensitiveData/Profile.php index 50d324df0..0e1fad2d4 100644 --- a/tests/Integration/PersonalData/Profile.php +++ b/tests/Integration/SensitiveData/Profile.php @@ -2,18 +2,18 @@ declare(strict_types=1); -namespace Patchlevel\EventSourcing\Tests\Integration\PersonalData; +namespace Patchlevel\EventSourcing\Tests\Integration\SensitiveData; use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot; use Patchlevel\EventSourcing\Attribute\Aggregate; use Patchlevel\EventSourcing\Attribute\Apply; use Patchlevel\EventSourcing\Attribute\Id; use Patchlevel\EventSourcing\Attribute\Snapshot; -use Patchlevel\EventSourcing\Tests\Integration\PersonalData\Events\NameChanged; -use Patchlevel\EventSourcing\Tests\Integration\PersonalData\Events\PersonalDataRemoved; -use Patchlevel\EventSourcing\Tests\Integration\PersonalData\Events\ProfileCreated; +use Patchlevel\EventSourcing\Tests\Integration\SensitiveData\Events\NameChanged; +use Patchlevel\EventSourcing\Tests\Integration\SensitiveData\Events\PersonalDataRemoved; +use Patchlevel\EventSourcing\Tests\Integration\SensitiveData\Events\ProfileCreated; use Patchlevel\Hydrator\Attribute\DataSubjectId; -use Patchlevel\Hydrator\Attribute\PersonalData; +use Patchlevel\Hydrator\Attribute\SensitiveData; #[Aggregate('profile')] #[Snapshot('default', 2)] @@ -23,7 +23,7 @@ final class Profile extends BasicAggregateRoot #[DataSubjectId] private ProfileId $id; - #[PersonalData(fallback: 'unknown')] + #[SensitiveData(fallback: 'unknown')] private string $name; public static function create(ProfileId $id, string $name): self diff --git a/tests/Integration/PersonalData/ProfileId.php b/tests/Integration/SensitiveData/ProfileId.php similarity index 77% rename from tests/Integration/PersonalData/ProfileId.php rename to tests/Integration/SensitiveData/ProfileId.php index 7b475b851..cf51c62e1 100644 --- a/tests/Integration/PersonalData/ProfileId.php +++ b/tests/Integration/SensitiveData/ProfileId.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Patchlevel\EventSourcing\Tests\Integration\PersonalData; +namespace Patchlevel\EventSourcing\Tests\Integration\SensitiveData; use Patchlevel\EventSourcing\Identifier\Identifier; use Patchlevel\EventSourcing\Identifier\RamseyUuidV7Behaviour; diff --git a/tests/Integration/PersonalData/PersonalDataTest.php b/tests/Integration/SensitiveData/SensitiveDataTest.php similarity index 87% rename from tests/Integration/PersonalData/PersonalDataTest.php rename to tests/Integration/SensitiveData/SensitiveDataTest.php index de690c902..3c9c5f0cc 100644 --- a/tests/Integration/PersonalData/PersonalDataTest.php +++ b/tests/Integration/SensitiveData/SensitiveDataTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Patchlevel\EventSourcing\Tests\Integration\PersonalData; +namespace Patchlevel\EventSourcing\Tests\Integration\SensitiveData; use Doctrine\DBAL\Connection; use Patchlevel\EventSourcing\Cryptography\DoctrineCipherKeyStore; @@ -19,13 +19,13 @@ use Patchlevel\EventSourcing\Subscription\Store\DoctrineSubscriptionStore; use Patchlevel\EventSourcing\Subscription\Subscriber\MetadataSubscriberAccessorRepository; use Patchlevel\EventSourcing\Tests\DbalManager; -use Patchlevel\EventSourcing\Tests\Integration\PersonalData\Processor\DeletePersonalDataProcessor; -use Patchlevel\Hydrator\Cryptography\PersonalDataPayloadCryptographer; +use Patchlevel\EventSourcing\Tests\Integration\SensitiveData\Processor\DeletePersonalDataProcessor; +use Patchlevel\Hydrator\Cryptography\SensitiveDataPayloadCryptographer; use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\TestCase; #[CoversNothing] -final class PersonalDataTest extends TestCase +final class SensitiveDataTest extends TestCase { private Connection $connection; @@ -42,7 +42,7 @@ public function tearDown(): void public function testSuccessfulWithEvent(): void { $cipherKeyStore = new DoctrineCipherKeyStore($this->connection); - $cryptographer = PersonalDataPayloadCryptographer::createWithOpenssl($cipherKeyStore); + $cryptographer = SensitiveDataPayloadCryptographer::createWithOpenssl($cipherKeyStore); $store = new StreamDoctrineDbalStore( $this->connection, @@ -73,7 +73,6 @@ public function testSuccessfulWithEvent(): void $profile = $repository->load($profileId); - self::assertInstanceOf(Profile::class, $profile); self::assertEquals($profileId, $profile->aggregateRootId()); self::assertSame(1, $profile->playhead()); self::assertSame('John', $profile->name()); @@ -82,16 +81,13 @@ public function testSuccessfulWithEvent(): void self::assertCount(1, $result); self::assertArrayHasKey(0, $result); - - $row = $result[0]; - - self::assertStringNotContainsString('John', $row['event_payload']); + self::assertStringNotContainsString('John', $result[0]['event_payload']); } public function testRemoveKeyWithEvent(): void { $cipherKeyStore = new DoctrineCipherKeyStore($this->connection); - $cryptographer = PersonalDataPayloadCryptographer::createWithOpenssl($cipherKeyStore); + $cryptographer = SensitiveDataPayloadCryptographer::createWithOpenssl($cipherKeyStore); $subscriptionStore = new DoctrineSubscriptionStore( $this->connection, @@ -136,7 +132,6 @@ public function testRemoveKeyWithEvent(): void $profile = $repository->load($profileId); - self::assertInstanceOf(Profile::class, $profile); self::assertEquals($profileId, $profile->aggregateRootId()); self::assertSame(1, $profile->playhead()); self::assertSame('John', $profile->name()); @@ -147,7 +142,6 @@ public function testRemoveKeyWithEvent(): void $profile = $repository->load($profileId); - self::assertInstanceOf(Profile::class, $profile); self::assertEquals($profileId, $profile->aggregateRootId()); self::assertSame(2, $profile->playhead()); self::assertSame('unknown', $profile->name()); @@ -157,7 +151,6 @@ public function testRemoveKeyWithEvent(): void $profile = $repository->load($profileId); - self::assertInstanceOf(Profile::class, $profile); self::assertEquals($profileId, $profile->aggregateRootId()); self::assertSame(3, $profile->playhead()); self::assertSame('hallo', $profile->name()); @@ -166,7 +159,7 @@ public function testRemoveKeyWithEvent(): void public function testRemoveKeyWithEventAndSnapshot(): void { $cipherKeyStore = new DoctrineCipherKeyStore($this->connection); - $cryptographer = PersonalDataPayloadCryptographer::createWithOpenssl($cipherKeyStore); + $cryptographer = SensitiveDataPayloadCryptographer::createWithOpenssl($cipherKeyStore); $subscriptionStore = new DoctrineSubscriptionStore( $this->connection, @@ -219,16 +212,20 @@ public function testRemoveKeyWithEventAndSnapshot(): void $profile = $repository->load($profileId); - self::assertInstanceOf(Profile::class, $profile); self::assertEquals($profileId, $profile->aggregateRootId()); self::assertSame(2, $profile->playhead()); self::assertSame('John 2', $profile->name()); + $result = $this->connection->fetchAllAssociative('SELECT * FROM event_store'); + + self::assertCount(2, $result); + self::assertArrayHasKey(1, $result); + self::assertStringNotContainsString('John 2', $result[1]['event_payload']); + $cipherKeyStore->remove($profileId->toString()); $profile = $repository->load($profileId); - self::assertInstanceOf(Profile::class, $profile); self::assertEquals($profileId, $profile->aggregateRootId()); self::assertSame(2, $profile->playhead()); self::assertSame('unknown', $profile->name()); diff --git a/tests/Integration/Subscription/SubscriptionTest.php b/tests/Integration/Subscription/SubscriptionTest.php index 6a5b60b13..b5e7f33d6 100644 --- a/tests/Integration/Subscription/SubscriptionTest.php +++ b/tests/Integration/Subscription/SubscriptionTest.php @@ -41,6 +41,8 @@ use Patchlevel\EventSourcing\Tests\Integration\Subscription\Subscriber\ProfileNewProjection; use Patchlevel\EventSourcing\Tests\Integration\Subscription\Subscriber\ProfileProcessor; use Patchlevel\EventSourcing\Tests\Integration\Subscription\Subscriber\ProfileProjection; +use Patchlevel\Hydrator\CoreExtension; +use Patchlevel\Hydrator\HydratorBuilder; use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\TestCase; use RuntimeException; @@ -1184,7 +1186,10 @@ public function testBlueGreenDeploymentRollback(): void public function testLookup(): void { $eventRegistry = (new AttributeEventRegistryFactory())->create([__DIR__ . '/Events']); - $serializer = new DefaultEventSerializer($eventRegistry); + $serializer = new DefaultEventSerializer( + $eventRegistry, + (new HydratorBuilder())->useExtension(new CoreExtension())->build(), + ); $store = new StreamDoctrineDbalStore( $this->connection, diff --git a/tests/Unit/Fixture/EmailNormalizer.php b/tests/Unit/Fixture/EmailNormalizer.php index d13924557..74ac99166 100644 --- a/tests/Unit/Fixture/EmailNormalizer.php +++ b/tests/Unit/Fixture/EmailNormalizer.php @@ -14,7 +14,7 @@ #[Attribute(Attribute::TARGET_PROPERTY)] final class EmailNormalizer implements Normalizer { - public function normalize(mixed $value): string + public function normalize(mixed $value, array $context): string { if (!$value instanceof Email) { throw new InvalidArgumentException(); @@ -23,7 +23,7 @@ public function normalize(mixed $value): string return $value->toString(); } - public function denormalize(mixed $value): Email|null + public function denormalize(mixed $value, array $context): Email|null { if ($value === null) { return null; diff --git a/tests/Unit/Fixture/MessageNormalizer.php b/tests/Unit/Fixture/MessageNormalizer.php index d18220bcb..ef7d31869 100644 --- a/tests/Unit/Fixture/MessageNormalizer.php +++ b/tests/Unit/Fixture/MessageNormalizer.php @@ -14,7 +14,7 @@ final class MessageNormalizer implements Normalizer { /** @return array|null */ - public function normalize(mixed $value): array|null + public function normalize(mixed $value, array $context): array|null { if ($value === null) { return null; @@ -27,7 +27,7 @@ public function normalize(mixed $value): array|null return $value->toArray(); } - public function denormalize(mixed $value): Message|null + public function denormalize(mixed $value, array $context): Message|null { if ($value === null) { return null;