@@ -406,22 +406,83 @@ readonly class Dto
406406}
407407```
408408
409+ ### Events
410+
411+ Another way to intervene in the extract and hydrate process is through events.
412+ There are two events: ` PostExtract ` and ` PreHydrate ` .
413+ For this functionality we use the [ symfony/event-dispatcher] ( https://symfony.com/doc/current/components/event_dispatcher.html ) .
414+
415+ ``` php
416+ use Patchlevel\Hydrator\Cryptography\PersonalDataPayloadCryptographer;
417+ use Patchlevel\Hydrator\Cryptography\Store\CipherKeyStore;
418+ use Patchlevel\Hydrator\Metadata\Event\EventMetadataFactory;
419+ use Patchlevel\Hydrator\MetadataHydrator;
420+ use Symfony\Component\EventDispatcher\EventDispatcher;
421+ use Patchlevel\Hydrator\Event\PostExtract;
422+ use Patchlevel\Hydrator\Event\PreHydrate;
423+
424+ $eventDispatcher = new EventDispatcher();
425+
426+ $eventDispatcher->addListener(
427+ PostExtract::class,
428+ static function (PostExtract $event): void {
429+ // do something
430+ }
431+ );
432+
433+ $eventDispatcher->addListener(
434+ PreHydrate::class,
435+ static function (PreHydrate $event): void {
436+ // do something
437+ }
438+ );
439+
440+ $hydrator = new MetadataHydrator(eventDispatcher: $eventDispatcher);
441+ ```
442+
409443### Cryptography
410444
411445The library also offers the possibility to encrypt and decrypt personal data.
446+ For this purpose, a key is created for each subject ID, which is used to encrypt the personal data.
447+
448+ #### DataSubjectId
449+
450+ First we need to define what the subject id is.
451+
452+ ``` php
453+ use Patchlevel\Hydrator\Attribute\DataSubjectId;
454+
455+ final class EmailChanged
456+ {
457+ public function __construct(
458+ #[DataSubjectId]
459+ public readonly string $profileId,
460+ ) {
461+ }
462+ }
463+ ```
464+
465+ > [ !WARNING]
466+ > The ` DataSubjectId ` must be a string. You can use a normalizer to convert it to a string.
467+ > The Subject ID cannot be personal data.
412468
413469#### PersonalData
414470
415- First of all, we have to mark the fields that contain personal data.
416- For our example, we use events, but you can do the same with aggregates.
471+ Next, we need to specify which fields we want to encrypt.
417472
418473``` php
474+ use Patchlevel\Hydrator\Attribute\DataSubjectId;
419475use Patchlevel\Hydrator\Attribute\PersonalData;
420476
421477final class DTO
422478{
423- #[PersonalData]
424- public readonly string|null $email;
479+ public function __construct(
480+ #[DataSubjectId]
481+ public readonly string $profileId,
482+ #[PersonalData]
483+ public readonly string|null $email,
484+ ) {
485+ }
425486}
426487```
427488
@@ -436,43 +497,40 @@ use Patchlevel\Hydrator\Attribute\PersonalData;
436497final class DTO
437498{
438499 public function __construct(
500+ #[DataSubjectId]
501+ public readonly string $profileId,
439502 #[PersonalData(fallback: 'unknown')]
440- public readonly string $email ,
503+ public readonly string $name ,
441504 ) {
442505 }
443506}
444507```
445508
446- > [ !DANGER]
447- > You have to deal with this case in your business logic such as aggregates and subscriptions.
448-
449- > [ !WARNING]
450- > You need to define a subject ID to use the personal data attribute.
451-
452- #### DataSubjectId
453-
454- In order for the correct key to be used, a subject ID must be defined.
455- Without Subject Id, no personal data can be encrypted or decrypted.
509+ You can also use a callable as a fallback.
456510
457511``` php
458512use Patchlevel\Hydrator\Attribute\DataSubjectId;
459513use Patchlevel\Hydrator\Attribute\PersonalData;
460514
461- final class EmailChanged
515+ final class ProfileCreated
462516{
463517 public function __construct(
464518 #[DataSubjectId]
465- public readonly string $personId,
466- #[PersonalData(fallback: 'unknown')]
467- public readonly string|null $email,
519+ public readonly string $profileId,
520+ #[PersonalData(fallback: 'deleted profile')]
521+ public readonly string $name,
522+ #[PersonalData(fallbackCallable: [self::class, 'anonymizedEmail'])]
523+ public readonly string $email,
468524 ) {
469525 }
526+
527+ public static function anonymizedEmail(string $subjectId): string
528+ {
529+ return sprintf('%s@anno.com', $subjectId);
530+ }
470531}
471532```
472533
473- > [ !WARNING]
474- > A subject ID can not be a personal data.
475-
476534#### Configure Cryptography
477535
478536Here we show you how to configure the cryptography.
@@ -484,10 +542,14 @@ use Patchlevel\Hydrator\Metadata\Event\EventMetadataFactory;
484542use Patchlevel\Hydrator\MetadataHydrator;
485543
486544$cipherKeyStore = new InMemoryCipherKeyStore();
487- $cryptographer = PersonalDataPayloadCryptographer::createWithOpenssl ($cipherKeyStore);
545+ $cryptographer = PersonalDataPayloadCryptographer::createWithDefaultSettings ($cipherKeyStore);
488546$hydrator = new MetadataHydrator(cryptographer: $cryptographer);
489547```
490548
549+ > [ !WARNING]
550+ > We recommend to use the ` useEncryptedFieldName ` option to recognize encrypted fields.
551+ > This allows data to be encrypted later without big troubles.
552+
491553#### Cipher Key Store
492554
493555The keys must be stored somewhere. For testing purposes, we offer an in-memory implementation.
0 commit comments