Skip to content

Commit

Permalink
fix value converter deep nested objects
Browse files Browse the repository at this point in the history
  • Loading branch information
jakubkulhan committed May 31, 2024
1 parent 22fdae7 commit 96662e7
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 21 deletions.
54 changes: 33 additions & 21 deletions data-access-kit/src/Converter/DefaultValueConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function __construct(
{
}

public function objectToDatabase(Table $table, Column $column, mixed $value): mixed
public function objectToDatabase(Table $table, Column $column, mixed $value, bool $encode = true): mixed
{
if ($value === null) {
return null;
Expand All @@ -49,12 +49,12 @@ public function objectToDatabase(Table $table, Column $column, mixed $value): mi
$valueType = $column->reflection->getType();
if ($valueType instanceof ReflectionNamedType) {
if (in_array($valueType->getName(), ["int", "float", "string", "bool"], true)) {
// passthrough
$returnValue = $value;
} else if ($valueType->getName() === "object") {
$value = json_encode($value);
$returnValue = $encode ? json_encode($value) : $value;
} else if ($valueType->getName() === "array") {
if ($column->itemType === null) {
$value = json_encode($value);
$returnValue = $encode ? json_encode($value) : $value;
} else {
$nestedTable = $this->registry->get($column->itemType);
$jsonArray = [];
Expand All @@ -65,24 +65,26 @@ public function objectToDatabase(Table $table, Column $column, mixed $value): mi
$nestedTable,
$nestedColumn,
$nestedColumn->reflection->getValue($item),
false,
);
}
}
$value = json_encode($jsonArray);
$returnValue = $encode ? json_encode($jsonArray) : $jsonArray;
}
} else if (in_array($valueType->getName(), [DateTime::class, DateTimeImmutable::class], true)) {
/** @var DateTime|DateTimeImmutable $value */
$value = (clone $value)->setTimezone($this->dateTimeZone)->format($this->dateTimeFormat);
$returnValue = (clone $value)->setTimezone($this->dateTimeZone)->format($this->dateTimeFormat);
} else if (null !== ($nestedTable = $this->registry->maybeGet($valueType->getName()))) {
$jsonObject = new stdClass();
foreach ($nestedTable->columns as $nestedColumn) {
$jsonObject->{$nestedColumn->name} = $this->objectToDatabase(
$nestedTable,
$nestedColumn,
$nestedColumn->reflection->getValue($value),
false,
);
}
$value = json_encode($jsonObject);
$returnValue = $encode ? json_encode($jsonObject) : $jsonObject;
} else {
throw new ConverterException(sprintf(
"Unsupported type [%s] of property [%s::\$%s].",
Expand All @@ -99,7 +101,7 @@ public function objectToDatabase(Table $table, Column $column, mixed $value): mi
));
}

return $value;
return $returnValue;

} finally {
if ($recursionGuardKey !== null) {
Expand All @@ -108,7 +110,7 @@ public function objectToDatabase(Table $table, Column $column, mixed $value): mi
}
}

