Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenvanassche committed Jul 26, 2021
1 parent a1a9d4f commit 639be15
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 52 deletions.
13 changes: 4 additions & 9 deletions src/Actions/ResolveDataObjectFromArrayAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ public function execute(string $class, array $values): Data
{
/** @var \Spatie\LaravelData\Data $data */
$data = collect($this->dataConfig->getDataProperties($class))
->mapWithKeys(fn (DataProperty $property) => [
->mapWithKeys(fn(DataProperty $property) => [
$property->name() => $this->resolveValue($property, $values[$property->name()] ?? null),
])
->pipe(fn (Collection $properties) => new $class(...$properties));
->pipe(fn(Collection $properties) => new $class(...$properties));

return $data;
}
Expand Down Expand Up @@ -51,7 +51,7 @@ private function resolveValue(DataProperty $property, mixed $value): mixed

if ($property->isDataCollection()) {
$items = array_map(
fn (array $item) => $this->execute($property->getDataClass(), $item),
fn(array $item) => $this->execute($property->getDataClass(), $item),
$value
);

Expand All @@ -72,12 +72,7 @@ private function resolveValueByAttributeCast(
DataProperty $property,
mixed $value
): mixed {
$attribute = $property->castAttribute();

/** @psalm-suppress all */
$cast = new ($attribute->castClass)(...$attribute->arguments);

return $cast->cast($property, $value);
return $property->castAttribute()->get()->cast($property, $value);
}

private function resolveGlobalCast(DataProperty $property): ?Cast
Expand Down
5 changes: 5 additions & 0 deletions src/Attributes/WithCast.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,9 @@ public function __construct(

$this->arguments = $arguments;
}

public function get(): Cast
{
return new ($this->castClass)(...$this->arguments);
}
}
30 changes: 30 additions & 0 deletions src/Attributes/WithTransformer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Spatie\LaravelData\Attributes;

use Attribute;
use Exception;
use Spatie\LaravelData\Transformers\Transformer;

#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY)]
class WithTransformer
{
public array $arguments;

public function __construct(
/** @var class-string<\Spatie\LaravelData\Transformers\Transformer> */
public string $transformerClass,
mixed ...$arguments
) {
if (! is_a($this->transformerClass, Transformer::class, true)) {
throw new Exception("Transformer given is not a transformer");
}

$this->arguments = $arguments;
}

public function get(): Transformer
{
return new ($this->transformerClass)(...$this->arguments);
}
}
8 changes: 5 additions & 3 deletions src/Casts/DateTimeInterfaceCast.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,25 @@
class DateTimeInterfaceCast implements Cast
{
public function __construct(
protected string $format
protected ?string $format = null
) {
}

public function cast(DataProperty $property, mixed $value): DateTimeInterface | Uncastable
{
$format = $this->format ?? config('data.date_format');

$type = $this->findType($property);

if ($type instanceof Uncastable) {
return $type;
}

/** @var \DateTime|\DateTimeImmutable $name */
$datetime = $type::createFromFormat($this->format, $value);
$datetime = $type::createFromFormat($format, $value);

if ($datetime === false) {
throw new Exception("Could not cast date: `{$value}` using format {$this->format}");
throw new Exception("Could not cast date: `{$value}` using format {$format}");
}

return $datetime;
Expand Down
20 changes: 0 additions & 20 deletions src/LaravelDataServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,6 @@ public function configurePackage(Package $package): void

public function packageRegistered()
{
$this->app->when(DateTimeCast::class)->needs('$format')->give(
config('data.date_format')
);

$this->app->when(DateTimeImmutableCast::class)->needs('$format')->give(
config('data.date_format')
);

$this->app->when(CarbonCast::class)->needs('$format')->give(
config('data.date_format')
);

$this->app->when(CarbonImmutableCast::class)->needs('$format')->give(
config('data.date_format')
);

$this->app->when(DateTransformer::class)->needs('$format')->give(
config('data.date_format')
);

$this->app->singleton(
DataConfig::class,
fn () => new DataConfig(config('data'))
Expand Down
9 changes: 1 addition & 8 deletions src/Support/DataConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,7 @@ public function getAutoRules(): array
return $this->autoRules;
}

public function transform(mixed $value): mixed
{
$transformer = $this->findTransformerForValue($value);

return $transformer?->transform($value) ?? $value;
}

protected function findTransformerForValue(mixed $value): ?Transformer
public function findTransformerForValue(mixed $value): ?Transformer
{
foreach ($this->transformers as $transformer) {
if ($transformer->canTransform($value)) {
Expand Down
22 changes: 22 additions & 0 deletions src/Support/DataProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use ReflectionUnionType;
use Spatie\LaravelData\Attributes\DataValidationAttribute;
use Spatie\LaravelData\Attributes\WithCast;
use Spatie\LaravelData\Attributes\WithTransformer;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
use Spatie\LaravelData\Exceptions\InvalidDataPropertyType;
Expand All @@ -35,6 +36,8 @@ class DataProperty

private ?WithCast $castAttribute;

private ?WithTransformer $transformerAttribute;

public static function create(ReflectionProperty $property): static
{
return new self($property);
Expand Down Expand Up @@ -113,6 +116,15 @@ public function castAttribute(): ?WithCast
return $this->castAttribute;
}

public function transformerAttribute(): ?WithTransformer
{
if (! isset($this->transformerAttribute)) {
$this->loadAttributes();
}

return $this->transformerAttribute;
}

/**
* @return class-string<\Spatie\LaravelData\Data>
*/
Expand Down Expand Up @@ -252,12 +264,22 @@ private function loadAttributes(): void

continue;
}

if ($initiatedAttribute instanceof WithTransformer) {
$this->transformerAttribute = $initiatedAttribute;

continue;
}
}

$this->validationAttributes = $validationAttributes;

if (! isset($this->castAttribute)) {
$this->castAttribute = null;
}

if (! isset($this->transformerAttribute)) {
$this->transformerAttribute = null;
}
}
}
23 changes: 13 additions & 10 deletions src/Transformers/DataTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

namespace Spatie\LaravelData\Transformers;

use ReflectionClass;
use ReflectionProperty;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
use Spatie\LaravelData\Lazy;
use Spatie\LaravelData\Support\DataConfig;
use Spatie\LaravelData\Support\DataProperty;

class DataTransformer
{
Expand Down Expand Up @@ -42,18 +41,17 @@ public function transform(Data $data): array

protected function resolvePayload(Data $data): array
{
$reflection = new ReflectionClass($data);

$inclusionTree = $data->getInclusionTree();
$exclusionTree = $data->getExclusionTree();

return array_reduce(
$reflection->getProperties(ReflectionProperty::IS_PUBLIC),
function (array $payload, ReflectionProperty $property) use ($data, $exclusionTree, $inclusionTree) {
$name = $property->getName();
$this->config->getDataProperties($data::class),
function (array $payload, DataProperty $property) use ($data, $exclusionTree, $inclusionTree) {
$name = $property->name();

if ($this->shouldIncludeProperty($name, $data->{$name}, $inclusionTree, $exclusionTree)) {
$payload[$name] = $this->resolvePropertyValue(
$property,
$data->{$name},
$inclusionTree[$name] ?? [],
$exclusionTree[$name] ?? []
Expand Down Expand Up @@ -96,6 +94,7 @@ protected function shouldIncludeProperty(
}

protected function resolvePropertyValue(
DataProperty $property,
mixed $value,
array $nestedInclusionTree,
array $nestedExclusionTree,
Expand All @@ -112,8 +111,12 @@ protected function resolvePropertyValue(
: $value;
}

return $this->withValueTransforming
? $this->config->transform($value)
: $value;
if (! $this->withValueTransforming) {
return $value;
}

$transformer = $property->transformerAttribute()?->get() ?? $this->config->findTransformerForValue($value);

return $transformer?->transform($value) ?? $value;
}
}
6 changes: 4 additions & 2 deletions src/Transformers/DateTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class DateTransformer implements Transformer
{
public function __construct(protected string $format)
public function __construct(protected ?string $format = null)
{
}

Expand All @@ -17,7 +17,9 @@ public function canTransform(mixed $value): bool

public function transform(mixed $value): string
{
$format = $this->format ?? config('data.date_format');

/** @var \DateTimeInterface $value */
return $value->format($this->format);
return $value->format($format);
}
}
19 changes: 19 additions & 0 deletions tests/DataTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Spatie\LaravelData\Tests;

use DateTime;
use Spatie\LaravelData\Attributes\WithTransformer;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
use Spatie\LaravelData\Lazy;
Expand All @@ -13,6 +14,7 @@
use Spatie\LaravelData\Tests\Fakes\LazyData;
use Spatie\LaravelData\Tests\Fakes\MultiLazyData;
use Spatie\LaravelData\Tests\Fakes\SimpleData;
use Spatie\LaravelData\Transformers\DateTransformer;

class DataTest extends TestCase
{
Expand Down Expand Up @@ -313,6 +315,23 @@ public function __construct(public DateTime $date)
$this->assertEquals(['date' => '1994-05-16T00:00:00+00:00'], $data->toArray());
}

/** @test */
public function it_can_manually_specify_a_transformer()
{
$date = new DateTime('16 may 1994');

$data = new class($date) extends Data {
public function __construct(
#[WithTransformer(DateTransformer::class, 'd-m-Y')]
public $date
)
{
}
};

$this->assertEquals(['date' => '16-05-1994'], $data->toArray());
}

/** @test */
public function it_can_dynamically_include_data_based_upon_the_request()
{
Expand Down
24 changes: 24 additions & 0 deletions tests/Support/DataPropertyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
use ReflectionProperty;
use Spatie\LaravelData\Attributes\Max;
use Spatie\LaravelData\Attributes\WithCast;
use Spatie\LaravelData\Attributes\WithTransformer;
use Spatie\LaravelData\Casts\DateTimeCast;
use Spatie\LaravelData\DataCollection;
use Spatie\LaravelData\Exceptions\InvalidDataPropertyType;
use Spatie\LaravelData\Lazy;
use Spatie\LaravelData\Support\DataProperty;
use Spatie\LaravelData\Tests\Fakes\SimpleData;
use Spatie\LaravelData\Tests\TestCase;
use Spatie\LaravelData\Transformers\DateTransformer;

class DataPropertyTest extends TestCase
{
Expand Down Expand Up @@ -281,6 +283,28 @@ public function it_can_get_the_cast_attribute_with_arguments()
$this->assertEquals(new WithCast(DateTimeCast::class, 'd-m-y'), $helper->castAttribute());
}

/** @test */
public function it_can_get_the_transformer_attribute()
{
$helper = $this->resolveHelper(new class {
#[WithTransformer(DateTransformer::class)]
public SimpleData $property;
});

$this->assertEquals(new WithTransformer(DateTransformer::class), $helper->transformerAttribute());
}

/** @test */
public function it_can_get_the_transformer_attribute_with_arguments()
{
$helper = $this->resolveHelper(new class {
#[WithTransformer(DateTransformer::class, 'd-m-y')]
public SimpleData $property;
});

$this->assertEquals(new WithTransformer(DateTransformer::class, 'd-m-y'), $helper->transformerAttribute());
}

/** @test */
public function it_can_get_the_data_class_for_a_data_object()
{
Expand Down

0 comments on commit 639be15

Please sign in to comment.