Skip to content

v1.16.0

Choose a tag to compare

@yuriizee yuriizee released this 27 Jul 10:30

What's New

Three additions this release, all backward-compatible.

Eloquent attribute casting — IsEloquentCastable and AsDataCollection

Assign a data object directly as an Eloquent attribute cast:

class Order extends Model
{
    protected function casts(): array
    {
        return ['address' => AddressData::class];
    }
}

Hydration/serialization go through the same from()/toArray() round trip as everywhere else. Both casters also hook into Eloquent's dirty-check via compare() (Laravel 12+) so a freshly re-serialized value with reordered JSON keys is correctly reported as clean.

No dependency on illuminate/database — same decoupling as HasLaravelIntegration/WireableData.

See Eloquent Attribute Casting.

#[WhenLoaded] — selective relation hydration

fromModel() now hydrates from the model's own attributes only; a relation is included solely when its property is marked #[WhenLoaded('relationName')] and that relation is actually loaded — no more accidentally serializing every eager-loaded relation whether the DTO wants it or not.

See #[WhenLoaded].

#[RejectUnknownKeys] — strict mode

#[RejectUnknownKeys]
class CreateOrderData extends BaseData
{
    // ...
}

CreateOrderData::from(['titel' => 'Widget']);
// throws — 'titel' isn't a recognized key

Catches typos and stale API fields instead of silently dropping them — the PHP equivalent of serde's deny_unknown_fields or zod's .strict().

Compiles directly into the generated hydrator, so classes that don't use it pay zero cost.

See #[RejectUnknownKeys].

Full Changelog: v1.15.0...v1.16.0