---
title: Guia – Formulário com e-mail, banco e listagem admin
---

# Formulário com e-mail + banco + admin

Indicado para:

- inscrições em eventos internos
- cadastros simples de interessados
- formulários institucionais que precisam de histórico interno

Regras importantes:

- usar Blade + Bootstrap (sem CSS/JS inline)
- usar `{{ __('texto') }}` em TODO texto visível
- separar bem camadas (Migration, Model, Request, Service, Controller, Views)
- módulo admin com permissão própria e middleware

Nos exemplos, vamos usar o caso genérico **“Inscrição em Evento”**.

---

## 1. Definir a migration

Padrão do projeto: **uma migration por módulo** quando possível.

Crie a migration (nome de exemplo):

```bash
php artisan make:migration create_inscricoes_eventos_table
```

Edite a migration em `database/migrations/...create_inscricoes_eventos_table.php`:

```php
<?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('inscricoes_eventos', function (Blueprint $table) {
            $table->id();
            $table->string('nome');
            $table->string('email');
            $table->string('telefone')->nullable();
            $table->string('evento');
            $table->text('observacoes')->nullable();
            $table->timestamps();
        });
    }

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

Rode a migration:

```bash
php artisan migrate
```

---

## 2. Criar o Model

Crie um único Model do módulo (ex.: `app/Models/InscricaoEvento.php`):

```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class InscricaoEvento extends Model
{
    protected $table = 'inscricoes_eventos';

    protected $fillable = [
        'nome',
        'email',
        'telefone',
        'evento',
        'observacoes',
    ];
}
```

---

## 3. Criar o Request de validação

Exemplo de Request (`app/Http/Requests/Admin/InscricoesEvento/InscricaoEventoRequest.php`):

```php
<?php

namespace App\Http\Requests\Admin\InscricoesEvento;

use Illuminate\Foundation\Http\FormRequest;

class InscricaoEventoRequest extends FormRequest
{
    public function authorize(): bool
    {
        // Permissão fina também é checada no middleware/controller.
        return true;
    }

    public function rules(): array
    {
        return [
            'nome'      => ['required', 'string', 'max:255'],
            'email'     => ['required', 'email', 'max:255'],
            'telefone'  => ['nullable', 'string', 'max:30'],
            'evento'    => ['required', 'string', 'max:255'],
            'observacoes' => ['nullable', 'string', 'max:5000'],
        ];
    }

    public function attributes(): array
    {
        return [
            'nome'       => __('Nome'),
            'email'      => __('E-mail'),
            'telefone'   => __('Telefone'),
            'evento'     => __('Evento'),
            'observacoes'=> __('Observações'),
        ];
    }
}
```

---

## 4. Criar o Service (persistência e e-mail)

Service único do módulo (`app/Services/InscricoesEventoService.php`):

```php
<?php

namespace App\Services;

use App\Mail\InscricaoEventoMail;
use App\Models\InscricaoEvento;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;

class InscricoesEventoService
{
    public function criarInscricao(array $dados): InscricaoEvento
    {
        return DB::transaction(function () use ($dados) {
            $inscricao = InscricaoEvento::create($dados);

            Mail::to(config('mail.formularios.inscricao_evento_destino'))
                ->send(new InscricaoEventoMail($inscricao));

            return $inscricao;
        });
    }
}
```

---

## 5. Criar o Mailable

`app/Mail/InscricaoEventoMail.php`:

```php
<?php

namespace App\Mail;

use App\Models\InscricaoEvento;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class InscricaoEventoMail extends Mailable
{
    use Queueable, SerializesModels;

    public InscricaoEvento $inscricao;

    public function __construct(InscricaoEvento $inscricao)
    {
        $this->inscricao = $inscricao;
    }

    public function build(): self
    {
        return $this
            ->subject(__('Nova inscrição em evento'))
            ->view('emails.formularios.inscricao-evento');
    }
}
```

View de e-mail (`resources/views/emails/formularios/inscricao-evento.blade.php`):

```blade
<p><strong>{{ __('Evento') }}:</strong> {{ $inscricao->evento }}</p>
<p><strong>{{ __('Nome') }}:</strong> {{ $inscricao->nome }}</p>
<p><strong>{{ __('E-mail') }}:</strong> {{ $inscricao->email }}</p>
<p><strong>{{ __('Telefone') }}:</strong> {{ $inscricao->telefone }}</p>

