domain/laravel-domain-generator

Pacote Laravel para geração automática de estruturas por domínio utilizando DDD, DTOs, Services, Repositories, Controllers e Form Requests

Maintainers

Package info

github.com/Diegosny/laravel-domain-generator

pkg:composer/domain/laravel-domain-generator

Transparency log

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.1 2026-08-14 18:33 UTC

This package is auto-updated.

Last update: 2026-08-14 18:36:39 UTC


README

Latest Stable Version License: MIT

O Laravel Domain Generator é um pacote para Laravel desenvolvido para automatizar e padronizar a criação de estruturas baseadas em Domain Driven Design (DDD) e Clean Architecture.

Com um único comando Artisan, o pacote gera a estrutura inicial de um domínio, incluindo Controller, FormRequest, DTO, Service, Repository, Model e Migration, já integrados às classes abstratas fornecidas pelo pacote.

A biblioteca também fornece suporte para API Resources, paginação, relacionamentos, respostas JSON padronizadas, autenticação JWT e hooks de ciclo de vida no Service.

💡 Funcionalidades

🚀 Geração de Domínio

Crie a estrutura inicial de um domínio utilizando um único comando:

php artisan make:domain User

O comando pode gerar:

  • Model
  • Migration
  • Controller
  • FormRequest
  • DTO
  • Service
  • Repository

🧱 Arquitetura baseada em DDD / Clean Architecture

A estrutura gerada separa as principais responsabilidades da aplicação:

HTTP
 │
 ├── Controller
 ├── FormRequest
 └── Resource
       │
       ▼
     DTO
       │
       ▼
   Application
       │
     Service
       │
       ▼
  Repository
       │
       ▼
     Model

Essa separação permite manter a camada HTTP desacoplada das regras de persistência e facilita a evolução da aplicação.

📦 DTOs

O pacote possui um AbstractDTO para criação de Data Transfer Objects.

Exemplo:

<?php

namespace App\Domain\User\DTO;

use Domain\DomainGenerator\Abstracts\AbstractDTO;

final class UserDTO extends AbstractDTO
{
    public function __construct(
        public readonly string $name,
        public readonly string $email,
        public readonly ?string $phone = null,
    ) {
    }
}

O DTO pode ser configurado diretamente no Controller:

protected ?string $requestDto = UserDTO::class;

O fluxo de criação passa a ser:

Request
   ↓
validated()
   ↓
UserDTO
   ↓
UserService
   ↓
UserRepository

O pacote mantém compatibilidade com Controllers que não utilizam DTOs.

🔐 Autenticação JWT

O pacote possui suporte integrado à autenticação JWT utilizando:

php-open-source-saver/jwt-auth

São disponibilizados endpoints para:

  • Login
  • Logout
  • Refresh
  • Usuário autenticado (me)

🏗️ Classes Abstratas

O pacote fornece classes base para padronizar a arquitetura.

AbstractController

Responsável por:

  • Respostas JSON padronizadas
  • ok()
  • success()
  • error()
  • Integração com FormRequests
  • Integração com DTOs
  • Integração com API Resources
  • Paginação
  • Tratamento de exceções
  • Controle de permissões
  • Relacionamentos através de with

AbstractService

Fornece operações comuns de aplicação:

  • getAll()
  • find()
  • save()
  • saveDto()
  • update()
  • updateDto()
  • delete()
  • create()
  • createDto()
  • updateOrCreate()
  • updateOrCreateDto()
  • preRequisite()
  • toSelect()

Também disponibiliza hooks:

beforeSave
afterSave

beforeUpdate
afterUpdate

beforeDelete
afterDelete

AbstractRepository

Fornece uma abstração sobre o Eloquent com suporte a:

  • Paginação
  • Filtros
  • Relacionamentos
  • Busca por ID
  • Busca por campo alternativo
  • findOrFail
  • where
  • findOneWhere
  • create
  • update
  • delete
  • deleteWhere
  • updateOrCreate
  • pluck

📦 Instalação

Instale o pacote via Composer:

composer require domain/laravel-domain-generator

