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

Many To Many Matrix Bundle Laravel Package

yokai/many-to-many-matrix-bundle

Symfony bundle that displays many-to-many relations as an editable matrix grid, letting admins toggle associations in bulk from a single screen. Configure entities, fields, and labels to manage complex mappings without custom forms. Ideal for admin panels.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit — poor, and the framing needs correcting up front. Despite being a PHP package, this is not a Laravel package. It is a Symfony bundle (yokai/many-to-many-matrix-bundle) built around the Symfony Form component, Doctrine ORM's ManyToMany mapping, and the Symfony DI container/kernel bundle registration model. Laravel's equivalents — Eloquent BelongsToMany, Blade/Livewire, service providers — share no interfaces with it. There is no adapter seam to bridge: you cannot composer require this into a Laravel app and boot it, because doing so drags in a second ORM and a second HTTP kernel's worth of assumptions. The reusable asset here is the pattern, not the code.

The pattern itself is narrow and well understood: render an owning-side ManyToMany join as an R×C checkbox grid, where row and column headers are the two entity sets and each cell toggles a join row. Laravel already solves the persistence half of this natively via sync() / syncWithoutDetaching() on a BelongsToMany relation. Only the grid UI is missing, and that is a Blade partial or a Filament CheckboxList with a grid layout — not a dependency.

Integration feasibility — effectively zero for direct adoption. Symfony 2/3-era form types (AbstractType::getName(), choices_as_values, templating helpers) were removed or changed in later majors. Composer will fail to resolve its symfony/form constraint against Laravel's symfony/* ^6/^7 transitive set on any modern install. The only viable path is vendoring it as MIT-licensed reference material and porting the rendering logic.

Technical risk — high, concentrated in abandonment. Last release 2016-05-31, 9 stars, 0 dependents. That combination means no maintainer, no issue triage, no security patching, and no community signal that the abstraction survives contact with real schemas. A dependency with zero dependents is unvalidated by definition; you would be the first production user of a nine-year-old artifact built for a framework generation Laravel no longer shares components with.

Key questions before any work is scheduled:

  • Is the stakeholder requirement the grid UX or the join-table sync semantics? If the latter, sync() is already the answer and this package is irrelevant.
  • What are realistic cardinalities on each axis? A matrix is O(R×C) DOM nodes; it is a good fit at 10×10 and unusable at 200×200.
  • Does the admin surface already have a BelongsToMany field (Filament, Nova, Backpack) that renders multi-select with search? If so, the gap is cosmetic, not functional.
  • Who owns the code if we port it, and does that person still exist in six months?

Integration Approach

Stack fit. Eloquent BelongsToMany + sync() covers persistence, pivot-table diffing, and detach-on-missing-key semantics out of the box. The matrix becomes a presentation concern: a Livewire component or Filament form field that renders the grid, binds to wire:model, and hands a flat array of selected IDs to sync(). No Doctrine, no bundle registration, no second container.

Migration path. Treat the repository as a specification document. Read the form type and its Twig template to extract the behavioral contract — header derivation from each side's collection, checked-state resolution from the owning entity, and the submitted payload shape (typically matrix[rowId][columnId]). Rebuild that contract natively against Blade + a form request. Do not fork the bundle into the application: forking preserves the Symfony/Doctrine baggage without preserving the maintainer, which is the worst of both outcomes.

Compatibility. Two hard blockers, both structural rather than version-pin annoyances. First, symfony/form ^2/^3 will not co-resolve with a modern Laravel symfony/* tree. Second, running Doctrine ORM alongside Eloquent means two connection managers, two migration systems, two identity maps, and two transaction boundaries over what is almost certainly the same database. That is an operational liability no UI feature justifies.

Sequencing.

  1. Confirm with the requester whether the grid is a hard UX requirement or a stand-in for "let admins manage these links."
  2. Prototype the grid in Livewire or Filament against a real pivot table — one to two days of engineering, not a procurement decision.
  3. Define the submitted payload and map it to sync(); explicitly decide partial-update semantics (see failure modes below).
  4. Wrap in a FormRequest with per-axis exists rules and an authorization policy — the matrix posts a large array of foreign keys and is a mass-assignment surface.
  5. Load-test at the upper cardinality bound before committing to the UX.
  6. Only if the prototype proves insufficient should a package build be scoped — and it should be an internal one, not this one.

Operational Impact

Maintenance. Zero upstream maintenance is available, so any adoption converts a dependency into a permanent in-house fork. Porting the pattern instead yields roughly a hundred lines of view and component code that the team already understands and can change without reading a nine-year-old Symfony changelog.

Support. No maintainer, no active issues, no documentation beyond a minimal README. Any production incident debugs to source code you wrote or vendored, which is acceptable if you own it deliberately and unacceptable if it arrives as a transitive dependency.

Scaling. The matrix is the scaling risk, not the package. Every cell is an input element: 50×50 is 2,500 controls, 100×100 is 10,000, and the HTML payload, browser render, and POST body all grow quadratically. Past a few hundred controls the UX degrades into scroll-hunting with no search affordance. If either axis is unbounded or operator-controlled, the grid will not survive; design in filtering, pagination, or per-row submission from the start.

Failure modes.

  • max_input_vars truncation — PHP's default is 1,000. A large matrix exceeds it and the request is silently truncated, producing a partial sync() that detaches valid join rows. This is the single most likely production incident and it fails quietly. Raise the limit, or chunk submissions, and assert the expected cell count server-side.
  • Partial-payload detachment — sync() treats absent IDs as removals. If the client submits only visible or filtered rows, hidden links are destroyed. Use syncWithoutDetaching() plus explicit removals, or scope the sync to the rendered subset.
  • Last-write-wins concurrency — the matrix is a full-state form. Two admins editing simultaneously silently overwrite each other's changes. Add optimistic locking on the pivot or an updated-at guard.
  • No transaction boundary — wrap the sync payload application in DB::transaction(); a mid-request validation failure leaves a half-applied matrix.
  • N+1 on load — eager-load both sides or the grid issues a query per row.

Ramp-up. A Laravel developer can reproduce this pattern in one to two days with no prior exposure. The high-cost path is the one where someone insists on Symfony/Doctrine knowledge transfer to interpret the bundle — that is a cost with no corresponding output.

Overall. At a 0.335 score with zero dependents and a 2016 release, this reads as a pattern reference, not a candidate dependency. The correct TPM action is to close the adoption question, cite the framework mismatch as the deciding factor rather than age or stars alone, and redirect the effort into a small native implementation that the team owns outright.

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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel