Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: property-morphable abstract data #921

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

bentleyo
Copy link
Contributor

@bentleyo bentleyo commented Jan 2, 2025

This PR adds a new feature where abstract data classes can dynamically choose which concrete variant of the class to use based on the payload. This feature works with validation, collections and nested payloads.

While the existing abstract class functionality is good, I find it to be limiting for our use case as it's only available when casting. I've maintained this existing functionality without any breaking changes.

An example use case is having Vehicle as an abstract data class with type (to determine which concrete to use) and a common max_passengers property used by every class that extends Vehicle. Each concrete can then add its own additional properties e.g.:

"vehicles": [
    { "type": "horse", "max_passengers": 1, "name": "Bill" },
    { "type": "car", "max_passengers": 5, "transmission": "manual" },
]

This is a feature that's been super useful for us (we have it working on v3 using a trait, but that's no longer possible) and it's a feature that I think would be really great to have built-in.

To use the feature you implement the new PropertyMorphableData contract and associated static morph method. This method is supplied with an array of properties and should return a class string.

E.g.

abstract class VehicleData extends Data implements PropertyMorphableData
{
    public function __construct(
        #[In('car', 'horse')]
        public string $type,
    ) {
    }

    public static function morph(array $properties): ?string
    {
        return match ($properties['type'] ?? null) {
            'car' => CarData::class,
            'horse' => HorseData::class,
            default => null,
        };
    }
}

@bentleyo bentleyo force-pushed the feature-property-morphable branch from ff6dc15 to 1f630b1 Compare January 2, 2025 08:03
@bentleyo
Copy link
Contributor Author

bentleyo commented Jan 3, 2025

The reason the return value for morph is nullable is because we need to know which type of class we're building when generating validation rules. However, at this point not all required properties may be available or supplied.

@Sagmedjo
Copy link

Really looking forward to this feature. Is it going to be in an upcoming release?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants