Product Decisions This Supports
- Build vs. Buy: Buy – Eliminates the need to build custom DTO hydration logic, validation layers, or manual type-casting utilities. Reduces technical debt by leveraging a battle-tested, type-safe solution.
- Feature Roadmap:
- API/Service Layer: Standardize DTO hydration across API responses, reducing boilerplate and improving consistency.
- Data Validation: Replace scattered validation logic (e.g., in Laravel Form Requests or manual checks) with centralized
#[Describe] attributes.
- Domain-Driven Design (DDD): Enforce strict property contracts for domain entities, improving maintainability and reducing runtime errors.
- Performance Optimization: Replace slow, ad-hoc array-to-object conversions with optimized, type-safe hydration.
- Use Cases:
- API Consumption: Hydrate API responses into strongly typed objects with minimal boilerplate.
- Database ORM Integration: Replace manual model hydration (e.g., Eloquent
fill()) with declarative, type-safe alternatives.
- User Input Handling: Validate and transform form submissions or CLI input with zero defensive programming.
- Legacy System Migration: Gradually introduce type safety to older PHP codebases without rewriting core logic.
When to Consider This Package
-
Adopt if:
- Your team struggles with boilerplate DTO hydration (e.g., repetitive
$obj->prop = $data['prop']).
- You need centralized validation and want to avoid scattering rules across constructors, factories, and services.
- Your project uses PHP 8.0+ (for attributes and type hints) and prioritizes static analysis (e.g., IDE autocompletion, PHPCS).
- You work with nested data structures (e.g., API responses with embedded objects/arrays) and want recursive hydration.
- You’re building a Laravel application and want to reduce reliance on Form Requests or manual validation.
- Your team values self-documenting code and wants to colocate metadata (e.g., validation rules, defaults) with property declarations.
-
Look elsewhere if:
- You’re on PHP < 8.0 (attributes and type hints are required).
- Your project already has a mature DTO library (e.g., Spatie’s Data Transfer Objects, Symfony’s Serializer) that meets your needs.
- You need highly dynamic hydration (e.g., runtime property resolution) and prefer flexibility over declarative syntax.
- Your team lacks familiarity with attributes or static analysis tools (e.g., PHPStan, Psalm).
- You’re working in a performance-critical context where reflection overhead is prohibitive (though benchmarks would be needed to confirm).
How to Pitch It (Stakeholders)
For Executives:
"This package lets us eliminate 30–50% of the boilerplate code in our API/data layers by automating DTO hydration, validation, and type casting. Instead of writing repetitive $obj->prop = $data['prop'] logic or scattering validation rules across services, we’ll use declarative attributes to define how data maps to objects—once, in one place. This reduces bugs, speeds up development, and makes our codebase more maintainable. For example, validating a user signup form would go from 10+ lines of manual checks to a single #[Describe] attribute. It’s a low-risk, high-reward upgrade that aligns with our shift toward type safety and cleaner architecture."
For Engineering Teams:
*"Problem: Our DTO hydration is messy—manual property assignment, duplicated validation logic, and no centralized way to document data contracts. This leads to bugs, tech debt, and slow onboarding.
Solution: zero-to-prod/data-model replaces all that with type-safe, declarative hydration using PHP attributes. Key benefits:
- No more boilerplate: Replace
User::fromArray($data) with a single User::from($data) call.
- Validation in one place: Define
required, nullable, cast, and default values next to the property (e.g., #[Describe(['required', 'cast' => 'strtoupper'])]).
- Recursive hydration: Automatically hydrate nested objects/arrays (e.g., API responses with embedded models).
- Static analysis friendly: IDEs can verify property contracts without running code.
- Composable: Layer behaviors like
pre/post hooks or custom metadata without subclassing.
How we’ll use it:
- API Layer: Hydrate all incoming/outgoing data as DTOs (e.g.,
UserResponse::from($apiData)).
- Form Handling: Replace Laravel Form Requests with
#[Describe]-driven validation.
- Database Models: Add
DataModel trait to Eloquent models for type-safe hydration.
Migration Path:
- Start with one high-impact module (e.g., user auth or API responses).
- Use composer scripts to auto-generate docs for the team.
- Pair with
data-model-helper for collections/arrays.
Risks: Minimal—attributes are stable in PHP 8.0+, and the library is MIT-licensed with active maintenance."*
For Developers:
*"This is like Laravel’s fill() on steroids—but type-safe, declarative, and recursive. Here’s how it changes your workflow:
- No more
isset() or array_key_exists(): Use required, nullable, or default in #[Describe].
- Custom logic in one place: Need to uppercase a field? Add
#[Describe(['cast' => 'strtoupper'])]. Need to validate a value? Use pre/post hooks.
- Nested data? No problem: Type-hint a property as
Address and it’ll auto-hydrate if the input has an address key.
- Works with Laravel: Replace
Validator::make() with #[Describe] for form/input validation.
Example:
class User {
use \Zerotoprod\DataModel\DataModel;
#[Describe(['required', 'cast' => 'trim'])]
public string $name;
#[Describe(['default' => 18])]
public int $age;
}
$user = User::from(['name' => ' Alice ']); // name = 'Alice', age = 18
Why this > manual DTOs:
- Less code: No constructors, factories, or validation classes.
- More correct: Static analysis catches typos or missing properties early.
- More flexible: Add custom metadata (e.g.,
#[Describe(['validation' => 'email'])]) without extending the library.
Try it: Add it to a new project or a single module to see the difference!"*