adrienlbt/hexagonal-maker-bundle
Symfony MakerBundle extension that scaffolds Hexagonal Architecture use cases. Generates a UseCase class plus Request/Response DTOs and a Presenter interface in a clean Domain folder structure, with optional configurable layer paths.
Installation:
composer require --dev adrienlbt/hexagonal-maker-bundle
Ensure HexagonalMakerBundle is enabled in config/bundles.php (Symfony Flex usually handles this automatically).
First Use Case: Run the interactive command:
bin/console make:hexagonal:usecase
Follow prompts to define:
CreateUser)User)--fields flag).Verify Output: Check generated files in:
Domain/UseCase/User/CreateUser.phpDomain/Request/User/CreateUserRequest.phpDomain/Response/User/CreateUserResponse.phpDomain/API/User/CreateUserPresenterInterface.phpUse Case Creation:
make:hexagonal:usecase and answer prompts for dynamic field generation.--fields flag:
bin/console make:hexagonal:usecase CreateUser --fields="name:string,email:string"
--folder to group related use cases (e.g., --folder=Admin).Integration with Hexagonal Layers:
UseCase class to encapsulate business logic. Example:
// Domain/UseCase/User/CreateUser.php
class CreateUser implements UseCaseInterface {
public function __invoke(CreateUserRequest $request): CreateUserResponse {
// Business logic here
}
}
UseCase into a Symfony command/controller:
use Domain\UseCase\User\CreateUser;
class UserController {
public function __construct(private CreateUser $createUser) {}
public function create(Request $request): Response {
$response = $this->createUser(new CreateUserRequest($request->all()));
return $this->presenter->present($response);
}
}
PresenterInterface to transform responses (e.g., to JSON/API format).Testing:
UseCase classes (e.g., repositories, services).Request → UseCase → Response → Presenter.tests/Unit/Domain/UseCase/User/
tests/Integration/Infrastructure/API/User/
Customizing Generation:
vendor/adrienlbt/hexagonal-maker-bundle/src/Resources/skeleton/.config/packages/hexagonal_maker.yaml:
hexagonal_maker:
templates:
use_case: 'path/to/custom/UseCase.php.twig'
Namespace Conflicts:
application_path, domain_path, and infrastructure_path in hexagonal_maker.yaml match your project’s actual structure. Defaults assume Application/, Domain/, and Infrastructure/ directories at the root.make:hexagonal:usecase command to generate files in the correct location.Circular Dependencies:
UseCase classes directly to infrastructure (e.g., Doctrine entities). Use interfaces (e.g., UserRepositoryInterface) injected via dependency injection.UseCase constructors.Presenter Interface Overuse:
--no-presenter flag).Field Validation:
#[Assert\NotBlank]). For complex rules, manually extend the Request class or use Symfony’s Validator component.Request class:
#[Assert\Email]
private string $email;
Command Line Arguments:
first name) may break the --fields flag. Use underscores or quotes:
--fields="first_name:string,last_name:string"
Generated Files:
vendor/adrienlbt/hexagonal-maker-bundle/src/Resources/skeleton/ to understand the default structure.Command Errors:
-v for verbose output:
bin/console make:hexagonal:usecase -v
hexagonal_maker.yaml.var/ directory is writable.Symfony Maker Conflicts:
symfony/maker-bundle) interfere, disable them temporarily or adjust command namespaces.Custom Use Case Types:
make:hexagonal:command) that reuses its logic. Example:
// src/Command/CustomUseCaseCommand.php
use AdrienLbt\HexagonalMakerBundle\Generator\UseCaseGenerator;
class CustomUseCaseCommand extends Command {
protected function execute(InputInterface $input, OutputInterface $output) {
$generator = new UseCaseGenerator();
$generator->generate($input->getArgument('name'), $input->getOption('fields'));
}
}
Dynamic Field Generation:
Request/Response generation to add dynamic fields (e.g., from a database schema). Override the generateRequest/generateResponse methods in a custom generator class.Integration with API Platform:
PresenterInterface to create API Platform serializers. Example:
// src/Infrastructure/API/User/CreateUserOutput.php
#[ApiResource]
class CreateUserOutput implements CreateUserPresenterInterface {
public function __construct(private CreateUserResponse $response) {}
public function __serialize(): array {
return $this->response->toArray();
}
}
Testing Generators:
FileSystem and PhpFile classes used by the bundle. Example:
$fileSystem = $this->createMock(FileSystem::class);
$generator = new UseCaseGenerator($fileSystem);
$generator->generate('TestUseCase', ['field:string']);
$this->assertFileExists('Domain/UseCase/Test/TestUseCase.php');
How can I help you explore Laravel packages today?