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

Object Mapper Laravel Package

league/object-mapper

A lightweight object-to-object mapper for PHP that converts one class into another using reflection and PHP attributes. Define property mappings, handle nested objects, arrays, and collections, and reduce boilerplate when transforming DTOs, entities, and API payloads.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What the package is. league/object-mapper is a reflection-based hydrator: it takes structured data (decoded JSON, request arrays, queue payloads, config arrays) and constructs strict, typed PHP objects — DTOs, command objects, value objects — resolving constructor arguments, nested objects, and collections, with an extensible cast layer for enums, dates, and scalar coercion. It is deliberately not an ORM, not a validator, and not a serializer with format awareness. It occupies the same slot as cuyz/valinor, spatie/laravel-data, and Symfony Serializer's object-constructor path.

Architecture fit. Good fit for a hexagonal/ports-and-adapters Laravel codebase where controllers and jobs currently hand-roll new SomeDto($request->input(...)) calls. It gives you a single, testable anti-corruption boundary between transport shapes and domain types. Poor fit if the team's mental model is "Eloquent models + API Resources" — the package adds nothing there and would be a second, competing hydration mechanism. It complements, and does not replace, Laravel's validation layer or Eloquent's attribute casting.

Integration feasibility. High on mechanics, low on conveniences. It is framework-agnostic PSR-4 Composer code: no service provider, no facade, no config file. Binding it into the container is a one-liner, and wrapping it behind an internal interface is trivial. The absence of Laravel-native affordances is the real cost: no FormRequest integration, no automatic ValidationException, no resource/response transformation, no queued-job DTO resolution. Every one of those is glue we write and own.

Technical risk. The score signal is unambiguous and worth stating plainly: 36 stars, zero dependents, and a composite score near 1.0 means effectively no production adoption footprint to inherit. Principal risks:

  • Bus factor / lifecycle. Single-maintainer, low-activity League package. League packages have been archived before. Assume we may need to fork.
  • Language-feature drift. Reflection-based mappers are acutely sensitive to PHP type-system changes: union and intersection types, readonly properties, promoted constructor params, default values, nullable-vs-missing-key semantics, enum backing types, and DNF types. Behavior on each must be verified, not assumed.
  • Error ergonomics. Type failures surface as mapping exceptions, not 422 responses. Without a translation layer, malformed client input becomes a 500.
  • Opportunity signal. The one encouraging number is the opportunity score (~21.8): the gap it fills — a small, dependency-light strict mapper without the weight of a full serializer — is real. That is a reason to pilot, not a reason to standardize.

Key questions to close before committing.

  1. Who maintains it, what is the release cadence, and what is the median issue-triage time over the last 12 months?
  2. Which PHP versions and Laravel versions are declared and CI-tested? Does it run clean on our target (8.3/8.4)?
  3. Exact support matrix for union/intersection types, enums, readonly, nested collections, and circular references — verified by spike, not by README.
  4. Failure semantics: missing key vs explicit null; extra/unknown keys; partial coercion. Is there a strict mode?
  5. Cast extension API: can we register our own casters for domain value objects (Money, UserId, Email) without forking?
  6. Can we express our whole usage as a ≤5-method internal interface, so the vendor is a swappable implementation detail?

Integration Approach

Stack fit. Clean. It sits at the inbound boundary of the application layer and has no opinion about HTTP, queues, or persistence, so it composes with Laravel rather than fighting it. The intended wiring is FormRequest validation → validated array → mapper → typed Command/Query DTO → handler. That keeps validation (Laravel's strength) and construction (the package's job) separate and individually testable.

Containment strategy — the non-negotiable. Do not let League\ObjectMapper\* types appear in application or domain code. Define a narrow internal contract, e.g. App\Support\Mapping\DataMapper with map(array $data, string $class): object, and ship a LeagueObjectMapperAdapter implementing it. This costs a day and converts an unquantified vendor risk into a one-class swap to Valinor or spatie/laravel-data. Given 0 dependents and a single maintainer, this is the difference between a reversible and an irreversible decision.

