v1.0.0
What's New
🔄 Pipes
Transform incoming values before hydration using the new #[Pipe] attribute. Apply pipes per-property or globally via class-level #[Pipe]:
#[Pipe(TrimStringsPipe::class, NullifyEmptyStringsPipe::class)]
class ContactData extends BaseData
{
public function __construct(
#[Pipe(UpperCasePipe::class)]
public readonly string $name,
public readonly ?string $comment,
) {}
}
- Built-in pipes:
TrimStringsPipe,NullifyEmptyStringsPipe,TrimValuePipe,NullifyEmptyStringValuePipe. - Implement
ValuePipeto create custom pipes.
🔀 Key Transformation
Automatically remap camelCase input keys to snake_case, kebab-case or STUDLY_CASE using #[TransformKeys]:
#[TransformKeys(TransformKeys::SNAKE_CASE)]
class UserData extends BaseData { ... }
💾 File-based Metadata Cache
Cache resolved class metadata to disk for near-zero overhead in production:
MetadataRegistry::setStoragePath(storage_path('framework/sdo'));
- Supports atomic writes and
__set_state-based serialization. - Skips non-exportable classes gracefully.
🛠️ New BaseData & Collection Methods
| Method | Description |
|---|---|
tryFrom(mixed $data) |
Returns null instead of throwing on failure |
with(...$overrides) |
Returns a new instance with overridden fields |
equals(self $other) |
Compares two instances by value |
diff(self $other) |
Returns array of changed fields |
only(string ...$keys) |
Returns a subset of fields |
except(string ...$keys) |
Returns all fields except specified |
fromValidated(mixed $data) |
Hydrates after Laravel validation |
validate(mixed $data) |
Runs validation without hydration |
TypedDataCollection
$collection->last(); // returns last item or null
🧪 100% Test Coverage
All classes, methods, and lines are covered. Enforced in CI via pcov.