Kurs Laravel 13 #3: struktura MVC, kontrolery i Blade
zweryfikowano 7 września 2026 · 6 min
MVC rozdziela dane (model), wyświetlanie (widok) i logikę (kontroler). Utwórz kontroler komendą php artisan make:controller, zwróć widok przez view('nom', [...]), a wartości wyświetlaj w Blade przez {{ $variable }}, które automatycznie escapuje HTML.
MVC dzieli aplikację na trzy odpowiedzialności: model opisuje dane, widok je wyświetla, a kontroler łączy jedno z drugim. Ten rozdział buduje kontroler i widoki Blade. Modele pojawią się w rozdziale 6, kiedy będzie już baza danych do odpytania.
Kontrolery
Kontroler odbiera żądanie, zbiera to, czego potrzebuje strona, i zwraca widok. Utwórz pierwszy:
php artisan make:controller IndexControllerINFO Controller [app/Http/Controllers/IndexController.php] created successfully.Wygenerowany plik jest prawie pusty. Laravel 13 importuje w nim Request z góry, choć ta klasa jeszcze się nie przydaje:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class IndexController extends Controller
{
//
}App\Http\Controllers zapisuje się z backslashami, nie z ukośnikami, i nigdy sklejone w jedno słowo. Linia w rodzaju namespace AppHttpControllers; nie wskazuje właściwej przestrzeni nazw, a autoloader Composera nie znajdzie klasy. Jeśli kopiujesz kod ze strony, która zjadła backslashe, sprawdź to w pierwszej kolejności.
Dodaj metodę, która zwraca tekst:
<?php
namespace App\Http\Controllers;
class IndexController extends Controller
{
public function index(): string
{
return 'Ceci vient de IndexController';
}
}Następnie skieruj na nią trasę strony głównej:
<?php
use App\Http\Controllers\IndexController;
use Illuminate\Support\Facades\Route;
Route::get('/', [IndexController::class, 'index']);Odśwież http://127.0.0.1:8000: zdanie się wyświetla. Trasa nie zawiera już logiki, wskazuje tylko, gdzie jej szukać.
Zwrócić widok zamiast łańcucha znaków
use Illuminate\View\View;
public function index(): View
{
return view('welcome');
}Funkcja view() przyjmuje nazwę pliku bez rozszerzenia: welcome odpowiada plikowi resources/views/welcome.blade.php. Kropka pełni rolę separatora katalogów: view('partials.sidebar') wczytuje resources/views/partials/sidebar.blade.php.
Kontrolery jednoakcyjne
Gdy kontroler ma tylko jedno zadanie, metoda __invoke pozwala nie nadawać mu nazwy. Plik istnieje już od początku rozdziału: --force go nadpisuje.
php artisan make:controller IndexController --invokable --forceWygenerowany plik zawiera pustą metodę __invoke(Request $request) poprzedzoną komentarzem. Zastąp ją tą:
<?php
namespace App\Http\Controllers;
use Illuminate\View\View;
class IndexController extends Controller
{
public function __invoke(): View
{
return view('welcome');
}
}Trasa upraszcza się o tyle samo: nie trzeba już podawać metody.
Route::get('/', IndexController::class);Ten kurs stosuje tę formę dla strony głównej, kategorii i tagów, a formę klasyczną dla artykułów, które będą miały dwie metody.
Przekazywanie danych do widoku
Drugi argument view() to tablica. Każdy klucz staje się zmienną w szablonie:
public function __invoke(): View
{
return view('accueil', [
'nom' => 'Damien',
'articles' => ['Premier article', 'Deuxième article'],
]);
}W widoku dostępne są $nom i $articles.
Widoki Blade
Blade to silnik szablonów Laravela. Plik .blade.php to HTML wzbogacony o kilka dyrektyw. Jest kompilowany do PHP raz, a potem trzymany w cache.
Wyświetlenie wartości
<p>Bonjour, {{ $nom }}.</p>Podwójne klamry automatycznie escapują zawartość: jeśli $nom zawiera <script>, przeglądarka wyświetli tekst, zamiast go wykonać. To domyślna ochrona przed wstrzyknięciem kodu.
Kiedy chcesz świadomie wyświetlić HTML, na przykład treść artykułu napisaną w zapleczu, użyj formy bez escapowania:
<div>{!! $post->content !!}</div>Stosuj ją wyłącznie do wartości, nad których pochodzeniem panujesz. Na tym, co wpisał odwiedzający, to podatność.
Warunki i pętle
@if (count($articles) === 1)
Un seul article.
@elseif (count($articles) > 1)
{{ count($articles) }} articles.
@else
Aucun article.
@endifPętla @foreach ma przydatny wariant, @forelse, który obsługuje pustą listę bez dodatkowego warunku:
@forelse ($articles as $article)
<h2>{{ $article }}</h2>
@empty
<p>Aucun article pour le moment.</p>
@endforelsePętle
@foreach jest najczęstsza, ale Blade przejmuje wszystkie pętle PHP-a:
@for ($i = 1; $i <= 3; $i++)
Passage numéro {{ $i }}
@endfor
@while ($compteur > 0)
Il reste {{ $compteur-- }}
@endwhileWewnątrz @foreach Blade udostępnia zmienną $loop, dzięki której nie trzeba liczyć ręcznie:
@foreach ($articles as $article)
{{ $loop->iteration }} sur {{ $loop->count }} :
{{ $article }}
@if ($loop->first) (le premier) @endif
@if ($loop->last) (le dernier) @endif
@endforeachNa liście dwóch artykułów ten szablon daje:
1 sur 2 : A (le premier)
2 sur 2 : B (le dernier)$loop wystawia też index (liczony od zera), remaining, even, odd oraz parent, żeby sięgnąć do pętli nadrzędnej.
Wybór wielokrotny
@switch($niveau)
@case('debutant')
Pour débuter
@break
@case('avance')
Pour aller plus loin
@break
@default
Niveau non précisé
@endswitch@break jest obowiązkowy na końcu każdego @case, tak jak w PHP: bez niego wykonanie przechodzi do kolejnego przypadku.
Dziedziczenie szablonów
Główna zaleta Blade’a to napisanie szkieletu serwisu tylko raz. Utwórz 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/pl/">{{ config('app.name') }}</a>
</header>
<main>
@yield('content')
</main>
<footer>
<p>{{ config('app.name') }}</p>
</footer>
</body>
</html>@yield('content') rezerwuje miejsce. Drugi argument @yield to wartość domyślna, użyta wtedy, gdy sekcja nie została zdefiniowana.
Konkretna strona rozszerza ten szablon i wypełnia zarezerwowane miejsca:
@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
@endsectionKrótka sekcja mieści się w jednej linii: @section('title', 'Accueil'). Blok otwiera się przez @section, a zamyka przez @endsection.
Dołączenie fragmentu wielokrotnego użytku
@include wstawia inny widok w wybranym miejscu, z dostępem do tych samych zmiennych:
@include('partials.sidebar')Ten kurs korzysta z niego przy pasku bocznym i liście artykułów, używanych na pięciu stronach.
Komponenty czy dziedziczenie?
Laravel proponuje drugie podejście, komponenty Blade, ze składnią opartą na znacznikach:
<x-layout title="Accueil">
<h1>Bonjour</h1>
</x-layout>Oba mechanizmy współistnieją w Laravelu 13 i żaden nie jest przestarzały. Komponenty wygrywają, gdy klocki przyjmują parametry i składają się ze sobą. @extends pozostaje bardziej bezpośredni przy zwykłym szkielecie strony. Ten kurs trzyma się @extends, czytelniejszego na początek. Komponenty opisuje dokumentacja Blade’a.
Słowo o cache widoków
Blade kompiluje każdy widok do PHP w storage/framework/views. Podczas developmentu rekompilacja jest automatyczna, gdy tylko plik się zmieni. Jeśli zmiana się nie pojawia, wyczyść cache:
php artisan view:clearKolejny rozdział instaluje panel administracyjny, w którym będziesz pisać artykuły.