kachnitel / admin-bundle
Modern Symfony admin bundle powered by LiveComponents for Doctrine entities with extensive customization
Package info
github.com/kachnitel/FrdAdminBundle
Type:symfony-bundle
pkg:composer/kachnitel/admin-bundle
Requires
- php: >=8.4
- doctrine/doctrine-bundle: ^3.0
- doctrine/orm: ^3.5
- kachnitel/datasource-contracts: ^0.1.0
- kachnitel/dynamic-form-bundle: ^0.1.0
- kachnitel/entity-components-bundle: ^0.0.3
- symfony/expression-language: ^6.4|^7.0|^8.0
- symfony/form: ^6.4|^7.0|^8.0
- symfony/framework-bundle: ^6.4|^7.0|^8.0
- symfony/property-info: ^6.4|^7.0|^8.0
- symfony/security-bundle: ^6.4|^7.0|^8.0
- symfony/serializer: ^6.4|^7.0|^8.0
- symfony/twig-bundle: ^6.4|^7.0|^8.0
- symfony/ux-autocomplete: ^3.0
- symfony/ux-live-component: ^2.13
- symfony/ux-twig-component: ^2.13
- symfony/validator: ^6.4|^7.0|^8.0
- twig/twig: ^3.15
Requires (Dev)
- brianium/paratest: ^7.23
- friendsofphp/php-cs-fixer: ^3.51
- marcocesarato/php-conventional-changelog: dev-main
- phpmd/phpmd: ^2.12
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-symfony: ^2.0
- phpunit/phpunit: ^13.0
- rector/rector: ^2.5
- smnandre/twigmetrics: ^1.1
- symfony/browser-kit: ^6.4|^7.0|^8.0
- symfony/console: ^6.4|^7.0|^8.0
- symfony/css-selector: ^6.4|^7.0|^8.0
- symfony/stimulus-bundle: ^2.31
- symfony/var-exporter: ^6.4|^7.0|^8.0
- symfony/webpack-encore-bundle: ^2.4
- symfony/yaml: ^6.4|^7.0|^8.0
Suggests
- kachnitel/entity-components-bundle: For attachment, tag, and comment features
README
A modern Symfony admin bundle powered by LiveComponents. Add the #[Admin] attribute to your entity and get a full CRUD interface with search, filters, pagination, and batch actions.
Why another admin bundle?
#### MotivationI have struggled with keeping my controllers DRY as my applications grew. All my attempts at solving the issue eventually timed perfectly with Live Components growing up into a mature and stable UX system. This bundle is the result of my attempts at previous reusable tables and admin generators, rebuilt on top of Live Components at its core.
While there's excellent admin bundles out there, I felt like defining their configuration replaced my controller problem with a new "configuration problem". I wanted something that was easy to get started with, non-repetitive, but also flexible enough to handle complex use cases while leaning on established patterns.
By leveraging Symfony UX, I was able to create a bundle that provides an admin interface with minimal boilerplate, while still allowing for deep customization through Twig templates and your own components.
Quick Start
1. Install
composer require kachnitel/admin-bundle
2. Add attribute to any entity
use Kachnitel\AdminBundle\Attribute\Admin; #[Admin] class Product { // Your existing entity... }
3. Visit /admin
Your entity appears with auto-detected columns, search, filters, and CRUD.
Manual setup (if not using Symfony Flex)
- Enable the bundle in
config/bundles.php, along its two dependency bundles:
Kachnitel\DynamicFormBundle\KachnitelDynamicFormBundle::class => ['all' => true], Kachnitel\EntityComponentsBundle\KachnitelEntityComponentsBundle::class => ['all' => true], Kachnitel\AdminBundle\KachnitelAdminBundle::class => ['all' => true],
- Import routes in
config/routes/kachnitel_admin.yaml:
kachnitel_admin: resource: '@KachnitelAdminBundle/config/routes.yaml' prefix: /admin
- Create config in
config/packages/kachnitel_admin.yaml:
kachnitel_admin: base_layout: 'base.html.twig' # Your app's base template
- Add assets to your controllers.json (AssetMapper) or import them in your main JS file (Webpack Encore). See Assets Guide for details.
What's Next?
Control Your Columns
Level 1: Auto-detection (zero config) - all properties shown automatically
Level 2: Specify columns and order:
#[Admin(columns: ['id', 'name', 'price'])]
Or exclude: excludeColumns: ['costPrice']
Level 3: Role-based visibility:
#[ColumnPermission('ROLE_HR')] private float $salary;
Level 4: User-toggleable:
#[Admin(enableColumnVisibility: true)]
Details: Configuration Guide | Column Visibility
Customize the Look
Level 1: Use your layout:
kachnitel_admin: base_layout: 'base.html.twig'
Level 2: Switch theme (Bootstrap/Tailwind):
kachnitel_admin: theme: '@KachnitelAdmin/theme/tailwind.html.twig'
Level 3: Override type templates:
templates/bundles/KachnitelAdminBundle/types/datetime/_preview.html.twig
Level 4: Entity-specific:
templates/bundles/KachnitelAdminBundle/types/App/Entity/Product/price.html.twig
Details: Template Overrides Guide
Add Custom Row Actions
Level 1: Route-based link, always visible:
#[AdminAction(name: 'duplicate', label: 'Duplicate', route: 'app_product_duplicate')]
Level 2: With a condition (expression):
#[AdminAction(name: 'approve', label: 'Approve', condition: 'entity.status == "pending"')]
Level 3: With a condition (service logic) and confirmation:
#[AdminAction(
name: 'refund',
label: 'Refund',
method: 'POST',
condition: [RefundService::class, 'canRefund'],
confirmMessage: 'Refund this order?',
)]
Level 4: Remove or replace default Show/Edit:
#[AdminActionsConfig(exclude: ['edit'])] #[AdminAction(name: 'show', label: 'Preview', icon: '🔍', override: true)]
Details: Row Actions Guide
Auto-Generated Forms
Level 1: Zero config — every #[Admin] entity gets New/Edit forms automatically, powered by kachnitel/dynamic-form-bundle:
#[Admin(label: 'Products')] class Product { } // Visit /admin/product/new — fields generated from Doctrine metadata, no FormType written
Level 2: Hand-written FormType (conventional naming, auto-discovered):
// src/Form/ProductFormType.php class ProductFormType extends AbstractType { /* ... */ }
Level 3: Custom LiveComponent for extra behaviour (collection management, computed fields):
#[AsLiveComponent(name: 'App:Form:PurchaseOrder')] final class PurchaseOrderForm extends AdminEntityForm { /* ... */ }
Level 4: Control which fields appear:
#[AdminColumn(editable: false)] // exclude from the form #[AdminColumn(editable: 'entity.status != "locked"')] // conditional
Details: Forms Guide
Archive / Soft-Delete Filtering
Level 1: Point at a boolean field — the list hides archived rows by default, with a toggle to reveal them:
#[Admin(label: 'Products', archiveExpression: 'item.isArchived()')] class Product { private bool $archived = false; public function isArchived(): bool { return $this->archived; } }
Level 2: Nullable-datetime (soft-delete pattern):
#[Admin(archiveExpression: 'item.getDeletedAt()')] class Order { private ?\DateTimeImmutable $deletedAt = null; public function getDeletedAt(): ?\DateTimeImmutable { return $this->deletedAt; } }
Level 3: Global default for all entities + role-gate the toggle:
kachnitel_admin: archive: expression: 'item.getDeletedAt()' role: 'ROLE_ADMIN'
Level 4: Opt out per entity when a global is configured:
#[Admin(label: 'Categories', archiveDisabled: true)]
Details: Archive Guide
Features
Core
- Easy start - Add
#[Admin]to entity, auto-detects columns - Auto-Generated Forms - Zero-config create/edit forms from Doctrine metadata via
kachnitel/dynamic-form-bundle, including associations and collections; drop in a hand-written FormType any time you need more control - Highly Customizable - From cell level templates to entire layout overrides using Symfony's Twig inheritance
- LiveComponent-Powered - Real-time search, filters, and updates without full page reloads
Advanced — opt in per entity
- Multi-Layer Permissions - Entity, action, and column-level control
- Row Actions — Per-row buttons with conditions, permissions, and priority ordering; extend defaults or replace them
- Inline Editing - Edit any field in-place, with type-aware inputs and per-column permission guards
- Archive / Soft-Delete — Hide archived rows by default with a live toggle; works with boolean flags and nullable-datetime fields; no Doctrine filter needed
- Column Visibility - Show/hide columns with session or database-backed preferences
- Composite Columns — Group related properties into a single stacked table cell with
#[AdminColumn(group: '...')] - DataSource Abstraction - Display data from external APIs, audit logs, or any source via
kachnitel/datasource-contracts
Documentation
Getting Started
| Guide | Description |
|---|---|
| Configuration | Entity attributes and bundle config |
| Filters | Automatic filtering and customization |
| Forms | Auto-generated and custom create/edit forms |
| Template Overrides | Customize the admin appearance |
Customizing Behavior
| Guide | Description |
|---|---|
| Row Actions | Custom action buttons per row — conditions, ordering, providers |
| Batch Actions | Multi-select and bulk operations |
| Archive | Soft-delete / archive filtering with show/hide toggle |
| Custom Columns | Virtual, template-driven columns not backed by a Doctrine field |
Advanced
| Guide | Description |
|---|---|
| Inline Editing | Per-field in-place editing in list views |
| Inline Add | Create related entities without leaving the current form |
| Composite Columns | Group related properties into one stacked table cell |
| Column Visibility | Permissions and user preferences |
| DataSource | Non-Doctrine data sources |
| Entity URLs | Link to related entities' admin pages from your own templates |
Project
| Guide | Description |
|---|---|
| Assets | AssetMapper and Webpack Encore setup |
| Development | Contributing and running tests |
| Upgrade Guide | Migrating between major versions |
How does this compare to EasyAdmin?
EasyAdmin and SonataAdmin use PHP configuration, while this bundle leans heavily on a single Live Component with Twig templates for customization. This allows for real-time UI updates, and separates configuration (security, columns) from presentation (templates).
Full comparison - philosophy, features, and when to choose each.
Requirements
- PHP 8.4 or higher
- Symfony 6.4 / 7.0 / 8.0
- Doctrine ORM 3.5+
kachnitel/datasource-contracts(pulled automatically by Composer)kachnitel/dynamic-form-bundle(pulled automatically by Composer — licensed MPL-2.0, a file-level copyleft compatible with this bundle's MIT license and with closed-source deployments)
License
MIT License - see LICENSE file for details.