Maker Commands Reference
Complete reference for all 19 maker commands in Hexagonal Maker Bundle.
Quick Reference
| Command | Layer | What it generates |
|---|---|---|
| make:hexagonal:entity | Domain | Pure PHP entities + XML mapping + AggregateRoot |
| make:hexagonal:value-object | Domain | Immutable VOs (Money/Status/ID patterns) + Doctrine types |
| make:hexagonal:exception | Domain | Business exceptions with factory methods |
| make:hexagonal:repository | Domain + Infra | Repository port + Doctrine adapter |
| make:hexagonal:command | Application | CQRS commands + handlers |
| make:hexagonal:query | Application | CQRS queries + handlers + responses |
| make:hexagonal:use-case | Application | Use cases (application services) |
| make:hexagonal:input | Application | Input DTOs with validation |
| make:hexagonal:controller | UI | Web controllers |
| make:hexagonal:form | UI | Symfony forms |
| make:hexagonal:cli-command | UI | Console commands |
| make:hexagonal:domain-event | Domain | Domain events |
| make:hexagonal:event-subscriber | App/Infra | Event subscribers |
| make:hexagonal:message-handler | Infrastructure | Async message handlers |
| make:hexagonal:use-case-test | Tests | Use case tests |
| make:hexagonal:controller-test | Tests | Controller tests |
| make:hexagonal:cli-command-test | Tests | CLI command tests |
| make:hexagonal:test-config | Config | Test configuration setup |
| make:hexagonal:crud | All | Complete CRUD module (30+ files) |
Domain Layer
Entity
Generate a pure domain entity with Doctrine XML mapping.
bin/console make:hexagonal:entity <module> <name> [--properties=<props>] [options]
Example:
bin/console make:hexagonal:entity user/account User --properties=email:string,age:int
Generated:
Domain/Model/User.php- Pure PHP entityInfrastructure/Persistence/Doctrine/Orm/Mapping/Model/User.orm.xml- Doctrine mapping- Auto-configured
doctrine.yamlmapping - Auto-configured
services.yamlexclusions
Options:
| Option | Description |
|---|---|
--properties |
Entity properties (format: name:type,name:type) |
--with-repository |
Generate repository interface + Doctrine implementation |
--with-id-vo |
Generate ID value object |
--aggregate-root |
Add AggregateRoot trait for domain events support |
--events |
Domain events to generate (comma-separated) |
Examples:
# Basic entity
bin/console make:hexagonal:entity blog/post Post --properties=title:string,content:text
# With repository
bin/console make:hexagonal:entity blog/post Post --with-repository
# Aggregate root with domain events
bin/console make:hexagonal:entity order/ordering Order \
--aggregate-root \
--events=OrderPlaced,OrderConfirmed,OrderCancelled \
--properties=customerId:string,total:int
# Combined options
bin/console make:hexagonal:entity blog/post Post \
--with-repository \
--with-id-vo \
--aggregate-root \
--events=PostCreated,PostPublished
AggregateRoot Example:
When using --aggregate-root, the entity includes the AggregateRoot trait:
final class Order
{
use AggregateRoot;
public static function create(string $id, string $customerId, int $total): self
{
$order = new self($id, $customerId, $total);
$order->recordThat(new OrderPlaced($id, $customerId, $total, new \DateTimeImmutable()));
return $order;
}
}
Value Object
Generate an immutable value object with optional patterns and Doctrine type.
bin/console make:hexagonal:value-object <module> <name> [options]
Example:
bin/console make:hexagonal:value-object user/account Email
Generated:
Domain/ValueObject/Email.php- Immutable readonly class
Options:
| Option | Description |
|---|---|
--pattern |
Value Object pattern: money, status, id, generic |
--with-doctrine-type |
Generate Doctrine DBAL custom type |
--storage-type |
DB storage type: string, integer, text, json (default: string) |
--statuses |
For status pattern: comma-separated status values |
--transitions |
For status pattern: state transitions (format: from:to1,to2;from2:to3) |
Pattern Examples:
# Money pattern (with arithmetic operations)
bin/console make:hexagonal:value-object order/catalog Price \
--pattern=money \
--with-doctrine-type \
--storage-type=integer
# Status pattern (with state machine)
bin/console make:hexagonal:value-object order/ordering OrderStatus \
--pattern=status \
--statuses=pending,confirmed,shipped,delivered,cancelled \
--transitions="pending:confirmed,cancelled;confirmed:shipped;shipped:delivered"
# ID pattern (with UUID validation)
bin/console make:hexagonal:value-object user/account UserId --pattern=id
# Generic with Doctrine type
bin/console make:hexagonal:value-object blog/post Slug \
--with-doctrine-type \
--storage-type=string
Money Pattern Generated:
final readonly class Price
{
public function __construct(public int $amount)
{
if ($amount < 0) {
throw new \InvalidArgumentException('Price cannot be negative');
}
}
public static function zero(): self { return new self(0); }
public static function fromCents(int $cents): self { return new self($cents); }
public function add(self $other): self { return new self($this->amount + $other->amount); }
public function subtract(self $other): self { /* ... */ }
public function multiply(int $quantity): self { return new self($this->amount * $quantity); }
public function isZero(): bool { return $this->amount === 0; }
public function isGreaterThan(self $other): bool { return $this->amount > $other->amount; }
public function equals(self $other): bool { return $this->amount === $other->amount; }
public function format(string $currency = 'EUR'): string { /* ... */ }
}
Status Pattern Generated:
final readonly class OrderStatus
{
public const string PENDING = 'pending';
public const string CONFIRMED = 'confirmed';
// ...
private const array TRANSITIONS = [
self::PENDING => [self::CONFIRMED, self::CANCELLED],
self::CONFIRMED => [self::SHIPPED],
// ...
];
public static function pending(): self { return new self(self::PENDING); }
public function canTransitionTo(self $next): bool { /* ... */ }
public function isPending(): bool { return $this->value === self::PENDING; }
}
With Doctrine Type Generated:
Infrastructure/Persistence/Doctrine/Type/PriceType.php- Doctrine DBAL type- Auto-configured in
doctrine.yaml
Exception
Generate a domain exception with optional factory method patterns.
bin/console make:hexagonal:exception <module> <name> [options]
Example:
bin/console make:hexagonal:exception user/account InvalidEmailException
Generated:
Domain/Exception/InvalidEmailException.php
Options:
| Option | Description |
|---|---|
--pattern |
Exception pattern: not-found, invalid-state, already-exists |
--entity |
Related entity name for factory methods |
Pattern Examples:
# Not Found pattern
bin/console make:hexagonal:exception order/ordering OrderNotFoundException \
--pattern=not-found \
--entity=Order
# Invalid State pattern
bin/console make:hexagonal:exception order/ordering InvalidOrderStateException \
--pattern=invalid-state \
--entity=Order
# Already Exists pattern
bin/console make:hexagonal:exception user/account UserAlreadyExistsException \
--pattern=already-exists \
--entity=User
Not Found Pattern Generated:
final class OrderNotFoundException extends \DomainException
{
public static function withId(string $id): self
{
return new self(sprintf('Order with ID "%s" was not found.', $id));
}
public static function withCriteria(string $criteria): self
{
return new self(sprintf('Order not found with criteria: %s', $criteria));
}
public static function forOrder(string $identifier): self
{
return new self(sprintf('Order "%s" does not exist.', $identifier));
}
}
Invalid State Pattern Generated:
final class InvalidOrderStateException extends \DomainException
{
public static function cannotTransition(string $from, string $to): self
{
return new self(sprintf('Cannot transition Order from "%s" to "%s".', $from, $to));
}
public static function invalidOperation(string $operation, string $currentState): self
{
return new self(sprintf('Cannot %s: Order is in "%s" state.', $operation, $currentState));
}
}
Repository
Generate repository interface (Port) and Doctrine implementation (Adapter).
bin/console make:hexagonal:repository <module> <entity>
Example:
bin/console make:hexagonal:repository user/account User
Generated:
Domain/Port/UserRepositoryInterface.php- Interface (Port)Infrastructure/Persistence/Doctrine/DoctrineUserRepository.php- Implementation (Adapter)
Application Layer
Command
Generate CQRS command for write operations.
bin/console make:hexagonal:command <module> <name> [options]
Example:
bin/console make:hexagonal:command blog/post create
Generated:
Application/Create/CreateCommand.php- Command DTOApplication/Create/CreateCommandHandler.php- Handler with#[AsMessageHandler]
Options:
# With factory pattern
--factory
# With tests
--with-tests
# Combined
bin/console make:hexagonal:command user/account register --factory --with-tests
With Factory Generated:
Application/Register/RegisterCommand.phpApplication/Register/RegisterCommandHandler.phpApplication/Register/UserFactory.php- Factory for creating entities
Query
Generate CQRS query for read operations.
bin/console make:hexagonal:query <module> <name>
Example:
bin/console make:hexagonal:query blog/post find-by-id
Generated:
Application/FindById/FindByIdQuery.php- Query DTOApplication/FindById/FindByIdQueryHandler.php- HandlerApplication/FindById/FindByIdResponse.php- Response DTO
Use Case
Generate a use case (application service).
bin/console make:hexagonal:use-case <module> <name>
Example:
bin/console make:hexagonal:use-case blog/post PublishPost
Generated:
Application/UseCase/PublishPostUseCase.php
Options:
# With test
--with-test
bin/console make:hexagonal:use-case blog/post CreatePost --with-test
Input
Generate input DTO with validation.
bin/console make:hexagonal:input <module> <name>
Example:
bin/console make:hexagonal:input blog/post CreatePostInput
Generated:
Application/Input/CreatePostInput.php- DTO with Symfony Validator constraints
UI Layer
Controller
Generate web controller.
bin/console make:hexagonal:controller <module> <name> <route>
Example:
bin/console make:hexagonal:controller blog/post CreatePost /posts/new
Generated:
UI/Http/Web/Controller/CreatePostController.php
Options:
# With complete workflow (Form + UseCase + Command + Input)
--with-workflow
bin/console make:hexagonal:controller blog/post CreatePost /posts/new --with-workflow
With Workflow Generated:
- Controller
- Form
- UseCase
- Command + Handler
- Input DTO
Form
Generate Symfony form type.
bin/console make:hexagonal:form <module> <name>
Example:
bin/console make:hexagonal:form blog/post Post
Generated:
UI/Http/Web/Form/PostType.php
Options:
# With command workflow
--with-command --action=Create
bin/console make:hexagonal:form blog/post Post --with-command --action=Create
With Command Generated:
- Form
- Command + Handler
- Input DTO
CLI Command
Generate console command.
bin/console make:hexagonal:cli-command <module> <name> <command-name>
Example:
bin/console make:hexagonal:cli-command blog/post CreatePost app:post:create
Generated:
UI/Cli/CreatePostCommand.php
Options:
# With use case workflow
--with-use-case
bin/console make:hexagonal:cli-command blog/post CreatePost app:post:create --with-use-case
Infrastructure Layer
Message Handler
Generate async message handler.
bin/console make:hexagonal:message-handler <module> <name>
Example:
bin/console make:hexagonal:message-handler user/account SendWelcomeEmail
Generated:
Infrastructure/Messaging/Handler/SendWelcomeEmailHandler.php
Options:
# With message class
--with-message
bin/console make:hexagonal:message-handler user/account SendEmail --with-message
Events
Domain Event
Generate domain event with aggregate and properties.
bin/console make:hexagonal:domain-event <module> <name> [options]
Example:
bin/console make:hexagonal:domain-event order/payment OrderPlaced
Generated:
Domain/Event/OrderPlacedEvent.php- Immutable event
Options:
| Option | Description |
|---|---|
--aggregate |
The aggregate this event belongs to |
--properties |
Event properties (format: name:type,name:type) |
--with-subscriber |
Generate event subscriber |
Examples:
# Basic event
bin/console make:hexagonal:domain-event order/ordering OrderPlaced
# With aggregate and properties
bin/console make:hexagonal:domain-event order/ordering OrderPlaced \
--aggregate=Order \
--properties=customerId:string,totalAmount:int,shippingAddress:string
# With subscriber
bin/console make:hexagonal:domain-event order/ordering OrderPlaced \
--aggregate=Order \
--properties=customerId:string \
--with-subscriber
Generated Event:
final readonly class OrderPlaced implements DomainEvent
{
public function __construct(
public string $orderId,
public string $customerId,
public int $totalAmount,
public string $shippingAddress,
public \DateTimeImmutable $occurredAt,
) {
}
public function occurredOn(): \DateTimeImmutable
{
return $this->occurredAt;
}
public function aggregateId(): string
{
return $this->orderId;
}
}
Event Subscriber
Generate event subscriber.
bin/console make:hexagonal:event-subscriber <module> <name> --layer=<application|infrastructure>
Example:
# Application layer (business workflow)
bin/console make:hexagonal:event-subscriber order/payment OrderPlaced --layer=application
# Infrastructure layer (technical concerns)
bin/console make:hexagonal:event-subscriber shared/logging Exception --layer=infrastructure
Tests
Use Case Test
Generate use case test.
bin/console make:hexagonal:use-case-test <module> <name>
Example:
bin/console make:hexagonal:use-case-test blog/post CreatePost
Generated:
tests/Blog/Post/Application/CreatePost/CreatePostTest.php- KernelTestCase
Controller Test
Generate controller test.
bin/console make:hexagonal:controller-test <module> <name> <route>
Example:
bin/console make:hexagonal:controller-test blog/post CreatePost /posts/new
Generated:
tests/Blog/Post/UI/Http/Web/Controller/CreatePostControllerTest.php- WebTestCase
CLI Command Test
Generate CLI command test.
bin/console make:hexagonal:cli-command-test <module> <name> <command-name>
Example:
bin/console make:hexagonal:cli-command-test blog/post CreatePost app:post:create
Generated:
tests/Blog/Post/UI/Cli/CreatePostCommandTest.php- CommandTester
Configuration
Test Config
Generate test environment configuration.
bin/console make:hexagonal:test-config
Generated:
config/packages/test/doctrine.yaml- Test database config.env.test- Test environment variables
Rapid Development
CRUD
Generate complete CRUD module.
bin/console make:hexagonal:crud <module> <entity> [options]
Example:
bin/console make:hexagonal:crud blog/post Post --with-tests --with-id-vo
Generated (30+ files):
Domain:
- Entity
- Repository Interface
- ID ValueObject (with
--with-id-vo)
Infrastructure:
- Doctrine Repository
- YAML Mapping
Application:
- 5 Use Cases (Create, Update, Delete, Get, List)
- 5 Commands + Handlers
- 5 Input DTOs
UI:
- 5 Controllers
- 1 Form
Tests (with --with-tests):
- 5 Use Case Tests
- 5 Controller Tests
Routes:
GET /posts- ListGET /posts/{id}- ShowGET /posts/new- Create formPOST /posts/new- SubmitGET /posts/{id}/edit- Edit formPOST /posts/{id}/edit- UpdateDELETE /posts/{id}/delete- Delete
Options Summary
Entity Options
| Option | Description |
|---|---|
--properties |
Entity properties (format: name:type,name:type) |
--with-repository |
Generate repository with entity |
--with-id-vo |
Generate ID value object |
--aggregate-root |
Add AggregateRoot trait for domain events |
--events |
Domain events to generate (comma-separated) |
Value Object Options
| Option | Description |
|---|---|
--pattern |
VO pattern: money, status, id, generic |
--with-doctrine-type |
Generate Doctrine DBAL custom type |
--storage-type |
DB storage: string, integer, text, json |
--statuses |
For status pattern: comma-separated values |
--transitions |
For status pattern: state machine transitions |
Exception Options
| Option | Description |
|---|---|
--pattern |
Exception pattern: not-found, invalid-state, already-exists |
--entity |
Related entity name for factory methods |
Domain Event Options
| Option | Description |
|---|---|
--aggregate |
Aggregate this event belongs to |
--properties |
Event properties (format: name:type,name:type) |
--with-subscriber |
Generate event subscriber |
Other Options
| Option | Available For | Description |
|---|---|---|
--factory |
Command | Generate factory pattern |
--with-tests |
Command, UseCase, CRUD | Generate tests |
--with-use-case |
CLI Command | Generate use case workflow |
--with-workflow |
Controller | Generate complete workflow |
--with-command |
Form | Generate command workflow |
--with-message |
Message Handler | Generate message class |
--layer |
Event Subscriber | Choose application or infrastructure |
--action |
Form | Specify action (Create, Update, etc.) |
Module Path Format
All commands use the module path format: <context>/<module>
Examples:
user/account→src/User/Account/blog/post→src/Blog/Post/order/payment→src/Order/Payment/
Flexibility:
module/user/account→src/Module/User/Account/shared/common→src/Shared/Common/
Next Steps
- Quick Start - Build your first module
- Examples - Real-world usage
- Architecture Guide - Understand the patterns