O pacote instalará automaticamente as dependências necessárias do JWT:

php-open-source-saver/jwt-auth

🏗️ Criando um domínio

Para criar um novo domínio:

php artisan make:domain User

Para forçar a recriação de arquivos existentes:

php artisan make:domain User --force

A estrutura gerada será semelhante a:

app/
├── Domain/
│   └── User/
│       ├── DTO/
│       │   └── UserDTO.php
│       │
│       ├── Repositories/
│       │   └── UserRepository.php
│       │
│       └── Service/
│           └── UserService.php
│
├── Http/
│   ├── Controllers/
│   │   └── UserController.php
│   │
│   └── Requests/
│       └── UserRequest.php
│
└── Models/
    └── User.php

API Resources são criados manualmente em app/Http/Resources, pois pertencem à camada HTTP da aplicação e não à camada de domínio.

🔄 Fluxo de uma requisição

Com DTO configurado, uma requisição de criação seguirá aproximadamente este fluxo:

HTTP Request
     │
     ▼
UserRequest
     │
     │ validated()
     ▼
UserDTO
     │
     ▼
UserController
     │
     ▼
UserService
     │
     ▼
UserRepository
     │
     ▼
User Model
     │
     ▼
UserResource
     │
     ▼
JSON Response

📝 FormRequest

O Request gerado pode ser utilizado normalmente para validação:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'name' => [
                'required',
                'string',
                'max:255',
            ],

            'email' => [
                'required',
                'email',
                'max:255',
            ],

            'phone' => [
                'nullable',
                'string',
                'max:30',
            ],
        ];
    }
}

📦 DTO

Depois de validar os dados, o Controller pode convertê-los automaticamente para um DTO.

<?php

namespace App\Domain\User\DTO;

use Domain\DomainGenerator\Abstracts\AbstractDTO;

final class UserDTO extends AbstractDTO
{
    public function __construct(
        public readonly string $name,
        public readonly string $email,
        public readonly ?string $phone = null,
    ) {
    }
}

No Controller:

protected ?string $requestValidate = UserRequest::class;

protected ?string $requestDto = UserDTO::class;

O AbstractController fará automaticamente:

$validated
    ↓
UserDTO::fromArray()

O Service recebe o DTO através de:

$this->service->saveDto($dto);

Internamente, o DTO é convertido para array antes de chegar ao Repository.

🧩 API Resources

Os API Resources devem ficar na camada HTTP:

app/
└── Http/
    └── Resources/
        └── UserResource.php

Para criar um Resource:

php artisan make:resource UserResource

Exemplo:

<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'phone' => $this->phone,
        ];
    }
}

No Controller:

use App\Http\Resources\UserResource;

class UserController extends AbstractController
{
    protected ?string $resource = UserResource::class;
}

A partir desse momento, o AbstractController utilizará automaticamente o Resource nas respostas.

📄 Resources com Collection

Para respostas de listas, o AbstractController também suporta Resources:

protected ?string $resource = UserResource::class;

O resultado será transformado automaticamente através de:

UserResource::collection($items)

📑 Resources com Paginação

Paginação também é suportada:

public function index(Request $request): JsonResponse
{
    return $this->handle(
        fn () => $this->service->getAll(
            $request->all(),
            $this->resolveWith($request)
        )
    );
}

Quando o Service retornar um LengthAwarePaginator, o AbstractController utilizará o Resource configurado e preservará os metadados de paginação.

🔗 Relacionamentos

É possível solicitar relacionamentos através do parâmetro with.

Por exemplo:

GET /api/users?with=roles,permissions

Ou definir relacionamentos padrão no Controller:

protected array $with = [
    'roles',
    'permissions',
];

O AbstractRepository normaliza automaticamente os relacionamentos recebidos.

🔎 Filtros

Os filtros podem ser enviados diretamente na requisição:

GET /api/users?name=John&status=active

O AbstractRepository remove automaticamente parâmetros técnicos como:

page
per_page
with
sort
order
search

antes de aplicar os filtros à consulta.

🔑 Configuração Rápida da Autenticação JWT

