Search by

gustavoqueiroz / hyperf-crud-generator

Gustavo-queirozman

Extensible CRUD generator for Hyperf applications.

Package info

github.com/Gustavo-queirozman/hyperf-crud-generator

pkg:composer/gustavoqueiroz/hyperf-crud-generator

Statistics

Installs: 6

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.2 2026-09-09 23:07 UTC

This package is auto-updated.

Last update: 2026-09-09 23:11:24 UTC


README

Gerador de APIs CRUD schema-aware para aplicações Hyperf 3.1 e 3.2, criado para transformar tabelas existentes de um banco de dados em uma estrutura de API organizada, validada e documentada.

O pacote inspeciona o schema real do banco e pode gerar automaticamente Model, DTO, Resource, Requests, Repository, Service, Controller, Policy, rotas, Factory, Seeder, OpenAPI/Swagger e testes.

Versão preparada por estas alterações: v1.2.0

Principais recursos

  • Geração a partir de tabelas existentes.
  • Geração de uma tabela específica ou de um banco/schema inteiro.
  • Suporte a MySQL, MariaDB, PostgreSQL e SQL Server.
  • Inferência automática do nome do Model a partir da tabela.
  • Leitura de colunas, chaves primárias simples/compostas, índices UNIQUE, chaves estrangeiras, ações referenciais e CHECK constraints.
  • $fillable, $casts, $hidden, timestamps e SoftDeletes derivados do schema.
  • Validações geradas a partir de tipos, nulabilidade, tamanho, enum, UNIQUE simples/composto, FK simples/composta e expressões CHECK comuns.
  • Relacionamentos BelongsTo, HasOne e HasMany quando inferíveis.
  • Repository Interface + implementação e binding automático no container.
  • DTO para limitar os campos recebidos pela camada de serviço.
  • Resource para controlar os campos retornados pela API.
  • Paginação, ordenação, filtros por igualdade e busca textual.
  • Policies com adaptador de autorização configurável.
  • Middleware de autenticação/autorização configurável nas rotas geradas.
  • Factory e Seeder.
  • OpenAPI 3.0.3 em JSON.
  • Swagger UI em /docs.
  • Testes de Controller e Service.
  • Teste de integração do Repository.
  • --dry-run e --diff antes de escrever arquivos.
  • Geração em lote com allowlist e exclusões.
  • Manifesto de geração para regeneração segura.
  • Preservação de código customizado dentro de blocos <crud-custom>.
  • Preflight de todos os arquivos antes da escrita para evitar geração parcial em caso de conflito.

Requisitos

  • PHP 8.2+
  • Hyperf 3.1 ou 3.2
  • Uma conexão de banco configurada em config/autoload/databases.php

Dependências principais do pacote:

hyperf/command
doctrine/inflector
hyperf/contract
hyperf/db-connection
hyperf/http-server
hyperf/paginator
hyperf/validation

Para PostgreSQL, a aplicação de destino deve possuir o driver PostgreSQL compatível com a versão do Hyperf.

Para SQL Server, a aplicação deve possuir o driver hyperf/database-sqlserver compatível com sua instalação do Hyperf.

O gerador não aceita conexões com prefix de tabela configurado. Para geração por introspecção, utilize uma conexão sem prefixo.

Instalação

Composer

Se o pacote estiver disponível no repositório Composer utilizado pelo projeto:

composer require gustavoqueiroz/hyperf-crud-generator:^1.2

Publique o arquivo de configuração:

php bin/hyperf.php vendor:publish gustavoqueiroz/hyperf-crud-generator

O arquivo será criado em:

config/autoload/crud_generator.php

Desenvolvimento local com repository path

No composer.json da aplicação Hyperf:

{
  "repositories": [
    {
      "type": "path",
      "url": "../hyperf-crud-generator",
      "options": {
        "symlink": true
      }
    }
  ]
}

Depois execute:

composer require gustavoqueiroz/hyperf-crud-generator:@dev
php bin/hyperf.php vendor:publish gustavoqueiroz/hyperf-crud-generator

Bancos suportados

Banco Driver reconhecido Schema padrão
MySQL mysql nome do banco configurado
MariaDB mariadb nome do banco configurado
PostgreSQL pgsql, postgres, postgresql public
SQL Server sqlsrv, sqlserver, mssql dbo

A listagem em lote considera somente tabelas base. Views não são incluídas automaticamente.

Uso rápido

Gerar CRUD informando o Model

php bin/hyperf.php crud:generate User

Neste caso, a tabela é inferida a partir do nome do Model:

User -> users
OrderItem -> order_items

Por padrão, a configuração atual gera todos os componentes suportados.

Informar uma tabela específica

php bin/hyperf.php crud:generate User --table=erp_users

O Model será User, mas os dados serão lidos de erp_users.

Também é possível informar schema e tabela juntos:

php bin/hyperf.php crud:generate User --table=public.users

Inferir o Model diretamente da tabela

Use o alias crud:generate-table:

php bin/hyperf.php crud:generate-table users

Exemplos de inferência:

users       -> User
order_items -> OrderItem
products    -> Product

Também pode ser utilizado com as demais opções do gerador:

php bin/hyperf.php crud:generate-table users \
  --connection=default \
  --schema=public \
  --dry-run

Gerar um banco/schema inteiro

Existem duas formas equivalentes.

php bin/hyperf.php crud:generate --database

ou:

php bin/hyperf.php crud:generate-database

O gerador lista as tabelas do schema selecionado, inspeciona os metadados e cria os componentes para cada tabela válida.

Por padrão, a tabela migrations é excluída da geração em lote.

Gerar somente algumas tabelas

php bin/hyperf.php crud:generate-database \
  --tables=users,teams,products

Se alguma tabela informada em --tables não existir, o comando falha antes da geração.

Excluir tabelas

php bin/hyperf.php crud:generate-database \
  --exclude=migrations,audit_logs,temp_data

As exclusões informadas pela CLI são combinadas com crud_generator.exclude_tables.

Ignorar tabelas sem PK

Em geração em lote:

php bin/hyperf.php crud:generate-database --skip-unsupported

Essa opção faz o gerador reportar e ignorar tabelas que não possuem chave primária.

Chaves primárias compostas são suportadas. As rotas recebem um parâmetro por coluna, na ordem do schema, como /{key1}/{key2}.

Sem essa opção, a primeira tabela não suportada interrompe a geração.

Seleção da conexão e schema

Outra conexão

php bin/hyperf.php crud:generate-table users --connection=reporting

Forma curta:

php bin/hyperf.php crud:generate-table users -c reporting

A conexão deve existir em:

config/autoload/databases.php

Outro schema

PostgreSQL:

php bin/hyperf.php crud:generate-table users \
  --connection=default \
  --schema=backoffice

SQL Server:

php bin/hyperf.php crud:generate-table users \
  --connection=sqlserver \
  --schema=erp

MySQL/MariaDB usam o nome do banco como schema de catálogo.

Componentes disponíveis

O gerador atualmente reconhece os seguintes componentes:

model
dto
resource
store_request
update_request
repository_interface
repository
binding
service
controller
factory
seeder
policy
routes
openapi
swagger
test
integration_test

Para selecionar apenas alguns:

php bin/hyperf.php crud:generate User \
  --components=model,repository,service,controller,routes

As dependências são incluídas automaticamente.

Por exemplo:

php bin/hyperf.php crud:generate User --components=controller

não gera somente o Controller. O motor também adiciona os componentes necessários para que ele funcione, como Model, DTO, Resource, Requests, Repository, binding, Service e Policy.

Gerar todos os componentes

php bin/hyperf.php crud:generate User --all

Na configuração distribuída atualmente, todos os componentes já são o padrão. --all continua útil caso crud_generator.components seja customizado na aplicação.

Estrutura gerada

Uma geração completa de User pode produzir:

app/
├── Contract/
│   └── UserRepositoryInterface.php
├── Controller/
│   └── UserController.php
├── DTO/
│   └── UserData.php
├── Factory/
│   └── UserFactory.php
├── Model/
│   └── User.php
├── Policy/
│   └── UserPolicy.php
├── Repository/
│   └── UserRepository.php
├── Request/
│   └── User/
│       ├── StoreUserRequest.php
│       └── UpdateUserRequest.php
├── Resource/
│   └── UserResource.php
├── Seeder/
│   └── UserSeeder.php
└── Service/
    └── UserService.php

config/
├── crud-generator/
│   ├── User.php
│   └── manifest.json
└── routes.php

docs/
└── openapi/
    └── user.json

test/
└── Cases/
    ├── UserControllerTest.php
    ├── UserServiceTest.php
    └── UserRepositoryIntegrationTest.php

O arquivo em config/crud-generator/User.php registra automaticamente:

UserRepositoryInterface::class => UserRepository::class

O ConfigProvider carrega os arquivos desse diretório como bindings do container.

Rotas geradas

Para uma tabela users, o recurso HTTP será /users.

Para uma tabela como order_items, o recurso será:

/order-items

As rotas geradas são:

Método Endpoint Ação
GET /users listagem paginada
POST /users criação
GET /users/{id} consulta por ID
PUT /users/{id} atualização
PATCH /users/{id} atualização parcial
DELETE /users/{id} exclusão

Uma PK composta gera um segmento para cada coluna, por exemplo /memberships/{key1}/{key2}. Cada parâmetro OpenAPI informa a coluna correspondente em x-database-column.

As rotas recebem os middlewares:

GustavoQueiroz\HyperfCrudGenerator\Http\ValidationMiddleware::class
Hyperf\Validation\Middleware\ValidationMiddleware::class

O primeiro normaliza falhas de validação para o contrato JSON da API.

As classes configuradas em crud_generator.route_middlewares são acrescentadas depois desses dois middlewares.

Listagem, paginação, ordenação, filtros e busca

O Repository gerado suporta:

page
per_page
sort
direction
filter
search

Exemplo:

GET /users?page=2&per_page=20&sort=name&direction=asc&search=gustavo

Filtros são enviados como objeto/query deepObject:

GET /users?filter[active]=1&filter[team_id]=10

Regras atuais

  • page mínimo: 1
  • per_page mínimo: 1
  • per_page máximo: 100
  • direction: asc ou desc
  • somente colunas permitidas pelo schema podem ser utilizadas em sort e filter
  • campos json e binários não são usados para ordenação
  • campos configurados como ocultos não são usados para ordenação ou filtro
  • search usa LIKE nas colunas textuais visíveis
  • quando a ordenação não é pela PK, a PK é adicionada como segundo critério para estabilizar a paginação

Resposta de listagem:

{
  "data": [],
  "meta": {
    "current_page": 1,
    "per_page": 15,
    "total": 0,
    "last_page": 1
  }
}

Introspecção do schema

O SchemaInspector lê o banco de dados real antes da geração.

Atualmente são coletados:

  • nome das tabelas;
  • nome e ordem das colunas;
  • tipo do banco;
  • nulabilidade;
  • valor/default informado pelo catálogo;
  • tamanho máximo;
  • precisão e escala numérica;
  • identidade/auto incremento;
  • colunas geradas/computadas;
  • chave primária;
  • índices UNIQUE;
  • foreign keys;
  • ações ON UPDATE e ON DELETE das foreign keys;
  • CHECK constraints;
  • enums nativos quando disponíveis.

Model gerado

O Model é configurado automaticamente com base no schema:

protected ?string $connection;
protected ?string $table;
protected string $primaryKey;
protected string $keyType;
protected array $fillable;
protected array $casts;
protected array $hidden;

Também são inferidos:

  • $timestamps;
  • CREATED_AT;
  • UPDATED_AT;
  • $incrementing;
  • SoftDeletes quando existe deleted_at nullable;
  • tratamento de identity do SQL Server;
  • relacionamentos inferíveis.

Colunas geradas, identity e timestamps convencionais não entram em $fillable.

A chave primária também é removida dos campos permitidos durante atualização.

Mapeamento de tipos

O pacote normaliza os tipos do banco em categorias usadas pelo Model, validação e OpenAPI.

Exemplos:

Banco Categoria usada
bool, boolean, bit boolean
smallint, int, integer, serial integer
bigint, bigserial bigint
decimal, numeric, money decimal
float, real, double number
json, jsonb json
uuid, uniqueidentifier uuid
date date
timestamps/datetimes datetime
time time
blob/binary/bytea/rowversion binary
tipos não reconhecidos especificamente string

Alguns casts gerados:

integer  -> integer
bigint   -> string
boolean  -> boolean
decimal  -> decimal:<scale>
number   -> float
json     -> json
date     -> date
datetime -> datetime

bigint é tratado como string na camada de representação/OpenAPI para reduzir risco de perda de precisão em clientes JSON.

Validações automáticas

Os StoreRequest e UpdateRequest são derivados das colunas reais.

O gerador pode produzir regras para:

  • required;
  • sometimes;
  • nullable;
  • integer;
  • numeric;
  • boolean;
  • string;
  • array para JSON;
  • uuid;
  • date;
  • date_format;
  • max:<length>;
  • min:0 para valores unsigned;
  • precisão/escala decimal por regex;
  • enum com Rule::in(...);
  • Rule::unique(...) para UNIQUE simples e composto;
  • Rule::exists(...) para foreign key simples e composta;
  • min, max, between e Rule::in(...) para formatos comuns de CHECK.

No Update, a regra unique exclui a linha identificada pela chave primária atual, inclusive quando a PK é composta. Em constraints compostas, required_with evita validar apenas uma parte da chave.

Campos que não podem ser escritos — como identity, colunas geradas e PK no Update — recebem regra:

['prohibited']

Isso evita que valores extras sejam aceitos silenciosamente pelo FormRequest.

DTO e proteção de atributos

O DTO gerado aplica uma allowlist antes de enviar os dados para o Service/Repository:

UserData::fromArray($request->validated())

Mesmo que um array contenha atributos extras, somente os campos permitidos pelo schema são mantidos.

Durante update, a chave primária não pode ser alterada pelo DTO.

Campos sensíveis

A configuração padrão contém:

'hidden' => [
    'password',
    'password_hash',
    'remember_token',
    'api_token',
    'secret',
],

Esses campos:

  • continuam podendo ser gravados quando forem colunas graváveis;
  • são omitidos do Resource/response;
  • não entram em filtros;
  • não entram em ordenação;
  • não entram na busca;
  • aparecem como writeOnly nos schemas de escrita do OpenAPI.

Campos binários também são excluídos da resposta padrão.

Relacionamentos automáticos

O gerador consegue criar relacionamentos para foreign keys de uma coluna.

BelongsTo

Quando a tabela atual possui uma FK conhecida e a tabela de destino está no model_map, pode ser gerado um BelongsTo.

Exemplo conceitual:

users.team_id -> teams.id

HasOne e HasMany

Durante geração em lote, o motor analisa as outras tabelas selecionadas e pode gerar a relação inversa.

Quando a FK da tabela relacionada também é UNIQUE/PK, a relação inversa é tratada como HasOne; caso contrário, HasMany.

Os nomes dos métodos são gerados de forma conservadora para evitar colisões com atributos existentes.

model_map

Use model_map para definir explicitamente o Model associado a uma tabela qualificada:

'model_map' => [
    'public.users' => 'User',
    'public.teams' => 'Team',
    'erp.customers' => 'Customer',
],

Isso também permite criar relações com Models existentes que não estejam sendo gerados naquele comando.

Em geração em lote, Models não configurados no mapa são inferidos a partir do nome da tabela.

Se duas tabelas resultarem no mesmo Model ou no mesmo recurso HTTP, o motor interrompe a geração antes de escrever arquivos.

Autorização e Policies

