🎓 Tutorial para Iniciantes

Aprenda Laravel
do Zero

Entenda toda a arquitetura do framework PHP mais popular do mundo. De MVC a Service Providers, explicado de forma simples e direta.

2011 Ano de lançamento
#1 Framework PHP
+30M Downloads mensais
9 Tópicos cobertos
1

O que é o Laravel?

Laravel é um framework PHP de código aberto (open-source) criado por Taylor Otwell em 2011. Ele fornece uma estrutura completa para o desenvolvimento de aplicações web modernas, seguindo o padrão de arquitetura MVC (Model-View-Controller).

💡
O que é um framework?
Pense num framework como uma caixa de ferramentas gigante que já vem montada. Em vez de criar tudo do zero (sistema de login, validação, conexão com banco de dados), você usa ferramentas prontas e testadas, focando só no que é único da sua aplicação.

Sem um framework, um desenvolvedor PHP precisaria resolver na mão problemas como: conexão com banco de dados, proteção contra ataques, roteamento de URLs, validação de formulários, envio de e-mails… O Laravel resolve tudo isso com código elegante e bem organizado.

🎯 Filosofia do Laravel

"PHP para artesãos" — o Laravel foi projetado para que escrever código seja uma experiência agradável e expressiva, sem sacrificar funcionalidade. Cada linha de código deve ser clara e intuitiva.

⚙️ O que o Laravel usa internamente

Tecnologias e padrões que ele abraça:

Composer PHP 8+ MVC ORM Blade REST

O Laravel usa o Composer (gerenciador de pacotes do PHP) para gerenciar suas dependências, o que torna super fácil adicionar novas bibliotecas ao projeto.

2

Por que o Laravel foi criado?

Para entender o porquê do Laravel existir, precisamos entender o contexto do PHP antes de 2011.

Taylor Otwell trabalhava com CodeIgniter, o framework PHP mais popular da época. Mas ficou frustrado com suas limitações: sem suporte nativo para autenticação, ORM fraco, sem migrations e sem tooling moderno. Ele decidiu criar o seu próprio framework.

Problemas que o Laravel veio resolver

😖 Antes do Laravel
  • Conexões com banco feitas manualmente com SQL crú
  • Sem estrutura definida — cada projeto era diferente
  • Autenticação reescrita do zero em cada projeto
  • Zero proteção automática (SQL Injection, XSS, CSRF)
  • Deploy caótico, sem controle de versão do banco
  • Testes difíceis ou simplesmente ignorados
😊 Com o Laravel
  • Eloquent ORM — banco de dados como objetos PHP
  • Estrutura MVC padronizada e consistente
  • Autenticação completa já integrada
  • Proteção contra ataques já ativada por padrão
  • Migrations — versionamento do banco de dados
  • Testes facilitados com abstrações prontas

Linha do tempo do Laravel

2011 Laravel 1.0 — Primeiro lançamento. Só tinha roteamento e controllers.
2012 Laravel 3.0 — Artisan CLI, migrations e pacotes introduzidos.
2013 Laravel 4.0 — Grande reescrita usando Composer. Fundação moderna.
2015 Laravel 5.0 — Nova estrutura de diretórios, Service Providers e Contracts.
2020 Laravel 8 — Jetstream, Livewire, Inertia.js, modelos em app/Models/.
2023 Laravel 10 — Suporte a PHP 8.1+, Pest 2, melhorias de performance.
2024 Laravel 11 — Estrutura simplificada, Reverb (WebSockets), Volt.
3

Padrão MVC no Laravel

MVC (Model-View-Controller) é um padrão de arquitetura de software que separa a aplicação em três camadas com responsabilidades distintas. É o padrão central do Laravel.

💡
Por que separar em camadas?
Imagine um restaurante: o garçom anota o pedido, o cozinheiro prepara o prato e o cardápio mostra as opções. Cada um tem sua função. Se o cardápio mudar, o cozinheiro não precisa ser treinado de novo. No software, essa separação facilita manutenção e trabalho em equipe.
M
Model
Modelo / Dados
Representa e gerencia os dados da aplicação. Contém a lógica de acesso ao banco de dados e as regras de negócio relacionadas aos dados. No Laravel, usa o Eloquent ORM.

