Docs›Infraestrutura & Ferramentas›Importação de dados
Infraestrutura & Ferramentas

Importação de dados

CSV → tabelas via template de mapeamento, upsert multi-driver. Status: experimental (WIP).

Importação de dados (Data Import)

Status: experimental. O código está completo e funcional — service, telas administrativas, model, migration e a API REST de templates estão todos implementados, sem stubs. O que falta é cobertura de teste automatizada: não há nenhum teste de feature exercitando o motor de import, que roda INSERT/REPLACE/UPSERT cru contra conexões e tabelas configuráveis pelo usuário. Use em produção com cautela e revisão manual até essa lacuna fechar — é por isso que o CHANGELOG.md ainda marca o módulo como "WIP".

O que faz

App\Service\Sys\DataImportService::import() lê um CSV, mapeia colunas para uma ou mais tabelas via um template de mapeamento salvo em JSON, e grava os dados com upsert nativo do driver da conexão de destino:

DataImportService::import(
    mappingJson: $template->mapping_json,   // {"database": "...", "mappings": [...]}
    csvPath:     $uploadedCsvPath,
    database:    'business',                // conexão Eloquent de destino
    mode:        'partial',                 // 'atomic' | 'partial'
);
  • atomic — tudo dentro de 1 transação; qualquer linha inválida reverte o lote inteiro.
  • partial — processa em lotes de 100, com fallback linha-a-linha dentro de um lote que falhou (boas commitam, ruins ficam só no log de erro do resultado).
  • Multi-driver: mysql (REPLACE INTO), sqlite (INSERT OR REPLACE), pgsql (ON CONFLICT), firebird (MERGE), com mssql como fallback default.
  • Parsing de CSV tolera formato pt-BR (separador decimal) e auto-detecta o delimitador.

Descoberta de bancos e tabelas — introspecção local

A lista de bancos/tabelas/colunas oferecida nos formulários vem de App\Service\Sys\DataImportDatabaseService, que faz introspecção local do schema pelo Schema (Illuminate SchemaBuilder) — sem depender do webservice externo do MadBuilder (manager_url) que o legado exigia:

use App\Service\Sys\DataImportDatabaseService;

DataImportDatabaseService::listDatabases();
// ['business' => 'business', 'iam' => 'iam', ...]
//  ← uma entrada por conexão listada em config('mad.app_connections')

DataImportDatabaseService::listTables('business');
// ['mad_iam_user' => ['name' => 'mad_iam_user',
//                     'columns' => [['name' => 'id', 'type' => 'integer'], ...]], ...]

O DataImportForm chama listDatabases() dentro de um try/catch no mount(): se a introspecção falhar (permissão, driver sem catálogo), o form ainda renderiza — só sem a lista de bancos pré-carregada.

Staging do CSV

DataImportForm::onUpload($tempPath) lê o cabeçalho (auto-detecta ; ou ,), monta a lista de colunas de origem e copia o arquivo para um nome único de scratch (tmp/<uniqid>.<ext>), guardado na prop pública csvTempPath. É esse caminho — não o $tempPath original da request — que onImport() valida com file_exists() e passa para DataImportService::import(), e cujo basename() vai para o file_name do ImportLog.

Telas e API

Peça O que é
Sys\DataImportDashboard Grid de templates de importação salvos (/app/admin/..., rota data_import).
Sys\DataImportTemplateForm Criar/editar um template — mapeamento CSV → colunas.
Sys\DataImportForm Upload do CSV + escolha do template + modo (atomic/partial).
Sys\DataImportUseForm Execução de uma importação a partir de um template existente.
Sys\DataImportLogView Resultado da última execução: linhas importadas, erros por linha.
App\Models\Sys\ImportTemplate (+ ImportTemplateGroup/ImportTemplateUser) Template + ACL de quem pode usá-lo (isAdmin()/getVisibleTemplates()).
Route::apiResource('import-templates', ...) CRUD JSON via Sys\ImportTemplateApiController (Mad\Rest\ApiResourceController), grupo mad.auth em routes/modules/admin.php — ver REST API para o padrão geral desse controller.

Schema em database/migrations/0001_01_01_000100_create_mad_schema.php: mad_sys_import_template, mad_sys_import_template_group, mad_sys_import_template_user, mad_sys_import_log.

Antes de usar em produção

  • Escreva testes de feature cobrindo pelo menos: atomic com 1 linha inválida (deve reverter tudo), partial com 1 linha inválida no meio de um lote de 100 (deve commitar as 99 boas), e um CSV com delimitador alternativo.
  • O database de destino é um parâmetro livre — trate a configuração do template como algo que só usuários de confiança devem poder editar (a ACL de ImportTemplate existe exatamente para isso).
  • Revise o mapeamento de colunas de um template antes de rodar contra dados reais; não há dry-run embutido na UI atual.

Ver também

  • REST API — o ApiResourceController que serve import-templates.
  • CLI — php artisan db:table para inspecionar a tabela de destino antes de importar.