@if($inscricao->observacoes)
    <p><strong>{{ __('Observações') }}:</strong></p>
    <p>{{ $inscricao->observacoes }}</p>
@endif
```

---

## 6. Criar o middleware e permissão do módulo (admin)

Crie (ou reutilize) a permissão única do módulo, por exemplo: `INSCRICOES_EVENTOS`.

Crie um middleware próprio (ex.: `app/Http/Middleware/Admin/InscricoesEventoMiddleware.php`) que:

- verifica se o usuário autenticado tem permissão no módulo
- em falha, faz **logout**, invalida sessão, regenera token e redireciona para `admin.login`

No `Kernel`, registre o middleware e use nas rotas admin do módulo.

Na view admin, use:

```blade
@if (auth()->user()->getPermissaoDetalhes('INSCRICOES_EVENTOS')['visualizar'])
    {{-- conteúdo --}}
@endif
```

---

## 7. Criar o Controller admin magro

Exemplo (`app/Http/Controllers/Admin/InscricoesEventoController.php`):

```php
<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\InscricoesEvento\InscricaoEventoRequest;
use App\Models\InscricaoEvento;
use App\Services\InscricoesEventoService;

class InscricoesEventoController extends Controller
{
    public function __construct(private InscricoesEventoService $service)
    {
    }

    public function index()
    {
        checkPermissao('INSCRICOES_EVENTOS', 'visualizar');

        $inscricoes = InscricaoEvento::orderByDesc('created_at')
            ->paginate(20);

        return view('admin.inscricoes-eventos.index', compact('inscricoes'));
    }

    public function store(InscricaoEventoRequest $request)
    {
        checkPermissao('INSCRICOES_EVENTOS', 'adicionar');

        $this->service->criarInscricao($request->validated());

        return back()->with('success', __('Inscrição registrada com sucesso.'));
    }
}
```

---

## 8. Definir as rotas (público + admin)

Rotas públicas (formulário de inscrição), em `routes/web.php`:

```php
use App\Http\Controllers\Paginas\InscricoesEventoPublicController;

Route::get('/eventos/inscricao', [InscricoesEventoPublicController::class, 'create'])
    ->name('paginas.inscricoes-eventos.create');

Route::post('/eventos/inscricao', [InscricoesEventoPublicController::class, 'store'])
    ->name('paginas.inscricoes-eventos.store');
```

Rotas admin, em `routes/admin.php` (exemplo):

```php
use App\Http\Controllers\Admin\InscricoesEventoController;

Route::middleware(['web', 'auth', 'inscricoes_eventos'])
    ->name('admin.inscricoes-eventos.')
    ->prefix('admin/inscricoes-eventos')
    ->group(function () {
        Route::get('/', [InscricoesEventoController::class, 'index'])
            ->name('index');
    });
```

---

## 9. Criar a view do formulário público

`resources/views/paginas/inscricoes-eventos/create.blade.php` (use o layout e componentes padrão do projeto):

```blade
@extends('layouts.app')

@section('content')
    <div class="container">
        <h1>{{ __('Inscrição em evento') }}</h1>

        @if(session('success'))
            <div class="alert alert-success" role="alert">
                {{ session('success') }}
            </div>
        @endif

        <form action="{{ route('paginas.inscricoes-eventos.store') }}" method="post">
            @csrf

            {{-- Campos semelhantes ao exemplo do formulário de e-mail simples --}}
            {{-- nome, email, telefone, evento, observacoes --}}

            <button type="submit" class="btn btn-primary">
                {{ __('Enviar inscrição') }}
            </button>
        </form>
    </div>
