symfony2admingenerator/generator-bundle
Symfony2AdminGenerator GeneratorBundle scaffolds customizable admin backends and CRUD interfaces for Symfony apps from YAML configuration, with templated forms, lists, filters, and Doctrine integration.
Before anything else, a reality check that shapes everything below: this is a Symfony 2 bundle, not a Laravel package. It has no service provider, no facade, no config/admin.php, and it will not autoload usefully into a Laravel app. It bootstraps off the Symfony 2 kernel, AppKernel, the app/console binary, and a directory layout (app/config/config.yml, src/Acme/Bundle/...) that Laravel developers will not recognise. So "leverage day-to-day" here means one of two scenarios: you have inherited or joined a Symfony 2 admin project, or you are studying it as a reference for code-generated admin panels while building the equivalent in Laravel (Filament/Nova/custom). Both are covered.
Minimal steps to get a running instance:
php:7.1-cli or php:5.6-apache image; do not try to run this on PHP 8.composer require symfony2admingenerator/generator-bundle (expect to pin a tagged release or a dev-* branch — the constraints are ancient).new Admingenerator\GeneratorBundle\AdmingeneratorGeneratorBundle() in app/AppKernel.php.app/config/config.yml under admingenerator_generator: — typically use_doctrine_orm: true (and use_propel: false, use_doctrine_odm: false).params, fields, and the list / filters / form / new / edit / show sections. This is the heart of the package.app/console admin:generate-admin AcmeAdminBundle:Post) and visit /admin for the module.Where to look first:
fields block and the per-action sections. Everything is driven from here; the PHP and Twig are output.Resources/config and Resources/templates (or Resources/views) — the generator reads Twig templates from here, and this is what you override.admin:generate-admin / admin:generate-bundle commands in Command/ — they tell you exactly where files land in your bundle.First use case: a single-entity CRUD admin (paginated list with filters, create/edit form, read-only show page) for a Doctrine entity. Then layer on object actions, batch actions, and credential checks once you trust the generation step.
If you are the Laravel developer evaluating this as inspiration: the idea worth copying is a single declarative YAML describing fields plus per-view field subsets, compiled into controllers/forms/templates. That maps cleanly onto Filament's Resource classes or a custom make:admin artisan command — but do not try to port the code.
Declarative resource definition. The generator YAML is effectively an admin resource class. You define the fields once and then narrow them per view:
params:
model_class: Acme\BlogBundle\Entity\Post
route_prefix: /admin/posts
fields:
title: { label: Title }
publishedAt: { label: Published, type: datetime }
author: { label: Author, type: many_to_one }
list:
display: [title, publishedAt, author]
actions: { new: ~, edit: ~, delete: ~ }
filters:
display: [title, publishedAt]
form:
display: [title, body, author, publishedAt]
Treat this file as source of truth and commit it. It is the only thing you should need to regenerate from.
Generate, then customise outward. The generator writes a base layer and a concrete layer into your bundle (a Controller/Admin/... base plus a thin concrete controller, plus templates). The intended pattern is: never edit the generated base — put your logic in the concrete controller and your markup in overridden Twig templates. If you edit base files, the next generation pass will stomp them.
Template overriding is the main extension mechanism. Override the bundle's Twig templates from your own bundle (or app/Resources/AdmingeneratorGeneratorBundle/...) and override individual blocks — list columns, form rows, show groups, action buttons. Because it is block-based Twig inheritance, you can restyle the whole admin without touching PHP. This is also how you swap Bootstrap versions or change the layout chrome.
Actions as configuration. Object actions and batch actions (delete, custom transitions, export) are declared per view with a route, label, and optional credentials. Use the credentials key rather than sprinkling isGranted checks in controllers — it keeps authorisation declarative and consistent with the generated templates, which already honour it when rendering buttons.
Security and menu integration. The bundle slots into the older Symfony admin stack: FOSUserBundle-style roles for credentials, KnpMenu for the admin sidebar, KnpPaginator for lists. Configure those once at the app level and the generated screens pick them up. Expect a session of wiring before the first screen feels coherent.
Regeneration workflow that survives review. Keep generation as a separate commit from customisation. When an entity changes: regenerate (accepting the diff on base files only), then re-apply any template overrides if the block names shifted. git diff on the generated output is a good smoke test for what the YAML change actually did.
Laravel-side analogy if you are porting the mental model. Map generator YAML → a PostResource class; list.display → table() columns; filters.display → table()->filters(); form.display → form() schema; actions → ->actions([...]); credentials → ->visible(fn () => Gate::allows(...)). The bundle's per-view field subsets are the part most home-grown Laravel admin panels get wrong — they usually share one schema across list and form, which forces awkward per-view closures.
fields entry or a duplicated key surfaces as a cache/runtime error far from the cause. After any YAML edit, run app/console cache:clear and, in dev, check app/logs/dev.log immediately — the stack trace usually names the generator file.app/cache and app/logs writable by the web user (the classic chmod -R 777 advice). Half the "blank page" reports on this stack are file permissions after a generate.route_prefix and the Admin bundle the generator writes into must already exist and be registered; generating into a non-registered bundle produces a working controller with unreachable routes.dump in dev and inspect which template block actually rendered (the profiler's Twig panel names the file and block). That answers "why is this button here" faster than reading the generator.app/console, Doctrine event system, the app/ directory) are load-bearing. Borrow the declarative-YAML-per-view idea; leave the implementation.How can I help you explore Laravel packages today?