fsi/admin-bundle
FSi Admin Bundle is a Symfony bundle for building extensible admin panels. It offers CRUD screens, data grids, filtering, sorting, and configurable actions for Doctrine-backed entities, reducing boilerplate for PHP teams managing application data.
Framework reality check first. fsi/admin-bundle is a Symfony bundle, not a Laravel package. There is no service provider, no config/admin.php, no Eloquent integration, and no Laravel-aware pagination or validation. A Laravel developer has two realistic paths:
generator.yml conventions and CRUD scaffolding ideas, then build the equivalent with Filament, Nova, or a custom Laravel admin. Do not try to shoehorn the bundle into vendor/ of a Laravel app.If you go the Symfony route, minimal setup looks like:
composer require fsi/admin-bundle:^4.1
// config/bundles.php
return [
// ...
FSi\Bundle\AdminBundle\FSiAdminBundle::class => ['all' => true],
];
# config/routes/fsi_admin.yaml
fsi_admin:
resource: "@FSiAdminBundle/Resources/config/routing/admin.xml"
prefix: /admin
Then install assets (bin/console assets:install --symlink) and make sure your security firewall covers the /admin prefix. On a fresh Symfony 7 project you will be pulled to DoctrineBundle 3.x — that combination only resolves from 4.1.3 onward (see Gotchas).
Where to look first:
Resources/doc/ — the generator.yml reference is the real documentation; the README is thin.Controller/AdminController (or the equivalent base controller in your tagged version) — this is the class you extend.Resources/config/ — service wiring and the config tree, useful when a YAML key silently does nothing.generator.yml accepts.First use case: scaffold a list/edit/new/delete admin for a single Doctrine entity (e.g. Post) by dropping a generator.yml into the expected location and pointing a route at the generated admin. Get one entity working end-to-end before touching filters, batch actions, or custom templates.
Configuration-driven CRUD. The bundle is built around per-admin generator.yml files rather than PHP classes. A typical shape:
# src/AppBundle/Resources/config/admin/post.yml
params:
Title: Posts
config:
title: Posts
actions:
list: ~
new: ~
edit: ~
delete: ~
fields:
id:
formType: hidden
title:
formType: text
body:
formType: textarea
createdAt:
formType: datetime
list:
display: [id, title, createdAt]
sort: [createdAt, desc]
filters:
display: [title]
Treat this file as the schema for the admin screen. Most day-to-day work is editing this YAML, not writing controllers.
Extending the base controller. When YAML is not enough, subclass the provided admin controller and override individual actions (listAction, editAction, deleteAction). This is where you add domain-specific behavior — e.g. populating a slug on save, scoping queries to the current tenant, or redirecting to a custom route after edit. Keep overrides narrow; the base controller handles a lot of request/response plumbing that is easy to break.
Custom form types. Any field can point at a service-backed Symfony form type via formType. This is the clean extension point for entity pickers, dependent selects, file uploads, and rich-text editors. Register the form type as a service and reference it by FQCN or alias in generator.yml.
Template overrides instead of forking. To change layout, per-row rendering, or action buttons, shadow the bundle's Twig templates under templates/bundles/FSiAdminBundle/... (Symfony's standard override path). Avoid editing files inside vendor/. Useful override targets: the list row template, the form layout, and the actions block.
Batch and object actions. Define bulk operations in generator.yml and back them with an action method or action class. This is the pattern for exports, bulk status changes, and bulk delete. Route them through the same security checks as the rest of the admin — don't rely on the UI hiding the button.
Security integration. Authentication and roles are standard Symfony Security: firewall, access control on /admin, and per-action credentials in generator.yml. If you are sharing a database with a Laravel app, do not try to share sessions or password hashes unless both sides use compatible hashing — either run a separate admin login or put the admin behind your Laravel auth via a reverse proxy/SSO.
Integration tips for the shared-DB pattern:
--from-database or explicit mapping..env, cache, and log directory so debugging stays sane.It is Symfony-only — budget for that. The biggest pitfall is assuming Laravel compatibility. There is no Laravel adapter, and none is planned upstream. If your team is Laravel-heavy, the maintenance cost of a second framework runtime usually outweighs the time saved by the generator.
Version alignment: pin ^4.1.3 minimum. The 4.1.3 patch is a maintenance release (phpcs tooling bump, no runtime feature or API changes), but it contains one genuinely useful compatibility change: doctrine/doctrine-bundle is now allowed at ^3.0. On 4.1.2 and earlier you will hit an unsatisfiable dependency graph as soon as you are on DoctrineBundle 3.x, which is the default on a fresh Symfony 7 install. If you see a Composer conflict mentioning doctrine/doctrine-bundle, this is why — bump the bundle rather than downgrading Doctrine. Note there is still no release note about new Symfony majors, so verify symfony/framework-bundle, doctrine/orm, and PHP constraints against your Symfony minor before committing; mismatches surface as cryptic container compile errors, not friendly messages.
Project health is a risk. Low star count, very few dependents, and a long history of Symfony-version churn mean you should pin the bundle version (tight, with a committed composer.lock) and read the changelog of each patch before upgrading. Recent releases have been maintenance-only, which is reassuring for stability but also means no new features are landing.
YAML is silently forgiving. A misspelled key under config.fields often does nothing rather than throwing. Symptoms: a field missing from the form, a filter with no effect, an action button that never appears. Debug with bin/console debug:config (when the config tree is exposed) and by clearing the cache.
Cache is the usual suspect. Changes to generator.yml or routing are cached. After any config edit:
bin/console cache:clear
bin/console assets:install --symlink
If the admin still looks stale, check var/cache/ for the environment you're actually running (dev vs prod).
Field naming and getters. Field names in generator.yml must match what Doctrine/your entity exposes. Association fields are the common failure point — they usually need an explicit formType and may need allow_add/by_reference handling. If a relation renders as a raw ID input, the form type was not picked up.
Route and template naming drift. Overrides fail quietly if the bundle name, template path, or route prefix is wrong. Confirm the actual bundle name (FSiAdminBundle) and the exact template path in vendor/ before creating an override — a misplaced file simply won't be used.
Assets and CSS framework assumptions. The bundle's templates assume a particular Bootstrap-era markup. Mixing in a modern CSS framework will fight the existing classes. Either accept the default styling or override the layout templates wholesale rather than patching individual classes.
Debugging checklist when a screen 500s:
bin/console cache:clear and re-check.var/log/dev.log — the real exception is usually a missing service, a bad form type, or an unresolvable entity field.debug:router to confirm the admin route is registered.debug:container to confirm your custom form type/action service is public or correctly tagged.debug:mapping alternatives in your Doctrine version).Best extension points, in order of safety:
generator.yml (no code, easiest to review).Rule of thumb for a Laravel team: use this bundle only if you already operate a Symfony service and want generated admin screens fast. For a pure Laravel stack, the honest assessment is that fsi/admin-bundle is a reference, not a dependency — its generator.yml-driven CRUD model is worth borrowing conceptually, but the code itself will cost more to integrate than to reimplement.
How can I help you explore Laravel packages today?