Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Data Model Laravel Package

zero-to-prod/data-model

DataModel hydrates PHP objects from external data with a single from($data) call using reflection and type hints. Validation and casting live in #[Describe] attributes (required, nullable, default, assign), replacing manual property wiring and scattered null checks.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package occupies a well-defined seam in a Laravel application: the boundary between transport-shaped data (validated FormRequest output, queued job payloads, third-party API responses, Model::toArray()) and typed domain objects. Laravel naturally produces associative arrays at that seam, and from() converts them into typed objects with one call. Because integration is a trait rather than a base class or interface, it composes with existing DTOs and imposes no inheritance constraint — a meaningful advantage in a codebase that already has base controllers, base jobs, and base models competing for the single-inheritance slot. The recursive hydration of class-typed properties maps cleanly onto nested request payloads. It does not fit where validation is the primary concern (spatie/laravel-data's rule integration, cuyz/valinor's schema-first mapping) or where DTOs are already standardized.

Integration feasibility. composer require, add a trait, done. No service provider, no config file, no migrations, no published assets, no queue/event wiring. The adoption cost is essentially zero at the technical level; the real cost is entirely social — establishing a team convention for when a DTO is warranted and how #[Describe] keys are used. That is a favorable cost profile for a pilot.

Technical risk. The concerns, roughly ordered by impact:

Risk Assessment
Reflection on every from() No documented metadata cache. Cost scales with property count × payload depth × collection size. Unacceptable on hot paths without benchmarking.
Silent misconfiguration Unrecognized #[Describe] keys are captured in $extra rather than raising. A typo ('requird' => true) degrades to "no constraint" instead of failing. Only three exception types exist, none for this.
Eight-level precedence ladder assign → default → cast → post → method-cast → class-cast → via → direct. Documented and deterministic, but debugging a wrong value means walking a stack of resolvers. The README's "predictable" claim is true at the property level and less true at the class level.
Single-vendor dependency Small org, 139 stars, 0 dependents on Packagist. Stars without dependents suggests interest, not production adoption. Bus factor is effectively 1.
Recursion without a depth guard Nested from() calls are unbounded and undocumented for cycles or pathological payloads.
Composer hook side effect The documented post-install-cmd/post-update-cmd pattern writes README into ./docs/. Vendor binaries mutating the working tree during install is an operational smell; do not enable it.
Version chasing First-class-callable (PHP 8.5) syntax in examples implies a moving minimum PHP version. Confirm the floor before committing.

Positive signals worth weighting: MIT license, test.yml and backwards_compatibility.yml CI workflows (the latter is a genuine semver-discipline indicator), no runtime dependencies, and — most valuable — near-zero lock-in. DTOs are plain PHP classes with public typed properties. Removing the package means deleting attributes and writing constructors, not rewriting call sites. That exit ramp materially lowers the cost of being wrong.

Key questions for the maintainer / spike.

  1. Hydration benchmark: from() at 1k / 10k / 100k objects, flat and 3-level nested, with and without casts.
  2. Is reflection metadata cached, and is there a warm-up path?
  3. Does it support readonly and constructor-promoted properties?
  4. Clean PHPStan/Larastan at level 8+ on a real DTO set?
  5. Handling of enums, union types, and Foo[]-style collections — the README pushes arrays-of-models to the separate DataModelHelper package. How much of the capability surface is actually in sibling packages?
  6. Minimum PHP version and support policy; security disclosure contact.
  7. Packagist download counts, to distinguish "starred" from "used in anger."

Integration Approach

Stack fit. Best fit is a Laravel app on PHP 8.2+ with an existing actions/services layer, where controllers currently pass arrays into services and the team wants typed boundaries. Worst fit is an app already invested in spatie/laravel-data, or one where DTOs must carry validation rules, Eloquent casting, or resource transformation — those capabilities live in sibling packages (DataModelHelper, DataModelFactory, Transformable), each an independent dependency with its own maturity profile. Adopting four small single-maintainer packages to get one capability is a materially different risk posture than adopting one.

Migration path. There is no migration — this is additive. Existing array-passing code stays; DTOs are introduced at one boundary at a time. Coexistence is trivial because nothing is registered globally.

