Especialização em Backend com PHP & Laravel • Laravel 11 & PHP 8.3+ • Eloquent ORM, Sanctum, Filas, Horizon e APIs Corporativas


🗺️ Mapa Conceitual do Tópico

flowchart TD
    A["Migration (arquivo versionado)"] --> B["Schema::create() / Schema::table()"]
    B --> C["Blueprint: colunas, tipos, índices"]
    C --> D["Foreign Keys e Constraints"]
    D --> E["php artisan migrate"]
    E --> F["Banco de Dados atualizado"]
    F -.rollback.-> G["método down() reverte"]

    style A fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
    style C fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
    style E fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style G fill:#ffebee,stroke:#e53935,stroke-width:2px

🏛️ 1. Migrations como Controle de Versão do Schema

Uma migration é um arquivo PHP com timestamp no nome que descreve uma alteração no schema do banco de forma reversível: todo up() (aplica a mudança) deve ter um down() correspondente (desfaz exatamente essa mudança). Isso torna o schema do banco versionável junto com o código-fonte, permitindo que qualquer desenvolvedor reconstrua o banco do zero rodando as migrations em ordem:

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('produtos', function (Blueprint $table) {
            $table->id();
            $table->string('nome', 150)->index();
            $table->string('sku', 50)->unique();
            $table->decimal('preco', 10, 2);
            $table->boolean('ativo')->default(true);
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('produtos');
    }
};

O index() acelera buscas por nome; o unique() em sku garante integridade a nível de banco (não apenas na validação do Form Request) — a última linha de defesa contra duplicidade em cenários de concorrência.


🔗 2. Chaves Estrangeiras e Integridade Referencial

foreignId()->constrained() é açúcar sintático que infere a tabela (users) e coluna (id) referenciadas a partir do nome da coluna (user_id), evitando repetir strings mágicas:

Schema::create('pedidos', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->cascadeOnDelete();
    $table->decimal('total', 10, 2);
    $table->string('status')->default('PENDENTE');
    $table->timestamps();
});

cascadeOnDelete() delega ao banco de dados a exclusão em cascata dos pedidos quando o usuário é removido — mais confiável que apagar registros relacionados manualmente em PHP, pois é atômico e não depende de o código da aplicação lembrar de fazê-lo em todo ponto de exclusão.


🛠️ 3. Alterando Tabelas Existentes com Segurança

Schema::table() (em vez de create()) altera uma tabela já existente. O down() de uma migration de alteração deve desfazer exatamente o que o up() fez — nunca recriar a tabela inteira:

public function up(): void
{
    Schema::table('pedidos', function (Blueprint $table) {
        $table->decimal('desconto', 8, 2)->default(0.0)->after('total');
    });
}

public function down(): void
{
    Schema::table('pedidos', function (Blueprint $table) {
        $table->dropColumn('desconto');
    });
}

Gotcha de produção: php artisan migrate:fresh (dropa e recria tudo) é destrutivo e só deve ser usado em desenvolvimento/CI. Em produção, aplica-se sempre php artisan migrate --force, incremental, e o down() de cada migration é o único caminho seguro de rollback (php artisan migrate:rollback).