modera/backend-dashboard-bundle
A backend dashboard bundle for Modera CMS that provides the administrative interface, menus, and layout scaffolding for building management panels and control screens.
Know what you're adopting first: modera/backend-dashboard-bundle is a Symfony bundle, not a Laravel package. It is the Ext JS–based backend "desktop" for Modera's MJR stack (it sits alongside mjr/core-bundle, modera/security-bundle, and friends). Last tagged release was June 2016 and the repo is archived, so treat it as a reference architecture or a legacy-maintenance dependency, not a live install.
Minimal steps for a legacy Symfony 2.x app that already uses MJR:
composer require modera/backend-dashboard-bundle — then immediately pin the exact version. Do not let a composer update float this, since its Symfony/Doctrine constraints are pinned to the 2.x era and will conflict with anything modern.AppKernel::registerBundles() after the MJR core and security bundles; the dashboard reads from their registries.app/console doctrine:migrations:migrate) — the dashboard persists per-user dashboard configuration.Where to look first, in this order:
Dashboard/ — the item contract (DashboardItemInterface / AbstractDashboardItem) and the provider/registry classes. This is the surface you actually code against.DependencyInjection/*Extension.php and Resources/config/services.xml — the config tree and, critically, the service tag name you must apply to your own widgets.Contributions/ — how the bundle feeds items, menu entries, and permissions into MJR.Resources/public/js — the Ext JS base class your front-end widget extends.First use case: add a "This week's signups" widget to the backend home screen, visible only to users holding a given role, backed by a route that returns the count. That exercises all three layers you'll touch daily: PHP provider → service tag → JS widget class.
The two-layer widget pattern. Every dashboard item is a PHP/JS pair:
AbstractDashboardItem), exposing an id, a label, an icon, a permission/role requirement, and the route or content it renders. Tag it with the tag name found in services.xml and give it a priority — that's what controls ordering.Prefer contributions over config edits. MJR's model is that bundles contribute to registries (Contributions/ classes) rather than editing vendor YAML. Follow it: add menu entries, permission definitions, and item registrations as contribution services so ordering is deterministic and nothing is lost on a cache rebuild.
Per-user state is the bundle's job, not yours. Don't build your own "which widgets does this user see" table — the bundle already persists dashboard layout/settings per user. Your item just declares defaults; the user customizes on top.
Integration tips that pay off daily:
curl and swappable later.config/*.php. The equivalents are bundle registration, Doctrine entities, Twig/Ext JS, and a semantic config tree. A Laravel "port" means re-implementing the registry and per-user settings from scratch — usually cheaper than translating this code.public: true in an old Symfony version means your widget simply never appears, with no error. Debug with app/console debug:container --tag=<tag> and confirm your service is in the compiled container before you touch JS.cache:clear (and in dev, cache:warmup) before concluding it's broken.Extension classes for defaults, contributions for registrations, and the item provider interface for anything dynamic (e.g., items only valid in certain contexts). These are the seams that let you avoid forking the bundle — use them, because a fork of an archived bundle is a permanent tax.How can I help you explore Laravel packages today?