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

Tomato Menus Laravel Package

tomatophp/tomato-menus

Menu management for Laravel and TomatoPHP: build database-backed navigation menus, organize nested items, and render dynamic links in admin panels or Blade views with a simple, reusable API.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit tomatophp/tomato-menus is a Laravel package that supplies three things: a menu data model (nested items, multiple named locations), a dual storage driver (JSON file or database table), and a Filament admin surface for editing menus at runtime. It assumes a conventional Laravel app — service provider registration, published config, published migrations, Blade rendering. It does not impose an application architecture, which is good for fit and bad for leverage: you get a menu CRUD layer, not a navigation platform.

The genuinely product-relevant architectural feature is the JSON-vs-database driver split, because it silently assigns operational ownership. JSON-backed menus ship with a release: code-reviewed, diffable, revertible. Database-backed menus are editable by marketing/ops at runtime without a deploy. Any TPM adopting this should force that decision per navigation surface up front — primary nav (JSON, engineering-owned), sidebars/footer/campaign links (DB, business-owned). If the package only supports a global provider selection rather than per-menu overrides, that is a real limitation and should be confirmed during the spike, not after.

Fit is strongest when the application is already inside the TomatoPHP/Filament ecosystem. Outside it, the Filament plugin, the config conventions, and the shared TomatoPHP assumptions become integration surface rather than convenience.

Integration feasibility Mechanically straightforward: composer require, publish config, publish and read the migration, optionally register the Filament plugin, render a menu in a Blade view. The recommended pattern is to wrap it behind an internal interface on day one — something like MenuRepository::tree(string $key): array — with all views and controllers depending on that interface rather than the package namespace. That wrapper is the single highest-value integration decision, because it converts vendor risk into a roughly two-day replacement cost (swap the implementation for spatie/laravel-menu or a hand-rolled menus/menu_items pair).

Rendering should also be owned: build a recursive Blade partial over the normalized tree, with your markup, classes, aria attributes, and active-state logic. Treat any package-provided Blade component as a reference implementation. This keeps design and accessibility changes from requiring forks of vendor views.

Feasibility caveats: documentation is effectively absent, so integration cost is dominated by source reading rather than wiring. Budget the spike accordingly.

Technical risk The adoption signals are weak and should be stated plainly to stakeholders: zero stars, zero dependents, single-author ecosystem, one release in May 2024, MIT license. That is not a disqualifier for a low-stakes internal surface, but it is a standing vendor risk on anything customer-facing.

Risk concentrates in four places:

  1. Schema and tree integrity. Read the migration before running it. Adjacency list vs. nested set, cycle guards, cascade-vs-nullify-vs-orphan on parent delete, order stability under concurrent drag-and-drop edits, and whether the parent relation is a real foreign key or app-code convention. Orphaned children become invisible, un-routable items — a silent defect that surfaces as "where did that link go?" weeks later.
  2. Cache invalidation. If the package does not bust its cache on save, the wrapper must, via model observers on saved/deleted. A stale menu is silent and customer-facing.
  3. Framework compatibility. A mid-2024 release sits in the Laravel 11 / Filament v3 window. Filament majors historically break plugin authors. Verify Laravel 12 / Filament v4 constraints in composer.json before trusting it, and never adopt in the same release window as a framework upgrade.
  4. Multi-tenancy. If per-tenant navigation is plausible within a year, check now whether the table carries a tenant column or scope. Retrofitting tenancy into a global menu table is a migration you do not want under production load.

Key questions

  • Is menu management a differentiator or commodity plumbing for this product? If navigation is product surface — personalization, localization workflows, publishing states, A/B — the package does not reach and the decision defaults to build.
  • Which navigation surfaces are engineering-owned (JSON, release-gated) and which are business-owned (DB, runtime-editable)? Is per-menu provider selection supported, or is the choice global?
  • Does the JSON driver write back to disk from the admin UI? If yes, we have a deployment hazard: file permissions, ephemeral storage/ in containers, and admin edits diverging silently from the repo.
  • What is the cascade behavior on parent delete, and will we write integrity tests to pin it?
  • Does the package understand our roles/permissions, or is visibility a bare is_active flag we must filter with a Gate in the wrapper?
  • Are we prepared to mirror the repo privately with an upstream remote, pin to v1.1.8, and budget roughly a day per quarter for compatibility churn?
  • Does a time-boxed spike surface more than two unresolved schema or caching concerns? If so, we build.

Integration Approach

Stack fit Best fit: Laravel 11 / Filament v3 applications, TomatoPHP-aligned codebases, internal admin panels, back-office tooling, and MVP marketing sites where menus are supporting infrastructure. The Filament admin surface comes largely for free in that context, which is where the sprint-day savings actually materialize.

Poor fit: applications outside the TomatoPHP ecosystem, apps with strict dependency governance that a single-maintainer package will not clear, or any stack where navigation is a revenue-bearing surface.

Migration path There is no migration path in the data sense — this is greenfield adoption into a package with no prior installed base and no documented upgrade history. The relevant "migration" is the exit path, and it should be planned before integration begins:

  • Define the wrapper interface first, then implement it against the package.
  • Keep all customizations confined to three extension points: the service provider (rebind the driver if forked), the config (driver selection), and model observers (cache invalidation, audit logging). Staying inside those three keeps rebasing cheap and replacement cheap.
  • Treat the JSON menu files as versioned fixtures: commit them, and have DatabaseSeeder read them into rows so a fresh environment boots with correct navigation. That gives you code-review benefits of JSON plus runtime editability via DB.
  • If the JSON driver is read-write at runtime, restrict it: treat the file as read-only in production and write only through a seeder or an explicit export command.

