Rozdział 3 z 9

Kurs Laravel 13 #3: struktura MVC, kontrolery i Blade

zweryfikowano 7 września 2026 · 6 min

Szybka odpowiedź

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.

Na koniec tego rozdziału, będziesz umieć utworzyć kontroler, zwrócić z niego widok Blade i zbudować szablon strony do wielokrotnego użytku.

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:

bash
php artisan make:controller IndexController
code
INFO  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:

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

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class IndexController extends Controller
{
    //
}
Backslashe mają znaczenie

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:

app/Http/Controllers/IndexController.php
<?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:

routes/web.php
<?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

app/Http/Controllers/IndexController.php
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.

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

Wygenerowany plik zawiera pustą metodę __invoke(Request $request) poprzedzoną komentarzem. Zastąp ją tą:

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');
    }
}

Trasa upraszcza się o tyle samo: nie trzeba już podawać metody.

routes/web.php
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:

app/Http/Controllers/IndexController.php
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

markup
<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:

markup
<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

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

Pętla @foreach ma przydatny wariant, @forelse, który obsługuje pustą listę bez dodatkowego warunku:

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

Pętle

@foreach jest najczęstsza, ale Blade przejmuje wszystkie pętle PHP-a:

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

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

Wewnątrz @foreach Blade udostępnia zmienną $loop, dzięki której nie trzeba liczyć ręcznie:

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

Na liście dwóch artykułów ten szablon daje:

code
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

markup
@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:

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:

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

Kró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:

markup
@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:

markup
<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:

bash
php artisan view:clear

Kolejny rozdział instaluje panel administracyjny, w którym będziesz pisać artykuły.

Częste błędy

Znikają backslashe w przestrzeni nazw Linia, która brzmi „namespace AppHttpControllers” zamiast „namespace App\Http\Controllers”, nie wskazuje właściwej przestrzeni nazw, a autoloader Composera nie znajduje klasy. To najczęstsza usterka w kodzie kopiowanym z sieci.
{{ }} wyświetla HTML jako tekst Tak ma być: podwójne klamry escapują zawartość. Żeby wyświetlić HTML świadomie, użyj {!! !!}, i tylko na zaufanym źródle.
Zapomniany @break w @switch Tak jak w PHP, bez @break wykonanie przechodzi do kolejnego przypadku.
Zmiana w widoku się nie pojawia Wyczyść cache skompilowanych widoków komendą php artisan view:clear.
Newsletter

Nowe testy, poradniki i projekty, e-mailem.

Powtarzalne testy, wersjonowany kod, datowane wyniki. Nigdy spamu.