📂 Fica em: app/Models/
V
View
Visão / Interface
É o que o usuário vê. Contém os templates HTML que exibem os dados recebidos do Controller. No Laravel, usa o motor de templates Blade. Views não devem ter lógica de negócio pesada.

📂 Fica em: resources/views/
C
Controller
Controlador / Lógica
O intermediário entre Model e View. Recebe a requisição do usuário, consulta os dados no Model, processa a lógica necessária e devolve a View preenchida.

📂 Fica em: app/Http/Controllers/

Como o fluxo MVC funciona?

Fluxo de uma requisição no padrão MVC
🌐 Browser
Usuário acessa URL
🗺️ Router
Direciona a rota
⚙️ Controller
Processa lógica
🗃️ Model
Acessa dados
🖼️ View
Renderiza HTML
✅ Response
Resposta ao usuário

Exemplos práticos de cada camada

routes/web.php — Definindo a rota
<?php
use App\Http\Controllers\PostController;
use Illuminate\Support\Facades\Route;

// Quando o usuário acessar "/posts", chama o método index() do PostController
Route::get('/posts', [PostController::class, 'index']);

// Quando acessar "/posts/5", chama o método show() passando id=5
Route::get('/posts/{id}', [PostController::class, 'show']);
app/Http/Controllers/PostController.php — Controller
<?php
namespace App\Http\Controllers;

use App\Models\Post; // Importa o Model

class PostController extends Controller
{
    // Lista todos os posts
    public function index()
    {
        // 1. Busca dados no Model
        $posts = Post::all();

        // 2. Passa os dados para a View
        return view('posts.index', ['posts' => $posts]);
    }

    // Exibe um post específico
    public function show($id)
    {
        $post = Post::findOrFail($id); // Busca por ID (retorna 404 se não achar)
        return view('posts.show', compact('post'));
    }
}
app/Models/Post.php — Model (Eloquent)
<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // O Laravel automaticamente mapeia esta classe para a tabela "posts" no banco

    // Campos que podem ser preenchidos em massa
    protected $fillable = ['titulo', 'conteudo', 'autor_id'];

    // Relacionamento: um post pertence a um usuário
    public function autor()
    {
        return $this->belongsTo(User::class, 'autor_id');
    }

    // Relacionamento: um post tem muitos comentários
    public function comentarios()
    {
        return $this->hasMany(Comentario::class);
    }
}
resources/views/posts/index.blade.php — View (Blade)
<!-- O Blade usa {{ }} para exibir dados de forma segura (protegido contra XSS) -->

<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <title>Lista de Posts</title>
</head>
<body>
    <h1>Todos os Posts</h1>

    @foreach($posts as $post)   {{-- Diretiva Blade para loop --}}
        <article>
            <h2>{{ $post->titulo }}</h2>
            <p>{{ $post->conteudo }}</p>
            <small>Por: {{ $post->autor->name }}</small>
        </article>
    @endforeach

    @if($posts->isEmpty())
        <p>Nenhum post encontrado.</p>
    @endif
</body>
</html>
4

Active Record — o padrão por trás do Eloquent

O Eloquent ORM do Laravel é construído sobre o padrão de design chamado Active Record. Entender esse padrão explica boa parte do "por que" o Eloquent funciona do jeito que funciona.

📖 Definição: No padrão Active Record, um objeto representa uma linha de uma tabela no banco de dados e carrega junto a si toda a lógica para ler, inserir, atualizar e deletar esse registro. O objeto e seus dados vivem juntos na mesma classe.

Active Record vs outros padrões

🟣 Active Record (Eloquent / Laravel)

A classe modelo representa o objeto e a tabela ao mesmo tempo. Ela sabe como se salvar, se buscar e se deletar.

  • Simples e intuitivo para começar
  • Menos código boilerplate
  • Objeto e persistência acoplados
  • Ideal para CRUD e regras de negócio simples
🔵 Data Mapper (Doctrine / Symfony)

Separa completamente o objeto de negócio (entidade) da lógica de persistência (repositório).

  • Mais complexo, porém mais flexível
  • Objeto não conhece o banco
  • Melhor para domínios complexos (DDD)
  • Mais fácil de testar de forma totalmente isolada

Como o Active Record se manifesta no Eloquent

Cada classe Model que estende Illuminate\Database\Eloquent\Model ganha automaticamente todos os métodos de interação com o banco. A classe em si é o registro da tabela — não precisa de nenhum repositório externo.

app/Models/Produto.php — estrutura de um Model Active Record
<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Produto extends Model
{
    use SoftDeletes; // Habilita soft delete (deleted_at)

    // Eloquent infere a tabela como "produtos" (snake_case + plural)
    // Para sobrescrever: protected $table = 'minha_tabela';

    // Campos que podem ser preenchidos via create() ou fill()
    protected $fillable = ['nome', 'preco', 'estoque', 'ativo'];

    // Cast automático de tipos ao ler/escrever atributos
    protected $casts = [
        'preco'   => 'decimal:2',
        'ativo'   => 'boolean',
        'criado_em' => 'datetime',
    ];
}
CRUD completo com Active Record / Eloquent
<?php

// ─── CREATE ─────────────────────────────────────────────────────────────
// Forma 1: instanciar, atribuir e salvar
$produto = new Produto();
$produto->nome    = 'Teclado Mecânico';
$produto->preco   = 299.90;
$produto->estoque = 50;
$produto->save();  // Executa: INSERT INTO produtos (nome, preco, estoque) VALUES (...)

// Forma 2: criar em massa de uma vez (requer campos em $fillable)
$produto = Produto::create([
    'nome'    => 'Mouse Gamer',
    'preco'   => 149.90,
    'estoque' => 30,
]);

// ─── READ ────────────────────────────────────────────────────────────────
$todos    = Produto::all();                            // SELECT * FROM produtos
$um       = Produto::find(1);                          // SELECT ... WHERE id = 1
$ou404    = Produto::findOrFail(99);                   // Lança erro 404 se não achar
$caros    = Produto::where('preco', '>', 100)->get(); // WHERE preco > 100
$primeiro = Produto::where('ativo', true)->first();    // Retorna apenas um

// Ordenar, limitar e paginar
$produtos = Produto::orderBy('preco', 'desc')->take(10)->get();
$paginado = Produto::paginate(15); // Paginação automática com links

// ─── UPDATE ─────────────────────────────────────────────────────────────
$produto = Produto::find(1);
$produto->preco = 259.90;
$produto->save();  // Executa: UPDATE produtos SET preco = 259.90 WHERE id = 1

// Atualizar múltiplos registros de uma vez
Produto::where('estoque', 0)->update(['ativo' => false]);

// ─── DELETE ─────────────────────────────────────────────────────────────
$produto = Produto::find(1);
$produto->delete();       // Com SoftDeletes: marca deleted_at = now()
                           // Sem SoftDeletes: DELETE FROM produtos WHERE id = 1

// Soft Delete — o registro não some do banco
$produto->restore();      // Desfaz o soft delete (limpa deleted_at)
$produto->forceDelete();  // Remove de verdade mesmo com SoftDeletes ativo

Convenções automáticas do Eloquent

Convenção Padrão assumido Como sobrescrever
Nome da tabela Snake_case plural do Model (Postposts, OrderItemorder_items) protected $table = 'minha_tabela';
Chave primária id inteiro auto-incremento protected $primaryKey = 'codigo';
Timestamps Colunas created_at e updated_at gerenciadas automaticamente public $timestamps = false;
Conexão com banco Conexão padrão definida no .env protected $connection = 'mysql_secundario';

Relacionamentos — a parte mais poderosa

No Active Record do Eloquent, os relacionamentos entre tabelas são definidos como métodos na própria classe Model. O Eloquent monta as queries SQL automaticamente.

Tipos de relacionamentos no Eloquent
<?php

// ── hasMany: Um user TEM MUITOS posts ────────────────────────────────────
class User extends Model {
    public function posts() {
        return $this->hasMany(Post::class); // Chave estrangeira inferida: user_id
    }
}

// ── belongsTo: Um post PERTENCE A um user ────────────────────────────────
class Post extends Model {
    public function autor() {
        return $this->belongsTo(User::class, 'user_id');
    }

    // ── belongsToMany: Um post TEM MUITAS tags (e vice-versa) ────────────
    public function tags() {
        return $this->belongsToMany(Tag::class); // Tabela pivot inferida: post_tag
    }

    // ── hasOne: Um post TEM UM resumo ────────────────────────────────────
    public function resumo() {
        return $this->hasOne(Resumo::class);
    }
}

// ── Usando os relacionamentos ─────────────────────────────────────────────
$user  = User::find(1);
$posts = $user->posts;         // SELECT * FROM posts WHERE user_id = 1

// ── Eager Loading: carrega tudo de uma vez (evita N+1) ───────────────────
$users = User::with('posts')->get();
// Gera APENAS 2 queries — uma para users, uma para todos os posts

// ── Eager Loading aninhado ────────────────────────────────────────────────
$posts = Post::with(['autor', 'tags', 'comentarios.autor'])->get();
⚠️
Problema N+1 — o erro mais comum com Active Record
O problema N+1 ocorre quando você faz 1 query para buscar N registros e depois dispara N queries extras para carregar um relacionamento de cada um deles.

❌ Ruim (N+1): Post::all() + acessar $post->autor no loop = 1 + N queries
✅ Bom (eager load): Post::with('autor')->get() = sempre 2 queries
💡
Criando um Model via Artisan
php artisan make:model Produto — cria só o model
php artisan make:model Produto -m — model + migration
php artisan make:model Produto -mcr — model + migration + controller com CRUD completo
5

Vantagens e Desvantagens

Como toda tecnologia, o Laravel tem seus pontos fortes e fracos. Conhecer ambos ajuda a decidir quando usá-lo e o que esperar durante o aprendizado.

✅ Vantagens
  • Sintaxe elegante — Código legível, expressivo e próximo do inglês natural.
  • Documentação excelente — Completa, atualizada e com exemplos claros em laravel.com.
  • Artisan CLI — Gera arquivos, roda migrations e muito mais com um comando.
  • Eloquent ORM — Banco de dados virou objetos PHP. Relacionamentos intuitivos.
  • Blade Templates — Motor de templates simples, poderoso e com layouts por herança.
  • Segurança embutida — Proteção contra CSRF, SQL Injection e XSS por padrão.
  • Ecossistema rico — Livewire, Inertia.js, Filament, Horizon, Telescope…
  • Comunidade enorme — Muitos pacotes, tutoriais, vídeos e fóruns de ajuda.
  • Queue & Jobs — Sistema de filas para tarefas pesadas em background.
  • Suporte LTS — Versões com suporte estendido para projetos de longo prazo.
❌ Desvantagens
  • Curva de aprendizado — Para iniciantes em PHP, pode ser sobrecarregante no início.
  • Muita "magia" — Façades e helpers escondem o que realmente acontece por baixo.
  • Pesado para pequenos projetos — Para uma API simples ou script, pode ser excessivo.
  • Versões quebram compatibilidade — Upgrades entre versões maiores exigem esforço.
  • Performance — Sem configuração adequada (cache, OPcache), pode ser mais lento que PHP puro.
  • PHP 8+ obrigatório — Versões recentes exigem PHP moderno, impossível em servidores legados.
  • Abstração excessiva — Pode esconder bugs difíceis de debugar para quem não conhece o internals.
Quando usar Laravel?
Laravel brilha em aplicações web de médio a grande porte: sistemas com múltiplos usuários, painéis administrativos, APIs REST, e-commerces, SaaS e portais. Se você precisa de algo robusto, seguro e com muito suporte da comunidade, Laravel é uma excelente escolha.
⚠️
Quando NÃO usar?
Para scripts simples, landing pages estáticas ou microservices muito pequenos, considere ferramentas mais leves como Lumen (versão micro do Laravel), SlimPHP ou até PHP puro.
6

Estrutura de Diretórios

Ao criar um novo projeto Laravel com composer create-project laravel/laravel meu-projeto, você recebe esta estrutura de pastas. Entendê-la é fundamental para trabalhar com o framework.

