kachnitel/admin-bundle

Modern Symfony admin bundle powered by LiveComponents for Doctrine entities with extensive customization

Maintainers

Package info

github.com/kachnitel/FrdAdminBundle

Type:symfony-bundle

pkg:composer/kachnitel/admin-bundle

Transparency log

Statistics

Installs: 474

Dependents: 1

Suggesters: 1

Stars: 5

Open Issues: 5

0.13.1 2026-08-25 16:35 UTC

README

Tests Coverage Assertions PHPStan PHPMD Code Style Vitest PHP Symfony

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? #### Motivation

I 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)
  1. 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],
  1. Import routes in config/routes/kachnitel_admin.yaml:
kachnitel_admin:
    resource: '@KachnitelAdminBundle/config/routes.yaml'
    prefix: /admin
  1. Create config in config/packages/kachnitel_admin.yaml:
kachnitel_admin:
    base_layout: 'base.html.twig'  # Your app's base template
  1. 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.