PHPackages                             alncris2/laravel-procedure - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. alncris2/laravel-procedure

ActiveLibrary[Database &amp; ORM](/categories/database)

alncris2/laravel-procedure
==========================

Procedure versioning and execution support for Laravel projects.

v0.2.0(1mo ago)03[1 issues](https://github.com/Alncris2/laravel-procedure/issues)MITPHPPHP &gt;=7.1.3

Since Apr 14Pushed 1w agoCompare

[ Source](https://github.com/Alncris2/laravel-procedure)[ Packagist](https://packagist.org/packages/alncris2/laravel-procedure)[ RSS](/packages/alncris2-laravel-procedure/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (3)Dependencies (4)Versions (4)Used By (0)

laravel-procedure
=================

[](#laravel-procedure)

Versionamento e aplicação de **stored procedures** para projetos Laravel, com snapshots automáticos em disco e histórico em banco.

- Laravel 5.8+ / PHP 7.1.3+
- Usa sempre a **connection default** do Laravel (`config('database.default')`)
- Estrutura por grupo: `database/procedures/{grupo}/{PROCEDURE}/current.sql` + `versions/YYYYMMdd_HHmmss_label.sql`
- `current.sql` é a fonte viva editada pelo dev; os snapshots em `versions/` são **gerados automaticamente**
- Snapshots com nome baseado em timestamp — sem conflito quando dois devs trabalham na mesma procedure

Instalação
----------

[](#instalação)

```
composer require alncris2/laravel-procedure
```

Publicar config e migration (tudo de uma vez):

```
php artisan vendor:publish --tag=procedure
php artisan migrate
```

Ou separadamente, se preferir:

```
php artisan vendor:publish --tag=procedure-config
php artisan vendor:publish --tag=procedure-migrations
```

Uso
---

[](#uso)

### Criar uma procedure

[](#criar-uma-procedure)

```
php artisan procedure:make atendimento PRC_BUSCAR_ATENDIMENTOS
```

Gera:

```
database/procedures/atendimento/PRC_BUSCAR_ATENDIMENTOS/
  current.sql
  versions/

```

O `current.sql` vem com um template compatível com o driver detectado (oracle, mysql, pgsql, sqlsrv).

### Editar

[](#editar)

Abra e edite `current.sql`. **Nunca** edite os arquivos em `versions/` — eles são snapshots congelados.

### Ver status

[](#ver-status)

```
php artisan procedure:status
php artisan procedure:status --group=atendimento
php artisan procedure:status --changed
```

Estados possíveis: `SYNCED`, `CHANGED`, `PENDING`, `FAILED`, `UNTRACKED`.

### Aplicar

[](#aplicar)

```
php artisan procedure:apply
php artisan procedure:apply --only=PRC_BUSCAR_ATENDIMENTOS --message="corrige filtro de status"
php artisan procedure:apply --group=atendimento
```

O apply:

1. Detecta o que mudou comparando o checksum do `current.sql` com a versão marcada como `is_current` no banco.
2. Cria automaticamente um snapshot em `versions/YYYYMMdd_HHmmss_slug.sql` (se `snapshot_on_apply` estiver habilitado).
3. Executa o SQL com `DB::connection()->unprepared(...)`.
4. Registra o histórico em `procedure_versions`.
5. Aplica o **rolling window**: se o número de snapshots em disco exceder `max_snapshots`, o mais antigo é removido automaticamente.

### Dump (importar procedures do banco)

[](#dump-importar-procedures-do-banco)

Para trazer procedures já existentes no banco para dentro do projeto:

```
# Sem --group: infere grupos automaticamente em modo dry-run
php artisan procedure:dump

# Efetiva a proposta do auto-group
php artisan procedure:dump --apply

# Grupo explícito (comportamento clássico)
php artisan procedure:dump --group=atendimento
php artisan procedure:dump --group=atendimento --only=PRC_BUSCAR_ATENDIMENTOS
php artisan procedure:dump --group=atendimento --owner=MYSCHEMA          # Oracle
php artisan procedure:dump --group=imported --no-register                # não grava linha em procedure_versions

# Forçar uma estratégia específica de auto-group
php artisan procedure:dump --apply --strategy=prefix   # cascade|prefix|tables|schema
```

#### Auto-group (quando `--group` é omitido)

[](#auto-group-quando---group-é-omitido)

O grupo de destino de cada procedure é inferido por uma **cascata determinística** (sem APIs externas, sem dependências de ML):

1. **Prefixo do nome** — `SP_INV_*`, `PRC_FIN_*`, `UpdateCustomer` → agrupa pelo token de domínio, pulando prefixos de tipo (`sp_`, `prc_`, etc.).
2. **Tabelas referenciadas** — parse leve de `FROM`/`JOIN`/`UPDATE`/`INSERT INTO`/`DELETE FROM`/`MERGE INTO`; procedures que compartilham tabelas caem no mesmo grupo, nomeado pela tabela mais frequente.
3. **Owner/schema** do banco como fallback.
4. **`ungrouped`** como último recurso.

Sem `--apply`, o comando apenas imprime a proposta (tabela `procedure | grupo proposto | estratégia | tabelas-chave`) sem gravar nada. Com `--apply`, efetiva.

Configurável em `config/procedure.php` no bloco `auto_group` (veja abaixo).

#### Comportamento por procedure

[](#comportamento-por-procedure)

- **Procedure nova no projeto** (primeira importação) → grava `current.sql` e uma **baseline silenciosa** em `procedure_versions` com label `dump_import`. **Nenhum arquivo** é criado em `versions/` — `status` já fica `SYNCED`.
- **Existe e banco == disco** → resultado `synced`, nenhuma escrita.
- **Existe e diverge** → sobrescreve `current.sql` e cria snapshot físico `versions/YYYYMMdd_HHmmss_dump_sync.sql` como uma versão real do histórico.

Dessa forma `versions/` só registra mudanças reais vindas do banco; a primeira importação não polui o diretório. Rollback sobre uma baseline sem snapshot físico retorna mensagem explicativa.

Suporta Oracle (`USER_SOURCE` / `ALL_SOURCE`) e MySQL (`SHOW CREATE PROCEDURE`).

### Rollback

[](#rollback)

```
php artisan procedure:rollback --only=PRC_BUSCAR_ATENDIMENTOS
php artisan procedure:rollback --only=PRC_BUSCAR_ATENDIMENTOS --to-version=1
php artisan procedure:rollback --group=atendimento
```

Reaplica o snapshot alvo completo (full-state) e marca o `is_current` no registro correspondente.

`--to-version=N` refere-se à **posição** do snapshot na lista ordenada por nome (do mais antigo para o mais novo).

---

Fluxo com dois devs na mesma procedure
--------------------------------------

[](#fluxo-com-dois-devs-na-mesma-procedure)

Este é o cenário mais comum em times que trabalham em paralelo.

### Situação inicial

[](#situação-inicial)

O time fez o dump do banco e commitou tudo na branch `prd`. Cada dev cria sua branch a partir dali:

```
# Dev A
git checkout -b feature/filtro-ativo prd

# Dev B (em paralelo)
git checkout -b fix/ordenacao prd
```

Ambos partem do mesmo `current.sql`:

```
-- SP_USUARIOS/current.sql
CREATE OR REPLACE PROCEDURE SP_USUARIOS AS
BEGIN
  SELECT * FROM usuarios;
END;
```

### Dev A faz sua alteração

[](#dev-a-faz-sua-alteração)

```
-- Adiciona filtro de ativos
SELECT * FROM usuarios WHERE ativo = 1;
```

```
php artisan procedure:apply --message="filtro ativo"
# Gera: versions/20260601_090000_filtro_ativo.sql
git add .
git commit -m "feat: SP_USUARIOS filtra apenas usuários ativos"
```

### Dev B faz sua alteração (em paralelo)

[](#dev-b-faz-sua-alteração-em-paralelo)

```
-- Adiciona ordenação
SELECT * FROM usuarios ORDER BY nome;
```

```
php artisan procedure:apply --message="ordenacao por nome"
# Gera: versions/20260601_103000_ordenacao_por_nome.sql
git add .
git commit -m "fix: SP_USUARIOS retorna usuários ordenados por nome"
```

### Merge na branch de desenvolvimento

[](#merge-na-branch-de-desenvolvimento)

O PR do Dev A entra primeiro — sem conflito, a branch `dev` ainda tem a base de `prd`.

Quando o PR do Dev B vai ser mergeado:

ArquivoResultado no git`versions/20260601_103000_ordenacao_por_nome.sql`**Sem conflito** — arquivo com nome único (timestamp diferente do de A)`current.sql`**Conflito** — A tem `WHERE ativo = 1`, B tem `ORDER BY nome`O git marca o conflito em `current.sql`:

```
 fix/ordenacao
```

Quem fizer o merge resolve mantendo as duas alterações:

```
  SELECT * FROM usuarios WHERE ativo = 1 ORDER BY nome;
```

### Deploy (CI/CD)

[](#deploy-cicd)

```
php artisan procedure:apply
```

O `procedure:status` detecta `CHANGED` — o `current.sql` mergeado tem checksum diferente de qualquer snapshot existente. O apply:

1. Cria `versions/20260601_140000_auto_snapshot.sql` com o SQL das duas alterações juntas.
2. Executa no banco.
3. Remove o snapshot mais antigo se o limite de `max_snapshots` for atingido.

**O banco fica com as alterações dos dois devs.** Nenhuma sobrescreve a outra.

### Por que não há conflito nos snapshots?

[](#por-que-não-há-conflito-nos-snapshots)

O nome do snapshot inclui o **timestamp do momento em que foi gerado**. Dev A gerou às 09:00, Dev B às 10:30 — nomes diferentes, o git os trata como dois arquivos novos independentes e não gera conflito entre eles.

Sem isso, ambos gerariam `versions/002_auto_snapshot.sql` — mesmo nome, conflito garantido no merge.

---

Configuração
------------

[](#configuração)

`config/procedure.php`:

```
return [
    'base_path'               => database_path('procedures'),
    'history_table'           => 'procedure_versions',
    'snapshot_on_apply'       => true,
    'default_snapshot_message'=> 'auto_snapshot',
    'max_snapshots'           => 5,
    'sql' => [
        'strip_trailing_oracle_slash' => true,
        'remove_mysql_delimiter'      => true,
    ],
    'auto_group' => [
        'min_cluster_size' => 2,
        'prefix_separator' => '_',
        'noise_prefixes'   => ['sp', 'usp', 'prc', 'proc', 'fn', 'fnc', 'p'],
        'noise_tables'     => ['dual'],
        'fallback'         => 'ungrouped',
    ],
];
```

### Opções principais

[](#opções-principais)

OpçãoPadrãoDescrição`base_path``database/procedures`Raiz da estrutura de procedures`history_table``procedure_versions`Tabela de histórico no banco`snapshot_on_apply``true`Grava snapshot em `versions/` antes de executar`default_snapshot_message``auto_snapshot`Label do snapshot quando `--message` não é passado`max_snapshots``5`Máximo de snapshots por procedure em disco. O mais antigo é removido quando excedido. Use `0` ou `false` para desativar.Tabela de histórico
-------------------

[](#tabela-de-histórico)

`procedure_versions`:

ColunaDescrição`group_name`, `procedure_name`Localização lógica`version_number`, `version_label`, `file_name`, `file_path`Rastreabilidade do snapshot`checksum`sha256 do conteúdo aplicado`execution_status``success` ou `failed``execution_time_ms`, `error_message`Métricas/erro da execução`applied_at`, `rolled_back_at`Auditoria`is_current`Flag da versão atualmente ativaFilosofia
---------

[](#filosofia)

- **Full-state, não patch**: cada snapshot contém o SQL completo da procedure. Simples de rollback, simples de auditar.
- **Git como fonte da verdade**: `current.sql` é o arquivo que o time edita e mergeia. O banco segue o git, não o contrário.
- **Sem conflito de snapshots em paralelo**: nomes baseados em timestamp eliminam colisões quando múltiplos devs trabalham na mesma procedure.
- **Idempotência no DDL**: escreva `CREATE OR REPLACE` / `DROP ... IF EXISTS` conforme o driver.
- **Uma fonte viva**: `current.sql` é o único arquivo editável; o resto é histórico.

Licença
-------

[](#licença)

MIT

###  Health Score

32

—

LowBetter than 70% of packages

Maintenance94

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity21

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

3

Last Release

55d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/ea3e46dfc23b7f443716bd489442b59d172bd2431b627d7805eb2999f1ce60da?d=identicon)[alncris2](/maintainers/alncris2)

---

Top Contributors

[![Alncris2](https://avatars.githubusercontent.com/u/51797670?v=4)](https://github.com/Alncris2 "Alncris2 (8 commits)")

---

Tags

laravelmysqloracleversioningprocedurestored-procedure

### Embed Badge

![Health badge](/badges/alncris2-laravel-procedure/health.svg)

```
[![Health](https://phpackages.com/badges/alncris2-laravel-procedure/health.svg)](https://phpackages.com/packages/alncris2-laravel-procedure)
```

###  Alternatives

[laravel/ai

The official AI SDK for Laravel.

9782.1M153](/packages/laravel-ai)[kirschbaum-development/eloquent-power-joins

The Laravel magic applied to joins.

1.6k29.9M42](/packages/kirschbaum-development-eloquent-power-joins)[illuminate/queue

The Illuminate Queue package.

20432.2M1.5k](/packages/illuminate-queue)[yajra/laravel-oci8

Oracle DB driver for Laravel via OCI8

8733.1M23](/packages/yajra-laravel-oci8)[itpathsolutions/dbstan

Database Standardization and Analysis Tool for Laravel

442.1k](/packages/itpathsolutions-dbstan)[laragear/populate

Populate your database with a supercharged, continuable seeder

8713.1k](/packages/laragear-populate)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
