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 entity
  • Infrastructure/Persistence/Doctrine/Orm/Mapping/Model/User.orm.xml - Doctrine mapping
  • Auto-configured doctrine.yaml mapping
  • Auto-configured services.yaml exclusions

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 DTO
  • Application/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.php
  • Application/Register/RegisterCommandHandler.php
  • Application/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 DTO
  • Application/FindById/FindByIdQueryHandler.php - Handler
  • Application/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 - List
  • GET /posts/{id} - Show
  • GET /posts/new - Create form
  • POST /posts/new - Submit
  • GET /posts/{id}/edit - Edit form
  • POST /posts/{id}/edit - Update
  • DELETE /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