Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/CoreExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Patchlevel\Hydrator;

use Patchlevel\Hydrator\Guesser\BuiltInGuesser;
use Patchlevel\Hydrator\Guesser\Guesser;
use Patchlevel\Hydrator\Middleware\Middleware;
use Patchlevel\Hydrator\Middleware\TransformMiddleware;

final class CoreExtension extends Extension
{
/** @return iterable<Middleware|array{0: Middleware, 1?: int}> */
public function middlewares(): iterable
{
yield new TransformMiddleware();
}

/** @return iterable<Guesser|array{0: Guesser, 1?: int}> */
public function guesser(): iterable
{
yield new BuiltInGuesser();
}
}
29 changes: 29 additions & 0 deletions src/Cryptography/CryptographyExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Patchlevel\Hydrator\Cryptography;

use Patchlevel\Hydrator\Extension;
use Patchlevel\Hydrator\Metadata\MetadataEnricher;
use Patchlevel\Hydrator\Middleware\Middleware;

final class CryptographyExtension extends Extension
{
public function __construct(
private readonly PayloadCryptographer $cryptography,
) {
}

/** @return iterable<Middleware|array{0: Middleware, 1?: int}> */
public function middlewares(): iterable
{
yield [new CryptographyMiddleware($this->cryptography), 64];
}

/** @return iterable<MetadataEnricher|array{0: MetadataEnricher, 1?: int}> */
public function metadataEnrichers(): iterable
{
yield [new CryptographyMetadataEnricher(), 64];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,18 @@
use Patchlevel\Hydrator\Attribute\DataSubjectId;
use Patchlevel\Hydrator\Attribute\SensitiveData;
use Patchlevel\Hydrator\Metadata\ClassMetadata;
use Patchlevel\Hydrator\Metadata\MetadataFactory;
use Patchlevel\Hydrator\Metadata\MetadataEnricher;
use ReflectionProperty;

use function array_key_exists;

final class CryptographyMetadataFactory implements MetadataFactory
final class CryptographyMetadataEnricher implements MetadataEnricher
{
public function __construct(
private readonly MetadataFactory $metadataFactory,
) {
}

public function metadata(string $class): ClassMetadata
public function enrich(ClassMetadata $classMetadata): void
{
$metadata = $this->metadataFactory->metadata($class);

$subjectIdMapping = [];

foreach ($metadata->properties as $property) {
foreach ($classMetadata->properties as $property) {
$isSubjectId = false;
$attributeReflectionList = $property->reflection->getAttributes(DataSubjectId::class);

Expand All @@ -34,8 +27,8 @@ public function metadata(string $class): ClassMetadata

if (array_key_exists($subjectIdIdentifier, $subjectIdMapping)) {
throw new DuplicateSubjectIdIdentifier(
$metadata->className,
$metadata->propertyForField($subjectIdMapping[$subjectIdIdentifier])->propertyName,
$classMetadata->className,
$classMetadata->propertyForField($subjectIdMapping[$subjectIdIdentifier])->propertyName,
$property->propertyName,
$subjectIdIdentifier,
);
Expand All @@ -53,17 +46,17 @@ public function metadata(string $class): ClassMetadata
}

if ($isSubjectId) {
throw new SubjectIdAndSensitiveDataConflict($metadata->className, $property->propertyName);
throw new SubjectIdAndSensitiveDataConflict($classMetadata->className, $property->propertyName);
}

$property->extras[SensitiveDataInfo::class] = $sensitiveDataInfo;
}

if ($subjectIdMapping !== []) {
$metadata->extras[SubjectIdFieldMapping::class] = new SubjectIdFieldMapping($subjectIdMapping);
if ($subjectIdMapping === []) {
return;
}

return $metadata;
$classMetadata->extras[SubjectIdFieldMapping::class] = new SubjectIdFieldMapping($subjectIdMapping);
}

private function sensitiveDataInfo(ReflectionProperty $reflectionProperty): SensitiveDataInfo|null
Expand Down
30 changes: 30 additions & 0 deletions src/Extension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Patchlevel\Hydrator;

use Patchlevel\Hydrator\Guesser\Guesser;
use Patchlevel\Hydrator\Metadata\MetadataEnricher;
use Patchlevel\Hydrator\Middleware\Middleware;

abstract class Extension
{
/** @return iterable<Middleware|array{0: Middleware, 1?: int}> */
public function middlewares(): iterable
{
return [];
}

/** @return iterable<MetadataEnricher|array{0: MetadataEnricher, 1?: int}> */
public function metadataEnrichers(): iterable
{
return [];
}

/** @return iterable<Guesser|array{0: Guesser, 1?: int}> */
public function guesser(): iterable
{
return [];
}
}
2 changes: 1 addition & 1 deletion src/Metadata/AttributeMetadataFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function __construct(
Guesser|null $guesser = null,
) {
$this->typeResolver = $typeResolver ?: TypeResolver::create();
$this->guesser = $guesser ?: new BuiltInGuesser(false);
$this->guesser = $guesser ?: new BuiltInGuesser();
}

/**
Expand Down
10 changes: 10 additions & 0 deletions src/Metadata/MetadataEnricher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Patchlevel\Hydrator\Metadata;

interface MetadataEnricher
{
public function enrich(ClassMetadata $classMetadata): void;
}
67 changes: 50 additions & 17 deletions src/MetadataHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@

namespace Patchlevel\Hydrator;

use Patchlevel\Hydrator\Guesser\BuiltInGuesser;
use Patchlevel\Hydrator\Guesser\ChainGuesser;
use Patchlevel\Hydrator\Guesser\Guesser;
use Patchlevel\Hydrator\Metadata\AttributeMetadataFactory;
use Patchlevel\Hydrator\Metadata\ClassMetadata;
use Patchlevel\Hydrator\Metadata\ClassNotFound;
use Patchlevel\Hydrator\Metadata\MetadataEnricher;
use Patchlevel\Hydrator\Metadata\MetadataFactory;
use Patchlevel\Hydrator\Middleware\Middleware;
use Patchlevel\Hydrator\Middleware\Stack;
use Patchlevel\Hydrator\Middleware\TransformMiddleware;
use Patchlevel\Hydrator\Normalizer\HydratorAwareNormalizer;
use ReflectionClass;

use function array_key_exists;
use function array_merge;
use function krsort;

use const PHP_VERSION_ID;

Expand All @@ -26,10 +27,14 @@
/** @var array<class-string, ClassMetadata> */
private array $classMetadata = [];

/** @param list<Middleware> $middlewares */
/**
* @param list<Middleware> $middlewares
* @param list<MetadataEnricher> $metadataEnrichers
*/
public function __construct(
private readonly MetadataFactory $metadataFactory = new AttributeMetadataFactory(),
private readonly array $middlewares = [],
private readonly array $metadataEnrichers = [],
private readonly bool $defaultLazy = false,
) {
}
Expand Down Expand Up @@ -110,32 +115,60 @@
$property->normalizer->setHydrator($this);
}

foreach ($this->metadataEnrichers as $enricher) {
$enricher->enrich($metadata);

Check warning on line 119 in src/MetadataHydrator.php

View workflow job for this annotation

GitHub Actions / Mutation tests on diff (locked, 8.4, ubuntu-latest)

Escaped Mutant for Mutator "MethodCallRemoval": @@ @@ $property->normalizer->setHydrator($this); } foreach ($this->metadataEnrichers as $enricher) { - $enricher->enrich($metadata); + } return $metadata; }
}

return $metadata;
}

/**
* @param list<Middleware> $additionalMiddleware
* @param iterable<Guesser> $guessers
*/
/** @param iterable<Extension> $extensions */
public static function create(
array $additionalMiddleware = [],
iterable $guessers = [],
iterable $extensions = [],
bool $defaultLazy = false,
): self {
$guesser = new BuiltInGuesser();
$extensions = [...$extensions, new CoreExtension()];

$middlewares = [];
$enrichers = [];
$guessers = [];

foreach ($extensions as $extension) {
foreach ($extension->middlewares() as $entry) {
if ($entry instanceof Middleware) {
$middlewares[0][] = $entry;

Check warning on line 139 in src/MetadataHydrator.php

View workflow job for this annotation

GitHub Actions / Mutation tests on diff (locked, 8.4, ubuntu-latest)

Escaped Mutant for Mutator "IncrementInteger": @@ @@ foreach ($extensions as $extension) { foreach ($extension->middlewares() as $entry) { if ($entry instanceof Middleware) { - $middlewares[0][] = $entry; + $middlewares[1][] = $entry; } else { $middlewares[$entry[1] ?? 0][] = $entry[0]; }
} else {
$middlewares[$entry[1] ?? 0][] = $entry[0];

Check warning on line 141 in src/MetadataHydrator.php

View workflow job for this annotation

GitHub Actions / Mutation tests on diff (locked, 8.4, ubuntu-latest)

Escaped Mutant for Mutator "IncrementInteger": @@ @@ if ($entry instanceof Middleware) { $middlewares[0][] = $entry; } else { - $middlewares[$entry[1] ?? 0][] = $entry[0]; + $middlewares[$entry[1] ?? 1][] = $entry[0]; } } foreach ($extension->metadataEnrichers() as $entry) {

Check warning on line 141 in src/MetadataHydrator.php

View workflow job for this annotation

GitHub Actions / Mutation tests on diff (locked, 8.4, ubuntu-latest)

Escaped Mutant for Mutator "DecrementInteger": @@ @@ if ($entry instanceof Middleware) { $middlewares[0][] = $entry; } else { - $middlewares[$entry[1] ?? 0][] = $entry[0]; + $middlewares[$entry[1] ?? -1][] = $entry[0]; } } foreach ($extension->metadataEnrichers() as $entry) {
}
}

foreach ($extension->metadataEnrichers() as $entry) {
if ($entry instanceof MetadataEnricher) {
$enrichers[0][] = $entry;
} else {
$enrichers[$entry[1] ?? 0][] = $entry[0];

Check warning on line 149 in src/MetadataHydrator.php

View workflow job for this annotation

GitHub Actions / Mutation tests on diff (locked, 8.4, ubuntu-latest)

Escaped Mutant for Mutator "IncrementInteger": @@ @@ if ($entry instanceof MetadataEnricher) { $enrichers[0][] = $entry; } else { - $enrichers[$entry[1] ?? 0][] = $entry[0]; + $enrichers[$entry[1] ?? 1][] = $entry[0]; } } foreach ($extension->guesser() as $entry) {

Check warning on line 149 in src/MetadataHydrator.php

View workflow job for this annotation

GitHub Actions / Mutation tests on diff (locked, 8.4, ubuntu-latest)

Escaped Mutant for Mutator "DecrementInteger": @@ @@ if ($entry instanceof MetadataEnricher) { $enrichers[0][] = $entry; } else { - $enrichers[$entry[1] ?? 0][] = $entry[0]; + $enrichers[$entry[1] ?? -1][] = $entry[0]; } } foreach ($extension->guesser() as $entry) {
}
}

if ($guessers !== []) {
$guesser = new ChainGuesser([
...$guessers,
$guesser,
]);
foreach ($extension->guesser() as $entry) {
if ($entry instanceof Guesser) {
$guessers[0][] = $entry;

Check warning on line 155 in src/MetadataHydrator.php

View workflow job for this annotation

GitHub Actions / Mutation tests on diff (locked, 8.4, ubuntu-latest)

Escaped Mutant for Mutator "IncrementInteger": @@ @@ } foreach ($extension->guesser() as $entry) { if ($entry instanceof Guesser) { - $guessers[0][] = $entry; + $guessers[1][] = $entry; } else { $guessers[$entry[1] ?? 0][] = $entry[0]; }
} else {
$guessers[$entry[1] ?? 0][] = $entry[0];
}
}
}

krsort($middlewares);

Check warning on line 162 in src/MetadataHydrator.php

View workflow job for this annotation

GitHub Actions / Mutation tests on diff (locked, 8.4, ubuntu-latest)

Escaped Mutant for Mutator "FunctionCallRemoval": @@ @@ } } } - krsort($middlewares); + krsort($enrichers); krsort($guessers); return new self(new AttributeMetadataFactory(guesser: new ChainGuesser([...array_merge(...$guessers)])), [...array_merge(...$middlewares)], [...array_merge(...$enrichers)], $defaultLazy); } }
krsort($enrichers);

