Skip to content

Commit

Permalink
Merge pull request #29 from nutgram/apply-mutators
Browse files Browse the repository at this point in the history
apply mutators to an attribute
  • Loading branch information
sergix44 authored Oct 5, 2023
2 parents 98e7a41 + e52a6d5 commit 7ef4ef2
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/Annotation/ConcreteResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
/**
* @Annotation
*
* @Target({"PROPERTY"})
* @Target({"CLASS"})
*/
#[Attribute(Attribute::TARGET_CLASS)]
abstract class ConcreteResolver
Expand Down
53 changes: 53 additions & 0 deletions src/Annotation/Mutate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace SergiX44\Hydrator\Annotation;

use Attribute;
use InvalidArgumentException;
use SergiX44\Hydrator\Mutator;

/**
* @Annotation
*
* @Target({"PROPERTY"})
*/
#[Attribute(Attribute::TARGET_PROPERTY)]
final class Mutate
{
/**
* The attribute value.
*
* @var class-string<Mutator>[]
*/
public array $mutators;

/**
* Constructor of the class.
*
* @param string ...$mutators
*/
public function __construct(string ...$mutators)
{
foreach ($mutators as $mutator) {
if (!is_subclass_of($mutator, Mutator::class)) {
throw new InvalidArgumentException(sprintf('Class %s must implements %s', $mutator, Mutator::class));
}
}

$this->mutators = $mutators;
}

/**
* @param $value
*
* @return mixed
*/
public function apply($value): mixed
{
foreach ($this->mutators as $mutator) {
$value = (new $mutator())->mutate($value);
}

return $value;
}
}
6 changes: 6 additions & 0 deletions src/Hydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use SergiX44\Hydrator\Annotation\Alias;
use SergiX44\Hydrator\Annotation\ArrayType;
use SergiX44\Hydrator\Annotation\ConcreteResolver;
use SergiX44\Hydrator\Annotation\Mutate;
use SergiX44\Hydrator\Annotation\SkipConstructor;
use SergiX44\Hydrator\Annotation\UnionResolver;
use SergiX44\Hydrator\Exception\InvalidObjectException;
Expand Down Expand Up @@ -138,6 +139,11 @@ public function hydrate(string|object $object, array|object $data): object
continue;
}

$mutator = $this->getAttributeInstance($property, Mutate::class);
if ($mutator !== null) {
$data[$key] = $mutator->apply($data[$key]);
}

$this->hydrateProperty($object, $class, $property, $propertyType, $data[$key]);
}

Expand Down
13 changes: 13 additions & 0 deletions src/Mutations/JsonDecodeArray.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace SergiX44\Hydrator\Mutations;

use SergiX44\Hydrator\Mutator;

class JsonDecodeArray implements Mutator
{
public function mutate(mixed $value): mixed
{
return json_decode($value, true, 512, JSON_THROW_ON_ERROR);
}
}
13 changes: 13 additions & 0 deletions src/Mutations/JsonDecodeObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace SergiX44\Hydrator\Mutations;

use SergiX44\Hydrator\Mutator;

class JsonDecodeObject implements Mutator
{
public function mutate(mixed $value): mixed
{
return json_decode($value, false, 512, JSON_THROW_ON_ERROR);
}
}
8 changes: 8 additions & 0 deletions src/Mutator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace SergiX44\Hydrator;

interface Mutator
{
public function mutate(mixed $value): mixed;
}
14 changes: 14 additions & 0 deletions tests/Fixtures/ObjectWithArrayToDeserialize.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace SergiX44\Hydrator\Tests\Fixtures;

use SergiX44\Hydrator\Annotation\Mutate;
use SergiX44\Hydrator\Mutations\JsonDecodeObject;

final class ObjectWithArrayToDeserialize
{
public string $name;

#[Mutate(JsonDecodeObject::class)]
public array $value;
}
12 changes: 12 additions & 0 deletions tests/HydratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -875,4 +875,16 @@ public function testSkipConstructorWithContainer(): void
$this->assertSame(Fixtures\StringableEnum::foo, $object->stringableEnum);
$this->assertSame(Fixtures\NumerableEnum::foo, $object->numerableEnums[0]);
}

public function testMutateProperty(): void
{
$object = (new Hydrator())->hydrate(Fixtures\ObjectWithArrayToDeserialize::class, [
'name' => 'foo',
'value' => json_encode(['foo' => 'bar'], JSON_THROW_ON_ERROR),
]);

$this->assertSame('foo', $object->name);
$this->assertIsArray($object->value);
$this->assertSame(['foo' => 'bar'], $object->value);
}
}

0 comments on commit 7ef4ef2

Please sign in to comment.