lin3s/admin-ddd-extensions-bundle
Lin3s Admin DDD Extensions Bundle offers reusable Symfony components and conventions for building admin interfaces around domain-driven design applications, extending admin tooling with DDD-friendly abstractions and integration helpers.
The package is a thin glue layer between LIN3S Admin (lin3s/admin-bundle) and a DDD-style application layer. Its job is to let an admin CRUD screen talk to a command bus for writes and query/read models for reads, instead of letting the admin controller persist Doctrine entities directly. Treat it as an adapter, not a framework.
Minimal steps:
composer require lin3s/admin-ddd-extensions-bundle
You will already need lin3s/admin-bundle, a command bus (Tactician/SimpleBus were the 2017-era choices), and a Doctrine setup for the read side. Register the bundle in AppKernel (this predates Symfony Flex, so there is no recipe and no auto-registration):
new LIN3S\AdminDDDExtensionsBundle\LIN3SAdminDDDExtensionsBundle(),
Where to look first, in this order:
DependencyInjection/Configuration.php — the bundle alias and every config key. This is the ground truth for how it wires itself; read it before assuming service IDs.Controller/ — the base resource/CRUD controller(s) you are meant to extend. This is where the "dispatch a command instead of flushing an entity" contract lives.Resources/config/services.xml — which services are public, which are abstract, and what the bus service alias is expected to be.Form/ or Form/Handler/ — how form submissions are translated into commands.First use case: take an existing LIN3S Admin resource (say Product), subclass the bundle's resource controller, and route its create/edit/delete actions through your command bus while list/show render projections read from a query service. The payoff is that the admin controller never references an EntityManager, and your write model stays behind the bus.
Note before you invest: last release was November 2017, zero stars, zero dependents. Verify PHP and Symfony compatibility against your project first — realistically this is Symfony 2.8–3.x / PHP 5.6–7.x territory.
Write side — commands from form submissions. Define CreateProduct, UpdateProduct, DeleteProduct in your Application/Command namespace. The admin controller builds the command from the request/form data and hands it to the bus. Keep the command's constructor arguments as scalars or a small DTO — never an entity. If the bundle exposes a form handler abstraction, put the DTO→Command mapping there so the controller stays a two-liner.
Read side — projections for lists and detail pages. A list action should call a query service (ProductListQuery, FindProductQuery) that returns read models, not entities. LIN3S Admin's list/pagination layer will call into whatever repository or finder you inject, so implement that interface against a DBAL query or a dedicated read repository. This is where the bundle earns its keep: it keeps the admin list decoupled from your ORM mappings, so you can reshaped projections without touching the aggregate.
Forms bound to DTOs, not entities. Set data_class to a form DTO with public/setter properties, and map DTO → Command explicitly. Avoid EntityType fields that hydrate managed entities; use an ID-based choice list plus a lookup in the command handler.
Per-resource service definitions. In your services.yml, define each admin resource as a service (controller + form + query service + bus alias) and reference it from the Admin/menu configuration. This keeps the resource wiring declarative and lets you swap the bus implementation per resource in tests.
Composition over inheritance. Where possible, decorate or wrap the bundle's base controller rather than extending it deeply — the base classes are old and likely to have hard-coded constructor signatures. If you must extend, keep the override surface to createAction/updateAction/deleteAction only.
Testing. Unit-test command handlers in isolation with an in-memory bus. For the admin endpoints, boot the kernel with a synchronous, recording bus so you can assert "submitting this form dispatched UpdateProduct with these values" rather than asserting database state. Assert read-model state separately via the projector/listener.
Integration tip. Keep the Admin class and all controllers in Infrastructure/Admin. If the DDD boundary is worth having, the admin UI is a delivery mechanism and belongs on the edge, alongside your HTTP API.
vcs repository entry in composer.json) so you can patch it, or honestly evaluate whether ~200 lines of glue in your own Infrastructure/Admin namespace replaces it entirely.AppKernel-era service definitions, and possibly Controller base classes that clash with Symfony 4+ AbstractController. PHP 8 will likely surface deprecations or hard errors on old signatures (missing return types are fine, but each(), create_function, or old Doctrine APIs are not).tactician.commandbus or a LIN3S-specific alias). If container compilation fails with "service not found," check Configuration.php and the XML for the expected ID and alias your bus to it rather than guessing.lin3s_admin_ddd_extensions). Confirm in Configuration::getAlias() — misnaming it silently yields an empty config, which looks like "the extension does nothing."bin/console debug:container --tag=<bundle tag> to see what got registered; debug:router to confirm the resource routes were generated; and dump the bus in a controller (dump(get_class($this->bus))) to prove the right bus implementation is injected.How can I help you explore Laravel packages today?