PHP

Artigo 43 — Blade — Templates no Laravel Já leu

8 min de leitura

Artigo 43 — Blade — Templates no Laravel
Blade é o motor de templates do Laravel. Ele compila templates para PHP puro e os armazena em cache, então não há penalidade de performance. A sintaxe é limpa,

Artigo 43 — Blade — Templates no Laravel

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


Introdução

Blade é o motor de templates do Laravel. Ele compila templates para PHP puro e os armazena em cache, então não há penalidade de performance. A sintaxe é limpa, expressiva, e evita que você misture lógica de negócio com apresentação — um problema clássico do PHP puro com HTML.

Blade não é apenas uma forma de escrever <?php echo ?> mais curto. Oferece herança de layouts, componentes reutilizáveis, slots, stacks, e diretivas que tornam templates complexos gerenciáveis.


Sintaxe básica

{{-- Comentário Blade — não aparece no HTML final --}}

{{-- Exibir variável com escape automático (equivalente a htmlspecialchars) --}}
{{ $produto->nome }}

{{-- Exibir HTML sem escape — use com cuidado --}}
{!! $produto->descricao_html !!}

{{-- Expressões PHP --}}
{{ strtoupper($produto->nome) }}
{{ $produto->preco_formatado }}
{{ now()->format('d/m/Y') }}

Estruturas de controle

{{-- Condicionais --}}
@if ($produto->estoque > 0)
    <span class="badge verde">Em estoque</span>
@elseif ($produto->estoque === 0)
    <span class="badge vermelho">Esgotado</span>
@else
    <span class="badge cinza">Indisponível</span>
@endif

{{-- unless = if negado --}}
@unless ($usuario->isAdmin())
    <p>Acesso restrito a administradores.</p>
@endunless

{{-- isset e empty --}}
@isset($produto->descricao)
    <p>{{ $produto->descricao }}</p>
@endisset

@empty($produtos)
    <p>Nenhum produto encontrado.</p>
@endempty

{{-- Loops --}}
@foreach ($produtos as $produto)
    <div class="produto">
        <h3>{{ $produto->nome }}</h3>
        <p>R$ {{ number_format($produto->preco, 2, ',', '.') }}</p>
    </div>
@endforeach

{{-- $loop — variável especial dentro de foreach --}}
@foreach ($produtos as $produto)
    <div class="{{ $loop->even ? 'par' : 'impar' }}">
        {{ $loop->iteration }}/{{ $loop->count }}: {{ $produto->nome }}
        @if ($loop->first) <span>← primeiro</span> @endif
        @if ($loop->last) <span>← último</span> @endif
    </div>
@endforeach

{{-- forelse: bloco para quando a coleção for vazia --}}
@forelse ($produtos as $produto)
    <p>{{ $produto->nome }}</p>
@empty
    <p>Nenhum produto cadastrado.</p>
@endforelse

{{-- for e while --}}
@for ($i = 1; $i <= 5; $i++)
    <p>Item {{ $i }}</p>
@endfor

Herança de layouts

O padrão mais comum no Blade é definir um layout principal que as views estendem:

{{-- resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <title>@yield('title', 'Minha Loja')</title>
    <link rel="stylesheet" href="{{ asset('css/app.css') }}">
    @stack('styles')
</head>
<body>
    <header>
        <nav>
            <a href="{{ route('home') }}">Início</a>
            <a href="{{ route('produtos.index') }}">Produtos</a>
            @auth
                <a href="{{ route('perfil') }}">{{ auth()->user()->nome }}</a>
                <a href="{{ route('logout') }}">Sair</a>
            @endauth
            @guest
                <a href="{{ route('login') }}">Entrar</a>
            @endguest
        </nav>
    </header>

    <main>
        @if (session('sucesso'))
            <div class="alerta sucesso">{{ session('sucesso') }}</div>
        @endif

        @if (session('erro'))
            <div class="alerta erro">{{ session('erro') }}</div>
        @endif

        @yield('content')
    </main>

    <footer>
        <p>© {{ date('Y') }} Minha Loja</p>
    </footer>

    <script src="{{ asset('js/app.js') }}"></script>
    @stack('scripts')
</body>
</html>
{{-- resources/views/produtos/index.blade.php --}}
@extends('layouts.app')

@section('title', 'Produtos | Minha Loja')

@push('styles')
    <link rel="stylesheet" href="{{ asset('css/produtos.css') }}">
@endpush

@section('content')
    <h1>Produtos</h1>

    <div class="grade-produtos">
        @forelse ($produtos as $produto)
            <div class="card-produto">
                <h3>
                    <a href="{{ route('produtos.show', $produto) }}">
                        {{ $produto->nome }}
                    </a>
                </h3>
                <p>{{ $produto->preco_formatado }}</p>
                <p>{{ $produto->categoria->nome }}</p>
            </div>
        @empty
            <p>Nenhum produto disponível.</p>
        @endforelse
    </div>

    {{-- Paginação --}}
    {{ $produtos->links() }}

@endsection

@push('scripts')
    <script src="{{ asset('js/produtos.js') }}"></script>
@endpush

Componentes

Componentes são o recurso mais poderoso do Blade moderno — permitem criar elementos reutilizáveis com lógica e template encapsulados:

php artisan make:component Alerta
php artisan make:component Produto/Card
<?php
// app/View/Components/Alerta.php

namespace App\View\Components;

use Illuminate\View\Component;

class Alerta extends Component
{
    public function __construct(
        public readonly string $tipo = 'info',  // info, sucesso, erro, aviso
        public readonly bool $descartavel = false,
    ) {}

    public function classes(): string
    {
        return match($this->tipo) {
            'sucesso' => 'alerta alerta-sucesso',
            'erro'    => 'alerta alerta-erro',
            'aviso'   => 'alerta alerta-aviso',
            default   => 'alerta alerta-info',
        };
    }

    public function render()
    {
        return view('components.alerta');
    }
}
{{-- resources/views/components/alerta.blade.php --}}
<div {{ $attributes->class([$classes()]) }}>
    {{ $slot }}
    @if ($descartavel)
        <button onclick="this.parentElement.remove()">×</button>
    @endif
</div>
{{-- Usando o componente --}}
<x-alerta tipo="sucesso">
    Produto criado com sucesso!
</x-alerta>

<x-alerta tipo="erro" :descartavel="true">
    Ocorreu um erro ao processar o pagamento.
</x-alerta>

{{-- Componente com múltiplos slots --}}
<x-card>
    <x-slot name="header">
        <h3>{{ $produto->nome }}</h3>
    </x-slot>

    <p>{{ $produto->descricao }}</p>

    <x-slot name="footer">
        <a href="{{ route('produtos.show', $produto) }}">Ver mais</a>
    </x-slot>
</x-card>

Formulários e erros de validação

{{-- Formulário de criação de produto --}}
<form method="POST" action="{{ route('produtos.store') }}" enctype="multipart/form-data">
    @csrf  {{-- Token CSRF automático --}}

    <div>
        <label for="nome">Nome</label>
        <input type="text"
               id="nome"
               name="nome"
               value="{{ old('nome') }}"
               class="{{ $errors->has('nome') ? 'erro' : '' }}">
        @error('nome')
            <span class="mensagem-erro">{{ $message }}</span>
        @enderror
    </div>

    <div>
        <label for="preco">Preço</label>
        <input type="number"
               id="preco"
               name="preco"
               step="0.01"
               value="{{ old('preco') }}">
        @error('preco')
            <span class="mensagem-erro">{{ $message }}</span>
        @enderror
    </div>

    <div>
        <label for="categoria_id">Categoria</label>
        <select id="categoria_id" name="categoria_id">
            <option value="">Selecione...</option>
            @foreach ($categorias as $categoria)
                <option value="{{ $categoria->id }}"
                    {{ old('categoria_id') == $categoria->id ? 'selected' : '' }}>
                    {{ $categoria->nome }}
                </option>
            @endforeach
        </select>
        @error('categoria_id')
            <span class="mensagem-erro">{{ $message }}</span>
        @enderror
    </div>

    {{-- Para edição: método PUT --}}
    {{-- @method('PUT') --}}

    <button type="submit">Salvar</button>
</form>

Resumo

Recurso Sintaxe
Exibir variável {{ $var }} (com escape) / {!! $var !!} (sem escape)
Condicional @if / @elseif / @else / @endif
Loop @foreach / @forelse / @for
Layout @extends / @section / @yield
Stack @stack / @push
Componente <x-nome-componente :prop="$valor">
CSRF @csrf — obrigatório em todo formulário POST
Erros @error('campo') {{ $message }} @enderror
Auth @auth / @guest / @can

Exercício da semana

  1. Crie um layout principal com header, footer e área de flash messages. Crie views para listar, exibir, criar e editar produtos, todas estendendo o layout.

  2. Construa um componente <x-produto-card> que recebe um $produto e exibe nome, preço, categoria e estoque. Use o componente na listagem.

  3. Implemente um componente <x-paginacao> que envolve $colecao->links() com estilos customizados.

  4. Desafio: crie um componente <x-data-table> genérico que recebe $colunas (array de configuração) e $dados (coleção) e renderiza uma tabela completa com ordenação por coluna via query string.


Referências

  • Blade Templates — Documentação: https://laravel.com/docs/blade
  • Blade Components: https://laravel.com/docs/blade#components
  • Laravel Collective Forms (helper adicional): https://laravelcollective.com/

Comentários

Mais em PHP

Interfaces Avançadas
Interfaces Avançadas

Interfaces s&atilde;o o principal mecanismo de abstra&ccedil;&atilde;o do PHP...

Artigo 48 — Deploy e Ambiente de Produção
Artigo 48 — Deploy e Ambiente de Produção

Saber desenvolver é necessário, mas não suficiente. Um sistema que funciona p...

Design Patterns: Singleton, Factory e Builder
Design Patterns: Singleton, Factory e Builder

Design Patterns (Padrões de Projeto) são soluções codificadas para problemas...