The stop-and-build threshold should be agreed in advance: a menus + menu_items pair is roughly three to five days to build, fully owned. The package's value is convenience, not capability — worth about one sprint-day of integration savings, not a standing vendor risk on our navigation surface.

Compatibility Pin the constraint to the exact v1.1.8 line. Do not float a zero-maintainer package. Verify the declared Laravel and Filament constraints in composer.json against the application's versions, and confirm the Filament major matches before registering the plugin in a PanelProvider. Verify the vendor publish tags against the provider rather than trusting documentation, since documentation does not exist. The package's Blade helpers and any package Blade components should be treated as advisory; our own partial is the production renderer.

Sequencing

  1. Spike (time-boxed, ~1–2 days). Read composer.json, the service provider, the config, and the migrations in that order. Render a two-item menu end-to-end via the JSON driver. Create a parent with children, delete the parent, assert the child behavior. Confirm cache behavior on save.
  2. Wrapper and rendering. Define MenuRepository::tree($key), implement it, build the recursive Blade partial, add the cache-invalidation observer and the Gate-based visibility filter.
  3. Single surface rollout. Ship one admin panel's navigation behind the package. Run a full release cycle. Do not widen until that cycle is clean — two halves of the app pulling navigation from different sources is a debugging tax nobody wants.
  4. Second surface, then steady state. Add DB-backed runtime-editable menus (sidebars, footers) once the JSON path is proven. Budget the quarterly compatibility allowance from here.

This belongs in the MVP or internal-tooling phase. Adopting it late, onto a mature app with tenancy or permissions requirements, invites schema work that should have been a day-one decision.

Operational Impact

Maintenance Assume we are the first real adopter and tool accordingly. Mirror the repo internally (private VCS or path repository with an upstream remote), keep our patches as one commit per fix so upstream merges remain possible if the maintainer revives the project, and budget roughly one day per quarter for Laravel/Filament compatibility churn. That budget is not optional — if it is not allocated, the integration savings are illusory and the package becomes deferred cost.

Our own maintenance surface is small if disciplined: the wrapper interface, the Blade partial, the cache observer, and the visibility filter. Everything else should stay inside the three extension points.

Support There is no vendor support, no SLA, no security review process, and no community to speak of — zero stars and zero dependents means no de facto peer support either. Support is entirely internal: whoever integrates it owns it. That is acceptable for internal admin navigation and unacceptable for anything with an enterprise support requirement or a customer-facing revenue dependency. This must be stated explicitly rather than implied, so that no stakeholder later assumes an escalation path exists.

Scaling Technical scaling is not the concern — menus are small, cacheable, and resolved once per request. Resolve each menu key once, normalize to an array, cache it, and invalidate on save. The scaling questions that matter are organizational:

  • Surface count. Each additional navigation surface multiplies the driver-choice decision and the visibility-filter logic. Keep the wrapper as the single choke point.
  • Concurrency. Drag-and-drop ordering under two simultaneous admins can race if order is not stable. Worth an explicit test if multiple editors are expected.
  • Tenancy. If per-tenant navigation is on the roadmap within a year, the current schema almost certainly does not support it. That is a build signal, not a config toggle.

Failure modes Ranked by business impact:

  1. Hard 500 on navigation render. Highest severity, highest visibility, fastest to detect. Typically a missing migration, a bad config, or a missing JSON file.
  2. Stale menu after an edit. Silent and customer-facing. Second-worst because it looks like an editorial failure, not a technical one, and gets reported to the wrong team. Prevented only by our own cache-invalidation observer.
  3. Orphaned menu items after a parent delete. Invisible, un-routable links. Noticed weeks later when someone asks where a link went. Prevented by integrity tests written during the spike.
  4. Silent provider switch. Wrong env, missing JSON file, or unrun migration causes the app to render an empty or default menu.
  5. Admin edits written to an ephemeral filesystem. Container redeploy discards them; repo and runtime diverge silently.

Establish a debugging order and document it: (1) is_active, (2) parent reachable in the tree, (3) wrapper cache stale, (4) visibility/Gate filter hiding it, (5) provider switched. Expose the raw normalized tree on a debug route — that collapses most investigations to a minute.

Ramp-up Low for anyone comfortable with Laravel and Filament: the concepts are a tree, a driver switch, and a Blade render. The real ramp-up cost is discovery, because there is no documentation — the first engineer must read the source, and that knowledge should be captured as internal notes (schema behavior, provider semantics, cache behavior) rather than rediscovered.

Recommended onboarding sequence for the team: read the wrapper interface and Blade partial first, not the package; the package is an implementation detail behind them. New engineers should never need to open vendor code to change navigation. That is the operational test of whether the wrapper was worth building — and it is the same test that makes the exit cheap if upstream goes quiet.

Decision summary for stakeholders. Green-light for internal admin panels, back-office tools, MVP marketing sites, TomatoPHP/Filament-aligned apps, and JSON-seeded default navigation, with a private mirror, a pinned version, a wrapper interface, owned rendering, and a budgeted quarterly compatibility allowance. Block for multi-tenant CMS navigation, approval or versioning workflows, personalized or A/B-tested menus, headless delivery, enterprise support requirements, and any surface where a stale menu is a revenue event.

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