alysontrizotto / laravel-ddl-crud
Gerador de CRUD a partir de DDL (SQL) para Laravel 12.
Installs: 105
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 1
pkg:composer/alysontrizotto/laravel-ddl-crud
Requires
- php: >=8.2
- illuminate/console: ^12.0
- illuminate/filesystem: ^12.0
- illuminate/support: ^12.0
This package is auto-updated.
Last update: 2025-11-15 19:52:12 UTC
README
Gere um CRUD completo (Migration, Model, Service, Requests, Resource, Controller API, Factory e Testes) a partir de um arquivo DDL (.sql) no Laravel 12.
- Framework alvo: Laravel 12
- Stubs personalizáveis:
stubs/cascade/ - Código organizado por geradores dedicados (SRP) e utilitários de suporte
Recursos
- Entrada via DDL: lê múltiplas
CREATE TABLEno mesmo arquivo - Geração completa: migrations, models, services, requests, resources, controllers, factories, testes unit/feature
- Stubs sobrescrevíveis: personalize a estrutura gerada publicando os stubs
- Heurísticas úteis: mapeamento de tipos, inferência de
fillable,casts, validações básicas - Separação de responsabilidades: parsing, geração e escrita extraídos para classes dedicadas
- Rotas automáticas: gera rotas REST em
routes/api.phpcom marcadores por domínio e idempotência (não duplica nem apaga rotas já existentes)
Sumário
- Pré-requisitos
- Instalação
- Publicar stubs (opcional)
- Uso
- Exemplo de DDL suportada
- O que é gerado (por tabela)
- Rotas
- Customização
- Testes
- Solução de problemas
- Licença
Pré-requisitos
- PHP e extensões do Laravel 12
- Projeto Laravel instalado e funcional
- Arquivo DDL (.sql) com instruções
CREATE TABLE ... (...);
Instalação
Instale via Composer:
composer require alysontrizotto/laravel-ddl-crud
Este pacote suporta auto-discovery no Laravel. O service provider exposto é
AlysonTrizotto\DdlCrud\DdlCrudServiceProvider (wrapper que aponta para
AlysonTrizotto\DdlCrud\Providers\DdlCrudServiceProvider).
Publicar stubs (opcional)
Publique os stubs para customização no seu projeto (tag stubs):
php artisan vendor:publish --tag=stubs
Os stubs serão publicados em stubs/cascade/ na raiz do projeto.
Stubs utilizados pelo gerador (se não existirem no projeto, um fallback interno será usado):
stubs/cascade/model.stubstubs/cascade/service.stubstubs/cascade/request.stubstubs/cascade/resource.stubstubs/cascade/controller.api.stubstubs/cascade/factory.stubstubs/cascade/unit.model.test.stubstubs/cascade/unit.service.test.stubstubs/cascade/feature.controller.test.stub
Uso
Você pode executar de duas formas:
- Interativo (responder aos prompts):
php artisan make:crud-from-ddl
Prompts:
- Domínio (CamelCase) — exemplo:
ChecklistouTrip. - Caminho do arquivo DDL — exemplo:
D:/Alyson/ddl/checklist.sql.
- Direto por argumentos (sem prompts):
php artisan make:crud-from-ddl Checklist D:/Alyson/ddl/checklist.sql
Opções úteis:
--no-routes— não gerar/adicionar rotas noroutes/api.php.--route-prefix=...— adicionaRoute::prefix('...')->group(...)envolvendo as rotas geradas (ex.:--route-prefix=v1).--route-name=...— define/override o slug da rota gerada (ex.:--route-name=annotations).--middleware=a|b|c— aplica middlewares na rota/agrupamento (ex.:--middleware=auth:sanctum|throttle:60,1).--name-prefix=...— prefixo de nomes de rotas (ex.:--name-prefix=checklist.→checklist.photo-annotations.index).--only=a,b— limita métodos do resource (ex.:--only=index,show).--except=a,b— exclui métodos do resource (ex.:--except=destroy).--nested=...— slug aninhado (ex.:--nested=orders/{order}/items).
Exemplo de DDL suportada (Postgres-like ou MySQL simples)
CREATE TABLE checklist.photo_annotations ( id uuid primary key, checklist_id uuid not null, label varchar(150) not null, metadata jsonb, created_at timestamptz, updated_at timestamptz );
O parser identifica o schema opcional (checklist), o nome da tabela (photo_annotations), colunas, tipos, nulos e chave primária.
O que é gerado (por tabela)
- Migration em
database/migrations/*_create_{schema_}{tabela}_table.php- Cria schema (se informado) e a tabela com colunas mapeadas a partir da DDL
- Model em
app/Models/{Domínio}/{Model}.phpuse HasFactory;use SoftDeletes;(apenas se a DDL contiverdeleted_at)$table,$primaryKey,$incrementing,$keyType$fillable(excluicreated_at,updated_at,deleted_at)$casts(json/jsonb/arrays mapeados paraarray)- Métodos:
store(array $data)eapplyUpdate(array $data) scopeFilter(array $filters)
- Service em
app/Services/{Domínio}/{Model}Service.php- Focado em regra de negócio
- Usa
Model::store,$model->applyUpdate,$model->delete() - Métodos:
paginate,find,create,update,delete
- Requests em
app/Http/Requests/{Domínio}/{Model}/Store{Model}Request.phpeUpdate{Model}Request.php- Regras inferidas da DDL (required, tipos básicos, unique quando aplicável)
- Resource em
app/Http/Resources/{Domínio}/{Model}Resource.php- Constrói a resposta padronizada com os campos da tabela
- Controller API em
app/Http/Controllers/API/{Domínio}/{Model}Controller.php- Endpoints:
index,store,show,update,destroy - Retorna
Resourcenas respostas
- Endpoints:
- Factory em
database/factories/{Domínio}/{Model}Factory.php- Namespace:
Database\\Factories\\{Domínio} $modelusando classe importada- PHPDoc
@extends Factory<{Model}>usando nome curto
- Namespace:
- Testes
- Unit (Model): valida configuração do model
- Unit (Service): cobre paginação e fluxo CRUD com asserts no banco
- Feature (Controller): cobre CRUD completo via HTTP, status codes corretos, usa
apiResource
Exemplo de execução
php artisan make:crud-from-ddl # Informe o domínio: Checklist # Informe o caminho da DDL: D:/Alyson/sql/checklist_tables.sql
Arquivos esperados (exemplo Checklist + tabela photo_annotations):
database/migrations/2025_08_13_000000_create_checklist_photo_annotations_table.phpapp/Models/Checklist/PhotoAnnotation.phpapp/Services/Checklist/PhotoAnnotationService.phpapp/Http/Requests/Checklist/PhotoAnnotation/StorePhotoAnnotationRequest.phpapp/Http/Requests/Checklist/PhotoAnnotation/UpdatePhotoAnnotationRequest.phpapp/Http/Resources/Checklist/PhotoAnnotationResource.phpapp/Http/Controllers/API/Checklist/PhotoAnnotationController.php
Rotas
As rotas REST são adicionadas automaticamente ao arquivo routes/api.php com marcadores por domínio e lógica idempotente (não duplica rotas existentes e não apaga nada fora dos blocos do pacote).
Exemplo do que será inserido:
use Illuminate\Support\Facades\Route; // BEGIN: DDL-CRUD routes [Checklist] Route::apiResource('photo-annotations', \App\Http\Controllers\API\Checklist\PhotoAnnotationController::class); // END: DDL-CRUD routes [Checklist]
Com --route-prefix=v1:
// BEGIN: DDL-CRUD routes [Checklist] Route::prefix('v1')->group(function () { Route::apiResource('photo-annotations', \App\Http\Controllers\API\Checklist\PhotoAnnotationController::class); }); // END: DDL-CRUD routes [Checklist]
Notas:
- O slug da rota é derivado do nome da tabela (
photo_annotations→photo-annotations). - Se o arquivo
routes/api.phpnão existir, ele será criado. - Use
--no-routespara pular a etapa de rotas.
Exemplos de flags de rota
- Somente leitura com prefixo e middlewares:
php artisan make:crud-from-ddl Checklist ddl.sql \
--route-prefix=v1 \
--middleware=auth:sanctum|throttle:60,1 \
--only=index,show
- Nome de rota prefixado e slug customizado:
php artisan make:crud-from-ddl Checklist ddl.sql \ --name-prefix=checklist. \ --route-name=annotations
- Rota aninhada:
php artisan make:crud-from-ddl Orders ddl.sql --nested=orders/{order}/items
Observações:
- Para
--middleware, separe múltiplos middlewares com|ou;(não use vírgulas, pois podem fazer parte de parâmetros como emthrottle:60,1). - Para
--nested, informe o slug final desejado (com placeholders, se necessário). O gerador usa esse slug diretamente noapiResource.
Remoção de rotas (segura por domínio)
Para remover o bloco de rotas gerado para um domínio (entre BEGIN/END), use:
php artisan ddl-crud:routes:remove Checklist
Esse comando remove apenas o bloco do domínio informado, preservando o restante de routes/api.php.
Customização
Edite os stubs em stubs/cascade/ para moldar o padrão do seu projeto:
- Adicionar/remover campos na resposta do
Resource - Ajustar validações nos
Requests - Adaptar
Servicepara suas regras de negócio - Evoluir o
Model(relations, mutators, etc.)
Observações
- O comando valida domínio (CamelCase) e lê múltiplas tabelas no mesmo arquivo DDL.
- Para tipos não suportados no Schema do Laravel, o gerador faz fallback para
string(36)(ex.: uuid) e outros mapeamentos simples. - Caso você utilize MySQL, ajuste os tipos/timezones nas DDLs conforme o seu banco.
- Fábricas são geradas por domínio:
database/factories/{Domínio}/{Model}Factory.php. Isso permite ao Laravel resolver automaticamente a factory de models namespaced. - O Controller usa vinculação de rota por nome de parâmetro; exemplo: para
PhotoAnnotationController, as assinaturas sãoshow(PhotoAnnotation $photoAnnotation),update(PhotoAnnotation $photoAnnotation, ...),destroy(PhotoAnnotation $photoAnnotation). - Em SQLite, colunas JSON podem ser persistidas como texto. Os testes gerados evitam comparar diretamente campos JSON com
assertDatabaseHaspara prevenir falsos negativos. - Para
SoftDeletes, incluadeleted_atna DDL para o gerador adicionar o trait ao Model e os asserts de soft delete aos testes. Caso seu schema inicial não tenhadeleted_at, crie uma migration complementar adicionandosoftDeletes().
Testes
- Configure
.env.testinge rode as migrations de teste. - Execute a suíte:
php artisan test.
Se precisar, abra uma issue ou peça para ajustar os stubs para novas regras do seu domínio.
Problemas comuns
- "Command cannot have an empty name": confira a assinatura do comando
make:crud-from-ddlemapp/Console/Commands/MakeCrudFromDdl.php. - Arquivo DDL inválido: certifique-se de terminar cada
CREATE TABLE ... (...);com;e usar sintaxe consistente.