Crudl Bundle
softspring/crudl-bundle is the Symfony bundle layer for softspring/crudl-controller.
Use crudl-controller when you want the lower-level action flow and you are happy wiring controllers and helpers yourself.
Use crudl-bundle when you want to declare those controllers in Symfony configuration and get a working admin-style CRUDL setup faster.
What This Package Adds
The bundle adds four practical things on top of crudl-controller:
- controller services generated from configuration
- default forms for simple create, update, delete, and list screens
- default Twig templates for CRUDL screens
- a dynamic controller argument resolver so config-based action names work like normal controller methods
That makes it useful for internal backoffices, admin panels, and repeated CRUDL sections where the flow is similar and the project wants less boilerplate.
When To Use It
This bundle is a good fit when:
- the application has many admin sections with the same CRUDL pattern
- each section needs small variations, not a totally different controller architecture
- you want fast setup with the option to override forms, templates, and events later
Typical examples:
- products
- customers
- orders
- invoices
- CMS blocks
- media or user administration
Installation
composer require softspring/crudl-bundle:^6.0
Enable the bundle if your application does not use Symfony Flex automatic registration.
Main Idea
You declare controllers under sfs_crudl.controllers.
Each configured controller:
- points to a manager or an entity class
- defines one or more actions
- can use the built-in defaults or override them
The bundle then registers a Symfony controller service for that section and routes can call it in different ways.
Quick Start
Minimal example:
# config/packages/sfs_crudl.yaml
sfs_crudl:
controllers:
products:
entity_manager: App\Manager\ProductManager
default_view_path: 'admin/product'
default_entity_attribute: 'product'
actions:
list_products:
action: list
is_granted: 'PRODUCT_LIST'
filter_form: App\Form\Admin\ProductListFilterForm
create_product:
action: create
is_granted: 'PRODUCT_CREATE'
read_product:
action: read
param_converter_key: 'id'
update_product:
action: update
param_converter_key: 'id'
is_granted: 'PRODUCT_UPDATE'
delete_product:
action: delete
param_converter_key: 'id'
is_granted: 'PRODUCT_DELETE'
With that configuration the bundle can generate the controller service and the missing default event names and templates.
Define The Manager
You can define a CRUDL controller in two main ways.
Option 1: Use A Manager Service
This is the most flexible and the most common approach.
sfs_crudl:
controllers:
products:
entity_manager: App\Manager\ProductManager
actions:
list_products:
action: list
Use this when:
- the application already has a custom manager
- entity loading or persistence needs custom logic
- the package works with interfaces or reusable model contracts
Option 2: Use An Entity Class
For simple Doctrine screens you can let the bundle create the default manager for you.
sfs_crudl:
controllers:
products:
entity_class: App\Entity\Product
actions:
list_products:
action: list
Use this when:
- the screen is straightforward
- the default Doctrine manager behavior is enough
- you want the shortest possible setup
Route Patterns
The bundle supports three route styles for the same configured action.
1. Generic Controller Entry Point
admin_products_list:
controller: sfs_crudl.controller.products
path: /admin/products
defaults:
configKey: 'list_products'
2. Specific Action Method
admin_products_list:
controller: sfs_crudl.controller.products::list
path: /admin/products
defaults:
configKey: 'list_products'
3. Dynamic Action Name
admin_products_list:
controller: sfs_crudl.controller.products::list_products
path: /admin/products
The third form is the most convenient when route names map directly to configured action names. The bundle argument resolver exists mainly to make this pattern work cleanly with Symfony.
Defaults The Bundle Adds
The main value of the bundle is not only service registration. It also fills in useful defaults.
Default Event Names
If you do not configure an event name, the bundle creates one automatically with this pattern:
sfs_crudl.<controller>.<action>.<event>
Example:
sfs_crudl.products.list_products.view
That gives you a stable naming scheme for listeners without writing every event name by hand.
Default Templates
If an action supports a view and you do not configure view, the bundle tries this order:
<default_view_path>/<action-name>.html.twig- the built-in template from
@SfsCrudl/crudl/...
For list actions it also sets a default view_page:
@SfsCrudl/crudl/list-page.html.twig
This is useful when you want:
- one common admin layout
- one per-entity page partial for rows
- very little boilerplate at the beginning
Default Forms
If you do not configure forms explicitly:
createandupdateuseDefaultEntityFormdeleteuses the default delete form fromcrudl-controllerlistusesDefaultFilterForm
That makes the bundle useful for quick admin prototypes and simple internal tools.
Action Types
The bundle supports the same main action types as the underlying controller package, but with Symfony config defaults.
List
Use list for paginated result pages with a filter form.
Interesting options:
filter_formviewview_pageread_routeis_grantedfilter_event_name
Good fit for:
- admin tables
- dashboards with filters
- management lists with sortable columns
Create And Update
Use create and update when the screen is mainly form-driven.
Interesting options:
formviewentity_attributesuccess_redirect_toform_prepare_event_nameapply_event_name
Good fit for:
- standard backoffice edit screens
- content editing
- simple onboarding flows
Read
Use read for detail pages.
Interesting options:
entity_attributeparam_converter_keyviewfound_event_name
Delete
Use delete when the application wants an explicit confirmation form and the normal CRUDL delete flow.
Apply
Use apply when the action changes an entity but is not a classic edit form.
Examples:
- mark as reviewed
- duplicate a record
- trigger a sync
- confirm a pending state
Transition
Use transition when the application already uses Symfony Workflow and the admin action should execute one named transition.
Interesting options:
workflow_nametransition_attributeparam_converter_keyviewsuccess_redirect_to
This is one of the places where the bundle saves the most repetitive wiring compared to using crudl-controller directly.
Default Forms In Practice
The default forms are useful, but they are intentionally simple.
DefaultEntityForm
DefaultEntityForm builds a form from Doctrine field and association metadata.
It is useful when:
- the entity is simple
- the admin form is internal
- you want a quick first screen before replacing it with a custom form
Replace it with your own form when:
- labels, widgets, or validation need more control
- associations need custom query logic
- the form should not expose every editable field
DefaultFilterForm
DefaultFilterForm extends the paginator form and builds filters from entity properties.
It is useful when:
- you want a basic list filter fast
- string properties should behave like simple search inputs
- you are happy with a generic admin filter UI
Replace it when:
- your filters need domain language
- you want custom operators
- joins or complex filtering matter
Templates And UI Integration
The built-in templates are intentionally thin. They are there to give a working screen, not to define a final product UI.
The default list template expects:
- a paginated collection
- a filter form
table_columns- a page partial referenced by
view_page
The default create, update, and delete templates render the form with a simple layout. That is enough for internal tools, but most real applications will override them.
Case 1: Fast Internal Admin Screen
Imagine an internal admin for Product.
You can start with:
entity_class: App\Entity\Product- default forms
- default templates
- a custom
default_view_path
That gives you a working CRUDL section quickly.
Later you can replace only the parts that need more control:
- a custom list filter form
- a custom update form
- a custom page partial for the list rows
- listeners for success and failure events
This is the common “start simple, specialize later” workflow the bundle is built for.
Case 2: Reusable Bundle Admin Area
In reusable bundles, crudl-bundle becomes more interesting when paired with:
- a manager service
doctrine-target-entity-resolverpermissions-bundlecrudl-controllerevents
The package can expose a configurable admin section without forcing the final entity class to live inside the bundle itself.
Extending Safely
The safest extension points are:
- your own manager service
- custom forms
- custom templates
- custom event listeners
- explicit action configuration overrides
That is usually better than forking the bundle defaults, because the project keeps the common action flow while changing only the parts that matter.
Relationship With Crudl Controller
crudl-controller is still the core engine.
crudl-bundle should be seen as:
- the Symfony config and DX layer
- the shortcut for default forms and templates
- the faster option when you want many similar backoffice sections
If a project needs very custom flow control, the answer is often:
- keep
crudl-controller - stop relying on some
crudl-bundledefaults - wire the advanced parts manually
Limits
This bundle is most useful when the CRUDL shape is still recognizable.
Once the screen becomes too custom, the bundle still helps with events and base flow, but the default forms and templates stop being the main value.
That is normal. The bundle is meant to reduce boilerplate, not to replace deliberate controller and UI design when the domain becomes more specific.