@endsection
```

---

## 10. Criar a listagem simples para admin

`resources/views/admin/inscricoes-eventos/index.blade.php`:

Use o componente de tabela padrão (`x-tables._table`) se já existir no projeto. Exemplo simplificado:

```blade
@extends('admin.layouts.app')

@section('content')
    @include('components.buttons._headLineButtonsBackAdd', [
        'headLine' => __('Inscrições em eventos'),
        'routeBack' => 'admin.dashboard',
        'routeBackParams' => [],
        'nameBack' => __('Voltar'),
        'permission' => 'INSCRICOES_EVENTOS',
    ])

    @if (auth()->user()->getPermissaoDetalhes('INSCRICOES_EVENTOS')['visualizar'])
        <div class="table-responsive">
            <table class="table table-striped table-hover align-middle">
                <thead>
                    <tr>
                        <th>{{ __('ID') }}</th>
                        <th>{{ __('Data') }}</th>
                        <th>{{ __('Evento') }}</th>
                        <th>{{ __('Nome') }}</th>
                        <th>{{ __('E-mail') }}</th>
                    </tr>
                </thead>
                <tbody>
                    @forelse($inscricoes as $inscricao)
                        <tr>
                            <td>{{ $inscricao->id }}</td>
                            <td>{{ $inscricao->created_at->format('d/m/Y H:i') }}</td>
                            <td>{{ $inscricao->evento }}</td>
                            <td>{{ $inscricao->nome }}</td>
                            <td>{{ $inscricao->email }}</td>
                        </tr>
                    @empty
                        <tr>
                            <td colspan="5">{{ __('Nenhum registro encontrado.') }}</td>
                        </tr>
                    @endforelse
                </tbody>
            </table>
        </div>

        {{ $inscricoes->withQueryString()->links() }}
    @endif
@endsection
```

- Sempre cheque permissão antes de mostrar ações.
- Use paginação (`paginate`) para melhor performance.
- Não use inline CSS/JS; use os assets do módulo.

---

## 11. Estrutura recomendada de arquivos (resumo)

Exemplo de estrutura mínima para o módulo:

```text
app/
  Http/
    Controllers/
      Admin/
        InscricoesEventoController.php
      Paginas/
        InscricoesEventoPublicController.php
    Middleware/
      Admin/
        InscricoesEventoMiddleware.php
    Requests/
      Admin/
        InscricoesEvento/
          InscricaoEventoRequest.php
  Mail/
    InscricaoEventoMail.php
  Models/
    InscricaoEvento.php
  Services/
    InscricoesEventoService.php

resources/
  views/
    paginas/
      inscricoes-eventos/
        create.blade.php
    admin/
      inscricoes-eventos/
        index.blade.php
    emails/
      formularios/
        inscricao-evento.blade.php
```

---

## 12. Passo a passo rápido – checklist

1. **Criar migration** `inscricoes_eventos` e rodar `php artisan migrate`.
2. **Criar Model** `InscricaoEvento`.
3. **Criar Request** `InscricaoEventoRequest` com validação completa.
4. **Criar Service** `InscricoesEventoService` (salva no banco + envia e-mail em transação).
5. **Criar Mailable** `InscricaoEventoMail` + view do e-mail.
6. **Configurar permissão** (`INSCRICOES_EVENTOS`) + middleware admin do módulo.
7. **Criar Controller admin** magro (`index` e, se necessário, outras ações).
8. **Criar Controller público** para exibir o formulário e chamar o Service no `store`.
9. **Criar views Blade** (formulário público + listagem admin) usando componentes e Bootstrap.
10. **Configurar destinatário** no `config/mail.php` + `.env`.

Com isso você terá um formulário que:

- **recebe dados do cidadão**
- **valida e sanitiza a entrada**
- **salva no banco**
- **envia e-mail**
- **permite listagem interna segura** no admin, seguindo o padrão arquitetural do projeto.