public function databaseToObject(Table $table, Column $column, mixed $value): mixed
public function databaseToObject(Table $table, Column $column, mixed $value, bool $decode = true): mixed
{
if ($value === null) {
return null;
Expand All @@ -117,41 +119,51 @@ public function databaseToObject(Table $table, Column $column, mixed $value): mi
$valueType = $column->reflection->getType();
if ($valueType instanceof ReflectionNamedType) {
if (in_array($valueType->getName(), ["int", "float", "string", "bool"], true)) {
// passthrough
$returnValue = $value;
} else if ($valueType->getName() === "object") {
$value = json_decode($value);
$returnValue = $decode ? json_decode($value) : $value;
} else if ($valueType->getName() === "array") {
if ($column->itemType === null) {
$value = json_decode($value);
$returnValue = $decode ? json_decode($value) : $value;
} else {
$nestedTable = $this->registry->get($column->itemType);
$array = [];
foreach (json_decode($value) as $jsonObject) {
foreach ($decode ? json_decode($value) : $value as $jsonObject) {
$nestedObject = $nestedTable->reflection->newInstanceWithoutConstructor();
foreach ($nestedTable->columns as $nestedColumn) {
$nestedColumn->reflection->setValue(
$nestedObject,
$this->databaseToObject($nestedTable, $nestedColumn, $jsonObject->{$nestedColumn->name}),
$this->databaseToObject(
$nestedTable,
$nestedColumn,
$jsonObject->{$nestedColumn->name},
false,
),
);
}
$array[] = $nestedObject;
}
$value = $array;
$returnValue = $array;
}
} else if ($valueType->getName() === DateTime::class) {
$value = DateTime::createFromFormat($this->dateTimeFormat, $value, $this->dateTimeZone);
$returnValue = DateTime::createFromFormat($this->dateTimeFormat, $value, $this->dateTimeZone);
} else if ($valueType->getName() === DateTimeImmutable::class) {
$value = DateTimeImmutable::createFromFormat($this->dateTimeFormat, $value, $this->dateTimeZone);
$returnValue = DateTimeImmutable::createFromFormat($this->dateTimeFormat, $value, $this->dateTimeZone);
} else if (null !== ($nestedTable = $this->registry->maybeGet($valueType->getName()))) {
$jsonObject = json_decode($value);
$jsonObject = $decode ? json_decode($value) : $value;
$nestedObject = $nestedTable->reflection->newInstanceWithoutConstructor();
foreach ($nestedTable->columns as $nestedColumn) {
$nestedColumn->reflection->setValue(
$nestedObject,
$this->databaseToObject($nestedTable, $nestedColumn, $jsonObject->{$nestedColumn->name}),
$this->databaseToObject(
$nestedTable,
$nestedColumn,
$jsonObject->{$nestedColumn->name},
false,
),
);
}
$value = $nestedObject;
$returnValue = $nestedObject;
} else {
throw new ConverterException(sprintf(
"Unsupported type [%s] of property [%s::\$%s].",
Expand All @@ -168,6 +180,6 @@ public function databaseToObject(Table $table, Column $column, mixed $value): mi
));
}

return $value;
return $returnValue;
}
}
7 changes: 7 additions & 0 deletions data-access-kit/test/Converter/DefaultValueConverterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use DataAccessKit\Attribute\Column;
use DataAccessKit\Attribute\Table;
use DataAccessKit\Converter\Fixture\DeepNestedObject;
use DataAccessKit\Converter\Fixture\NestedObject;
use DataAccessKit\Registry;
use DateTime;
Expand Down Expand Up @@ -96,6 +97,9 @@ public static function data()
/** @var NestedObject[] */ #[Column] public array $nestedArrayDoc;
/** @var NestedObject[]|null */ #[Column] public ?array $nullableNestedArrayDocNull;
/** @var NestedObject[]|null */ #[Column] public ?array $nullableNestedArrayDocNotNull;
#[Column] public DeepNestedObject $deepNestedObject;
#[Column] public ?DeepNestedObject $nullableDeepNestedObjectNull;
#[Column] public ?DeepNestedObject $nullableDeepNestedObjectNotNull;
});

$data = [
Expand Down Expand Up @@ -132,6 +136,9 @@ public static function data()
"nestedArrayDoc" => [[new NestedObject("value1"), new NestedObject("value2")], '[{"key":"value1"},{"key":"value2"}]'],
"nullableNestedArrayDocNull" => [null, null],
"nullableNestedArrayDocNotNull" => [[new NestedObject("value1"), new NestedObject("value2")], '[{"key":"value1"},{"key":"value2"}]'],
"deepNestedObject" => [new DeepNestedObject(new DeepNestedObject()), '{"nested":{"nested":null}}'],
"nullableDeepNestedObjectNull" => [null, null],
"nullableDeepNestedObjectNotNull" => [new DeepNestedObject(new DeepNestedObject()), '{"nested":{"nested":null}}'],
];
foreach ($data as $columnName => [$objectValue, $databaseValue]) {
yield $columnName => [$table, $table->columns[$columnName], $objectValue, $databaseValue];
Expand Down
14 changes: 14 additions & 0 deletions data-access-kit/test/Converter/Fixture/DeepNestedObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Converter\Fixture;

use DataAccessKit\Attribute\Column;

class DeepNestedObject
{
public function __construct(
#[Column] public ?DeepNestedObject $nested = null,
)
{
}
}

0 comments on commit 96662e7

Please sign in to comment.