📁 meu-projeto/
├── 📁 app/⭐ Código principal da aplicação
│ ├── 📁 Console/Comandos Artisan customizados
│ ├── 📁 Exceptions/Handler de exceções e erros
│ ├── 📁 Http/Recebe e trata as requisições HTTP
│ │ ├── 📁 Controllers/⭐ Controllers da aplicação
│ │ ├── 📁 Middleware/Filtros de requisição
│ │ └── 📁 Requests/Validação de formulários (Form Requests)
│ ├── 📁 Models/⭐ Models do Eloquent (dados)
│ └── 📁 Providers/⭐ Service Providers
├── 📁 bootstrap/Inicialização do framework (não editar)
├── 📁 config/⭐ Arquivos de configuração (app, db, mail…)
├── 📁 database/Tudo relacionado ao banco de dados
│ ├── 📁 factories/Fábricas de dados falsos para testes
│ ├── 📁 migrations/⭐ Controle de versão do banco de dados
│ └── 📁 seeders/Populadores de dados iniciais
├── 📁 public/⭐ Única pasta acessível pelo navegador
│ └── 📄 index.phpPonto de entrada de TODAS as requisições
├── 📁 resources/Recursos "crus" (antes de compilar)
│ ├── 📁 css/Arquivos CSS / Tailwind
│ ├── 📁 js/Arquivos JavaScript
│ └── 📁 views/⭐ Templates Blade (.blade.php)
├── 📁 routes/⭐ Definição de todas as rotas
│ ├── 📄 web.phpRotas da aplicação web (com sessão e CSRF)
│ └── 📄 api.phpRotas da API REST (sem sessão, com throttle)
├── 📁 storage/Arquivos gerados: logs, cache, uploads
├── 📁 tests/Testes automatizados (Feature e Unit)
├── 📁 vendor/Dependências do Composer (não editar, não versionar)
├── 📄 .env⭐ Variáveis de ambiente (senhas, chaves — NUNCA versionar!)
└── 📄 composer.jsonLista de dependências PHP do projeto
⚠️
Atenção: .env e vendor/
Esses dois nunca devem ser enviados para o Git! O .env contém senhas e chaves secretas. O vendor/ pode ser recriado com composer install. O .gitignore já os exclui por padrão.

As pastas que você mais vai usar

📁 app/Http/Controllers/

Aqui ficam seus Controllers. Cada controller geralmente corresponde a um recurso (PostController, UserController…). Para criar um: php artisan make:controller PostController

📁 app/Models/

Seus Models Eloquent. Cada model representa uma tabela no banco. Para criar um com migration: php artisan make:model Post -m

📁 resources/views/

Templates Blade (.blade.php). Organize em subpastas por recurso (posts/, users/, layouts/…). São como HTML com superpoderes PHP embutidos.

📁 database/migrations/

Cada arquivo representa uma alteração no banco de dados. Execute com php artisan migrate. Permite que o time tenha o mesmo schema do banco sem compartilhar dumps SQL.

7

Ciclo de Vida de uma Request

Entender o que acontece desde que o usuário digita uma URL até a página aparecer na tela é essencial para dominar o Laravel. Todo esse processo é chamado de ciclo de vida de uma requisição (request lifecycle).

Visão geral do ciclo de vida
🌐 Browser
📄 index.php
🔌 Kernel
🛡️ Middleware
🗺️ Router
⚙️ Controller
📨 Response

Passo a passo detalhado

1
Servidor Web recebe a requisição Nginx / Apache

O usuário acessa uma URL no navegador. O servidor web (Nginx ou Apache) recebe a requisição HTTP e a direciona para o ponto de entrada do Laravel.

2
public/index.php — O ponto de entrada

Todo tráfego vai para este único arquivo. Ele faz três coisas: (1) carrega o autoloader do Composer, (2) cria a instância da aplicação ($app), e (3) envia a requisição para o Kernel. Você raramente edita este arquivo.

3
Application Container é criado IoC Container

O Service Container do Laravel é criado. É o coração do framework — um sistema de Inversão de Controle (IoC) que sabe como criar e injetar qualquer dependência. Pense nele como um "registro central" de todos os serviços.

4
HTTP Kernel é inicializado app/Http/Kernel.php

O HTTP Kernel define os middleware globais que toda requisição deve passar. Ele também lista os grupos de middleware ("web" e "api") e os bootstrap classes que preparam o ambiente (como carregar variáveis de ambiente e configurações).

5
Service Providers são registrados e inicializados

Todos os Service Providers listados em config/app.php são carregados. Primeiro o método register() de todos é chamado, depois o boot() de todos. É aqui que o framework se "monta" completamente.

6
Pipeline de Middleware Filtros

A requisição passa por uma "fila" de middleware configurada para aquela rota. Cada middleware pode deixar passar, modificar ou barrar a requisição. Exemplos: verificar se o usuário está logado, verificar CSRF, limitar requisições (rate limiting).

7
Router resolve a rota routes/web.php

O Router compara a URL e o método HTTP da requisição com as rotas definidas em routes/web.php ou routes/api.php e encontra a rota correspondente, identificando qual Controller e método devem ser chamados.

8
Controller é executado Lógica de negócio

O método do Controller é chamado. Aqui acontece a lógica da sua aplicação: buscar dados no banco via Model, processar, validar e preparar a resposta.

9
Response é gerada e enviada de volta

O Controller retorna uma Response (HTML renderizado pelo Blade, JSON, redirect, etc). Essa Response passa pelo middleware de volta (no sentido inverso) para qualquer pós-processamento, e finalmente é enviada para o navegador do usuário.

public/index.php — O ponto de entrada simplificado
<?php

// 1. Carrega o autoloader do Composer (conhece todas as classes do Laravel)
require __DIR__.'/../vendor/autoload.php';

// 2. "Liga" o Laravel: cria o Application Container
$app = require_once __DIR__.'/../bootstrap/app.php';

// 3. Cria o Kernel HTTP (que gerencia middleware e bootstrap)
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

// 4. Passa a requisição para o Kernel e obtém a Response
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

// 5. Envia a Response para o browser
$response->send();

// 6. Finaliza e limpa (dispara eventos de encerramento)
$kernel->terminate($request, $response);
8

Service Providers

Service Providers são a espinha dorsal do bootstrap do Laravel. São eles que "montam" o framework, registrando todos os componentes no Service Container antes de qualquer requisição ser tratada.

🔑 Analogia: Imagine que você está abrindo uma loja. Antes de abrir a porta para os clientes, você precisa ligar as luzes, colocar os produtos nas prateleiras, ligar o caixa, conectar o sistema… Isso tudo é o que os Service Providers fazem com o Laravel antes de atender uma requisição.

Os dois métodos de um Service Provider

🔧 register()

Chamado primeiro. Use para registrar bindings no Service Container. Aqui você diz ao Laravel: "quando alguém precisar de X, crie assim". Nunca use o método boot() de outros providers aqui — eles podem não estar carregados ainda.

🚀 boot()

Chamado depois que todos os providers foram registrados. Use para tarefas que dependem de outros serviços: registrar rotas, publicar views, definir validators customizados, registrar observers de Model, etc.

app/Providers/AppServiceProvider.php — Exemplo real
<?php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Services\PagamentoService;
use App\Contracts\PagamentoInterface;

class AppServiceProvider extends ServiceProvider
{
    /**
     * register() — Liga classes/interfaces a implementações no Container.
     * Chamado ANTES de qualquer outro boot().
     */
    public function register(): void
    {
        // Diz ao Laravel: "quando alguém pedir PagamentoInterface,
        // entregue uma instância de PagamentoService"
        $this->app->bind(PagamentoInterface::class, PagamentoService::class);

        // Singleton: cria apenas UMA instância durante toda a requisição
        $this->app->singleton('relatorio', function ($app) {
            return new \App\Services\RelatorioService(
                config('relatorio.driver')
            );
        });
    }

    /**
     * boot() — Inicializações que dependem de outros serviços.
     * Chamado APÓS todos os register().
     */
    public function boot(): void
    {
        // Força HTTPS em produção
        if ($this->app->environment('production')) {
            \URL::forceScheme('https');
        }

        // Registra um validator customizado
        \Validator::extend('cpf_valido', function ($attribute, $value) {
            return validarCpf($value);
        });

        // Registra observer do Model Post
        \App\Models\Post::observe(\App\Observers\PostObserver::class);
    }
}
config/app.php — Onde os providers são registrados
<?php
return [
    // ...

    'providers' => ServiceProvider::defaultProviders()->merge([
        /*
         * Providers do Framework (não mexa nestes)
         */
        // Illuminate\Auth\AuthServiceProvider::class,
        // Illuminate\Cache\CacheServiceProvider::class,
        // ...

        /*
         * Providers da sua aplicação
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,

        // Providers de pacotes de terceiros:
        // Spatie\Permission\PermissionServiceProvider::class,
    ])->toArray(),
];
💡
Criando seu próprio Service Provider
Use o Artisan: php artisan make:provider MeuNomeProvider
O arquivo é criado em app/Providers/. Não esqueça de registrá-lo em config/app.php (nas versões mais antigas) ou em bootstrap/providers.php (Laravel 11+).
9

Facades

Facades são uma das features mais características do Laravel. Elas fornecem uma interface estática simples para classes disponíveis no Service Container, sem precisar injetar dependências manualmente.

🪟 Analogia: Uma Facade é como o painel de controle de um avião. O piloto aperta um botão e o motor responde — ele não precisa saber como os pistões funcionam internamente. A Facade esconde a complexidade e expõe uma interface simples.

Como as Facades funcionam internamente?

Quando você escreve Cache::get('usuario_1'), o Laravel faz o seguinte:

Cache::get()
__callStatic()
Container resolve 'cache'
CacheManager::get()

Facades mais usados no dia a dia

Facade O que faz Exemplo de uso
Route Define rotas da aplicação Route::get('/home', [HomeController::class, 'index']);
DB Acesso ao banco de dados DB::table('users')->where('id', 1)->first();
Cache Armazenamento em cache Cache::put('chave', 'valor', 3600);
Auth Autenticação de usuários Auth::user(); / Auth::check();
Mail Envio de e-mails Mail::to($user)->send(new WelcomeMail());
Storage Sistema de arquivos Storage::disk('public')->put('foto.jpg', $conteudo);
Log Registro de logs Log::error('Erro crítico!', ['dados' => $dados]);
Session Dados de sessão Session::put('carrinho', $itens);
Event Disparar e ouvir eventos Event::dispatch(new UserRegistered($user));
Validator Validação de dados Validator::make($dados, ['nome' => 'required|max:255']);

Facade vs Injeção de Dependência

Ambas as abordagens são válidas. A Facade é mais concisa; a injeção de dependência é mais explícita e facilita os testes unitários.

🪟 Usando Facade
<?php
namespace App\Http\Controllers;

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

class UserController extends Controller
{
    public function index()
    {
        // Simples e direto
        $users = Cache::remember(
            'all_users',
            3600,
            fn() => User::all()
        );

        Log::info('Users listados');

        return view('users.index', compact('users'));
    }
}
💉 Usando Injeção de Dependência
<?php
namespace App\Http\Controllers;

use Illuminate\Cache\CacheManager;
use Psr\Log\LoggerInterface;

class UserController extends Controller
{
    public function __construct(
        private CacheManager $cache,
        private LoggerInterface $log
    ) {}

    public function index()
    {
        // Mais explícito — ótimo para testes
        $users = $this->cache->remember(
            'all_users',
            3600,
            fn() => User::all()
        );

        $this->log->info('Users listados');

        return view('users.index', compact('users'));
    }
}
💡
Helpers são atalhos ainda mais curtos!
O Laravel também oferece funções helper globais como alternativa às Facades: cache(), auth(), session(), config(), view(), redirect()… São funções comuns que podem ser chamadas de qualquer lugar.
10

Middleware

Middleware são camadas intermediárias que uma requisição atravessa antes de chegar ao Controller (e que a resposta pode atravessar no caminho de volta). É o mecanismo de "filtros" do Laravel.

🛡️ Analogia: Imagine entrar num prédio corporativo. Antes de chegar à sua sala (o Controller), você passa pela portaria (autenticação), pelo detector de metais (validação de segurança) e pelo leitor de crachá (autorização de acesso). Cada um desses é um middleware.

Fluxo do Middleware (vai e volta)
A requisição passa pelos middlewares de ida e de volta
Request
Auth
CSRF
Throttle
Controller
Throttle
CSRF
Response

Middlewares nativos do Laravel

Middleware Alias O que faz
Authenticate auth Verifica se o usuário está autenticado. Redireciona para login se não estiver.
VerifyCsrfToken csrf Protege contra ataques CSRF (Cross-Site Request Forgery) em formulários.
ThrottleRequests throttle Limita o número de requisições por minuto. Padrão: 60/minuto para APIs.
RedirectIfAuthenticated guest Redireciona usuários já logados (para não acessar login/registro novamente).
EnsureEmailIsVerified verified Garante que o e-mail do usuário foi verificado para acessar a rota.
TrimStrings — (global) Remove espaços extras de todos os inputs automaticamente.
HandleCors — (global) Configura os headers CORS para APIs acessadas por outros domínios.

Criando um Middleware customizado

Terminal — Gerando o arquivo via Artisan
# Gera o arquivo em app/Http/Middleware/VerificarIdade.php
php artisan make:middleware VerificarIdade
app/Http/Middleware/VerificarIdade.php — Middleware customizado
<?php
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class VerificarIdade
{
    /**
     * Toda a lógica fica no método handle().
     *
     * @param  Request  $request   A requisição atual
     * @param  Closure  $next      A "próxima camada" do pipeline
     */
    public function handle(Request $request, Closure $next): Response
    {
        $idade = $request->input('idade');

        // Se a idade for menor que 18, barra a requisição
        if ($idade !== null && $idade < 18) {
            return response()->json([
                'erro' => 'Acesso restrito para maiores de 18 anos.'
            ], 403);
        }

        // "Deixa passar" para o próximo middleware ou controller
        return $next($request);
    }
}
routes/web.php — Aplicando middleware em rotas
<?php
use App\Http\Controllers\PainelController;
use App\Http\Controllers\AdminController;
use Illuminate\Support\Facades\Route;

// Aplica um middleware em uma rota específica
Route::get('/painel', [PainelController::class, 'index'])
    ->middleware('auth'); // Apenas usuários logados

// Aplica múltiplos middlewares
Route::get('/admin', [AdminController::class, 'index'])
    ->middleware(['auth', 'verified']); // Logado + e-mail verificado

// Grupo de rotas com middleware compartilhado
Route::middleware(['auth'])->group(function () {
    Route::get('/perfil', [PerfilController::class, 'show']);
    Route::get('/configuracoes', [ConfigController::class, 'index']);
    Route::get('/pedidos', [PedidoController::class, 'index']);
});

// Usando o middleware customizado com alias
Route::get('/conteudo-adulto', [ConteudoController::class, 'index'])
    ->middleware('verificar.idade');
💡
Registrando o alias do seu middleware
No Laravel 10 e anteriores, registre em app/Http/Kernel.php no array $routeMiddleware. No Laravel 11+, use o arquivo bootstrap/app.php com ->withMiddleware().

'verificar.idade' => \App\Http\Middleware\VerificarIdade::class

Grupos de Middleware: "web" vs "api"

🌐 Grupo web

Aplicado automaticamente em routes/web.php. Inclui:

  • Sessões (StartSession)
  • Proteção CSRF (VerifyCsrfToken)
  • Cookies criptografados
  • Flash messages
  • Compartilhar erros com views
🔌 Grupo api

Aplicado automaticamente em routes/api.php. Inclui:

  • Rate limiting (60 req/min)
  • Sem sessão (stateless)
  • Sem CSRF (usa tokens de autenticação)
  • Prefixo /api automático
🎉

Parabéns! Você chegou ao final.

Agora você entende os conceitos fundamentais da arquitetura Laravel: MVC, ciclo de vida de uma requisição, Service Providers, Facades e Middleware. Essa é a base para construir aplicações profissionais!

Próximos passos sugeridos

📚 Aprofunde nos conceitos
  • Eloquent ORM e Relacionamentos
  • Migrations e Seeders
  • Blade Templates avançado
  • Validação com Form Requests
  • Autenticação com Laravel Breeze
🚀 Evolua para features avançadas
  • Queues e Jobs
  • Events e Listeners
  • APIs REST com Sanctum
  • Testes com PHPUnit/Pest
  • Deploy com Laravel Forge/Vapor