Skip to content

Commit

Permalink
Merge pull request #54 from WendellAdriel/fix-dto-transform
Browse files Browse the repository at this point in the history
Fix issue when transforming DTOs with nested Collections or Models
  • Loading branch information
WendellAdriel committed Oct 6, 2023
2 parents 9d05280 + 573141b commit 3cfbda2
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 3cfbda2

Please sign in to comment.