Capítulo 3 de 9

Tutorial Laravel 13 #3: estrutura MVC e views Blade

verificado a 7 Setembro 2026 · 6 min

Resposta rápida

O MVC separa os dados (modelo), a apresentação (view) e a lógica (controlador). Cria um controlador com php artisan make:controller, devolve uma view com view('nom', [...]) e mostra os valores no Blade com {{ $variable }}, que escapa o HTML automaticamente.

No fim deste capítulo, saberás criar um controlador, fazê-lo devolver uma view Blade e construir um template de página reutilizável.

O MVC divide uma aplicação em três responsabilidades: o modelo descreve os dados, a view mostra-os, o controlador faz a ligação entre ambos. Este capítulo constrói um controlador e algumas views Blade. Os modelos chegam no capítulo 6, quando houver uma base de dados para interrogar.

Os controladores

Um controlador recebe um pedido, reúne aquilo de que a página precisa e devolve uma view. Cria um:

bash
php artisan make:controller IndexController
code
INFO  Controller [app/Http/Controllers/IndexController.php] created successfully.

O ficheiro gerado está quase vazio. O Laravel 13 importa Request por defeito, mesmo que essa classe ainda não sirva:

app/Http/Controllers/IndexController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class IndexController extends Controller
{
    //
}
As barras invertidas contam

O App\Http\Controllers escreve-se com barras invertidas, não com barras normais, e nunca colado numa só palavra. Uma linha como namespace AppHttpControllers; não designa o espaço de nomes certo e o carregamento automático do Composer não encontra a classe. Se copiares código de um site que engoliu as barras invertidas, é a primeira coisa a verificar.

Acrescenta um método que devolve texto:

app/Http/Controllers/IndexController.php
<?php

namespace App\Http\Controllers;

class IndexController extends Controller
{
    public function index(): string
    {
        return 'Ceci vient de IndexController';
    }
}

Depois aponta a rota da página inicial para ele:

routes/web.php
<?php

use App\Http\Controllers\IndexController;
use Illuminate\Support\Facades\Route;

Route::get('/', [IndexController::class, 'index']);

Recarrega http://127.0.0.1:8000: a frase aparece. A rota já não contém lógica, apenas indica onde a encontrar.

Devolver uma view em vez de uma string

app/Http/Controllers/IndexController.php
use Illuminate\View\View;

public function index(): View
{
    return view('welcome');
}

A função view() recebe o nome do ficheiro sem a extensão: welcome corresponde a resources/views/welcome.blade.php. O ponto serve de separador de pastas: view('partials.sidebar') carrega resources/views/partials/sidebar.blade.php.

Os controladores de ação única

Quando um controlador só tem uma coisa a fazer, o método __invoke evita ter de lhe dar um nome. O ficheiro já existe desde o início do capítulo: --force substitui-o.

bash
php artisan make:controller IndexController --invokable --force

O ficheiro gerado contém um método __invoke(Request $request) vazio, precedido de um comentário. Substitua-o por este:

app/Http/Controllers/IndexController.php
<?php

namespace App\Http\Controllers;

use Illuminate\View\View;

class IndexController extends Controller
{
    public function __invoke(): View
    {
        return view('welcome');
    }
}

A rota simplifica-se na mesma medida: deixa de ser preciso indicar o método.

routes/web.php
Route::get('/', IndexController::class);

Este tutorial usa esta forma para a página inicial, as categorias e as etiquetas, e a forma clássica para os artigos, que vão ter dois métodos.

Passar dados à view

O segundo argumento de view() é um array. Cada chave passa a ser uma variável no template:

app/Http/Controllers/IndexController.php
public function __invoke(): View
{
    return view('accueil', [
        'nom' => 'Damien',
        'articles' => ['Premier article', 'Deuxième article'],
    ]);
}

Na view, o $nom e o $articles ficam disponíveis.

As views Blade

O Blade é o motor de templates do Laravel. Um ficheiro .blade.php é HTML ao qual se juntam algumas diretivas. É compilado para PHP uma vez e depois guardado em cache.

Mostrar um valor

markup
<p>Bonjour, {{ $nom }}.</p>

As chavetas duplas escapam o conteúdo automaticamente: se o $nom contiver <script>, o navegador mostra o texto em vez de o executar. É a proteção por omissão contra as injeções de código.

Quando queres mesmo mostrar HTML, por exemplo o conteúdo de um artigo escrito no back-office, usa a forma não escapada:

markup
<div>{!! $post->content !!}</div>

Reserva-a para valores cuja origem controlas. Sobre o que um visitante escreve, é uma falha de segurança.

Condições e ciclos

markup
@if (count($articles) === 1)
    Un seul article.