Cada Controller gerado depende de uma Policy específica do recurso.

Abilities utilizadas:

viewAny
view
create
update
delete

A implementação padrão é:

GustavoQueiroz\HyperfCrudGenerator\Authorization\ConfigAuthorization

Ela lê:

'authorization' => [
    'default' => 'allow',
    'rules' => [],
],

Importante sobre segurança

O código distribuído atualmente utiliza:

'default' => 'allow'

Portanto, na ausência de uma regra específica, o acesso é permitido.

Para APIs privadas, é recomendado alterar para:

'authorization' => [
    'default' => 'deny',
    'rules' => [],
],

As regras podem ser callables indexados por Model e ability:

use Hyperf\HttpServer\Contract\RequestInterface;

'authorization' => [
    'default' => 'deny',
    'rules' => [
        'User' => [
            'viewAny' => static function (RequestInterface $request, mixed $subject): bool {
                return true;
            },
            'view' => static function (RequestInterface $request, mixed $subject): bool {
                return true;
            },
        ],
    ],
],

Também é possível substituir o binding de:

GustavoQueiroz\HyperfCrudGenerator\Authorization\AuthorizationInterface

por um adaptador próprio para RBAC, ACL ou outro mecanismo da aplicação.

O pacote não escolhe um mecanismo de login/JWT/OAuth, pois isso depende da aplicação. Configure as classes já instaladas no projeto em route_middlewares; elas serão adicionadas a todos os grupos CRUD gerados.

Respostas HTTP

O Controller gerado padroniza alguns erros:

Status Situação
201 recurso criado
204 recurso removido
403 autorização negada
404 Model não encontrado
409 conflito de constraint do banco (SQLSTATE classe 23)
422 falha de validação

Formato de validação:

{
  "message": "Validation failed",
  "errors": {
    "email": [
      "The email field is required."
    ]
  }
}

OpenAPI e Swagger UI

O componente openapi gera um documento OpenAPI 3.0.3 para cada recurso:

docs/openapi/user.json

O documento inclui:

  • rotas CRUD;
  • parâmetros de paginação;
  • ordenação;
  • busca;
  • filtros;
  • schemas de Response, Store e Update;
  • tipos derivados das colunas;
  • required;
  • nullable;
  • enums;
  • tamanho máximo;
  • campos read-only;
  • campos write-only;
  • metadata de PK, UNIQUE, FKs, ações referenciais e CHECK em x-database;
  • respostas 403, 404, 409 e 422 quando aplicável.

O componente swagger adiciona ao arquivo de rotas:

GET /docs
GET /docs/openapi/{name}.json

A página /docs usa Swagger UI e lista os arquivos JSON existentes em crud_generator.openapi_path.

O HTML atual do Swagger UI carrega os assets de swagger-ui-dist por CDN. Ambientes isolados podem optar por customizar essa camada.

Dry run

Valida a geração inteira sem criar arquivos:

php bin/hyperf.php crud:generate User --dry-run

O planejamento executa verificações de:

  • componentes;
  • colisões de Model/recurso;
  • conflitos de destino;
  • sintaxe PHP dos arquivos planejados;
  • permissões dos diretórios de destino;
  • integridade dos blocos de rota;
  • existência de arquivos que seriam sobrescritos.

Nenhum diretório ou arquivo é criado durante o dry-run.

Diff

Exibe um diff unificado sem alterar os arquivos:

php bin/hyperf.php crud:generate User --diff

Também funciona em lote:

php bin/hyperf.php crud:generate-database --diff

Como --diff trabalha em modo de preview, ele não grava os arquivos planejados.

Regeneração segura

O pacote mantém um manifesto em:

config/crud-generator/manifest.json

Para regenerar código depois de uma alteração no schema:

php bin/hyperf.php crud:generate User --regenerate

O motor compara hashes do conteúdo anteriormente gerado.

Arquivos que ainda correspondem à versão gerada podem ser atualizados automaticamente.

Blocos customizados

Alguns stubs possuem:

// <crud-custom>
// </crud-custom>

