PHP

Artigo 41 — Introdução ao Laravel Já leu

7 min de leitura

Artigo 41 — Introdução ao Laravel
Laravel é o framework PHP mais popular do mundo, e por boas razões. Ele não apenas resolve problemas técnicos — ele define uma forma de pensar sobre o

Artigo 41 — Introdução ao Laravel

Módulo 7 · Semana 41 · Nível: Intermediário


Introdução

Laravel é o framework PHP mais popular do mundo, e por boas razões. Ele não apenas resolve problemas técnicos — ele define uma forma de pensar sobre o desenvolvimento web. Com Laravel, você tem um roteador expressivo, ORM elegante, sistema de templates, autenticação, filas, eventos, testes e dezenas de outros recursos integrados e funcionando em harmonia desde o primeiro composer create-project.

Mas Laravel não é magia. Cada recurso que ele oferece é construído sobre os fundamentos que você já aprendeu: namespaces, PSR-4, injeção de dependência, interfaces, padrões de projeto. Entender isso transforma você de um usuário do framework em alguém que realmente domina o que está usando.


Instalação e estrutura

# Criando um novo projeto Laravel
composer create-project laravel/laravel minha-loja

cd minha-loja

# Iniciando o servidor de desenvolvimento
php artisan serve
# http://localhost:8000

# Ou com o Laravel Herd (recomendado para desenvolvimento local)
# https://herd.laravel.com/

Estrutura de diretórios:

minha-loja/
├── app/
│   ├── Http/
│   │   ├── Controllers/     ← Controladores
│   │   └── Middleware/      ← Middlewares HTTP
│   ├── Models/              ← Models Eloquent
│   ├── Providers/           ← Service Providers
│   └── Services/            ← Lógica de negócio (você cria)
├── bootstrap/               ← Bootstrap da aplicação
├── config/                  ← Configurações (database, mail, etc.)
├── database/
│   ├── factories/           ← Factories para testes
│   ├── migrations/          ← Migrations de banco de dados
│   └── seeders/             ← Seeds de dados iniciais
├── public/                  ← Document root (index.php)
├── resources/
│   └── views/               ← Templates Blade
├── routes/
│   ├── web.php              ← Rotas web (com sessão, CSRF)
│   └── api.php              ← Rotas API (stateless)
├── storage/                 ← Logs, cache, uploads
├── tests/                   ← Testes automatizados
├── .env                     ← Variáveis de ambiente
└── artisan                  ← CLI do Laravel

Configuração — o arquivo .env

# .env
APP_NAME="Minha Loja"
APP_ENV=local
APP_KEY=base64:...        # Gerado automaticamente — nunca commite
APP_DEBUG=true
APP_URL=http://localhost:8000

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=minha_loja
DB_USERNAME=root
DB_PASSWORD=

MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025

O arquivo .env nunca vai para o git (está no .gitignore). Em vez disso, commite o .env.example com as chaves mas sem os valores sensíveis. Para gerar a APP_KEY:

php artisan key:generate

Roteamento

<?php
// routes/web.php

use App\Http\Controllers\ProdutoController;
use App\Http\Controllers\CarrinhoController;
use Illuminate\Support\Facades\Route;

// Rota simples com closure
Route::get('/', function () {
    return view('home');
});

// Rota com parâmetro
Route::get('/produtos/{id}', function (int $id) {
    return "Produto: {$id}";
});

// Rota com parâmetro opcional
Route::get('/blog/{slug?}', function (?string $slug = null) {
    return $slug ? "Post: {$slug}" : "Lista do blog";
});

// Rota apontando para controller
Route::get('/produtos', [ProdutoController::class, 'index']);
Route::get('/produtos/{produto}', [ProdutoController::class, 'show']);
Route::post('/produtos', [ProdutoController::class, 'store']);
Route::put('/produtos/{produto}', [ProdutoController::class, 'update']);
Route::delete('/produtos/{produto}', [ProdutoController::class, 'destroy']);

// Resource route — cria as 7 rotas CRUD de uma vez
Route::resource('produtos', ProdutoController::class);

// Rotas agrupadas com prefixo e middleware
Route::middleware('auth')->prefix('admin')->group(function () {
    Route::resource('produtos', ProdutoController::class);
    Route::resource('pedidos', PedidoController::class);
});

// Rotas nomeadas — facilita geração de URLs
Route::get('/contato', [ContatoController::class, 'index'])->name('contato');
// Uso: route('contato') → /contato

Controllers

# Criar um controller com os métodos CRUD já estruturados
php artisan make:controller ProdutoController --resource
<?php
declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\Produto;
use App\Http\Requests\ProdutoRequest;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;

class ProdutoController extends Controller
{
    // GET /produtos
    public function index(): View
    {
        $produtos = Produto::where('ativo', true)
            ->orderBy('nome')
            ->paginate(15);

        return view('produtos.index', compact('produtos'));
    }

    // GET /produtos/{produto}
    // O Laravel resolve automaticamente o Model pelo ID (Route Model Binding)
    public function show(Produto $produto): View
    {
        return view('produtos.show', compact('produto'));
    }

    // GET /produtos/create
    public function create(): View
    {
        return view('produtos.create');
    }

    // POST /produtos
    public function store(ProdutoRequest $request): RedirectResponse
    {
        // $request->validated() retorna apenas os campos que passaram na validação
        $produto = Produto::create($request->validated());

        return redirect()
            ->route('produtos.show', $produto)
            ->with('sucesso', 'Produto criado com sucesso!');
    }

    // PUT /produtos/{produto}
    public function update(ProdutoRequest $request, Produto $produto): RedirectResponse
    {
        $produto->update($request->validated());

        return redirect()
            ->route('produtos.show', $produto)
            ->with('sucesso', 'Produto atualizado.');
    }

    // DELETE /produtos/{produto}
    public function destroy(Produto $produto): RedirectResponse
    {
        $produto->delete();

        return redirect()
            ->route('produtos.index')
            ->with('sucesso', 'Produto removido.');
    }
}

Form Requests — validação encapsulada

php artisan make:request ProdutoRequest
<?php
declare(strict_types=1);

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ProdutoRequest extends FormRequest
{
    // Autorização — quem pode fazer esta requisição?
    public function authorize(): bool
    {
        return $this->user()?->isAdmin() ?? false;
    }

    // Regras de validação
    public function rules(): array
    {
        return [
            'nome'     => ['required', 'string', 'min:3', 'max:200'],
            'preco'    => ['required', 'numeric', 'min:0'],
            'estoque'  => ['required', 'integer', 'min:0'],
            'ativo'    => ['boolean'],
            'descricao'=> ['nullable', 'string', 'max:2000'],
            'imagem'   => ['nullable', 'image', 'max:2048'], // máx 2MB
        ];
    }

    // Mensagens customizadas
    public function messages(): array
    {
        return [
            'nome.required'  => 'O nome do produto é obrigatório.',
            'preco.min'      => 'O preço não pode ser negativo.',
            'imagem.image'   => 'O arquivo deve ser uma imagem.',
            'imagem.max'     => 'A imagem deve ter no máximo 2MB.',
        ];
    }
}

Service Container e Service Providers

O Service Container do Laravel é um container de DI poderoso. Você registra como criar objetos, e o Laravel injeta automaticamente onde forem necessários:

<?php
// app/Providers/AppServiceProvider.php

namespace App\Providers;

use App\Repositories\ProdutoRepositorioInterface;
use App\Repositories\EloquentProdutoRepositorio;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Bind interface → implementação concreta
        $this->app->bind(
            ProdutoRepositorioInterface::class,
            EloquentProdutoRepositorio::class,
        );
    }

    public function boot(): void
    {
        // Executado após todos os providers registrarem seus serviços
    }
}

// Agora o controller pode declarar a interface no construtor:
class ProdutoController extends Controller
{
    public function __construct(
        private readonly ProdutoRepositorioInterface $repositorio,
    ) {}
}
// O Laravel injeta automaticamente a implementação concreta

Artisan — a CLI do Laravel

# Listar todos os comandos disponíveis
php artisan list

# Criar arquivos
php artisan make:model Produto -mfc      # Model + migration + factory + controller
php artisan make:migration criar_tabela_pedidos
php artisan make:seeder ProdutoSeeder
php artisan make:job ProcessarPagamento
php artisan make:event PedidoCriado
php artisan make:listener EnviarEmailDePedido
php artisan make:command ImportarProdutos

# Executar
php artisan migrate                      # Roda as migrations pendentes
php artisan migrate:fresh --seed         # Recria o banco e roda seeds
php artisan db:seed                      # Apenas seeds
php artisan queue:work                   # Processa filas
php artisan schedule:run                 # Executa tarefas agendadas

# Informações
php artisan route:list                   # Lista todas as rotas
php artisan config:show database         # Exibe config do banco
php artisan tinker                       # REPL interativo — testado no console

Resumo

Conceito Laravel
Roteamento routes/web.php — fluente, com grupos e middleware
Controllers Classes em app/Http/Controllers/ — um método por ação
Validação FormRequest encapsula regras e autorização
DI Container ServiceProvider registra bindings — injeção automática
CLI php artisan — gera código, migra banco, processa filas
Configuração .env + config/ — nunca hardcode de credenciais

Exercício da semana

  1. Crie um projeto Laravel do zero. Configure o banco de dados. Crie um CRUD completo de Categoria com: migration, model, controller resource, form request com validação, e views Blade básicas.

  2. Adicione Route Model Binding ao CRUD: ao acessar /categorias/{categoria}, o Laravel deve resolver automaticamente o model pelo ID e retornar 404 se não encontrar.

  3. Implemente uma interface CategoriaRepositorioInterface com método listarAtivas(): Collection. Crie a implementação com Eloquent. Registre o binding no AppServiceProvider. Injete no controller.

  4. Desafio: crie um comando Artisan customizado php artisan categorias:importar {arquivo} que leia um CSV e importe categorias no banco, exibindo progresso com $this->progressBar().


Referências

  • Documentação oficial do Laravel: https://laravel.com/docs
  • Laracasts (vídeos): https://laracasts.com/
  • Laravel News: https://laravel-news.com/
  • Awesome Laravel: https://github.com/chiraggude/awesome-laravel

Comentários

Mais em PHP

Variáveis, Tipos de Dados e Operadores
Variáveis, Tipos de Dados e Operadores

Todo programa de computador, em sua ess&ecirc;ncia, faz tr&ecirc;s coisas: re...

Sessions e Cookies
Sessions e Cookies

HTTP é um protocolo sem estado (stateless). Cada requisição é independente —...

Exceções Avançadas
Exceções Avançadas

Tratamento de erros &eacute; onde c&oacute;digo bom se separa de c&oacute;dig...