Skip to content

Commit

Permalink
Fix issue when transforming DTOs with nested Collections or Models in…
Browse files Browse the repository at this point in the history
…to array or json
  • Loading branch information
WendellAdriel committed Oct 6, 2023
1 parent 9d05280 commit 573141b
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 30 deletions.
25 changes: 23 additions & 2 deletions src/SimpleDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -400,14 +400,35 @@ private function formatArrayableValue(mixed $value): array
{
return match (true) {
is_array($value) => $value,
$value instanceof Collection => $value->toArray(),
$value instanceof Model => $value->toArray(),
$value instanceof Collection => $this->transformCollectionToArray($value),
$value instanceof Model => $this->transformModelToArray($value),
$value instanceof SimpleDTO => $this->transformDTOToArray($value),
is_object($value) => (array) $value,
default => [],
};
}

private function transformCollectionToArray(Collection $collection): array
{
return $collection->map(function ($item) {
return $this->isArrayable($item)
? $this->formatArrayableValue($item)
: $item;
})->toArray();
}

private function transformModelToArray(Model $model): array
{
$result = [];
foreach ($model->getAttributes() as $key => $value) {
$result[$key] = $this->isArrayable($value)
? $this->formatArrayableValue($value)
: $value;
}

return $result;
}

private function transformDTOToArray(SimpleDTO $dto): array
{
$result = [];
Expand Down
37 changes: 37 additions & 0 deletions tests/Datasets/UserNestedCollectionDTO.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace WendellAdriel\ValidatedDTO\Tests\Datasets;

use Illuminate\Support\Collection;
use WendellAdriel\ValidatedDTO\Casting\CollectionCast;
use WendellAdriel\ValidatedDTO\Casting\DTOCast;
use WendellAdriel\ValidatedDTO\ValidatedDTO;

class UserNestedCollectionDTO extends ValidatedDTO
{
public Collection $names;

public string $email;

protected function rules(): array
{
return [
'names' => ['required', 'array'],
'email' => ['required', 'email'],
];
}

protected function defaults(): array
{
return [];
}

protected function casts(): array
{
return [
'names' => new CollectionCast(new DTOCast(NameDTO::class)),
];
}
}
108 changes: 80 additions & 28 deletions tests/Unit/ValidatedDTOTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use WendellAdriel\ValidatedDTO\Tests\Datasets\NullableDTO;
use WendellAdriel\ValidatedDTO\Tests\Datasets\User;
use WendellAdriel\ValidatedDTO\Tests\Datasets\UserDTO;
use WendellAdriel\ValidatedDTO\Tests\Datasets\UserNestedCollectionDTO;
use WendellAdriel\ValidatedDTO\Tests\Datasets\UserNestedDTO;
use WendellAdriel\ValidatedDTO\Tests\Datasets\ValidatedDTOInstance;
use WendellAdriel\ValidatedDTO\ValidatedDTO;
Expand Down Expand Up @@ -200,78 +201,129 @@ public function __invoke()
});

it('validates that the ValidatedDTO can be converted into an array', function () {
$validatedDTO = new ValidatedDTOInstance(['name' => $this->subject_name]);
$dataStructure = ['name' => $this->subject_name];
$validatedDTO = new ValidatedDTOInstance($dataStructure);

expect($validatedDTO)->toArray()
->toBe(['name' => $this->subject_name]);
->toBe($dataStructure);
});

it('validates that the ValidatedDTO can be converted into a JSON string', function () {
$validatedDTO = new ValidatedDTOInstance(['name' => $this->subject_name]);
$dataStructure = ['name' => $this->subject_name];
$validatedDTO = new ValidatedDTOInstance($dataStructure);

expect($validatedDTO)->toJson()
->toBe('{"name":"' . $this->subject_name . '"}');
->toBe(json_encode($dataStructure));
});

