Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Hexagonal Maker Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require --dev adrienlbt/hexagonal-maker-bundle
    

    Ensure HexagonalMakerBundle is enabled in config/bundles.php (Symfony Flex usually handles this automatically).

  2. First Use Case: Run the interactive command:

    bin/console make:hexagonal:usecase
    

    Follow prompts to define:

    • Use case name (e.g., CreateUser)
    • Folder (e.g., User)
    • Request/Response fields (interactive or via --fields flag).
  3. Verify Output: Check generated files in:

    • Domain/UseCase/User/CreateUser.php
    • Domain/Request/User/CreateUserRequest.php
    • Domain/Response/User/CreateUserResponse.php
    • Domain/API/User/CreateUserPresenterInterface.php

Implementation Patterns

Core Workflows

  1. Use Case Creation:

    • Interactive Mode: Run make:hexagonal:usecase and answer prompts for dynamic field generation.
    • Non-Interactive Mode: Predefine fields via --fields flag:
      bin/console make:hexagonal:usecase CreateUser --fields="name:string,email:string"
      
    • Folder Structure: Use --folder to group related use cases (e.g., --folder=Admin).
  2. Integration with Hexagonal Layers:

    • Domain Layer: Use the generated 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
          }
      }
      
    • Application Layer: Inject the 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);
          }
      }
      
    • Infrastructure Layer: Implement PresenterInterface to transform responses (e.g., to JSON/API format).
  3. Testing:

    • Unit Tests: Mock dependencies in UseCase classes (e.g., repositories, services).
    • Integration Tests: Test the full flow from Request → UseCase → Response → Presenter.
    • Example test structure:
      tests/Unit/Domain/UseCase/User/
      tests/Integration/Infrastructure/API/User/
      
  4. Customizing Generation:

    • Override default templates by copying files from: vendor/adrienlbt/hexagonal-maker-bundle/src/Resources/skeleton/.
    • Place custom templates in config/packages/hexagonal_maker.yaml:
      hexagonal_maker:
        templates:
          use_case: 'path/to/custom/UseCase.php.twig'
      

Gotchas and Tips

Pitfalls

  1. Namespace Conflicts:

    • Ensure 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.
    • Fix: Update paths in config or adjust the bundle’s make:hexagonal:usecase command to generate files in the correct location.
  2. Circular Dependencies:

    • Avoid coupling UseCase classes directly to infrastructure (e.g., Doctrine entities). Use interfaces (e.g., UserRepositoryInterface) injected via dependency injection.
    • Tip: Use Symfony’s autowiring to resolve interfaces in UseCase constructors.
  3. Presenter Interface Overuse:

    • Presenters are generated for every use case by default. For simple APIs, consider skipping them or merging logic into controllers.
    • Workaround: Extend the bundle’s templates to conditionally generate presenters (e.g., based on --no-presenter flag).
  4. Field Validation:

    • The bundle generates basic validation (e.g., #[Assert\NotBlank]). For complex rules, manually extend the Request class or use Symfony’s Validator component.
    • Tip: Add validation annotations in the generated Request class:
      #[Assert\Email]
      private string $email;
      
  5. Command Line Arguments:

    • Fields with spaces or special characters (e.g., first name) may break the --fields flag. Use underscores or quotes:
      --fields="first_name:string,last_name:string"
      

Debugging

  1. Generated Files:

    • Check the bundle’s skeleton templates in vendor/adrienlbt/hexagonal-maker-bundle/src/Resources/skeleton/ to understand the default structure.
    • Override templates locally to debug or customize generation.
  2. Command Errors:

    • Run with -v for verbose output:
      bin/console make:hexagonal:usecase -v
      
    • Common errors:
      • Directory Not Found: Verify paths in hexagonal_maker.yaml.
      • Permission Issues: Ensure the var/ directory is writable.
  3. Symfony Maker Conflicts:

    • If other maker bundles (e.g., symfony/maker-bundle) interfere, disable them temporarily or adjust command namespaces.

Extension Points

  1. Custom Use Case Types:

    • Extend the bundle by creating a new command (e.g., 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'));
          }
      }
      
  2. Dynamic Field Generation:

    • Hook into the bundle’s Request/Response generation to add dynamic fields (e.g., from a database schema). Override the generateRequest/generateResponse methods in a custom generator class.
  3. Integration with API Platform:

    • Use the generated 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();
          }
      }
      
  4. Testing Generators:

    • Test custom generators by mocking the 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');
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen