Skip to content

Commit

Permalink
Merge pull request #59 from WendellAdriel/to-array-fix
Browse files Browse the repository at this point in the history
Fix how to handle enums and carbon objects when transforming DTO
  • Loading branch information
WendellAdriel committed Oct 16, 2023
2 parents 93e7086 + 6126279 commit 9e3da20
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 4 deletions.
24 changes: 20 additions & 4 deletions src/SimpleDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,23 @@

namespace WendellAdriel\ValidatedDTO;

use BackedEnum;
use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Validation\ValidationException;
use ReflectionClass;
use ReflectionProperty;
use UnitEnum;
use WendellAdriel\ValidatedDTO\Attributes\Cast;
use WendellAdriel\ValidatedDTO\Attributes\DefaultValue;
use WendellAdriel\ValidatedDTO\Attributes\Map;
use WendellAdriel\ValidatedDTO\Attributes\Rules;
use WendellAdriel\ValidatedDTO\Casting\ArrayCast;
use WendellAdriel\ValidatedDTO\Casting\Castable;
use WendellAdriel\ValidatedDTO\Casting\EnumCast;
use WendellAdriel\ValidatedDTO\Concerns\DataResolver;
use WendellAdriel\ValidatedDTO\Concerns\DataTransformer;
use WendellAdriel\ValidatedDTO\Contracts\BaseDTO;
Expand Down Expand Up @@ -261,9 +266,17 @@ protected function buildCasts(): array
{
$casts = [];
foreach ($this->dtoCasts as $property => $cast) {
$casts[$property] = is_null($cast->param)
? new $cast->type()
: new $cast->type(new $cast->param());
if (is_null($cast->param)) {
$casts[$property] = new $cast->type();

continue;
}

$param = $cast->type === EnumCast::class
? $cast->param
: new $cast->param();

$casts[$property] = new $cast->type($param);
}

return [
Expand Down Expand Up @@ -420,10 +433,13 @@ private function isArrayable(mixed $value): bool
is_object($value);
}

private function formatArrayableValue(mixed $value): array
private function formatArrayableValue(mixed $value): array|int|string
{
return match (true) {
is_array($value) => $value,
$value instanceof BackedEnum => $value->value,
$value instanceof UnitEnum => $value->name,
$value instanceof Carbon || $value instanceof CarbonImmutable => $value->toISOString(),
$value instanceof Collection => $this->transformCollectionToArray($value),
$value instanceof Model => $this->transformModelToArray($value),
$value instanceof SimpleDTO => $this->transformDTOToArray($value),
Expand Down
43 changes: 43 additions & 0 deletions tests/Datasets/ValidatedEnumDTO.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace WendellAdriel\ValidatedDTO\Tests\Datasets;

use Carbon\Carbon;
use Carbon\CarbonImmutable;
use WendellAdriel\ValidatedDTO\Attributes\Cast;
use WendellAdriel\ValidatedDTO\Attributes\DefaultValue;
use WendellAdriel\ValidatedDTO\Attributes\Rules;
use WendellAdriel\ValidatedDTO\Casting\CarbonCast;
use WendellAdriel\ValidatedDTO\Casting\CarbonImmutableCast;
use WendellAdriel\ValidatedDTO\Casting\EnumCast;
use WendellAdriel\ValidatedDTO\Concerns\EmptyCasts;
use WendellAdriel\ValidatedDTO\Concerns\EmptyDefaults;
use WendellAdriel\ValidatedDTO\Concerns\EmptyRules;
use WendellAdriel\ValidatedDTO\ValidatedDTO;

class ValidatedEnumDTO extends ValidatedDTO
{
use EmptyCasts, EmptyDefaults, EmptyRules;

#[Rules(['sometimes', 'string'])]
#[DefaultValue('ONE')]
#[Cast(EnumCast::class, DummyEnum::class)]
public DummyEnum $unitEnum;

#[Rules(['sometimes', 'string'])]
#[DefaultValue('bar')]
#[Cast(EnumCast::class, DummyBackedEnum::class)]
public DummyBackedEnum $backedEnum;

#[Rules(['sometimes', 'string'])]
#[DefaultValue('2023-10-16')]
#[Cast(CarbonCast::class)]
public Carbon $carbon;

#[Rules(['sometimes', 'string'])]
#[DefaultValue('2023-10-15')]
#[Cast(CarbonImmutableCast::class)]
public CarbonImmutable $carbonImmutable;
}
26 changes: 26 additions & 0 deletions tests/Unit/ValidatedDTOTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@

declare(strict_types=1);

use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Illuminate\Console\Application;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use WendellAdriel\ValidatedDTO\Exceptions\InvalidJsonException;
use WendellAdriel\ValidatedDTO\Tests\Datasets\DummyBackedEnum;
use WendellAdriel\ValidatedDTO\Tests\Datasets\DummyEnum;
use WendellAdriel\ValidatedDTO\Tests\Datasets\MapBeforeExportDTO;
use WendellAdriel\ValidatedDTO\Tests\Datasets\MapBeforeValidationDTO;
use WendellAdriel\ValidatedDTO\Tests\Datasets\MapDataDTO;
Expand All @@ -19,6 +23,7 @@
use WendellAdriel\ValidatedDTO\Tests\Datasets\UserNestedCollectionDTO;
use WendellAdriel\ValidatedDTO\Tests\Datasets\UserNestedDTO;
use WendellAdriel\ValidatedDTO\Tests\Datasets\ValidatedDTOInstance;
use WendellAdriel\ValidatedDTO\Tests\Datasets\ValidatedEnumDTO;
use WendellAdriel\ValidatedDTO\ValidatedDTO;

beforeEach(function () {
Expand Down Expand Up @@ -326,6 +331,27 @@ public function __invoke()
->toBe(json_encode($dataStructure, JSON_PRETTY_PRINT));
});

it('validates that the ValidatedDTO with Enums and Carbon properties can be correctly converted into an array', function () {
$dto = new ValidatedEnumDTO([]);

expect($dto)->toBeInstanceOf(ValidatedEnumDTO::class)
->and($dto->unitEnum)
->toBeInstanceOf(DummyEnum::class)
->and($dto->backedEnum)
->toBeInstanceOf(DummyBackedEnum::class)
->and($dto->carbon)
->toBeInstanceOf(Carbon::class)
->and($dto->carbonImmutable)
->toBeInstanceOf(CarbonImmutable::class)
->and($dto->toArray())
->toBe([
'unitEnum' => 'ONE',
'backedEnum' => 'bar',
'carbon' => '2023-10-16T00:00:00.000000Z',
'carbonImmutable' => '2023-10-15T00:00:00.000000Z',
]);
});

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

Expand Down

0 comments on commit 9e3da20

Please sign in to comment.