Migration path. Do not retrofit. Introduce it only at new boundaries and at boundaries already being touched. Concretely: pick one bounded context, replace its manual new Dto(...) blocks, and run the old and new hydration paths side by side behind a feature flag with contract tests asserting deep equality of the resulting objects. Retire the flag after one release cycle.

Compatibility checks. Run composer why-not league/object-mapper against the current lockfile before anything else; confirm the PHP constraint against our CI matrix and production runtime; confirm attribute usage (likely the configuration surface for casts) does not collide with any static analysis or code-style tooling; confirm Rector/PHPStan behavior on mapped classes, since reflection-heavy code sometimes needs baseline entries.

Sequencing.

  1. Spike (1–2 days). Three real production payloads, including one with nested collections and one with an enum and a nullable field. Capture actual exception messages for malformed input.
  2. Contract + adapter (1 day). Internal interface, adapter, container binding, one unit test proving the adapter can be swapped.
  3. Error translation (1 day). Map package exceptions to ValidationException/422 with field-path context. Without this, do not ship.
  4. Pilot (1 sprint). One bounded context, parallel-run, measured.
  5. Decision gate. Adopt broadly, hold at pilot scope, or replace the adapter implementation. Explicitly scheduled, not drifted into.

Operational Impact

Maintenance. Low surface area, low code volume, but concentration risk. Budget: pin to a minor version, review the changelog on every bump, and pre-agree a fork trigger (e.g. no release or issue response for 6 months, or a blocking incompatibility with a PHP minor we must adopt). Because the integration is contained behind the adapter, a fork is a repositories entry and a namespace change, not a refactor.

Support. No first-party Laravel support and effectively no community corpus to search — Stack Overflow will not save an engineer here. Required investment: a one-page internal pattern guide ("how we map inbound data"), the adapter contract documented as the only sanctioned entry point, and the swap procedure written down while the context is fresh. This is the main hidden cost and it is small but real.

Scaling. Reflection-based hydration is comfortable at request-scale volumes; the overhead is per-object construction, not per-byte. Two things to watch: (a) hot paths with large collections — mapping 10k rows item-by-item will show up in profiles, and reflection metadata caching (if the package offers it — verify) or bulk handling becomes necessary; (b) queue workers mapping high-throughput payloads, where a 0.2 ms per-object cost multiplies. Measure in the pilot rather than pre-optimizing; the failure mode is not catastrophic, just wasteful.

Failure modes.

  • Shape mismatch → opaque mapping exception; without the translation layer this is a 500 on user input. Highest-severity risk, mitigated by step 3 above.
  • Over-permissive coercion → a string "1" silently becoming an int and masking an upstream contract violation. Mitigate with strict mode if available, plus contract tests on representative payloads.
  • Missing vs null ambiguity → a field absent from the payload behaving differently than a field explicitly set to null. Document the chosen semantics; test both.
  • Deep nesting → error messages lose the property path, making production triage slow. Verify whether exceptions carry a path; if not, add it in the adapter.
  • Vendor abandonment → mitigated structurally by the adapter, not by diligence.

Ramp-up. Low. A mid-level Laravel developer is productive in half a day; the concept (typed objects instead of arrays) is already idiomatic in the codebase or it is not, and that — not the package — determines adoption speed. The realistic risk is pattern divergence: three teams, three ways of mapping. Mitigate by making the internal DataMapper interface the only approved path and enforcing it in review, which also happens to be the mitigation for the maintenance risk. One decision, two problems.

Recommendation. Conditional pilot, not standards adoption. The package is technically well-shaped for the problem and cheap to integrate, but the adoption and maintenance signals (36 stars, 0 dependents, single maintainer) do not support making it a team-wide standard on the strength of its design alone. Contain it behind an internal interface, prove it on one boundary with real payloads and a real error-translation layer, then make an explicit adopt/hold/replace call at the end of the pilot. The opportunity score is the reason to run that pilot; it is not evidence that the pilot will pass.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource