Tutorial Laravel 13 #3: estrutura MVC e views Blade
verificado a 7 Setembro 2026 · 6 min
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.
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:
php artisan make:controller IndexControllerINFO 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:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class IndexController extends Controller
{
//
}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:
<?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:
<?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
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.
php artisan make:controller IndexController --invokable --forceO ficheiro gerado contém um método __invoke(Request $request) vazio, precedido de um comentário. Substitua-o por este:
<?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.
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:
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
<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:
<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
@if (count($articles) === 1)
Un seul article.
@elseif (count($articles) > 1)
{{ count($articles) }} articles.
@else
Aucun article.
@endifO ciclo @foreach tem uma variante útil, o @forelse, que trata do caso da lista vazia sem condição adicional:
@forelse ($articles as $article)
<h2>{{ $article }}</h2>
@empty
<p>Aucun article pour le moment.</p>
@endforelseOs ciclos
O @foreach é o mais corrente, mas o Blade retoma todos os ciclos do PHP:
@for ($i = 1; $i <= 3; $i++)
Passage numéro {{ $i }}
@endfor
@while ($compteur > 0)
Il reste {{ $compteur-- }}
@endwhileDentro de um @foreach, o Blade fornece uma variável $loop que evita contar à mão:
@foreach ($articles as $article)
{{ $loop->iteration }} sur {{ $loop->count }} :
{{ $article }}
@if ($loop->first) (le premier) @endif
@if ($loop->last) (le dernier) @endif
@endforeachNuma lista de dois artigos, este template produz:
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
@switch($niveau)
@case('debutant')
Pour débuter
@break
@case('avance')
Pour aller plus loin
@break
@default
Niveau non précisé
@endswitchO @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:
<!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:
@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
@endsectionPara 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:
@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:
<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:
php artisan view:clearO capítulo seguinte instala o painel de administração que vai servir para escrever os artigos.