romanzipp/dto
Lightweight data transfer objects for PHP and Laravel. Define typed properties, cast and validate values, and convert DTOs to and from arrays with ease, keeping request and response data structured and type-safe.
Architecture fit. romanzipp/dto provides an explicit, typed DTO base class (AbstractData) with array hydration and toArray() serialization, plus attribute-based validation (Required, Nullable, Between, In). As a TPM, the relevant question is not "does this map arrays to objects" but "where do typed boundaries belong in our architecture." This package supports the pattern of typed object at the edge, plain values inside — DTOs formed at HTTP/queue/CLI boundaries and passed into actions and services. It deliberately does not replace Laravel validation, Eloquent casting, API resources, or container wiring, and it does not offer a transformation pipeline. That makes it an architectural enabler for tightening a boundary, not a data-layer strategy. Treat it as a small, adoptable snippet rather than a platform commitment.
Integration feasibility. Technically low-friction: a single Composer dependency, subclasses extending AbstractData, hydration from $request->validated() or a job payload, nested DTOs auto-hydrated from arrays, and toArray() for responses or persistence. The real integration cost is convention, not code: teams must agree on when to introduce a DTO, how to validate before hydration, how to represent dates/enums/nullability, and how serialization is expected to look at each boundary. Because the package has 12 stars and zero dependents, adoption should pass a formal build-vs-adopt gate — a 50–100 line internal base class may deliver the same value with lower ownership risk. This is a reversible, single-sprint decision, and should be framed as such to stakeholders.
Technical risk. The dominant risk is ecosystem, not runtime. Near-zero adoption, no dependents, and no visible LTS or security posture mean there are few production references and no community backstop. Any adoption implies "we are the maintainers now." Secondary risks are scope mismatch (teams expecting validation pipelines, Eloquent casting, or recursive collection mapping the package does not promise), PHP-version drift (readonly properties, constructor promotion, future language semantics), and serialization drift between DTOs and API resources. Note a documentation inconsistency worth resolving early: the package description claims PHP 7.4+, while the API surface relies on PHP 8 features (typed properties, attributes, constructor promotion). That discrepancy should be verified against composer.json and src/ before any decision is recorded.
Key questions.
AddressData[]), and what is the failure behavior for missing, extra, or mistyped fields?Stack fit. Appropriate for Laravel/PHP 8 codebases that already separate concerns into Form Requests, actions/services, jobs/events, and API Resources. The DTO sits between validation and domain logic: Form Request validates, DTO carries the typed shape, action consumes it, Resource or toArray() produces output. It is not a fit where requirements include nested collection mapping, computed fields, conditional transforms, or Eloquent model casting — in those cases spatie/laravel-data is the better-maintained answer and should be the explicit comparison in the ADR.
Migration path. Incremental by construction. Pick one bounded surface — a single endpoint, one queue job payload, or a third-party API response mapper — and introduce a DTO only at that boundary. Keep arrays and models in place elsewhere. Back the pilot with contract tests that assert hydration and toArray() round-trips. Resist an organization-wide "DTO everywhere" mandate until the pilot demonstrates concrete ergonomic and debugging wins over raw arrays.
Compatibility. Compatibility risk is concentrated in Composer resolution and PHP language features, not Laravel internals. Verify the PHP constraint against the team's supported matrix, check for transitive dependency conflicts, and confirm the package is framework-agnostic enough to test outside Laravel. Pin an exact version, record the fork point, and add the package to the existing CI matrix rather than a special-case pipeline. If attributes interact with any reflection-based tooling in the stack (serializers, openapi generators), test those explicitly.
Sequencing.
spatie/laravel-data; record the outcome as an ADR with an explicit reversal trigger.src/AbstractData.php, src/Attributes/, and src/Exceptions/ directly; confirm the description matches the source.toArray() output shape.Maintenance. Runtime maintenance is low; the surface is small and explicit, with no reflection-heavy indirection to debug. Dependency maintenance is the real line item: with low stars, zero dependents, and uncertain release cadence, the team should budget for occasional forking or vendoring. Centralizing inheritance behind an internal base class keeps the blast radius of a future replacement to a single file. Document the fork point and the upgrade policy in the ADR so the decision does not decay into folklore.
Support. Community-only, no SLA, no vendor escalation, no guaranteed triage. Production use should therefore require named internal ownership, documented conventions, and a written fallback path to an internal replacement. If upstream goes quiet, the correct posture is to treat the code as vendored utility source we own, not as a dependency awaiting updates. This is the single most important governance point for the TPM to enforce.
Scaling. Runtime overhead is negligible for typical request and action payloads, and "no magic" suggests it should remain competitive — but that is an assumption to benchmark, not a claim to repeat. The real scaling concerns are organizational and payload-shaped: nested DTO mapping becomes verbose as structures deepen, eager hydration of large collections adds memory and CPU, and inconsistent toArray() conventions cause API contract drift across teams. Set explicit limits (depth, collection size) and keep pagination/streaming at the boundary rather than inside DTOs.
Failure modes. Expect type errors on hydration, silent handling of missing or extra fields, inconsistent nested and collection mapping, date/enum conversion mistakes, serialization drift between DTOs and API Resources, Composer or PHP-version conflicts, and — the slow-burn one — abandonment, where the code keeps working but stops being supported. Mitigations: pinned versions, contract tests around every hydrated boundary, adapter isolation, a documented replacement path, and a scheduled quarterly review of upstream activity that triggers re-evaluation rather than silent drift.
Ramp-up. Developer ramp-up is low for PHP 8 engineers because there is no __get/__set indirection and stack traces point at real code. The actual learning curve is team convention: when a DTO is warranted, how validation composes with hydration, how nested structures are mapped, and what serialization contract each boundary commits to. Ship one reference implementation plus lint/static-analysis rules before broadening adoption — that reference implementation is the cheapest artifact for converting this from a code-style preference into an engineering standard.
How can I help you explore Laravel packages today?