O conteúdo colocado dentro desses marcadores é preservado durante a regeneração.

Atualmente esses blocos existem nos componentes:

  • Model;
  • Repository;
  • Service;
  • Controller;
  • Policy.

Exemplo:

// <crud-custom>
public function customMethod(): string
{
    return 'preserved';
}
// </crud-custom>

Alterações manuais fora das áreas protegidas fazem a regeneração recusar a substituição, a menos que --force seja utilizado.

Force

Para sobrescrever arquivos existentes e blocos de rota gerados:

php bin/hyperf.php crud:generate User --force

Forma curta:

php bin/hyperf.php crud:generate User -f

Use com cuidado: --force permite substituir conteúdo existente.

O motor executa um preflight de todos os destinos antes da escrita para evitar gerar metade de um CRUD e falhar somente no último arquivo.

Rotas e marcadores

Rotas são inseridas em blocos identificados:

// <hyperf-crud-generator:User>
// ...
// </hyperf-crud-generator:User>

As rotas do Swagger utilizam um bloco próprio:

// <hyperf-crud-generator:_swagger>
// ...
// </hyperf-crud-generator:_swagger>

O motor detecta:

  • marcadores duplicados;
  • marcadores incompletos;
  • marcadores invertidos;
  • alteração manual do bloco gerado.

O arquivo de rotas não deve possuir ?> no final quando novos blocos precisarem ser adicionados.

Configuração

Configuração distribuída atualmente:

<?php

declare(strict_types=1);

return [
    'namespace' => 'App',
    'base_path' => BASE_PATH . '/app',
    'routes_file' => BASE_PATH . '/config/routes.php',
    'openapi_path' => BASE_PATH . '/docs/openapi',
    'test_path' => BASE_PATH . '/test/Cases',
    'test_namespace' => 'HyperfTest\\Cases',
    'binding_path' => BASE_PATH . '/config/crud-generator',

    'connection' => 'default',
    'schema' => null,

    'exclude_tables' => [
        'migrations',
    ],

    'model_map' => [],

    'stub_path' => null,

    'authorization' => [
        'default' => 'allow',
        'rules' => [],
    ],

    'route_middlewares' => [
        // \App\Middleware\JwtAuthMiddleware::class,
    ],

    'hidden' => [
        'password',
        'password_hash',
        'remember_token',
        'api_token',
        'secret',
    ],

    'force' => false,

    'components' => \GustavoQueiroz\HyperfCrudGenerator\Generator\CrudGenerator::COMPONENTS,
];

Opções

Chave Função
namespace namespace base dos artefatos gerados
base_path diretório principal de código
routes_file arquivo que recebe os blocos de rota
openapi_path diretório dos JSON OpenAPI
test_path diretório dos testes gerados
test_namespace namespace dos testes
binding_path bindings e manifesto do gerador
connection conexão padrão de banco
schema schema/banco padrão para introspecção
exclude_tables exclusões automáticas em geração em lote
model_map mapeamento schema.table => Model
stub_path diretório opcional de stubs customizados
authorization regras do adaptador de autorização padrão
route_middlewares middlewares da aplicação adicionados aos grupos de rotas CRUD
hidden campos graváveis que não devem aparecer nas respostas/filtros
force permite sobrescrita global via configuração
components componentes gerados quando a CLI não especifica --components

Stubs customizados

É possível substituir stubs individuais configurando:

'stub_path' => BASE_PATH . '/stubs/crud',

O gerador procura primeiro, nesse diretório:

model.stub
dto.stub
resource.stub
store_request.stub
update_request.stub
repository_interface.stub
repository.stub
binding.stub
service.stub
controller.stub
factory.stub
seeder.stub
policy.stub
routes.stub
swagger.stub
test.stub
service_test.stub
repository_test.stub

Se um stub customizado não existir, o pacote utiliza automaticamente o stub interno correspondente.

Factory e Seeder

A Factory gera valores de exemplo com base nos tipos detectados.

Exemplo de uso:

$user = UserFactory::create([
    'email' => 'user@example.com',
]);

Valores de foreign keys obrigatórias devem ser fornecidos por override quando não puderem ser derivados com segurança:

$user = UserFactory::create([
    'team_id' => $team->id,
]);

O Seeder recebe uma lista de linhas e executa a criação dentro de transação:

$seeder = new UserSeeder();

$seeder->run([
    ['name' => 'User 1', 'email' => 'user1@example.com'],
    ['name' => 'User 2', 'email' => 'user2@example.com'],
]);

Testes gerados

O componente test gera:

UserControllerTest.php
UserServiceTest.php

Os testes verificam cenários como:

  • autorização;
  • 404;
  • criação 201;
  • atualização;
  • exclusão 204;
  • proteção de campos inesperados;
  • passagem correta de paginação/filtros;
  • imutabilidade da chave primária no DTO de update.

O componente integration_test gera:

UserRepositoryIntegrationTest.php

Esse teste é desativado por padrão e requer:

CRUD_INTEGRATION_TESTS=1

além de um bootstrap real da aplicação Hyperf e um banco descartável com o schema existente.

Quando uma tabela possui foreign keys obrigatórias, overrides podem ser fornecidos por variável de ambiente específica do Model:

CRUD_TEST_User_FIXTURE

com JSON contendo valores de FK existentes.

Testes do próprio pacote

Testes unitários

composer test

Equivalente a:

vendor/bin/phpunit

Somente a suíte unitária:

vendor/bin/phpunit --testsuite unit

Testes de catálogo com bancos reais

O repositório inclui compose.test.yaml com:

  • MySQL 8.4;
  • MariaDB 11.4;
  • PostgreSQL 16;
  • SQL Server 2022.

Uma forma de executar a suíte em containers é:

docker compose -f compose.test.yaml up \
  --build \
  --abort-on-container-exit \
  --exit-code-from runner \
  runner

A suíte de integração também pode ser executada diretamente quando as variáveis CRUD_TEST_* estiverem configuradas:

composer test:integration

Opções da CLI

Principais opções disponíveis nos comandos de geração:

Opção Descrição
--table=<table> tabela utilizada para geração
--database gera todas as tabelas do schema
--tables=a,b,c allowlist em geração de database
--exclude=a,b,c exclui tabelas
--connection=<name> / -c conexão de banco
--schema=<schema> schema ou banco para introspecção
--components=a,b,c seleciona componentes
--all seleciona todos os componentes
--dry-run valida sem gravar
--diff imprime diff sem gravar
--regenerate regenera arquivos controlados pelo manifesto
--skip-unsupported ignora tabelas sem PK em modo database
--force / -f força substituição

--tables e --skip-unsupported só podem ser utilizados no modo de geração de database.

--database não pode ser combinado com um Model ou --table.

Arquitetura interna

Os principais componentes do pacote são:

Command
 └── GenerateCrudCommand
     ├── GenerateTableCommand
     └── GenerateDatabaseCommand

Schema
 ├── SchemaInspector
 ├── MySqlCatalog
 ├── PostgresCatalog
 ├── SqlServerCatalog
 ├── Table
 └── Column

Generator
 ├── CrudGenerator
 ├── GeneratorContext
 ├── SchemaVariables
 └── OpenApiGenerator

Support
 ├── FileWriter
 ├── Manifest
 ├── StubRenderer
 ├── Diff
 ├── Name
 ├── Uuid
 └── SqlServerIdentity

Authorization
 ├── AuthorizationInterface
 └── ConfigAuthorization

Http
 ├── ValidationMiddleware
 └── DocumentationController

Fluxo simplificado

CLI
 ↓
Connection config
 ↓
SchemaInspector
 ↓
Table + Column metadata
 ↓
GeneratorContext
 ↓
SchemaVariables
 ↓
CrudGenerator
 ↓
Stubs / OpenApiGenerator
 ↓
Preflight
 ↓
Manifest
 ↓
Arquivos gerados

Limitações atuais