Compatibility. Verify against the team's PHP floor first, then against Larastan. The package's own compatibility workflow covers its public API, not its behavior under your static analysis configuration. Laravel version is largely irrelevant given no framework coupling — worth confirming that the "Laravel Validation" and "Hydrating From a Laravel Model" examples are documentation, not integrations.

Sequencing.

  1. Spike (2–3 days): one bounded context, ~10 DTOs, run the benchmark and PHPStan questions above.
  2. Codify: written convention for attributes, permitted cast callables, and who owns shared cast helpers. Restrict pre/post hooks to a reviewed allowlist — they are the highest-blast-radius feature.
  3. Pilot: one production endpoint, instrumented for hydration latency.
  4. Expand or exit: gate wider adoption on the benchmark and on six months without an upstream breaking change. Set an explicit trigger for reconsidering (upstream stall, or a Laravel version bump the package doesn't track within 90 days).

Do not standardize org-wide on the strength of the README. The 29/100 composite score and 18.19 opportunity score both reflect a crowded category with an entrenched incumbent; this package's case rests on ergonomics and low lock-in, not on differentiation or ecosystem depth.

Operational Impact

Maintenance. The package itself is small and stable-looking; the maintenance burden is the convention layer you build on top. Expect to own a Casts/ directory of static helper methods, because the attribute model encourages callable references to project code. Those helpers become de facto platform code and need an owner. Upstream maintenance risk is concentrated in one maintainer with no visible commercial backing — plan for the possibility of vendor-forking.

Support. Community-only: GitHub issues, no SLA, no security policy documented in the README. For an internal utility with a cheap exit ramp, that is tolerable; the mitigation is to keep DTO usage confined to layers you can rewrite in a sprint.

Scaling. Two axes. Throughput: reflection cost multiplies by object count and nesting depth — this is the single most likely reason the pilot fails, and it must be measured before expansion. Payload shape: unbounded recursion on nested input means a deeply nested or maliciously shaped JSON body drives correspondingly deep hydration work before validation rejects it. Ensure FormRequest validation runs before hydration, always.

Failure modes.

  • Silent no-op: misspelled attribute key, or from() receiving a string/null (documented as "empty context") — yields a partially populated DTO rather than an error. Most dangerous with optional properties.
  • Coercion surprises: '30' becomes int 30; PHP's native type juggling under reflection is not always what reviewers expect. Strict-types behavior per property should be verified.
  • Hydration exceptions in the request cycle: PropertyRequiredException and InvalidValue are unhandled by default and surface as 500s unless mapped to 422s in the exception handler. This must be wired on day one of the pilot.
  • assign semantics: value always null for callables and always wins over context — a property that can never be overridden by input. Intentional, but a trap for anyone reading the DTO without reading the attribute.
  • Duplicate method-level casts: correctly raises DuplicateDescribeAttributeException — a rare case of fail-fast.

Ramp-up. Low for the base case (a developer is productive in an hour). Moderate for casts and hooks: the four-parameter callable signature, auto-detected arity, and the precedence table are learnable but not obvious, and the failure mode of getting them wrong is a wrong value, not an exception. Budget a short internal write-up and a code-review checklist. Junior developers will copy-paste cast callables; treat that as the primary source of drift.

Bottom line for a TPM. Low-cost, low-lock-in, low-differentiation. Worth a bounded pilot on the strength of the exit ramp alone; not worth a standardized dependency without a passing benchmark and a named internal owner.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
wandesnet/mercadopago-laravel
tsfcorp/email
larafony/core
laravel-enso/currencies
tartan/laravel-online-payment
gam/laravel-sat-catalogs
cloudcreativity/laravel-stripe
abdulelahragih/querybuilder
wedevbr/celcoin-laravel
surazdott/nepali-date
devsquad-cockpit/laravel
coding-socks/laravel-upload-handler
artisanbarista/laravel-shield
shopwwi/laravel-cache
instance-code/repository
flooris/prestashop-models
lab2view/laravel-generator
lenderspender/laravel-wizard
joecampo/laravel-notification-basecamp
square1/laravel-collection-rolling-average