yorcreative/laravel-argonaut-dto
Lightweight, composable Laravel DTO package to transform arrays/objects/collections into typed, validated data objects. Supports deep nested casting, type-safe conversion, Laravel Validator rules, explicit attribute priority, clean toArray/toJson serialization, and immutable readonly DTOs.
composer require yorcreative/laravel-argonaut-dtoArgonautDTO or ArgonautImmutableDTO, defining typed public properties, $casts array, rules() method for validation, and optionally $nestedAssemblers for deep transformationArgonautAssembler and implementing a to<DTOName>() method (e.g., toUserDTO()) to map raw input → DTO arrayUserDTOAssembler::assemble($rawData, UserDTO::class) or use instance methods like assembleInstance()First practical use case: Transform a Laravel request or API response (array/object) into a strongly-typed DTO with validation before storing in database or returning in an API response. For immutable DTOs (PHP ≥8.1), extend
ArgonautImmutableDTO.
Static vs Instance Assemblers:
public static function to...)public function to...)assemble(), fromArray(), fromCollection() methods when using non-static to...() methods.Immutable DTOs (ArgonautImmutableDTO):
ArgonautImmutableDTO for DTOs with readonly public properties (PHP ≥8.1)cloneWith() for changesreadonly support is powered by reflection — no #[AllowDynamicProperties] neededsetAttributes() is deprecated; prefer cloneWith($attributes) for immutablesNested DTOs & Casting:
$casts = ['nestedField' => NestedDTO::class] for single nested objectsCollection::class . ':' . ItemDTO::class for collections of DTOs[$ItemDTO::class] for array-based DTO collectionsBackedEnum casting now supported natively — use MyEnum::class, array<MyEnum::class>, or Collection::class . ':' . MyEnum::classDeep Transformation with Nested Assemblers:
$nestedAssemblers = ['user' => UserDTOAssembler::class] in your DTOUserDTOAssembler::toUserDTO() before castingBatch Processing:
fromArray($inputs, DTO::class) or fromCollection($collection, DTO::class) (pass assembler instance if needed)MyModel::all()->transform(fn($m) => Assembler::assemble($m, DTO::class))Serialization Helpers (NEW):
only(['field1', 'field2']) and except(['field3']) for selective serializationmerge(['extraKey' => $value]) to augment serialized output$casts, readonly, and #[Ignore] attributesValidation & Errors:
rules()$dto->getValidator()->errors() if validation failsvalidator() or catch ValidationException in controllers🔥 Assembler method naming matters: Must be to<ClassName> or from<ClassName> (case-sensitive), where <ClassName> is the basename (e.g., UserDTO → toUserDTO, not toUser)
🐞 DI doesn’t work in static methods: If your toUserDTO() method needs services, make it non-static and ensure you pass an assembler instance to assemble(), fromArray, etc.
🧩 Cast order of operations (unchanged, now reinforced by trait refactor):
$nestedAssemblers exists for the key, assembler runs$casts is applied (including BackedEnum)__construct assigns and casts (including readonly enforcement)⚠️ Immutable DTOs require PHP ≥8.1:
readonly fields throw type errors on reassignment — always use ?DTO for nullable fieldscloneWith() creates a shallow copy with new values — useful in services (e.g., state transitions)📦 Serialization improvements:
toArray()/toJson() now respect only(), except(), merge() helpers#[Ignore] still works for excluding fields, but prefer only()/except() for clean explicitnessBackedEnum values serialize as their scalar backing value ('active' for StatusEnum::ACTIVE)🧪 Testing tip: Mock or resolve() assemblers — e.g., make(UserAssembler::class) in tests. For immutables, verify cloneWith() side effects.
🔄 Deep cast fallbacks: If a nested DTO field is null but not nullable (e.g., UserDTO instead of ?UserDTO), PHP throws TypeError. Always type-hint nullable fields with ?.
How can I help you explore Laravel packages today?