Para utilizar os endpoints de autenticação prontos, faça as seguintes etapas.

1. Gere a chave secreta

php artisan jwt:secret

2. Configure o Guard da API

No arquivo:

config/auth.php

configure o guard:

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],

3. Atualize o Model User

Adicione JWTSubject e HasJwtAuth:

<?php

namespace App\Models;

use Domain\DomainGenerator\Traits\HasJwtAuth;
use Illuminate\Foundation\Auth\User as Authenticatable;
use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject
{
    use HasJwtAuth;

    // ...
}

🌐 Endpoints de Autenticação

O pacote disponibiliza rotas de autenticação sob o prefixo:

/api/auth
Método Endpoint Protegido Descrição
POST /api/auth/login Realiza login e retorna o token JWT
GET /api/auth/me Retorna o usuário autenticado
POST /api/auth/refresh Renova o token
POST /api/auth/logout Invalida o token atual

🔐 Permissões

O AbstractController possui suporte à verificação de permissões:

$this->hasPermissionTo('users.create');

Caso o usuário não possua a permissão necessária, será lançada uma exceção de autorização.

⚙️ Configuração do diretório de Domínios

Por padrão, os domínios são criados dentro de:

app/Domain

É possível alterar esse comportamento através da variável:

APP_DOMAIN_FOLDER=Domain

Por exemplo:

APP_DOMAIN_FOLDER=Modules

Nesse caso:

app/Modules/User/

será utilizado como diretório do domínio.

🧪 Exemplo completo

Uma implementação básica pode ficar assim:

Controller

<?php

namespace App\Http\Controllers;

use App\Domain\User\DTO\UserDTO;
use App\Domain\User\Service\UserService;
use App\Http\Requests\UserRequest;
use App\Http\Resources\UserResource;
use Domain\DomainGenerator\Abstracts\AbstractController;

class UserController extends AbstractController
{
    protected mixed $service;

    protected ?string $requestValidate = UserRequest::class;

    protected ?string $requestDto = UserDTO::class;

    protected ?string $resource = UserResource::class;

    public function __construct(UserService $service)
    {
        $this->service = $service;
    }
}

DTO

<?php

namespace App\Domain\User\DTO;

use Domain\DomainGenerator\Abstracts\AbstractDTO;

final class UserDTO extends AbstractDTO
{
    public function __construct(
        public readonly string $name,
        public readonly string $email,
    ) {
    }
}

Service

<?php

namespace App\Domain\User\Service;

use App\Domain\User\Repositories\UserRepository;
use Domain\DomainGenerator\Abstracts\AbstractService;

class UserService extends AbstractService
{
    public function __construct(UserRepository $repository)
    {
        $this->repository = $repository;
    }
}

Repository

<?php

namespace App\Domain\User\Repositories;

use App\Models\User;
use Domain\DomainGenerator\Abstracts\AbstractRepository;

class UserRepository extends AbstractRepository
{
    public function __construct(User $model)
    {
        parent::__construct($model);
    }
}

Resource

<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
        ];
    }
}

🧠 Princípios da arquitetura

A biblioteca busca manter as responsabilidades separadas:

Camada Responsabilidade
Controller Entrada HTTP e resposta
FormRequest Validação da entrada
DTO Transporte dos dados
Service Regras/processos da aplicação
Repository Persistência e consultas
Model Representação Eloquent
Resource Transformação da resposta HTTP

Uma regra importante é evitar colocar dependências HTTP dentro do domínio.

Por isso:

DTO
Service
Repository

ficam dentro do domínio, enquanto:

Controller
Request
Resource

ficam na camada HTTP.

🚀 Roadmap

Possíveis evoluções futuras:

  • Geração automática de API Resources
  • Geração de DTOs baseada no $fillable do Model
  • DTOs específicos para Store e Update
  • Conversão automática de tipos nos DTOs
  • Value Objects
  • Domain Events
  • Repository Interfaces
  • Use Cases / Application Services
  • Policies
  • Testes automatizados gerados pelo comando
  • Suporte a diferentes estratégias de persistência

📄 Licença

Este projeto está licenciado sob a licença MIT.