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

tadcka/mapper-bundle

tadcka/mapper-bundle is a PHP bundle for mapping data between objects and arrays, simplifying DTO conversion and decoupling domain entities from application layers. It provides a configurable mapper integration for bundle-based PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check before anything else: this is a Symfony bundle, not a Laravel package. It targets the Symfony 2.x kernel (AppKernel, services.yml/services.xml, Doctrine ORM) and was last tagged in October 2015. You cannot composer require it into a Laravel app and expect anything to boot. The realistic "day-to-day leverage" is one of two things:

  1. You are maintaining a legacy Symfony 2 application that already depends on Tadcka bundles (tree, classifier, text, menu, mapper). In that case this bundle is the glue layer that links those elements together.
  2. You are building something in Laravel today and want the concept — a generic association table that lets any source record link to any number of target records under a named "mapper type." In that case read the source for the schema and reimplement the pivot; do not port the code.

Where to look first, in this order:

  • composer.json — the hard constraints live here. Note the symfony/* and php requirements; they tell you immediately whether it can coexist with the rest of your dependency graph.
  • Entity/ — almost certainly contains a Mapper entity plus a MapperInterface. This is the actual data model and the only part worth reading closely.
  • DependencyInjection/ and Resources/config/ — the service ids and constructor arguments you will need to wire or override.
  • README.md / Resources/doc/ — Tadcka bundles of this era usually document the entity extension recipe rather than the manager API.
  • Tests/ — check whether it exists at all before trusting behaviour.

Minimal steps (legacy Symfony 2 host):

// app/AppKernel.php
new Tadcka\MapperBundle\TadckaMapperBundle(),
# app/config/config.yml
doctrine:
    orm:
        mappings:
            tadcka_mapper: ~   # verify the exact alias from the bundle's DI extension

Then update the schema (doctrine:schema:update --dump-sql first, always) and confirm the generated table — expect something shaped like mapper (id, mapper_type, source_id, target_id, position).

First use case to validate the install: take one existing entity, map it against an existing target entity under a string type such as gallery, persist two or three links through the bundle's manager service, then read them back. If that round-trip works you understand the bundle; everything else is variation.

Implementation Patterns

Generic association table. The bundle's value proposition is that you do not create a join table per relationship. One mapper table carries (mapper_type, source_id, target_id) rows. Your domain entities stay ignorant of each other — the source entity holds no collection property, and the bundle's manager resolves links at read time. This is the pattern to internalise, because it is also the pattern's main weakness: you lose Doctrine's object graph, so no $node->getGalleries() unless you write it yourself.

Manager-service usage. Do not reach into the repository directly; the bundle will have a manager (something like tadcka_mapper.manager or per-type managers) that validates the mapper type, orders items, and dispatches events. The typical call shape:

$manager->map($sourceId, $targetId, 'gallery');
$manager->unmap($sourceId, $targetId, 'gallery');
$manager->getMappedItems($sourceId, 'gallery'); // returns target ids or hydrated entities

Treat the manager as the public seam. If you need something it does not offer, add a method to your own thin wrapper service rather than subclassing it — subclassing couples you to internals that will never be fixed upstream.

Entity extension for typed mappers. If the bundle exposes a base Mapper entity with single-table or joined inheritance, the intended extension pattern is a per-type subclass (GalleryMapper extends Mapper) so you can attach type-specific columns. Weigh this carefully: it multiplies tables and complicates queries. For most applications the plain string mapper_type column plus an index is enough, and cheaper.

Ordering. Mapper bundles of this vintage almost always carry a position column with the manager handling reordering. Use the manager's move methods rather than writing position yourself; the reindex logic on delete is the part you do not want to reimplement.

Doctrine listener for cleanup. The most useful integration tip: register a postRemove listener on your source and target entities that deletes mapped rows. Nothing in a generic mapper table enforces referential integrity — no foreign keys, because the columns are polymorphic. Without the listener you accumulate orphan rows silently, and they only surface as a wrong count months later.

Form and admin integration. Because the source entity has no collection property, Symfony form types cannot bind it out of the box. The usual approach is a non-mapped field plus a PRE_SUBMIT/POST_SUBMIT handler that diffs submitted ids against getMappedItems() and calls map/unmap. Write this once as a reusable form type extension.

Laravel translation of the pattern (the genuinely useful takeaway if you are not on Symfony): implement it as a polymorphic pivot with an explicit type column, a morphTo on the source, a morphTo on the target, a composite unique index on (mapper_type, source_id, target_id), and a Mapper model with attach/detach/sync semantics mirroring BelongsToMany. You get 90% of the bundle's behaviour in ~80 lines and you get PHP 8, maintained code, and tests.

Gotchas and Tips

Abandoned status is the headline risk, not a footnote. Zero stars, zero dependents, last release 2015. That means no security patches, no PHP 7.4/8.x compatibility, no Symfony 4+ support, and no one to ask when something breaks. Treat it as vendored legacy code: if you take it on, fork it into your own namespace so you can patch it, and pin the exact commit.

PHP 8 will break it. This era of code uses count() on non-countables, implicit nullable parameter types, each(), and Doctrine getEntityManager() naming. If you are on modern PHP you are not installing this — you are reimplementing it.

No foreign keys by design. Polymorphic source_id/target_id cannot have FKs. Consequences: no cascade deletes, no integrity checks, and joins to target tables are string-keyed and unindexed unless you add indexes manually. Add a composite index on (mapper_type, source_id) and (mapper_type, target_id) in a migration immediately after installing; the bundle's own schema almost certainly omits them.

Table-name collisions and naming strategy. Old bundles hardcode table names via @ORM\Table(name="mapper"). If your app uses a custom naming_strategy or a table prefix, you get inconsistency between what the bundle expects and what Doctrine creates. Check the emitted SQL from --dump-sql rather than trusting the annotation.

Silent no-ops. map() implementations of this vintage frequently check for an existing row and return early without signalling. If a link "doesn't appear," confirm the mapper type string matches exactly — a typo produces an empty result set, not an exception. Add an enum or constant class for your mapper types on day one; free-text strings are the number one source of bugs here.

Bulk operations are not batched. Expect one flush per mapped item. Mapping a few hundred records on save will crawl. Wrap imports in an explicit transaction, flush once, and bypass the manager with a direct INSERT ... ON DUPLICATE KEY (or upsert in Laravel) for bulk paths.

Debugging. Enable the Doctrine SQL logger in the profiler and read the actual queries the manager emits — with zero documentation, the SQL is the specification. For orphan detection, run a periodic SELECT source_id FROM mapper WHERE mapper_type = ? AND source_id NOT IN (SELECT id FROM source) as a maintenance job.

Extension points are narrower than they look. The DI extension likely accepts little configuration. Do not plan on overriding services via compiler passes unless you have verified the service ids and their public flags in Resources/config/*.xml. In practice your extension surface is: your own manager wrapper, your own form type extension, your own delete listener, and a fork of the entity. Budget for all four.

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.
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo
bernskioldmedia/laravel-harvest
bernskiold/laravel-data-scrubber
bernskiold/laravel-currency-converter
bernskiold/laravel-campaign-monitor
bernskioldmedia/laravel-autotranslate
siberfx/telegram-bot
roy-sandip/laravel-view-extended
gregsphotography/site-builder-core
roy-sandip/laravel-view
anodyne/blade-fluentui-icons
webx-ui/module-catalog-collections