@elseif (count($articles) > 1)
    {{ count($articles) }} articles.
@else
    Aucun article.
@endif

O ciclo @foreach tem uma variante útil, o @forelse, que trata do caso da lista vazia sem condição adicional:

markup
@forelse ($articles as $article)
    <h2>{{ $article }}</h2>
@empty
    <p>Aucun article pour le moment.</p>
@endforelse

Os ciclos

O @foreach é o mais corrente, mas o Blade retoma todos os ciclos do PHP:

markup
@for ($i = 1; $i <= 3; $i++)
    Passage numéro {{ $i }}
@endfor

@while ($compteur > 0)
    Il reste {{ $compteur-- }}
@endwhile

Dentro de um @foreach, o Blade fornece uma variável $loop que evita contar à mão:

markup
@foreach ($articles as $article)
    {{ $loop->iteration }} sur {{ $loop->count }} :
    {{ $article }}
    @if ($loop->first) (le premier) @endif
    @if ($loop->last) (le dernier) @endif
@endforeach

Numa lista de dois artigos, este template produz:

code
1 sur 2 : A (le premier)
2 sur 2 : B (le dernier)

O $loop expõe ainda index (a começar em zero), remaining, even, odd e parent, para subir ao ciclo envolvente.

A escolha múltipla

markup
@switch($niveau)
    @case('debutant')
        Pour débuter
        @break
    @case('avance')
        Pour aller plus loin
        @break
    @default
        Niveau non précisé
@endswitch

O @break é obrigatório no fim de cada @case, tal como em PHP: sem ele, a execução continua no caso seguinte.

A herança de templates

O principal interesse do Blade é escrever a estrutura do site uma só vez. Cria o resources/views/layouts/app.blade.php:

resources/views/layouts/app.blade.php
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>@yield('title', config('app.name'))</title>
</head>
<body>
    <header>
        <a href="https://www.gekkode.com/pt/">{{ config('app.name') }}</a>
    </header>

    <main>
        @yield('content')
    </main>

    <footer>
        <p>{{ config('app.name') }}</p>
    </footer>
</body>
</html>

O @yield('content') reserva um lugar. O segundo argumento de @yield é o valor por omissão, usado quando a secção não está definida.

Uma página concreta estende este template e preenche os lugares reservados:

resources/views/accueil.blade.php
@extends('layouts.app')

@section('title', 'Accueil')

@section('content')
    <h1>Bonjour, {{ $nom }}.</h1>

    @forelse ($articles as $article)
        <h2>{{ $article }}</h2>
    @empty
        <p>Aucun article pour le moment.</p>
    @endforelse
@endsection

Para uma secção curta, o @section('title', 'Accueil') cabe numa linha. Para um bloco, abre-se com @section e fecha-se com @endsection.

Incluir um pedaço reutilizável

O @include insere outra view no sítio pretendido, com acesso às mesmas variáveis:

markup
@include('partials.sidebar')

Este tutorial usa-o para a barra lateral e para a lista de artigos, reutilizadas em cinco páginas.

Componentes ou herança?

O Laravel propõe uma segunda abordagem, os componentes Blade, com uma sintaxe de tags:

markup
<x-layout title="Accueil">
    <h1>Bonjour</h1>
</x-layout>

Os dois mecanismos coexistem no Laravel 13 e nenhum está descontinuado. Os componentes impõem-se quando as peças recebem parâmetros e se compõem umas com as outras, o @extends continua mais direto para uma simples estrutura de página. Este tutorial fica-se pelo @extends, mais legível para começar. A documentação do Blade detalha os componentes.

Uma nota sobre a cache das views

O Blade compila cada view para PHP em storage/framework/views. Em desenvolvimento, a recompilação é automática assim que o ficheiro muda. Se uma alteração não aparecer, limpa a cache:

bash
php artisan view:clear

O capítulo seguinte instala o painel de administração que vai servir para escrever os artigos.

Erros frequentes

As barras invertidas do espaço de nomes desaparecem Uma linha que se lê «namespace AppHttpControllers» em vez de «namespace App\Http\Controllers» não designa o espaço de nomes certo, e o carregamento automático do Composer não encontra a classe. É o defeito mais frequente no código copiado da web.
{{ }} mostra o HTML como texto É intencional: as chavetas duplas escapam o conteúdo. Para mostrar HTML de propósito, usa {!! !!}, e apenas sobre uma fonte de confiança.
@break esquecido num @switch Tal como em PHP, sem @break a execução continua no caso seguinte.
Uma alteração numa view não aparece Limpa a cache das views compiladas com php artisan view:clear.
Newsletter

Os novos testes, tutoriais e projetos, por e-mail.

Testes reproduzíveis, código versionado, resultados datados. Nunca spam.