Skip to content
Closed
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
9 changes: 3 additions & 6 deletions src/Guesser/MappedGuesser.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
use Patchlevel\Hydrator\Normalizer\Normalizer;
use Symfony\Component\TypeInfo\Type\ObjectType;

use function array_key_exists;

final readonly class MappedGuesser implements Guesser
{
/** @param array<class-string, class-string<Normalizer>> $map */
Expand All @@ -24,12 +22,11 @@ public function __construct(private array $map)
public function guess(ObjectType $type): Normalizer|null
{
$className = $type->getClassName();
if (! array_key_exists($className, $this->map)) {

if (!isset($this->map[$className])) {
return null;
}

$normalizerType = $this->map[$className];

return new $normalizerType();
return new $this->map[$className]();
}
}
14 changes: 8 additions & 6 deletions src/MetadataHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use Patchlevel\Hydrator\Normalizer\HydratorAwareNormalizer;
use ReflectionClass;

use function array_key_exists;
use function is_array;

use const PHP_VERSION_ID;
Expand All @@ -24,12 +23,15 @@ final class MetadataHydrator implements Hydrator
/** @var array<class-string, ClassMetadata> */
private array $classMetadata = [];

private readonly Stack $stack;

/** @param list<Middleware> $middlewares */
public function __construct(
private readonly MetadataFactory $metadataFactory = new AttributeMetadataFactory(),
private readonly array $middlewares = [new TransformMiddleware()],
private readonly bool $defaultLazy = false,
) {
$this->stack = new Stack($this->middlewares);
}

/**
Expand Down Expand Up @@ -63,22 +65,22 @@ public function hydrate(string $class, mixed $data, array $context = []): object
}

if (PHP_VERSION_ID < 80400) {
$stack = new Stack($this->middlewares);
$stack = clone $this->stack;

return $stack->next()->hydrate($metadata, $data, $context, $stack);
}

$lazy = $metadata->lazy ?? $this->defaultLazy;

if (!$lazy) {
$stack = new Stack($this->middlewares);
$stack = clone $this->stack;

return $stack->next()->hydrate($metadata, $data, $context, $stack);
}

return (new ReflectionClass($class))->newLazyProxy(
function () use ($metadata, $data, $context): object {
$stack = new Stack($this->middlewares);
$stack = clone $this->stack;

return $stack->next()->hydrate($metadata, $data, $context, $stack);
},
Expand All @@ -94,7 +96,7 @@ public function extract(object $object, array $context = []): mixed
return $metadata->normalizer->normalize($object, $context);
}

$stack = new Stack($this->middlewares);
$stack = clone $this->stack;

return $stack->next()->extract($metadata, $object, $context, $stack);
}
Expand All @@ -108,7 +110,7 @@ public function extract(object $object, array $context = []): mixed
*/
public function metadata(string $class): ClassMetadata
{
if (array_key_exists($class, $this->classMetadata)) {
if (isset($this->classMetadata[$class])) {
return $this->classMetadata[$class];
}

Expand Down
10 changes: 1 addition & 9 deletions src/Middleware/Stack.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,6 @@ public function __construct(

public function next(): Middleware
{
$next = $this->middlewares[$this->index] ?? null;

if ($next === null) {
throw new NoMoreMiddleware();
}

$this->index++;

return $next;
return $this->middlewares[$this->index++] ?? throw new NoMoreMiddleware();
}
}
2 changes: 1 addition & 1 deletion src/Middleware/TransformMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public function extract(ClassMetadata $metadata, object $object, array $context,
{
$objectId = spl_object_id($object);

if (array_key_exists($objectId, $this->callStack)) {
if (isset($this->callStack[$objectId])) {
$references = array_values($this->callStack);
$references[] = $object::class;

Expand Down
25 changes: 15 additions & 10 deletions src/Normalizer/EnumNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Attribute;
use BackedEnum;
use RuntimeException;
use Symfony\Component\TypeInfo\Type;
use Symfony\Component\TypeInfo\Type\BackedEnumType;
use Symfony\Component\TypeInfo\Type\NullableType;
Expand All @@ -30,13 +31,7 @@
return null;
}

$enum = $this->getEnum();

if (!$value instanceof $enum) {
throw InvalidArgument::withWrongType($enum . '|null', $value);
}

return $value->value;

Check failure on line 34 in src/Normalizer/EnumNormalizer.php

View workflow job for this annotation

GitHub Actions / Static Analysis by PHPStan (locked, 8.5, ubuntu-latest)

Cannot access property $value on mixed.
}

/** @param array<string, mixed> $context */
Expand All @@ -50,18 +45,20 @@
throw InvalidArgument::withWrongType('string|int|null', $value);
}

$enum = $this->getEnum();
if ($this->enum === null) {
throw InvalidType::missingType();
}

try {
return $enum::from($value);
return $this->enum::from($value);
} catch (Throwable $error) {
throw InvalidArgument::fromThrowable($error);
}
}

public function handleType(Type|null $type): void
{
if ($this->enum !== null || $type === null) {
if ($type === null) {
return;
}

Expand All @@ -70,10 +67,18 @@
}

if (!$type instanceof BackedEnumType) {
throw new RuntimeException();
}

if ($this->enum === null) {
$this->enum = $type->getClassName();

return;
}

$this->enum = $type->getClassName();
if (!$type->isIdentifiedBy($this->enum)) {
throw new RuntimeException();
}
}

/** @return class-string<BackedEnum> */
Expand Down
16 changes: 8 additions & 8 deletions src/Normalizer/ObjectMapNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ public function setHydrator(Hydrator $hydrator): void
*/
public function normalize(mixed $value, array $context): mixed
{
if (!$this->hydrator) {
throw new MissingHydrator();
}

if ($value === null) {
return null;
}

if (!$this->hydrator) {
throw new MissingHydrator();
}

if (!is_object($value)) {
throw InvalidArgument::withWrongType(
sprintf('%s|null', implode('|', array_keys($this->classToTypeMap))),
Expand Down Expand Up @@ -84,14 +84,14 @@ public function normalize(mixed $value, array $context): mixed
*/
public function denormalize(mixed $value, array $context): mixed
{
if (!$this->hydrator) {
throw new MissingHydrator();
}

if ($value === null) {
return null;
}

if (!$this->hydrator) {
throw new MissingHydrator();
}

if (!is_array($value)) {
throw InvalidArgument::withWrongType('array<string, mixed>|null', $value);
}
Expand Down
35 changes: 20 additions & 15 deletions src/Normalizer/ObjectNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Attribute;
use Patchlevel\Hydrator\Hydrator;
use RuntimeException;
use Symfony\Component\TypeInfo\Type;
use Symfony\Component\TypeInfo\Type\GenericType;
use Symfony\Component\TypeInfo\Type\NullableType;
Expand All @@ -26,37 +27,33 @@
/** @param array<string, mixed> $context */
public function normalize(mixed $value, array $context): mixed
{
if (!$this->hydrator) {
throw new MissingHydrator();
}

if ($value === null) {
return null;
}

$className = $this->getClassName();

if (!$value instanceof $className) {
throw InvalidArgument::withWrongType($className . '|null', $value);
if (!$this->hydrator) {
throw new MissingHydrator();
}

return $this->hydrator->extract($value, $context);

Check failure on line 38 in src/Normalizer/ObjectNormalizer.php

View workflow job for this annotation

GitHub Actions / Static Analysis by PHPStan (locked, 8.5, ubuntu-latest)

Parameter #1 $object of method Patchlevel\Hydrator\Hydrator::extract() expects object, mixed given.
}

/** @param array<string, mixed> $context */
public function denormalize(mixed $value, array $context): object|null
{
if ($value === null) {
return null;
}

if (!$this->hydrator) {
throw new MissingHydrator();
}

if ($value === null) {
return null;
if ($this->className === null) {
throw InvalidType::missingType();
}

$className = $this->getClassName();

return $this->hydrator->hydrate($className, $value, $context);
return $this->hydrator->hydrate($this->className, $value, $context);
}

public function setHydrator(Hydrator $hydrator): void
Expand All @@ -66,7 +63,7 @@

public function handleType(Type|null $type): void
{
if ($type === null || $this->className !== null) {
if ($type === null) {
return;
}

Expand All @@ -83,10 +80,18 @@
}

if (!$type instanceof ObjectType) {
throw new RuntimeException();
}

if ($this->className === null) {
$this->className = $type->getClassName();

return;
}

$this->className = $type->getClassName();
if (!$type->isIdentifiedBy($this->className)) {
throw new RuntimeException();
}
}

/** @return class-string */
Expand Down
Loading