Работа с PHP и HTML в представлениях Laravel через Blade
Введение в 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, что приводит к некорректному рендерингу.
Как вставить 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Как передать данные из контроллера в представление?
Самый распространённый способ второй параметр метода 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Как создать компоненты для повторного использования?
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 /> с передачей атрибутов.
Как подключать частичные представления (partials)?
Директива @include вставляет содержимое другого файла. Полезно для формы, шапки или подвала:
@include('partials.header', ['logo' => $logo])
@includeIf('partials.sidebar') // только если файл существует
@includeWhen($showFooter, 'partials.footer')Можно передавать переменные вторым аргументом. Если нужно избежать конфликтов имён, используйте @each для итерации с частичным представлением (устарело, лучше @foreach внутри).
Как защититься от XSS при выводе данных?
По умолчанию конструкция {{ $var }} экранирует HTML. Никогда не используйте {!! $var !!} без необходимости, так как это отключает экранирование и опасно, если данные приходят от пользователя:
// Безопасно:
<p>{{ $comment->body }}</p>
// Только если $var содержит доверенный HTML:
<div>{!! $post->formattedBody !!}</div>Как управлять стилями и скриптами с помощью стеков?
Стеки позволяют добавлять скрипты и стили в разных частях шаблона и выводить их в одном месте. В 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Стеки гарантируют порядок загрузки и избегают дублирования.
Расширенные примеры работы с 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Результат: динамическое отображение изображения.