alexandrebulete / ddd-symfony-bundle
Symfony Bundle for DDD Foundation - Messenger Command/Query Bus integration
Installs: 1
Dependents: 1
Suggesters: 0
Security: 0
Stars: 11
Watchers: 0
Forks: 0
Open Issues: 0
Type:symfony-bundle
pkg:composer/alexandrebulete/ddd-symfony-bundle
Requires
- php: ^8.2
- alexandrebulete/ddd-foundation: ^1.1
- symfony/config: ^7.0 || ^8.0
- symfony/dependency-injection: ^7.0 || ^8.0
- symfony/framework-bundle: ^7.0 || ^8.0
- symfony/messenger: ^7.0 || ^8.0
README
Symfony Bundle for DDD Foundation. Provides Messenger integration for Command/Query buses and a base Kernel for DDD projects.
Installation
composer require alexandrebulete/ddd-symfony-bundle
Configuration
Add the bundle to your config/bundles.php:
return [ // ... AlexandreBulete\DddSymfonyBundle\DddSymfonyBundle::class => ['all' => true], ];
Features
DddKernel - Auto-import Bounded Contexts
The bundle provides a DddKernel that automatically imports services, packages, and routes from your Bounded Contexts.
Setup
Extend DddKernel in your application's src/Kernel.php:
<?php declare(strict_types=1); namespace App; use AlexandreBulete\DddSymfonyBundle\DddKernel; class Kernel extends DddKernel { // You can override configureContainer/configureRoutes if needed }
What it does
The DddKernel automatically imports:
- Services:
src/*/Infrastructure/Symfony/config/services.{php,yaml} - Packages:
src/*/Infrastructure/Symfony/config/packages/*.{php,yaml} - Routes:
src/*/Infrastructure/Symfony/routes/*.{php,yaml}
This means each Bounded Context can define its own configuration without modifying the main config/ folder.
Expected BC Structure
src/
├── Post/ # Bounded Context
│ └── Infrastructure/
│ └── Symfony/
│ ├── config/
│ │ ├── services.php # Auto-imported
│ │ └── packages/
│ │ └── doctrine.yaml # Auto-imported
│ └── routes/
│ └── api.yaml # Auto-imported
└── User/ # Another Bounded Context
└── Infrastructure/
└── Symfony/
└── config/
└── services.php # Auto-imported
Command/Query Bus
The bundle automatically configures two Symfony Messenger buses:
command.bus- For write operations (Commands)query.bus- For read operations (Queries)
Automatic Handler Registration
Handlers decorated with #[AsCommandHandler] or #[AsQueryHandler] are automatically registered to their respective buses.
use AlexandreBulete\DddFoundation\Application\Command\AsCommandHandler; use AlexandreBulete\DddFoundation\Application\Command\CommandInterface; readonly class CreatePostCommand implements CommandInterface { public function __construct( public string $title, public string $content, ) {} } #[AsCommandHandler] readonly class CreatePostHandler { public function __invoke(CreatePostCommand $command): void { // Handle the command } }
Using the Buses
use AlexandreBulete\DddFoundation\Application\Command\CommandBusInterface; use AlexandreBulete\DddFoundation\Application\Query\QueryBusInterface; class PostController { public function __construct( private CommandBusInterface $commandBus, private QueryBusInterface $queryBus, ) {} public function create(): Response { $this->commandBus->dispatch(new CreatePostCommand( title: 'My Post', content: 'Content...', )); // ... } public function list(): Response { $posts = $this->queryBus->ask(new GetPostsQuery( page: 1, itemsPerPage: 10, )); // ... } }
Autocomplete Form Field
The bundle provides an Autocomplete Symfony Form field powered by Stimulus + Tom Select (no jQuery).
It is designed for admin back-offices and DDD projects, and works with ID-based values (Value Objects friendly).
Assets setup (Importmap)
If your application uses Importmap / AssetMapper:
php bin/console importmap:require tom-select php bin/console importmap:require tom-select/dist/css/tom-select.default.css
Enable the Stimulus controller in assets/controllers.json:
{
"controllers": {
"@alexandrebulete/ddd-symfony-bundle": {
"autocomplete": {
"enabled": true,
"fetch": "eager",
"path": "@alexandrebulete/ddd-symfony-bundle/autocomplete_controller",
"autoimport": {
"tom-select/dist/css/tom-select.default.css": true
}
}
}
}
}
Usage
use AlexandreBulete\DddSymfonyBundle\Form\Type\AutocompleteType; $builder->add('authorId', AutocompleteType::class, [ 'label' => 'Author', 'remote_url' => $this->urlGenerator->generate('admin_user_autocomplete'), 'placeholder' => 'Search by email…', 'min_length' => 2, ]);
The autocomplete endpoint must return:
{
"results": [
{ "id": "uuid-1", "text": "user@example.com" }
]
}
Options
| Option | Description |
|---|---|
| remote_url | AJAX endpoint URL |
| placeholder | Input placeholder |
| min_length | Minimum characters before search |
| limit | Maximum results returned |
| initial_text | Preselected label (edit forms) |
Customization
Override Messenger Configuration
You can override the messenger configuration by creating your own config/packages/messenger.yaml:
framework: messenger: buses: command.bus: middleware: - doctrine_transaction query.bus: ~
Extend DddKernel
If you need custom container or routes configuration, override the methods:
<?php declare(strict_types=1); namespace App; use AlexandreBulete\DddSymfonyBundle\DddKernel; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; class Kernel extends DddKernel { protected function configureContainer(ContainerConfigurator $container): void { parent::configureContainer($container); // Add your custom imports here $container->import($this->getProjectDir().'/config/custom/*.yaml'); } }