Работа с PHP и HTML в представлениях Laravel через Blade

Раздел: Laravel -> Шаблоны и представления в Laravel

Введение в Blade шаблоны

Blade представляет собой мощный шаблонизатор, встроенный в Laravel. Он позволяет использовать чистый PHP код внутри HTML, а также предоставляет удобные директивы для управления данными, условиями, циклами и наследованием макетов. Правильное сочетание PHP и HTML в Blade делает разработку быстрой и безопасной. Ниже рассмотрены основные подходы к организации представлений.

Как организовать общий макет и наполнять его содержимым?

Самый эффективный способ создание layout с секциями и наследование через @extends. Сначала определяется базовый шаблон layouts/app.blade.php:

<!DOCTYPE html>
<html>
<head>
    <title>@yield('title', 'Default Title')</title>
    <link rel="stylesheet" href="{{ asset('css/app.css') }}">
    @stack('styles')
</head>
<body>
    <div class="container">
        @yield('content')
    </div>
    @stack('scripts')
</body>
</html>

Laravel php html (laravel php html)

Дочернее представление home.blade.php расширяет его и определяет секции:

@extends('layouts.app')

@section('title', 'Главная страница')

@section('content')
    <h2>Добро пожаловать!</h2>
    <p>Это пример наследования макетов.</p>
@stop

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

Такой подход позволяет единообразно подключать стили, скрипты и избегать дублирования. Типичная ошибка забыть указать @stop или @endsection, что приводит к некорректному рендерингу.

Проблема: секция не отображается, если забыть закрыть @section. Решение: всегда использовать @stop или @endsection. Другая ошибка попытка переопределить уже переданную секцию без использования @parent это приводит к полной замене.

Как вставить PHP код напрямую в шаблон Blade?

Blade предоставляет директиву @php для выполнения произвольного PHP кода без выхода в HTML:

@php
    $start = Carbon\Carbon::now();
    $days = $start->diffInDays($endDate);
    $status = $days > 30 ? 'просрочено' : 'в срок';
@endphp
<p>{{ $status }}</p>

Можно использовать и обычные PHP теги, но это нарушает стиль Blade. Директива @verbatim полезна, когда нужно вывести фигурные скобки без интерпретации:

@verbatim
    <div>{ { $var } }</div>
@endverbatim
Типичная ошибка попытка использовать <?php ?> внутри Blade это работает, но ухудшает читаемость. Рекомендуется придерживаться @php.

Как передать данные из контроллера в представление?

Самый распространённый способ второй параметр метода view():

// В контроллере
$users = User::where('active', 1)->get();
return view('users.index', ['usersList' => $users]);

// В представлении users/index.blade.php
@foreach($usersList as $user)
    <p>{{ $user->name }}</p>
@endforeach

Альтернатива использование compact() или with():

return view('users.index')->with('usersList', $users);
// или
return view('users.index', compact('users'));
Проблема: переменная не определена в шаблоне, если имя ключа отличается от ожидаемого. Всегда проверяйте соответствие.

Как использовать условные операторы и циклы в Blade?

Blade предоставляет удобные директивы для управления логикой. Примеры:

@if($role === 'admin')
    <p class="fw-bold">Администратор</p>
@elseif($role === 'user')
    <p>Пользователь</p>
@else
    <p>Гость</p>
@endif

@unless($user->isBanned)
    <p>Пользователь активен</p>
@endunless

@isset($profile)
    <img src="{{ $profile->avatar }}">
@endisset

@empty($comments)
    <p>Комментариев нет</p>
@endempty

Циклы:
@for($i = 0; $i < 10; $i++)
    <span>{{ $i }}</span>
@endfor

@foreach($products as $product)
    <div>{{ $product->title }}</div>
@endforeach

@forelse($posts as $post)
    <article>{{ $post->content }}</article>
@empty
    <p>Нет записей</p>
@endforelse
Ошибка: неправильное закрытие директивы (например, @endif вместо @endisset). Blade выдаст синтаксическую ошибку. Следует соблюдать пары: @if/@endif, @foreach/@endforeach и т.д.

Как создать компоненты для повторного использования?

Blade поддерживает два вида компонентов: анонимные (в папке resources/views/components/) и классовые (регистрируются через artisan). Пример анонимного компонента alert.blade.php:

<div class="alert alert-{{ $type ?? 'info' }}">
    {{ $slot }}
</div>

Использование в шаблоне:

<x-alert type="warning">
    Внимание! Проверьте данные.
</x-alert>

Для классовых компонентов создаётся класс командой php artisan make:component Alert, в представлении используется <x-alert /> с передачей атрибутов.

Типичная ошибка забыть пробросить слоты или использовать неверное имя компонента. Имена компонентов пишутся в kebab-case, папка components должна быть в views.

Как подключать частичные представления (partials)?

Директива @include вставляет содержимое другого файла. Полезно для формы, шапки или подвала:

@include('partials.header', ['logo' => $logo])

@includeIf('partials.sidebar')   // только если файл существует
@includeWhen($showFooter, 'partials.footer')

Можно передавать переменные вторым аргументом. Если нужно избежать конфликтов имён, используйте @each для итерации с частичным представлением (устарело, лучше @foreach внутри).

Проблема: при многократном @include одной переменной может возникнуть переопределение. Лучше явно передавать нужные данные.

Как защититься от XSS при выводе данных?

По умолчанию конструкция {{ $var }} экранирует HTML. Никогда не используйте {!! $var !!} без необходимости, так как это отключает экранирование и опасно, если данные приходят от пользователя:

// Безопасно:
<p>{{ $comment->body }}</p>

// Только если $var содержит доверенный HTML:
<div>{!! $post->formattedBody !!}</div>
Типичная ошибка вывод пользовательского ввода через {!! !!} приводит к уязвимости XSS. Всегда фильтруйте данные.

Как управлять стилями и скриптами с помощью стеков?

Стеки позволяют добавлять скрипты и стили в разных частях шаблона и выводить их в одном месте. В layout:

@stack('scripts')
@stack('styles')

В дочернем представлении:

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

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

@prepend('scripts')
    <script>console.log('Этот скрипт будет первым')</script>
@endprepend

Стеки гарантируют порядок загрузки и избегают дублирования.

Ошибка: использование @push вне контекста layout, где нет @stack, приведёт к тому, что контент не отобразится. Всегда проверяйте, что стек определён в родительском шаблоне.

Расширенные примеры работы с Blade

Пользовательская директива Blade

Создайте директиву, которая форматирует дату. В методе boot сервис-провайдера AppServiceProvider:

Пример
use Illuminate\Support\Facades\Blade;

Blade::directive('dateformat', function ($expression) {
    return "<?php echo \Carbon\Carbon::parse($expression)->format('d.m.Y'); ?>";
});

Использование в шаблоне:

Пример
@dateformat($user->created_at)

Результат: 01.01.2025

Использование коллекций в циклах

Blade отлично работает с коллекциями. Группировка и фильтрация прямо в шаблоне (но лучше делать в контроллере):

Пример
@foreach($users->groupBy('city') as $city => $group)
    <h3>Город: {{ $city }}</h3>
    @foreach($group as $user)
        <p>{{ $user->name }}</p>
    @endforeach
@endforeach

Результат: вывод пользователей, сгруппированных по городам.

Вложенные компоненты со слотами

Создайте компонент card, который принимает header, body и footer:

Пример
<div class="card">
    <div class="card-header">
        {{ $header }}
    </div>
    <div class="card-body">
        {{ $slot }}
    </div>
    @if(isset($footer))
        <div class="card-footer">
            {{ $footer }}
        </div>
    @endif
</div>

Использование с именованными слотами:

Пример
<x-card>
    <x-slot name="header">Заголовок карточки</x-slot>
    Основное содержимое.
    <x-slot name="footer">Подвал</x-slot>
</x-card>

Результат: полноценная карточка Bootstrap 5.

View Composer для передачи данных во все представления

Зарегистрируйте композер в AppServiceProvider.php:

Пример
use Illuminate\Support\Facades\View;

View::composer('*', function ($view) {
    $view->with('globalSettings', \App\Models\Setting::pluck('value', 'key'));
});

Теперь переменная $globalSettings доступна во всех шаблонах без передачи через контроллер. Можно ограничить композер только определёнными шаблонами, передав массив.

Использование Blade с Livewire (кратко)

Установите Livewire: composer require livewire/livewire. Создайте компонент:

Пример
php artisan make:livewire Counter

В представлении counter.blade.php:

Пример
<div>
    <h1>{{ $count }}</h1>
    <button wire:click="increment">+</button>
</div>

Результат: интерактивный счётчик без перезагрузки страницы.

Отладка переменных в шаблоне

Используйте директиву @dump:

Пример
@dump($users)

Результат: выводит содержимое переменной в стиле var_dump, обёрнутый в стилизованный блок.

Проверка существования переменной с помощью @isset и @empty

Пример с выводом аватара, если он есть:

Пример
@isset($user->avatar)
    <img src="{{ asset('storage/'.$user->avatar) }}" alt="Аватар">
@else
    <img src="{{ asset('default-avatar.png') }}" alt="Аватар по умолчанию">
@endisset

Результат: динамическое отображение изображения.

Laravel PHP HTML - comments

En
Laravel php html (php)