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

Mapper Bundle Laravel Package

silpo-tech/mapper-bundle

A Symfony bundle for silpo-tech/mapper that automatically configures object-to-object and array mapping services. Register mappers, define mapping profiles, and convert DTOs, entities, and arrays with minimal boilerplate, keeping domain and transport layers clean and decoupled.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and inspect the package first.

    composer require silpo-tech/mapper-bundle
    

    Before writing any mapping code, read three files in the repo: composer.json (to confirm the namespace and whether a framework-agnostic core exists alongside the bundle wrapper), README.md, and src/DependencyInjection/Configuration.php. The last one is the authoritative list of config keys — the README is frequently behind the code in low-maintenance packages.

  2. Register it.

    • Symfony — add the bundle to config/bundles.php:
      SilpoTech\MapperBundle\MapperBundle::class => ['all' => true],
      
      then create config/packages/mapper.yaml with whatever keys Configuration.php exposes (typically mapping paths, cache flags, and custom normalizers).
    • Laravel — there is no bundle auto-discovery. A Symfony Bundle class will not be loaded by Laravel's package discovery, so you cannot composer require and expect app(SomeMapper::class) to resolve. Check whether the repo ships a framework-agnostic service/attribute layer under src/ that you can instantiate directly; if it does, bind it in an AppServiceProvider:
      $this->app->singleton(MapperInterface::class, fn () => new Mapper(/* deps */));
      
      If all the logic lives inside DependencyInjection/ and compiler passes, treat the package as a reference implementation rather than a dependency.
  3. First use case — map a request payload to a typed DTO. The highest-value day-one application is replacing manual $dto->name = $request->input('name') blocks. Inject the mapper into a controller/service and map the validated array into a DTO. Confirm the attribute namespace from src/Attribute/ (e.g. #[MapFrom], #[MapTo], or a single #[Map]) and use that exact name — guessing attribute class names here is the fastest way to waste an afternoon.

Implementation Patterns

  • Controller → DTO boundary. After FormRequest validation, map the validated array to a DTO in one call. This keeps controllers thin and gives you a single place to change when the payload shape moves. Return the DTO from the controller and let a JsonResource/transformer handle serialization.

  • DTO ↔ Entity around the repository. Use the mapper for both directions: request DTO → entity before save(), entity → response DTO after find(). Keeping entities out of API responses is the main reason to adopt a mapper at all; if you're only doing array → DTO, a plain constructor is usually cheaper.

  • Collections and nesting. Map arrays of items by mapping each element, not by mapping the array as a whole — most mapper APIs are scalar-object oriented. For nested DTOs, verify whether the mapper recurses automatically or whether you must nest map() calls manually. Build a small MapCollection/mapMany helper once and reuse it.

  • Custom value resolution. Anything the mapper can't infer — enums, CarbonImmutable, money objects, decrypted columns — belongs in a dedicated resolver/converter class registered via config. Centralizing these is what makes the mapper worth keeping as the domain grows.

  • Constructor vs property mapping. Prefer mapping immutable DTOs through the constructor (all args required, no setters). If the package only supports property writes, either relax DTO immutability at the boundary or wrap the mapper in a factory that constructs the DTO.

  • Testing. In Symfony, resolve the mapper from the container in a KernelTestCase. In Laravel, instantiate the mapper directly in a unit test with fake dependencies — this is faster and avoids booting the framework. Either way, assert on the DTO's contents, not on intermediate arrays.

  • Wrap it, don't sprinkle it. Inject a project-owned App\Mapping\Mapper facade that delegates to the package. When you need to swap or drop the dependency (likely, given 0 stars / 0 dependents), you change one class instead of dozens of call sites.

Gotchas and Tips

  • The bundle/maintenance gap. Zero stars and zero dependents is a signal: pin an exact version in composer.lock, and read the diff between the tag you install and main before upgrading. Assume no upstream support timeline.

  • Symfony-only by construction. Bundle, Extension, and compiler passes have no Laravel equivalent. Do not add this to a Laravel composer.json expecting it to "just work" — verify the core is separable first, or skip it and use spatie/laravel-data / manual hydration.

  • Attribute discovery and caching. Mapping metadata derived from PHP attributes is usually cached. After changing an attribute or config, run bin/console cache:clear (Symfony) or clear your own cache in Laravel. Stale metadata produces silent mis-mapping, not errors — the worst failure mode.

  • Attribute targets matter. #[Attribute(Attribute::TARGET_PROPERTY)] won't apply to a constructor parameter, and vice versa. If a mapping silently does nothing, check the attribute's declared target first.

  • Null vs. missing. Decide explicitly whether null in the payload overwrites a defaulted property. Many mappers treat "key absent" and "key present with null" identically; if your DTO has a non-null default, this becomes a real bug.

  • Type coercion is quiet. "1" → 1, "true" → true, invalid dates → null or an exception depending on config. Validate at the boundary with a FormRequest/Validator and let the mapper assume correct types; don't use the mapper as a validator.

  • Recursion and cycles. Bidirectional entity ↔ DTO mapping can loop on circular relations. Handle back-references by mapping IDs instead of objects, or by excluding the field in config.

  • Performance in loops. Mapping thousands of rows reflects over attributes each call unless metadata is cached. If you map inside a foreach over a large result set, benchmark it; if it's hot, batch-map or hydrate directly.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource