Skip to content

Commit

Permalink
Merge pull request #7 from sunrise-php/release/v1.4.0
Browse files Browse the repository at this point in the history
v1.4.0
  • Loading branch information
fenric authored Jul 30, 2021
2 parents b206924 + 2cf55d5 commit 5d02b0d
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 3 deletions.
48 changes: 48 additions & 0 deletions src/Hydrator/Hydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ private function hydrateProperty(
return;
}

if (Json::class === $type->getName()) {
$this->hydratePropertyWithJson($object, $class, $property, $type, $value);
return;
}

if ('array' === $type->getName() || is_subclass_of($type->getName(), ArrayAccess::class)) {
$this->hydratePropertyWithArray($object, $class, $property, $type, $value);
return;
Expand Down Expand Up @@ -280,6 +285,49 @@ private function hydratePropertyWithScalar(
}
}

/**
* Hydrates the given property with the given json value
*
* @param HydrableObjectInterface $object
* @param ReflectionClass $class
* @param ReflectionProperty $property
* @param ReflectionNamedType $type
* @param mixed $value
*
* @return void
*
* @throws Exception\InvalidValueException
* If the given value isn't valid.
*/
private function hydratePropertyWithJson(
HydrableObjectInterface $object,
ReflectionClass $class,
ReflectionProperty $property,
ReflectionNamedType $type,
$value
) : void {
if (!is_string($value)) {
throw new Exception\InvalidValueException(sprintf(
'The <%s.%s> property only accepts a string.',
$class->getShortName(),
$property->getName(),
));
}

json_decode(''); // reset previous error...
$value = (array) json_decode($value, true);
if (JSON_ERROR_NONE <> json_last_error()) {
throw new Exception\InvalidValueException(sprintf(
'The <%s.%s> property only accepts valid JSON data (%s).',
$class->getShortName(),
$property->getName(),
json_last_error_msg(),
));
}

$property->setValue($object, new Json($value));
}

/**
* Hydrates the given property with the given array value
*
Expand Down
79 changes: 79 additions & 0 deletions src/Hydrator/Json.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php declare(strict_types=1);

/**
* It's free open-source software released under the MIT License.
*
* @author Anatoly Fenric <anatoly@fenric.ru>
* @copyright Copyright (c) 2021, Anatoly Fenric
* @license https://github.com/sunrise-php/hydrator/blob/master/LICENSE
* @link https://github.com/sunrise-php/hydrator
*/

namespace Sunrise\Hydrator;

/**
* Import classes
*/
use ArrayAccess;
use JsonSerializable;

/**
* Import functions
*/
use function array_key_exists;

/**
* Json
*/
class Json implements ArrayAccess, JsonSerializable
{
protected array $data;

/**
* Constructor of the class
*/
public function __construct(array $data)
{
$this->data = $data;
}

/**
* {@inheritdoc}
*/
public function offsetExists($offset) : bool
{
return array_key_exists($offset, $this->data);
}

/**
* {@inheritdoc}
*/
public function offsetGet($offset)
{
return $this->data[$offset] ?? null;
}

/**
* {@inheritdoc}
*/
public function offsetSet($offset, $value) : void
{
$this->data[$offset] = $value;
}

/**
* {@inheritdoc}
*/
public function offsetUnset($offset) : void
{
unset($this->data[$offset]);
}

/**
* {@inheritdoc}
*/
public function jsonSerialize() : array
{
return $this->data;
}
}
13 changes: 13 additions & 0 deletions tests/Hydrator/Fixture/TestJsonTypeDto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Sunrise\Hydrator\Tests\Fixture;

use Sunrise\Hydrator\HydrableObjectInterface;
use Sunrise\Hydrator\Json;

final class TestJsonTypeDto implements HydrableObjectInterface
{
public Json $json;
}
79 changes: 76 additions & 3 deletions tests/Hydrator/HydratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,80 @@ public function testHydrate() : void
/**
* @return void
*/
public function testJson() : void
public function testJsonTypeArrayAccess() : void
{
$object = (new Hydrator)->hydrate(new Fixture\TestJsonTypeDto(), ['json' => '[]']);

$this->assertFalse(isset($object->json['foo']));
$this->assertNull($object->json['foo']);

$object->json['foo'] = 1;
$this->assertTrue(isset($object->json['foo']));
$this->assertSame(1, $object->json['foo']);

unset($object->json['foo']);
$this->assertFalse(isset($object->json['foo']));
$this->assertNull($object->json['foo']);
}

/**
* @return void
*/
public function testJsonTypeJsonSerialize() : void
{
$object = (new Hydrator)->hydrate(new Fixture\TestJsonTypeDto(), ['json' => '[]']);

$object->json['foo'] = 1;
$object->json['bar'] = 2;

$this->assertSame([
'foo' => 1,
'bar' => 2,
], $object->json->jsonSerialize());
}

/**
* @return void
*/
public function testJsonTypeDeserializeJson() : void
{
$json = '{"foo":1,"bar":2,"baz":{"qux":3}}';

$object = (new Hydrator)->hydrate(new Fixture\TestJsonTypeDto(), ['json' => $json]);

$this->assertSame(1, $object->json['foo']);
$this->assertSame(2, $object->json['bar']);
$this->assertSame(3, $object->json['baz']['qux']);
}

/**
* @return void
*/
public function testJsonTypeInvalidJsonSyntax() : void
{
$this->expectException(Exception\InvalidValueException::class);
$this->expectExceptionMessage(
'The <TestJsonTypeDto.json> property only accepts valid JSON data (Syntax error).'
);

(new Hydrator)->hydrate(new Fixture\TestJsonTypeDto(), ['json' => '{']);
}

/**
* @return void
*/
public function testJsonTypeInvalidJsonType() : void
{
$this->expectException(Exception\InvalidValueException::class);
$this->expectExceptionMessage('The <TestJsonTypeDto.json> property only accepts a string.');

(new Hydrator)->hydrate(new Fixture\TestJsonTypeDto(), ['json' => []]);
}

/**
* @return void
*/
public function testJsonableObjectDeserializeJson() : void
{
$json = '{"foo":"foo:value","bar":"bar:value"}';

Expand All @@ -99,7 +172,7 @@ public function testJson() : void
/**
* @return void
*/
public function testInvalidSyntaxJson() : void
public function testJsonableObjectInvalidJsonSyntax() : void
{
$this->expectException(Exception\InvalidValueException::class);
$this->expectExceptionMessage('The <TestJsonDto.json> property only accepts valid JSON data (Syntax error).');
Expand All @@ -110,7 +183,7 @@ public function testInvalidSyntaxJson() : void
/**
* @return void
*/
public function testInvalidJsonType() : void
public function testJsonableObjectInvalidJsonType() : void
{
$this->expectException(Exception\InvalidValueException::class);
$this->expectExceptionMessage('The <TestJsonDto.json> property only accepts a string.');
Expand Down

0 comments on commit 5d02b0d

Please sign in to comment.