it('validates that the ValidatedDTO can be converted into a pretty JSON string', function () {
$validatedDTO = new ValidatedDTOInstance(['name' => $this->subject_name]);
$dataStructure = ['name' => $this->subject_name];
$validatedDTO = new ValidatedDTOInstance($dataStructure);

expect($validatedDTO)->toPrettyJson()
->toBe(json_encode(['name' => $this->subject_name], JSON_PRETTY_PRINT));
->toBe(json_encode($dataStructure, JSON_PRETTY_PRINT));
});

it('validates that the ValidatedDTO with nested data can be converted into an array', function () {
$validatedDTO = new UserNestedDTO([
$dataStructure = [
'name' => [
'first_name' => $this->subject_name,
'last_name' => 'Doe',
],
'email' => $this->subject_email,
]);
];
$validatedDTO = new UserNestedDTO($dataStructure);

expect($validatedDTO)->toArray()
->toBe([
'name' => [
'first_name' => $this->subject_name,
'last_name' => 'Doe',
],
'email' => $this->subject_email,
]);
->toBe($dataStructure);
});

it('validates that the ValidatedDTO with nested data can be converted into a JSON string', function () {
$validatedDTO = new UserNestedDTO([
$dataStructure = [
'name' => [
'first_name' => $this->subject_name,
'last_name' => 'Doe',
],
'email' => $this->subject_email,
]);
];
$validatedDTO = new UserNestedDTO($dataStructure);

expect($validatedDTO)->toJson()
->toBe('{"name":{"first_name":"' . $this->subject_name . '","last_name":"Doe"},"email":"' . $this->subject_email . '"}');
->toBe(json_encode($dataStructure));
});

it('validates that the ValidatedDTO with nested data can be converted into a pretty JSON string', function () {
$validatedDTO = new UserNestedDTO([
$dataStructure = [
'name' => [
'first_name' => $this->subject_name,
'last_name' => 'Doe',
],
'email' => $this->subject_email,
]);
];
$validatedDTO = new UserNestedDTO($dataStructure);

expect($validatedDTO)->toPrettyJson()
->toBe(json_encode(
->toBe(json_encode($dataStructure, JSON_PRETTY_PRINT));
});

it('validates that the ValidatedDTO with nested collection data can be converted into an array', function () {
$dataStructure = [
'names' => [
[
'name' => [
'first_name' => $this->subject_name,
'last_name' => 'Doe',
],
'email' => $this->subject_email,
'first_name' => $this->subject_name,
'last_name' => 'Doe',
],
[
'first_name' => 'Jane',
'last_name' => 'Doe',
],
JSON_PRETTY_PRINT
));
],
'email' => $this->subject_email,
];
$validatedDTO = new UserNestedCollectionDTO($dataStructure);

expect($validatedDTO)->toArray()
->toBe($dataStructure);
});

it('validates that the ValidatedDTO with nested collection data can be converted into a JSON string', function () {
$dataStructure = [
'names' => [
[
'first_name' => $this->subject_name,
'last_name' => 'Doe',
],
[
'first_name' => 'Jane',
'last_name' => 'Doe',
],
],
'email' => $this->subject_email,
];
$validatedDTO = new UserNestedCollectionDTO($dataStructure);

expect($validatedDTO)->toJson()
->toBe(json_encode($dataStructure));
});

it('validates that the ValidatedDTO with nested collection data can be converted into a pretty JSON string', function () {
$dataStructure = [
'names' => [
[
'first_name' => $this->subject_name,
'last_name' => 'Doe',
],
[
'first_name' => 'Jane',
'last_name' => 'Doe',
],
],
'email' => $this->subject_email,
];
$validatedDTO = new UserNestedCollectionDTO($dataStructure);

expect($validatedDTO)->toPrettyJson()
->toBe(json_encode($dataStructure, JSON_PRETTY_PRINT));
});

it('validates that the ValidatedDTO can be converted into an Eloquent Model', function () {
Expand Down

0 comments on commit 573141b

Please sign in to comment.