Download the PHP package chamber-orchestra/cms-bundle without Composer
On this page you can find all versions of the php package chamber-orchestra/cms-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download chamber-orchestra/cms-bundle
More information about chamber-orchestra/cms-bundle
Files in chamber-orchestra/cms-bundle
Package cms-bundle
Short Description Symfony 8 bundle providing a full-featured CMS admin panel — trait-based CRUD operations, DTO↔entity sync, CSV export, sortable lists, soft delete, copy/move, toggle, and Bootstrap 5 admin UI
License Apache-2.0
Informations about the package cms-bundle
ChamberOrchestra CMS Bundle
A Symfony 8 bundle that provides a full-featured CMS admin panel built around trait-based CRUD composition. Controllers opt into exactly the operations they need — list, create, update, delete, copy, move, toggle, export, and meta — by mixing in the corresponding Supports*Operation traits.
Requirements
- PHP ^8.5
- Symfony ^8.0
- Doctrine ORM ^3.0
Installation
Register the bundle in config/bundles.php:
Core Concepts
Trait-based CRUD composition
Every admin controller extends AbstractCrudController and mixes in the operations it needs:
Shortcut traits are available for common combinations:
| Trait | Includes |
|---|---|
SupportsCudOperation |
Create + Update + Delete |
SupportsLcudOperation |
List + Create + Update + Delete |
Available operations
| Trait | Route suffix | Description |
|---|---|---|
SupportsListOperation |
index |
Paginated, filterable, sortable list |
SupportsCreateOperation |
create |
Create new entity via DTO form |
SupportsUpdateOperation |
update |
Edit existing entity |
SupportsDeleteOperation |
delete |
Hard or soft delete |
SupportsCopyOperation |
copy |
Clone entity (resets id, slug, enabled) |
SupportsMoveOperation |
move |
Reorder sortable entities |
SupportsToggleOperation |
toggle |
Toggle enabled/disabled flag |
SupportsExportOperation |
export |
Export filtered list as CSV |
SupportsUpdateMetaOperation |
meta |
Edit SEO meta fields |
Controller options
The $options array passed to the constructor drives all behaviour. Every option is resolved through CrudControllerConfigurator (powered by Symfony's OptionsResolver), so defaults are applied, types validated, and values normalised automatically.
Options reference
Core options
| Option | Type | Default | Description |
|---|---|---|---|
class |
string (class-string) |
required | FQCN of the managed entity |
controller_class |
string (class-string) |
required | FQCN of the controller. Auto-set by AbstractCrudController::resolve() to static::class |
translation_domain |
string |
'cms' |
Symfony translation domain for all labels |
Parent / hierarchy options
| Option | Type | Default | Description |
|---|---|---|---|
parent_controller_class |
?string |
null |
FQCN of a parent AbstractCrudController for hierarchical CRUD |
parent_controller |
?object |
null |
Auto-resolved from parent_controller_class via the controllers service locator. Do not set manually |
parent |
?object |
null |
The parent entity instance (for nested CRUD views). When set, its getId() is added to route_params |
_parent |
null\|object\|callable\|string |
null |
Determines how to extract the parent entity from a child. string — name of a property on the child entity (resolved via reflection). callable — fn(object $entity): ?object. object — used directly. null — auto-detected by matching the parent controller's entity class against the child entity's property types |
Entity label options
| Option | Type | Default | Description |
|---|---|---|---|
entity_label |
?callable |
auto | A callable(object $entity): ?string that returns the display label for an entity. Default tries __toString(), then reads name, title, or id properties via reflection. The result is passed through strip_tags() |
label_format |
?string |
null |
Symfony form label format passed to form types |
Form & DTO options
| Option | Type | Default | Description |
|---|---|---|---|
form_class |
?string |
'' |
Symfony FormType FQCN for create/update forms |
data_class |
callable\|string\|null |
null |
DTO class or factory. string — class-string implementing DtoInterface; instantiated via Instantiator with ['entityClass' => ..., 'parent' => ...]. callable — fn(string $entityClass, array $options): DtoInterface. null — no DTO |
form_themes |
array |
['@ChamberOrchestraCms/form/horizontal.html.twig', '@ChamberOrchestraFile/cms/form/horizontal.html.twig'] |
Twig form themes applied to all forms |
Routing options
| Option | Type | Default | Description |
|---|---|---|---|
route_prefix |
?string |
auto | Base route name for all actions. Auto-detected from #[Route] attribute's name parameter, or derived as cms_{snake_entity_name} if unset. Trailing _ is stripped |
route_params |
array |
[] |
Additional route parameters merged into every action's route_params. When parent is set, ['parent' => $parent->getId()] is appended automatically |
View / template options
| Option | Type | Default | Description |
|---|---|---|---|
view_prefix |
?string |
null |
Base path for Twig templates. When null, defaults to @ChamberOrchestraCms/crud/. When set, templates are resolved as {view_prefix}/{action}.html.twig |
view_params |
array |
[] |
Extra template variables merged into every action's view params. Auto-populated with class, parent, title, label_format, translation_domain, form_themes |
title |
?string |
auto | Human-readable title for the managed entity (used in breadcrumbs, nav). Default: short class name extracted from class (e.g. App\Entity\Article becomes Article) |
Navigation options
| Option | Type | Default | Description |
|---|---|---|---|
nav |
null\|bool\|callable\|string |
null |
Sidebar navigation customisation. false — disables nav entirely. callable — fn(MenuBuilder $builder, ?object $entity, array $options) for custom items. string — FQCN of a navigation class (instantiated automatically). null — default nav (index, export, create + update/meta for existing entities) |
breadcrumbs |
null\|bool\|callable\|string |
null |
Breadcrumb customisation. false — disables breadcrumbs. callable — fn(Breadcrumbs $crumbs, array $options). string — FQCN instantiated automatically. null — default breadcrumbs based on current action |
Index (list) options
The index key accepts an array of sub-options that configure the list page:
| Option | Type | Default | Description |
|---|---|---|---|
index.fields |
?array |
[] |
Column definitions for the list table. Accepts several formats (see Fields format below) |
index.actions |
?callable |
null |
Row-level action buttons. fn(MenuBuilder $builder, object $entity, ?object $parent): void |
index.filter |
?string |
null |
FQCN of a FormTypeInterface subclass for the list filter form |
index.filter_mapping |
array |
[] |
Maps filter form field names to DQL expressions. String values rename the field; callables receive (QueryBuilder $qb, mixed $value) for full control |
index.query_builder |
QueryBuilder\|Closure\|null |
null |
Custom query builder for the list. Closure — fn(EntityRepository $repo): QueryBuilder. QueryBuilder — used directly. null — default $repo->createQueryBuilder('r') |
index.order_by |
array |
[] |
Default sort order, e.g. ['createdAt' => 'DESC'] |
index.order_by_mapping |
?array |
[] |
Fields allowed for column sorting. Auto-generated from index.fields by default; fields named image, video, preview, prefixed with !, or containing . without a callable are excluded. Set false for a field to explicitly exclude it |
index.export |
?array |
[] |
Export field configuration |
index.alias |
?array |
[] |
Field aliases for the list view |
index.bulk_operation |
bool |
true |
Whether to show bulk operation checkboxes |
index.bulk_nav |
?callable |
null |
Custom bulk operation navigation. fn(MenuBuilder $builder, array $options): void. Auto-disabled when bulk_operation is false |
index.view |
string |
'{view_prefix}/index.html.twig' |
Template for the list page |
index.view_params |
array |
[] |
Extra template variables (auto-merged with fields, actions, alias) |
index.route |
string |
'{route_prefix}_index' |
Route name |
index.route_params |
array |
inherited | Route parameters |
index.title |
?string |
null |
Title override for breadcrumbs/nav |
Fields format
The index.fields option supports multiple formats:
When processed, each field is normalised to ['field_name' => ['format' => ..., 'transform' => [...]]]. Callable values in a numeric-keyed position are collected under the transform key.
Action options
Actions are divided into two groups: actions with views (have template + route) and actions without views (route only).
Set any action to null to disable it entirely.
Actions with views
create, update, view, meta, export — each accepts null to disable, or an array with these sub-options:
| Sub-option | Type | Default | Description |
|---|---|---|---|
title |
?string |
null |
Title override. Can contain nested keys for context: ['breadcrumbs' => '...', 'nav' => '...'] |
view |
string |
'{view_prefix}/{action}.html.twig' |
Twig template path |
view_params |
array |
inherited from top-level view_params |
Template variables |
route |
string |
'{route_prefix}_{action}' |
Route name |
route_params |
array |
inherited from top-level route_params |
Route parameters |
Actions without views
delete, bulk_delete, move, toggle, copy — each accepts null to disable, or an array:
| Sub-option | Type | Default | Description |
|---|---|---|---|
route |
string |
'{route_prefix}_{action}' |
Route name |
route_params |
array |
inherited from top-level route_params |
Route parameters |
bulk_delete is automatically disabled when index.bulk_operation is false.
Full example
DTO ↔ Entity sync
CrudUtils::sync(object $source, object $target) copies values between two objects by property-name intersection using reflection:
- Scalar properties — copied when source ≠ target value
- Collections / associations — items added/removed to reconcile source into target
DtoInterface-typed properties — recursively syncedMetaInterfacetargets — auto-populates emptymetaTitle,metaDescription,metaImagefrom sibling properties
Events
Each mutating operation dispatches events in order:
| Operation | Events dispatched |
|---|---|
create() |
CreateEvent → SyncEvent → PostSyncEvent |
update() |
UpdateEvent → SyncEvent → PostSyncEvent |
delete() |
DeleteEvent → SyncEvent → PostSyncEvent |
All events extend AbstractEvent and expose getEntity() and getClassMetadata(). SyncEvent also exposes getDto().
Every mutating operation is wrapped in an explicit beginTransaction() / commit() / rollback().
Soft delete
If an entity implements SoftDeleteInterface, CrudProcessor::delete() calls $entity->delete() instead of EntityManager::remove(), leaving the row in the database:
DTOs
DTOs must implement DtoInterface (provides getId(): ?Uuid and getEntityClass(): string). The abstract AbstractDto handles the entity class resolution automatically:
List filtering & sorting
FilterHelper and SortHelper translate simple arrays into Doctrine QueryBuilder clauses:
Both helpers support callable and string mappings to rename or override fields:
Frontend assets (Vite)
The bundle ships SCSS + JS source files under Resources/assets/. You build them yourself so you can customise variables and override styles.
Setup with pentatrion/vite-bundle
Install the Symfony integration and the required plugins:
Register a dedicated CMS build in config/packages/pentatrion_vite.yaml:
Create vite.cms.config.js in your project root:
Add scripts to package.json:
Include assets in the admin base template using the vite() Twig helper:
Customising Bootstrap 5 variables — create your own SCSS file that overrides variables before importing the bundle's
_init.scss:
Twig integration
The bundle registers Twig extensions under the @ChamberOrchestraCms namespace. Admin views extend @ChamberOrchestraCms/base.html.twig and use the Bootstrap 5 form theme at @ChamberOrchestraCms/form/layout.html.twig.
CSV export
When SupportsExportOperation is used, the filtered list can be exported as CSV via CsvGenerator. The export respects the same filter and mapping configuration as the list action.
Testing
Integration tests require a PostgreSQL database. By default the test kernel connects to a local socket database named cms_bundle_test. Override with:
License
Apache License 2.0. See LICENSE for details.
All versions of cms-bundle with dependencies
chamber-orchestra/breadcrumbs Version 8.0.*
chamber-orchestra/doctrine-clock-bundle Version 8.0.*
chamber-orchestra/doctrine-extensions-bundle Version 8.0.*
chamber-orchestra/doctrine-sort-bundle Version 8.0.*
chamber-orchestra/file-bundle Version 8.0.*
chamber-orchestra/form-bundle Version 8.0.*
chamber-orchestra/image-bundle Version 8.0.*
chamber-orchestra/menu-bundle Version 8.0.*
chamber-orchestra/meta Version 8.0.*
chamber-orchestra/metadata-bundle Version 8.0.*
chamber-orchestra/pagination-bundle Version 8.0.*
doctrine/collections Version ^2.0
doctrine/orm Version ^3.0
symfony/event-dispatcher Version 8.0.*
symfony/form Version 8.0.*
symfony/framework-bundle Version 8.0.*
symfony/http-foundation Version 8.0.*
symfony/http-kernel Version 8.0.*
symfony/options-resolver Version 8.0.*
symfony/property-access Version 8.0.*
symfony/routing Version 8.0.*
symfony/string Version 8.0.*
symfony/twig-bridge Version 8.0.*
symfony/twig-bundle Version 8.0.*
symfony/uid Version 8.0.*
symfony/yaml Version 8.0.*
twig/html-extra Version ^3.23