- How do I convert an Eloquent model’s `toArray()` output into a DataModel DTO in Laravel?
- Use `DataModel::from($model->toArray())` on your DTO class. The package recursively hydrates nested objects, so it works with relationships too. For example, `UserDTO::from(User::find(1)->toArray())` maps all attributes while respecting your `#[Describe]` rules like casting or validation.
- Can I use DataModel for API request validation instead of Laravel’s FormRequest?
- Yes, but consider a hybrid approach. DataModel handles type safety and casting via `#[Describe]`, while FormRequest can enforce Laravel-specific rules (e.g., `unique`). For example, validate with `#[Describe(['required', 'string'])]` in your DTO, then use `FormRequest::validate()` for additional business logic.
- Will DataModel work with Laravel 10+ and PHP 8.1+? Any breaking changes?
- The package supports Laravel 10+ and PHP 8.1+ (attributes) out of the box. No breaking changes are expected for minor Laravel updates, but always check the [changelog](https://github.com/zero-to-prod/data-model/blob/main/CHANGELOG.md) for major versions. PHP 8.5+ adds first-class callable support for hooks like `#[Describe(['assign' => fn($val) => ...])]`.
- How do I handle nested objects or arrays in DataModel? Does it support recursive hydration?
- Yes, DataModel automatically hydrates nested objects and arrays if they implement the `DataModel` trait. For example, `#[Describe(['address' => new AddressDTO()])]` will recursively map `address` from the input array. Arrays are hydrated as `DataModelCollection` objects by default, but you can customize this with `#[Describe(['items' => new ItemDTO()])]`.
- Is DataModel faster than manual DTO hydration or Laravel’s `Validator`?
- Performance depends on use case. Reflection-based hydration has overhead compared to manual `array_map`, but it’s often faster than writing and maintaining custom constructors. For high-throughput APIs, benchmark `DataModel::from()` against your current method. The package avoids Laravel’s `Validator` for hydration, which is lighter but requires separate validation logic if needed.
- How do I test DataModel classes with PHPUnit? Should I mock the reflection attributes?
- Test hydration directly with `DataModel::from($testData)` and assert properties. For edge cases (e.g., `assign` hooks), use real data since mocking reflection is complex. Example: `$dto = UserDTO::from(['name' => 'Test']); $this->assertEquals('Test', $dto->name)`. For validation, combine with Laravel’s `Validator` or use `try-catch` on `from()` with invalid data.
- Can I use DataModel with Laravel’s API Resources (e.g., `JsonResource`)?
- Yes, but avoid mixing hydration logic. Use DataModel to transform Eloquent models into DTOs *before* passing them to `JsonResource`. For example: `return new UserResource(UserDTO::from(User::find(1)))` ensures type safety and casting are applied once. Avoid hydrating directly in `toArray()` to prevent duplicate logic.
- What’s the difference between `#[Describe]` and Laravel’s `#[Cast]` or `#[Attribute]`?
- DataModel’s `#[Describe]` is a superset: it combines casting (`#[Cast]`), validation (like `#[Rule]`), defaults, and assignment logic in one attribute. For example, `#[Describe(['email', 'required', 'string', 'default' => 'user@example.com'])]` replaces separate `#[Cast]` and manual validation. Use both where needed, but prefer `#[Describe]` for DTOs to centralize rules.
- How do I handle database hydration with eager loading? Will DataModel bypass Laravel’s query caching?
- DataModel hydrates after Eloquent loads data, so it respects eager loading (`with()`) and query caching (`remember()`). However, recursive hydration (e.g., nested relationships) happens in PHP, not the database. For complex queries, hydrate only the root model with `DataModel::from($model->toArray())` and manually map relationships to avoid N+1 issues.
- Are there alternatives to DataModel for Laravel DTOs? When should I choose another package?
- Alternatives include `spatie/data-transfer-object`, `php-http/message`, or manual hydration. Choose DataModel if you need **declarative attributes**, **recursive hydration**, or **Laravel integration** (e.g., Eloquent). Use `spatie/data-transfer-object` for simpler DTOs without reflection. Avoid DataModel if you’re on PHP <8.1 or need minimal runtime overhead—manual hydration may be faster for trivial cases.