Installation
Complete installation and configuration guide for Hexagonal Maker Bundle.
Requirements
- PHP: 8.1 or higher
- Symfony: 6.4+ or 7.x
- Composer: Latest version
Step 1: Install via Composer
composer require ahmed-bhs/hexagonal-maker-bundle --dev
The --dev flag ensures the bundle is only installed in development environment.
Step 2: Enable the Bundle
With Symfony Flex (Automatic)
If youβre using Symfony Flex, the bundle is auto-registered. Skip to Step 3.
Without Symfony Flex (Manual)
Add the bundle to config/bundles.php:
<?php
return [
// ... other bundles ...
AhmedBhs\HexagonalMakerBundle\HexagonalMakerBundle::class => ['dev' => true],
];
Step 3: Configure Doctrine (Required)
Hexagonal Maker Bundle uses YAML mapping to keep domain entities pure (no annotations).
3.1 Create Doctrine Configuration
Edit config/packages/doctrine.yaml:
doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%'
# Use utf8mb4 for full Unicode support
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
orm:
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
# IMPORTANT: Add YAML mappings for each module
mappings: {}
# Example mappings will be added per module
# See section 3.2 below
3.2 Add Module Mappings
Each time you create a new module (e.g., User/Account), add its mapping:
doctrine:
orm:
mappings:
# User Account Module
UserAccount:
is_bundle: false
type: yml
dir: '%kernel.project_dir%/src/User/Account/Infrastructure/Persistence/Doctrine/Orm/Mapping'
prefix: 'App\User\Account\Domain\Model'
alias: UserAccount
# Blog Post Module (example)
BlogPost:
is_bundle: false
type: yml
dir: '%kernel.project_dir%/src/Blog/Post/Infrastructure/Persistence/Doctrine/Orm/Mapping'
prefix: 'App\Blog\Post\Domain\Model'
alias: BlogPost
# Add more modules as needed...
Pattern:
dir: Path to YAML mapping files (Infrastructure layer)prefix: Namespace of domain entities (Domain layer)alias: Short alias for DQL queries
Step 4: Configure Symfony Messenger (Optional)
For CQRS commands and queries, configure Symfony Messenger.
Edit config/packages/messenger.yaml:
framework:
messenger:
default_bus: command.bus
buses:
command.bus:
middleware:
- validation
- doctrine_transaction
query.bus:
middleware:
- validation
event.bus:
default_middleware: allow_no_handlers
middleware:
- validation
transports:
async: '%env(MESSENGER_TRANSPORT_DSN)%'
routing:
# Route commands to command.bus
'App\*\Application\*\*Command': command.bus
# Route queries to query.bus
'App\*\Application\*\*Query': query.bus
# Route async messages to async transport
'App\*\Infrastructure\Messaging\*': async
Configure Transport (Optional - for async)
In .env:
###> symfony/messenger ###
# For async processing (optional)
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=false
# Or use RabbitMQ, Redis, etc.
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
###< symfony/messenger ###
Step 5: Configure Bundle (Optional)
Create config/packages/hexagonal_maker.yaml to customize skeleton templates:
hexagonal_maker:
# Directory where custom skeleton templates are stored
skeleton_dir: '%kernel.project_dir%/config/skeleton'
# Root source directory (default: 'src')
root_dir: 'src'
# Root namespace (default: 'App')
root_namespace: 'App'
Step 6: Verify Installation
Check that maker commands are available:
bin/console list make:hexagonal
Expected output:
make:hexagonal:cli-command Generate a CLI command
make:hexagonal:command Generate a CQRS command
make:hexagonal:controller Generate a web controller
make:hexagonal:controller-test Generate a controller test
make:hexagonal:crud Generate complete CRUD module
make:hexagonal:domain-event Generate a domain event
make:hexagonal:entity Generate a domain entity
make:hexagonal:event-subscriber Generate an event subscriber
make:hexagonal:exception Generate a domain exception
make:hexagonal:form Generate a Symfony form
make:hexagonal:input Generate an input DTO
make:hexagonal:message-handler Generate a message handler
make:hexagonal:query Generate a CQRS query
make:hexagonal:repository Generate a repository
make:hexagonal:test-config Generate test configuration
make:hexagonal:use-case Generate a use case
make:hexagonal:use-case-test Generate a use case test
make:hexagonal:value-object Generate a value object
Directory Structure
After installation, your project will generate code in this structure:
src/
βββ Module/ # Recommended: organize by bounded context
β βββ User/
β β βββ Account/ # Sub-domain module
β β βββ Domain/
β β β βββ Model/
β β β βββ ValueObject/
β β β βββ Exception/
β β β βββ Port/
β β βββ Application/
β β β βββ Command/
β β β βββ Query/
β β β βββ UseCase/
β β βββ Infrastructure/
β β β βββ Persistence/
β β β βββ Doctrine/
β β β βββ DoctrineUserRepository.php
β β β βββ Orm/Mapping/
β β β βββ User.orm.yml
β β βββ UI/
β β βββ Http/Web/
β β β βββ Controller/
β β β βββ Form/
β β βββ Cli/
β βββ Blog/
β βββ Post/ # Another module
βββ Shared/ # Shared kernel (optional)
βββ Domain/
βββ Application/
βββ Infrastructure/
Or simpler flat structure:
src/
βββ User/Account/ # Module without "Module/" prefix
βββ Blog/Post/
βββ Shared/
Configuration Files Summary
Essential Files
config/
βββ packages/
β βββ doctrine.yaml β REQUIRED: Add YAML mappings
β βββ messenger.yaml β Optional: CQRS buses
β βββ hexagonal_maker.yaml β Optional: Custom templates
βββ services.yaml β Service configuration
Recommended Services Configuration
# config/services.yaml
services:
_defaults:
autowire: true
autoconfigure: true
# Make controllers public
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/*/Domain/Model/' # Exclude entities
- '../src/Kernel.php'
# Repository interfaces autowiring
App\User\Account\Domain\Port\UserRepositoryInterface:
class: App\User\Account\Infrastructure\Persistence\Doctrine\DoctrineUserRepository
# OR use bind for automatic interface resolution
_defaults:
bind:
$commandBus: '@messenger.bus.command'
$queryBus: '@messenger.bus.query'
$eventBus: '@messenger.bus.event'
Database Setup
1. Configure Database URL
In .env:
DATABASE_URL="mysql://user:password@127.0.0.1:3306/hexagonal_app?serverVersion=8.0"
2. Create Database
bin/console doctrine:database:create
3. Generate Migrations
After creating entities with makers:
# Validate mapping
bin/console doctrine:schema:validate
# Generate migration
bin/console doctrine:migrations:diff
# Execute migration
bin/console doctrine:migrations:migrate
Testing Setup (Optional)
1. Install PHPUnit
composer require --dev phpunit/phpunit symfony/phpunit-bridge
2. Configure Test Environment
# Generate test configuration
bin/console make:hexagonal:test-config
This creates:
config/packages/test/doctrine.yaml(test database).env.test(test environment variables)
3. Create Test Database
bin/console doctrine:database:create --env=test
bin/console doctrine:schema:create --env=test
Next Steps
Installation complete! Now:
- Quick Start - Generate your first module
- First Module Tutorial - Complete step-by-step guide
- Maker Commands - Learn all 19 commands
Troubleshooting
Bundle not found in bin/console list
Solution: Clear cache and check config/bundles.php
bin/console cache:clear
Doctrine mapping errors
Error: The class 'X' was not found in the chain configured namespaces
Solution: Ensure YAML mapping is configured in config/packages/doctrine.yaml for your module
Autowiring fails for repositories
Error: Cannot autowire service "X": argument "$repository" references interface but no such service exists
Solution: Add interface alias in config/services.yaml:
services:
App\User\Account\Domain\Port\UserRepositoryInterface:
class: App\User\Account\Infrastructure\Persistence\Doctrine\DoctrineUserRepository
Commands not generating files
Solution: Check permissions on src/ directory:
chmod -R 755 src/
Uninstallation
To remove the bundle:
composer remove ahmed-bhs/hexagonal-maker-bundle
Then remove from config/bundles.php if added manually.