Skip to content

Commit

Permalink
Merge pull request #581 from bastien-phi/allow_attributes_from_parent…
Browse files Browse the repository at this point in the history
…_classes

Fetch attributes from parent classes to allow reusability
  • Loading branch information
rubenvanassche authored Oct 12, 2023
2 parents 8a43055 + e27501c commit 1d17ac5
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 3 deletions.
20 changes: 17 additions & 3 deletions src/Support/DataClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ public function __construct(

public static function create(ReflectionClass $class): self
{
$attributes = collect($class->getAttributes())
->filter(fn (ReflectionAttribute $reflectionAttribute) => class_exists($reflectionAttribute->getName()))
->map(fn (ReflectionAttribute $reflectionAttribute) => $reflectionAttribute->newInstance());
$attributes = static::resolveAttributes($class);

$methods = collect($class->getMethods());

Expand Down Expand Up @@ -81,6 +79,22 @@ public static function create(ReflectionClass $class): self
);
}

protected static function resolveAttributes(
ReflectionClass $class
): Collection {
$attributes = collect($class->getAttributes())
->filter(fn (ReflectionAttribute $reflectionAttribute) => class_exists($reflectionAttribute->getName()))
->map(fn (ReflectionAttribute $reflectionAttribute) => $reflectionAttribute->newInstance());

$parent = $class->getParentClass();

if ($parent !== false) {
$attributes = $attributes->merge(static::resolveAttributes($parent));
}

return $attributes;
}

protected static function resolveMethods(
ReflectionClass $reflectionClass,
): Collection {
Expand Down
31 changes: 31 additions & 0 deletions tests/Support/DataClassTest.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
<?php

use Spatie\LaravelData\Attributes\MapName;
use Spatie\LaravelData\Attributes\WithCast;
use Spatie\LaravelData\Attributes\WithTransformer;
use Spatie\LaravelData\Casts\DateTimeInterfaceCast;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\Mappers\SnakeCaseMapper;
use Spatie\LaravelData\Support\DataClass;
use Spatie\LaravelData\Support\DataMethod;
use Spatie\LaravelData\Tests\Fakes\DataWithMapper;
use Spatie\LaravelData\Tests\Fakes\Models\DummyModel;
use Spatie\LaravelData\Tests\Fakes\SimpleData;
use Spatie\LaravelData\Transformers\DateTimeInterfaceTransformer;

it('keeps track of a global map from attribute', function () {
$dataClass = DataClass::create(new ReflectionClass(DataWithMapper::class));
Expand Down Expand Up @@ -85,6 +91,31 @@ public function __construct(
->mappedDataObjects->toBeEmpty();
});

it('resolves parent attributes', function () {
#[MapName(SnakeCaseMapper::class)]
#[WithTransformer(DateTimeInterfaceTransformer::class, 'd-m-Y')]
#[WithCast(DateTimeInterfaceCast::class, format: 'Y-m-d')]
class TestRecursiveAttributesParentData extends Data
{
}

class TestRecursiveAttributesChildData extends TestRecursiveAttributesParentData
{
public function __construct(
public DateTimeInterface $dateTime
) {
}
}

$dataClass = DataClass::create(new ReflectionClass(TestRecursiveAttributesChildData::class));

expect($dataClass->attributes)
->toHaveCount(3)
->contains(fn ($attribute) => $attribute instanceof MapName)->toBeTrue()
->contains(fn ($attribute) => $attribute instanceof WithTransformer)->toBeTrue()
->contains(fn ($attribute) => $attribute instanceof WithCast)->toBeTrue();
});

#[\JetBrains\PhpStorm\Immutable]
class PhpStormClassAttributeData extends Data
{
Expand Down

0 comments on commit 1d17ac5

Please sign in to comment.