O pacote é schema-aware, mas nem toda estrutura possível de um banco relacional pode ser transformada automaticamente em CRUD Hyperf.

Chave primária

É exigida uma chave primária. Chaves simples e compostas são aceitas:

PRIMARY KEY (column_a, column_b)

Para PK composta, o Controller e o OpenAPI usam /{key1}/{key2}, e Service/Repository usam um array associativo como:

['column_a' => $key1, 'column_b' => $key2]

O Repository gerado consulta, atualiza e remove a linha por todas as colunas da PK, sem depender de Model::find() para a chave composta. Tabelas sem PK continuam sem um identificador seguro para CRUD.

Em lote, use:

--skip-unsupported

para ignorá-las.

Constraints compostas

Índices UNIQUE e foreign keys compostos geram regras com escopo pelas demais colunas da constraint. As partes também recebem required_with.

Relacionamentos ORM BelongsTo, HasOne e HasMany continuam sendo gerados apenas para FKs de uma coluna, porque as relações nativas do Hyperf/Eloquent não possuem chave composta.

O banco permanece a autoridade final para concorrência entre a validação e a gravação; violações ainda são convertidas em HTTP 409.

Views

A geração em lote lista apenas tabelas base. Views e materialized views não são tratadas como recursos CRUD automaticamente.

Índices funcionais/parciais

No PostgreSQL, índices funcionais e parciais não são convertidos em regras simples de validação.

No SQL Server, índices filtrados são ignorados pela introspecção de UNIQUE usada pelo gerador.

Tipos específicos do banco

Tipos conhecidos são normalizados. Tipos especializados não mapeados explicitamente caem na categoria string.

Revise o resultado para tipos como geoespaciais, ranges, arrays e tipos definidos pelo usuário.

CHECK constraints

O catálogo preserva todas as expressões em x-database.checks. O gerador converte automaticamente padrões escalares seguros com BETWEEN, >=, <=, IN e limite de tamanho por CHAR_LENGTH, CHARACTER_LENGTH, LENGTH ou LEN.

Expressões com funções específicas do banco, comparações entre colunas, regex SQL, subexpressões complexas ou lógica dependente de sessão permanecem sob responsabilidade do banco.

Ações de FK

Regras como estas são lidas e publicadas em x-database.foreignKeys:

ON DELETE CASCADE
ON DELETE SET NULL
ON UPDATE CASCADE

O gerador não duplica cascatas no Service/Repository. O banco executa a ação referencial de forma atômica.

Autenticação

O pacote possui Policy/autorização e adiciona os middlewares informados em route_middlewares às rotas geradas.

Como o schema não informa qual biblioteca de identidade a aplicação usa, a instalação e a configuração do middleware de login/JWT/OAuth continuam sendo feitas no projeto consumidor.

Recomendações para bancos grandes

Ao utilizar o gerador em ERPs ou bancos com centenas de tabelas, prefira começar com preview:

php bin/hyperf.php crud:generate-database \
  --dry-run \
  --skip-unsupported

Depois reduza o escopo com:

--tables=...

ou:

--exclude=...

Também pode ser útil customizar crud_generator.components para não gerar Controller/rotas para tabelas internas que não devem ser expostas como API.

Exemplo de fluxo recomendado

1. Conferir conexão

php bin/hyperf.php crud:generate-table users --dry-run

2. Ver o diff

php bin/hyperf.php crud:generate-table users --diff

3. Gerar

php bin/hyperf.php crud:generate-table users

4. Revisar autorização

Para APIs privadas:

'authorization' => [
    'default' => 'deny',
    'rules' => [
        // ...
    ],
],

5. Configurar autenticação das rotas conforme a aplicação

'route_middlewares' => [
    \App\Middleware\JwtAuthMiddleware::class,
],

6. Executar os testes

composer test

7. Depois de alterar o schema

php bin/hyperf.php crud:generate-table users --diff --regenerate

Se o preview estiver correto:

php bin/hyperf.php crud:generate-table users --regenerate

Licença

MIT.