Check warning on line 163 in src/MetadataHydrator.php

View workflow job for this annotation

GitHub Actions / Mutation tests on diff (locked, 8.4, ubuntu-latest)

Escaped Mutant for Mutator "FunctionCallRemoval": @@ @@ } } krsort($middlewares); - krsort($enrichers); + krsort($guessers); return new self(new AttributeMetadataFactory(guesser: new ChainGuesser([...array_merge(...$guessers)])), [...array_merge(...$middlewares)], [...array_merge(...$enrichers)], $defaultLazy); } }
krsort($guessers);

Check warning on line 164 in src/MetadataHydrator.php

View workflow job for this annotation

GitHub Actions / Mutation tests on diff (locked, 8.4, ubuntu-latest)

Escaped Mutant for Mutator "FunctionCallRemoval": @@ @@ } krsort($middlewares); krsort($enrichers); - krsort($guessers); + return new self(new AttributeMetadataFactory(guesser: new ChainGuesser([...array_merge(...$guessers)])), [...array_merge(...$middlewares)], [...array_merge(...$enrichers)], $defaultLazy); } }

return new self(
new AttributeMetadataFactory(
guesser: $guesser,
guesser: new ChainGuesser([...array_merge(...$guessers)]),
),
[...$additionalMiddleware, new TransformMiddleware()],
[...array_merge(...$middlewares)],
[...array_merge(...$enrichers)],
$defaultLazy,
);
}
Expand Down
17 changes: 6 additions & 11 deletions tests/Benchmark/HydratorWithCryptographyBench.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@

namespace Patchlevel\Hydrator\Tests\Benchmark;

use Patchlevel\Hydrator\Cryptography\CryptographyMetadataFactory;
use Patchlevel\Hydrator\Cryptography\CryptographyMiddleware;
use Patchlevel\Hydrator\Cryptography\CryptographyExtension;
use Patchlevel\Hydrator\Cryptography\SensitiveDataPayloadCryptographer;
use Patchlevel\Hydrator\Cryptography\Store\InMemoryCipherKeyStore;
use Patchlevel\Hydrator\Hydrator;
use Patchlevel\Hydrator\Metadata\AttributeMetadataFactory;
use Patchlevel\Hydrator\MetadataHydrator;
use Patchlevel\Hydrator\Middleware\TransformMiddleware;
use Patchlevel\Hydrator\Tests\Benchmark\Fixture\ProfileCreated;
use Patchlevel\Hydrator\Tests\Benchmark\Fixture\ProfileId;
use Patchlevel\Hydrator\Tests\Benchmark\Fixture\Skill;
Expand All @@ -28,13 +25,11 @@ public function __construct()
{
$this->store = new InMemoryCipherKeyStore();

$this->hydrator = new MetadataHydrator(
new CryptographyMetadataFactory(new AttributeMetadataFactory()),
[
new CryptographyMiddleware(SensitiveDataPayloadCryptographer::createWithDefaultSettings($this->store)),
new TransformMiddleware(),
],
);
$this->hydrator = MetadataHydrator::create([
new CryptographyExtension(
SensitiveDataPayloadCryptographer::createWithDefaultSettings($this->store),
),
]);
}

public function setUp(): void
Expand Down
Loading
Loading