1. Основы
  2. Шаблоны Blade

Введение

Blade - это простой, но мощный шаблонизатор, включенный в Laravel. В отличие от некоторых шаблонизаторов PHP, Blade не ограничивает вас в использовании чистого PHP-кода в ваших шаблонах. Фактически все шаблоны Blade компилируются в чистый PHP-код и кешируются до их изменения, что означает, что Blade добавляет практически нулевую нагрузку на ваше приложение. Файлы шаблонов Blade имеют расширение файла .blade.php и обычно хранятся в каталоге resources/views.

Представления Blade могут быть возвращены из маршрутов или контроллеров с использованием глобального помощника view. Как упоминалось в документации по представлениям, данные могут быть переданы в представление Blade с использованием второго аргумента помощника view:

Route::get('/', function () {
return view('greeting', ['name' => 'Finn']);
});

Улучшение Blade с Livewire

Хотите улучшить ваши шаблоны Blade и легко создавать динамические интерфейсы? Посмотрите Laravel Livewire. Livewire позволяет вам создавать компоненты Blade, дополненные динамической функциональностью, которая обычно возможна только с использованием фронтенд-фреймворков, таких как React или Vue, предоставляя отличный подход к созданию современных реактивных интерфейсов без сложностей, рендеринга на стороне клиента или этапов сборки многих фреймворков JavaScript.

Отображение Данных

Вы можете отображать данные, переданные ваши представления Blade, обернув переменную в фигурные скобки. Например, учитывая следующий маршрут:

Route::get('/', function () {
return view('welcome', ['name' => 'Samantha']);
});

Вы можете отобразить содержимое переменной name следующим образом:

Привет, {{ $name }}.

Примечание Выражения {{ }} в Blade автоматически обрабатываются функцией htmlspecialchars PHP для предотвращения атак XSS.

Вы не ограничены отображением содержимого переменных, переданных в представление. Вы также можете выводить результаты любой PHP-функции. Фактически, вы можете поместить любой PHP-код внутрь оператора Blade echo:

Текущая временная метка UNIX {{ time() }}.

Кодирование HTML Сущностей

По умолчанию Blade (и функция Laravel e) будет дважды кодировать HTML-сущности. Если вы хотите отключить двойное кодирование, вызовите метод Blade::withoutDoubleEncoding из метода boot вашего AppServiceProvider:

<?php
 
namespace App\Providers;
 
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
 
class AppServiceProvider extends ServiceProvider
{
/**
* Инициализация любых сервисов приложения.
*/
public function boot(): void
{
Blade::withoutDoubleEncoding();
}
}

Отображение Неэкранированных Данных

По умолчанию, выражения Blade {{ }} автоматически обрабатываются функцией htmlspecialchars PHP для предотвращения атак XSS. Если вы не хотите, чтобы ваши данные были экранированы, вы можете использовать следующий синтаксис:

Привет, {!! $name !!}.

Внимание Будьте очень осторожны при выводе контента, предоставленного пользователями вашего приложения. Вы обычно должны использовать экранированный синтаксис двойных фигурных скобок, чтобы предотвратить атаки XSS при отображении данных, предоставленных пользователями.

Blade и JavaScript Фреймворки

Поскольку многие JavaScript-фреймворки также используют "фигурные" скобки для отображения выражений в браузере, вы можете использовать символ @, чтобы сообщить движку рендеринга Blade, что выражение должно остаться нетронутым. Например:

<h1>Laravel</h1>
 
Привет, @{{ name }}.

В этом примере символ @ будет удален Blade; однако выражение {{ name }} останется нетронутым Blade-движком, что позволит его рендерить ваш фреймворк JavaScript.

Символ @ также может использоваться для экранирования директив Blade:

{{-- Blade template --}}
@@if()
 
<!-- HTML output -->
@if()

Рендеринг JSON

Иногда вы можете передать массив в представление с намерением отображения его как JSON для инициализации переменной JavaScript. Например:

<script>
var app = <?php echo json_encode($array); ?>;
</script>

Однако вместо того чтобы вызывать json_encode вручную, вы можете использовать метод директивы Illuminate\Support\Js::from. Метод from принимает те же аргументы, что и функция json_encode в PHP; однако он обеспечит правильное экранирование результирующего JSON для включения в HTML-цитаты. Метод from вернет строковый оператор JSON.parse JavaScript, который преобразует заданный объект или массив в допустимый объект JavaScript:

<script>
var app = {{ Illuminate\Support\Js::from($array) }};
</script>

В последних версиях структуры приложения Laravel включен фасад Js, который обеспечивает удобный доступ к этой функциональности в ваших шаблонах Blade:

<script>
var app = {{ Js::from($array) }};
</script>

Внимание Вы должны использовать метод Js::from только для отображения существующих переменных в виде JSON. Шаблонизация Blade основана на регулярных выражениях, и попытка передачи сложного выражения директиве может вызвать неожиданные сбои.

Директива @verbatim

Как только ваш собственный обработчик вывода будет определен, вы можете просто вывести объект в вашем шаблоне Blade:

@verbatim
<div class="container">
Привет, {{ name }}.
</div>
@endverbatim

Директивы Blade

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

Условные Выражения

Вы можете создавать операторы if, используя директивы @if, @elseif, @else и @endif. Эти директивы функционируют идентично своим PHP-аналогам:

@if (count($records) === 1)
У меня есть одна запись!
@elseif (count($records) > 1)
У меня есть несколько записей!
@else
У меня нет записей!
@endif

Для удобства Blade также предоставляет директиву @unless:

@unless (Auth::check())
Вы не вошли в систему.
@endunless

Помимо уже обсужденных условных директив, можно использовать директивы @isset и @empty как удобные ярлыки для соответствующих функций PHP:

@isset($records)
// $records определен и не равен null...
@endisset
 
@empty($records)
// $records is "empty"...
@endempty

Директивы Аутентификации

Директивы @auth и @guest могут быть использованы для быстрого определения, аутентифицирован ли текущий пользователь или гость:

@auth
// Пользователь аутентифицирован...
@endauth
 
@guest
// Пользователь не аутентифицирован...
@endguest

При необходимости можно указать сторож аутентификации, который должен быть проверен при использовании директив @auth и @guest:

@auth('admin')
// Пользователь аутентифицирован...
@endauth
 
@guest('admin')
// Пользователь не аутентифицирован...
@endguest

Директивы Окружения

Вы можете проверить, работает ли приложение в производственной среде, используя директиву @production:

@production
// Содержимое специфичное для производства...
@endproduction

Или вы можете определить, работает ли приложение в определенной среде, используя директиву @env:

@env('staging')
// Приложение работает в "staging"...
@endenv
 
@env(['staging', 'production'])
// Приложение работает в "staging" или "production"...
@endenv

Директивы Разделов

Вы можете определить, содержит ли раздел наследования шаблона контент, используя директиву @hasSection:

@hasSection('navigation')
<div class="pull-right">
@yield('navigation')
</div>
 
<div class="clearfix"></div>
@endif

Вы можете использовать директиву sectionMissing для определения отсутствия контента в разделе:

@sectionMissing('navigation')
<div class="pull-right">
@include('default-navigation')
</div>
@endif

Switch Statements

Операторы switch могут быть построены с использованием директив @switch, @case, @break, @default и @endswitch:

@switch($i)
@case(1)
Первый случай...
@break
 
@case(2)
Второй случай...
@break
 
@default
Случай по умолчанию...
@endswitch

Циклы

Помимо условных операторов, Blade предоставляет простые директивы для работы с циклами в PHP. Каждая из этих директив функционирует идентично своим аналогам в PHP:

@for ($i = 0; $i < 10; $i++)
Текущее значение: {{ $i }}
@endfor
 
@foreach ($users as $user)
<p>Это пользователь {{ $user->id }}</p>
@endforeach
 
@forelse ($users as $user)
<li>{{ $user->name }}</li>
@empty
<p>Нет пользователей</p>
@endforelse
 
@while (true)
<p>Я бесконечно повторяюсь.</p>
@endwhile

Примечание Проходя через цикл foreach, вы можете использовать переменную цикла, чтобы получить ценную информацию о цикле, например, находитесь ли вы в первой или последней итерации цикла.

При использовании циклов вы также можете пропустить текущую итерацию или завершить цикл, используя директивы @continue и @break:

@foreach ($users as $user)
@if ($user->type == 1)
@continue
@endif
 
<li>{{ $user->name }}</li>
 
@if ($user->number == 5)
@break
@endif
@endforeach

Вы также можете включить условие продолжения или завершения в объявление директивы:

@foreach ($users as $user)
@continue($user->type == 1)
 
<li>{{ $user->name }}</li>
 
@break($user->number == 5)
@endforeach

Переменная Цикла

При итерации через цикл foreach в вашем цикле будет доступна переменная $loop. Эта переменная предоставляет доступ к некоторой полезной информации, такой как текущий индекс цикла и является ли это первой или последней итерацией цикла:

@foreach ($users as $user)
@if ($loop->first)
Это первая итерация.
@endif
 
@if ($loop->last)
Это последняя итерация.
@endif
 
<p>Это пользователь {{ $user->id }}</p>
@endforeach

Если вы находитесь во вложенном цикле, вы можете получить доступ к переменной $loop родительского цикла через свойство parent:

@foreach ($users as $user)
@foreach ($user->posts as $post)
@if ($loop->parent->first)
Это первая итерация внешнего цикла.
@endif
@endforeach
@endforeach

Переменная $loop также содержит различные другие полезные свойства:

Свойство Описание
$loop->index Индекс текущей итерации цикла (начиная с 0).
$loop->iteration Текущая итерация цикла (начиная с 1).
$loop->remaining Оставшиеся итерации в цикле.
$loop->count Общее количество элементов в массиве, по которому выполняется итерация.
$loop->first Является ли это первой итерацией цикла.
$loop->last Является ли это последней итерацией цикла.
$loop->even Является ли это четной итерацией цикла.
$loop->odd Является ли это нечетной итерацией цикла.
$loop->depth Уровень вложенности текущего цикла.
$loop->parent При использовании вложенного цикла - переменная родительского цикла.

Условные Классы и Стили

Директива @class условно компилирует строку CSS-класса. Директива принимает массив классов, где ключ массива содержит класс или классы, которые вы хотите добавить, а значение - логическое выражение. Если элемент массива имеет числовой ключ, он всегда будет включен в список отображаемых классов:

@php
$isActive = false;
$hasError = true;
@endphp
 
<span @class([
'p-4',
'font-bold' => $isActive,
'text-gray-500' => ! $isActive,
'bg-red' => $hasError,
])></span>
 
<span class="p-4 text-gray-500 bg-red"></span>

Точно так же директиву @style можно использовать для условного добавления встроенных стилей CSS в элемент HTML:

@php
$isActive = true;
@endphp
 
<span @style([
'background-color: red',
'font-weight: bold' => $isActive,
])></span>
 
<span style="background-color: red; font-weight: bold;"></span>

Дополнительные Атрибуты

Для удобства вы можете использовать директиву @checked, чтобы легко указать, должен ли данный HTML-элемент флажка быть "отмечен". Эта директива выведет checked, если предоставленное условие оценивается как true:

<input type="checkbox"
name="active"
value="active"
@checked(old('active', $user->active)) />

Точно так же директиву @selected можно использовать для указания, должен ли данный вариант выбора быть "выбранным":

<select name="version">
@foreach ($product->versions as $version)
<option value="{{ $version }}" @selected(old('version') == $version)>
{{ $version }}
</option>
@endforeach
</select>

Кроме того, директиву @disabled можно использовать для указания, должен ли данный элемент быть "отключенным":

<button type="submit" @disabled($errors->isNotEmpty())>Submit</button>

Более того, директиву @readonly можно использовать для указания, должен ли данный элемент быть "только для чтения":

<input type="email"
name="email"
@readonly($user->isNotAdmin()) />

Кроме того, директиву @required можно использовать для указания, должен ли данный элемент быть "обязательным":

<input type="text"
name="title"
value="title"
@required($user->isAdmin()) />

Включение Подпредставлений

Примечание Хотя вы можете свободно использовать директиву @include, компоненты Blade предлагают аналогичный функционал и несколько преимуществ перед директивой @include, таких как привязка данных и атрибутов.

Директива @include в Blade позволяет включать представление Blade внутри другого представления. Все переменные, доступные в родительском представлении, будут также доступны включенному представлению:

<div>
@include('shared.errors')
 
<form>
<!-- Form Contents -->
</form>
</div>

Несмотря на то что включенный вид унаследует все данные, доступные в родительском виде, вы также можете передать массив дополнительных данных, которые должны быть доступны включенному виду:

@include('view.name', ['status' => 'complete'])

Если вы пытаетесь @include вид, которого не существует, Laravel выдаст ошибку. Если вы хотите включить вид, который может существовать или не существовать, вы должны использовать директиву @includeIf:

@includeIf('view.name', ['status' => 'complete'])

Если вы хотите включить вид в случае истинного или ложного выражения, вы можете использовать директивы @includeWhen и @includeUnless:

@includeWhen($boolean, 'view.name', ['status' => 'complete'])
 
@includeUnless($boolean, 'view.name', ['status' => 'complete'])

Чтобы включить первый вид из заданного массива видов, вы можете использовать директиву includeFirst:

@includeFirst(['custom.admin', 'admin'], ['status' => 'complete'])

Внимание Следует избегать использования констант __DIR__ и __FILE__ в представлениях Blade, поскольку они будут относиться к местоположению кешированного, скомпилированного представления.

Рендеринг Представлений для Коллекций

Вы можете объединить циклы и включения в одну строку с использованием директивы @each Blade:

@each('view.name', $jobs, 'job')

Первый аргумент директивы @each - это вид, который будет отображаться для каждого элемента в массиве или коллекции. Второй аргумент - это массив или коллекция, по которой вы хотите выполнить итерацию, а третий аргумент - это имя переменной, которая будет присвоена текущей итерации в представлении. Например, если вы выполняете итерацию по массиву jobs, обычно вы захотите получить доступ к каждому заданию, как к переменной job в представлении. Ключ массива для текущей итерации будет доступен как переменная key в представлении.

Вы также можете передать четвертый аргумент директиве @each. Этот аргумент определяет вид, который будет отображаться, если заданный массив пуст.

@each('view.name', $jobs, 'job', 'view.empty')

Внимание Представления, отображаемые с помощью @each, не наследуют переменные от родительского представления. Если дочернему представлению нужны эти переменные, следует использовать директивы @foreach и @include.

Директива @once

Директива @once позволяет определить часть шаблона, которая будет оценена только один раз за цикл отображения. Это может быть полезно для внедрения определенного фрагмента JavaScript в заголовок страницы с использованием стеков. Например, если вы отображаете данный компонент в цикле, вы можете захотеть добавить JavaScript в заголовок только при первом отображении компонента:

@once
@push('scripts')
<script>
// Ваш пользовательский JavaScript...
</script>
@endpush
@endonce

Поскольку директива @once часто используется в сочетании с директивами @push или @prepend, для вашего удобства предоставляются директивы @pushOnce и @prependOnce:

@pushOnce('scripts')
<script>
// Ваш пользовательский JavaScript...
</script>
@endPushOnce

Сырой PHP

В некоторых ситуациях полезно вставлять PHP-код в ваши представления. Вы можете использовать директиву @php Blade для выполнения блока обычного PHP в вашем шаблоне:

@php
$counter = 1;
@endphp

Комментарии

Blade также позволяет вам определять комментарии в ваших представлениях. Однако, в отличие от HTML-комментариев, комментарии Blade не включаются в HTML, возвращаемый вашим приложением:

{{-- Этот комментарий не будет присутствовать в результирующем HTML --}}

Компоненты

Компоненты и слоты предоставляют схожие преимущества по сравнению с секциями, макетами и включениями; однако некоторые могут считать модель компонентов и слотов более понятной. Существует два подхода к написанию компонентов: компоненты на основе классов и анонимные компоненты.

Для создания компонента на основе класса вы можете использовать команду Artisan make:component. Для иллюстрации того, как использовать компоненты, мы создадим простой компонент Alert. Команда make:component поместит компонент в каталог app/View/Components:

php artisan make:component Alert

Команда make:component также создаст шаблон представления для компонента. Представление будет размещено в каталоге resources/views/components. При написании компонентов для вашего собственного приложения компоненты автоматически обнаруживаются в каталоге app/View/Components и каталоге resources/views/components, поэтому обычно не требуется дополнительной регистрации компонента.

Вы также можете создавать компоненты в подкаталогах:

php artisan make:component Forms/Input

Команда выше создаст компонент Input в каталоге app/View/Components/Forms, а представление будет размещено в каталоге resources/views/components/forms.

Если вы хотите создать анонимный компонент (компонент только с шаблоном Blade и без класса), вы можете использовать флаг --view при вызове команды make:component:

php artisan make:component forms.input --view

Команда выше создаст файл Blade по пути resources/views/components/forms/input.blade.php, который можно будет отображать в виде компонента с использованием <x-forms.input />.

Ручная Регистрация Компонентов Пакета

При написании компонентов для вашего собственного приложения компоненты автоматически обнаруживаются в каталоге app/View/Components и каталоге resources/views/components.

Однако, если вы создаете пакет, который использует компоненты Blade, вам нужно вручную зарегистрировать класс компонента и его псевдоним тега HTML. Обычно компоненты регистрируются в методе boot сервис-провайдера вашего пакета:

use Illuminate\Support\Facades\Blade;
 
/**
* Инициализация сервисов вашего пакета.
*/
public function boot(): void
{
Blade::component('package-alert', Alert::class);
}

После регистрации вашего компонента его можно отобразить с использованием его псевдонима тега:

<x-package-alert/>

Кроме того, вы можете использовать метод componentNamespace для автоматической загрузки классов компонентов по соглашению. Например, пакет Nightshade может иметь компоненты Calendar и ColorPicker, которые находятся в пространстве имен Package\Views\Components:

use Illuminate\Support\Facades\Blade;
 
/**
* Инициализация сервисов вашего пакета.
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}

Это позволит использовать компоненты пакета по их пространству имен поставщика с использованием синтаксиса package-name:::

<x-nightshade::calendar />
<x-nightshade::color-picker />

Blade автоматически обнаруживает класс, связанный с этим компонентом, преобразуя имя компонента в Pascal case. Поддерживается также использование подкаталогов с использованием нотации "точка".

Рендеринг Компонентов

Чтобы отобразить компонент, вы можете использовать тег компонента Blade в одном из ваших шаблонов Blade. Теги компонентов Blade начинаются со строки x-, за которой следует имя класса компонента в kebab case:

<x-alert/>
 
<x-user-profile/>

Если класс компонента находится глубже в каталоге app/View/Components, вы можете использовать символ . для указания вложенности каталогов. Например, если предположить, что компонент расположен в app/View/Components/Inputs/Button.php, мы можем отобразить его следующим образом:

<x-inputs.button/>

Если вы хотите условно отобразить свой компонент, вы можете определить метод shouldRender в классе вашего компонента. Если метод shouldRender возвращает false, компонент не будет отображаться:

use Illuminate\Support\Str;
 
/**
* Должен ли компонент быть отрисован
*/
public function shouldRender(): bool
{
return Str::length($this->message) > 0;
}

Передача Данных Компонентам

Вы можете передавать данные в компоненты Blade с использованием HTML-атрибутов. Значения, захардкоженные и примитивные, могут быть переданы в компонент с использованием простых строк атрибутов HTML. PHP-выражения и переменные следует передавать компоненту через атрибуты, использующие символ : в качестве префикса:

<x-alert type="error" :message="$message"/>

Все атрибуты данных компонента следует определять в конструкторе его класса. Все общедоступные свойства компонента автоматически становятся доступными представлению компонента. Нет необходимости передавать данные в представление из метода render компонента:

<?php
 
namespace App\View\Components;
 
use Illuminate\View\Component;
use Illuminate\View\View;
 
class Alert extends Component
{
/**
* Создание экземпляра компонента.
*/
public function __construct(
public string $type,
public string $message,
) {}
 
/**
* Получить представление / содержимое, которое представляет компонент.
*/
public function render(): View
{
return view('components.alert');
}
}

При рендеринге вашего компонента вы можете отобразить содержимое общедоступных переменных вашего компонента, эхом переменных по имени:

<div class="alert alert-{{ $type }}">
{{ $message }}
</div>

Регистр

Аргументы конструктора компонента должны быть указаны в стиле camelCase, в то время как kebab-case следует использовать при ссылке на имена аргументов в ваших HTML-атрибутах. Например, учитывая следующий конструктор компонента:

/**
* Создание экземпляра компонента.
*/
public function __construct(
public string $alertType,
) {}

Аргумент $alertType может быть предоставлен компоненту следующим образом:

<x-alert alert-type="danger" />

Сокращенный Синтаксис Атрибутов

При передаче атрибутов компонентам вы также можете использовать сокращенный синтаксис атрибутов. Это часто удобно, поскольку имена атрибутов часто соответствуют именам переменных, которые они представляют:

{{-- Short attribute syntax... --}}
<x-profile :$userId :$name />
 
{{-- Is equivalent to... --}}
<x-profile :user-id="$userId" :name="$name" />

Экранирование Рендеринга Атрибутов

Поскольку некоторые фреймворки JavaScript, такие как Alpine.js, также используют атрибуты с двоеточием в качестве префикса, вы можете использовать двойное двоеточие (::) в Blade, чтобы указать, что атрибут не является выражением PHP. Например, учитывая следующий компонент:

<x-button ::class="{ danger: isDeleting }">
Submit
</x-button>

Blade отобразит следующий HTML:

<button :class="{ danger: isDeleting }">
Submit
</button>

Методы Компонента

Помимо общедоступных переменных, доступных в представлении вашего компонента, можно вызывать любые общедоступные методы компонента. Например, представьте себе компонент, в котором есть метод isSelected:

/**
* Определить, является ли данный вариант текущим выбранным вариантом.
*/
public function isSelected(string $option): bool
{
return $option === $this->selected;
}

Вы можете выполнить этот метод из вашего компонента, вызвав переменную с именем метода:

<option {{ $isSelected($value) ? 'selected' : '' }} value="{{ $value }}">
{{ $label }}
</option>

Доступ к Атрибутам и Слотам в Классах Компонентов

Компоненты Blade также позволяют вам получать доступ к имени компонента, атрибутам и слоту внутри метода render класса. Однако для доступа к этим данным вы должны вернуть замыкание из метода render вашего компонента. Замыкание будет принимать массив $data в качестве единственного аргумента. Этот массив будет содержать несколько элементов, предоставляющих информацию о компоненте:

use Closure;
 
/**
* Получить представление / содержимое, которое представляет компонент.
*/
public function render(): Closure
{
return function (array $data) {
// $data['componentName'];
// $data['attributes'];
// $data['slot'];
 
return 'modify_10x/blade.return_text_856';
};
}

componentName равен имени, используемому в HTML-теге после префикса x-. Таким образом, componentName <x-alert /> будет alert. Элемент attributes будет содержать все атрибуты, присутствующие в HTML-теге. Элемент slot - это экземпляр Illuminate\Support\HtmlString с содержимым слота компонента.

Замыкание должно возвращать строку. Если возвращаемая строка соответствует существующему представлению, это представление будет отображаться; в противном случае возвращаемая строка будет рассматриваться как встроенное представление Blade.

Дополнительные Зависимости

Если вашему компоненту требуются зависимости из контейнера служб Laravel, вы можете перечислить их перед любыми атрибутами данных компонента, и они будут автоматически внедрены контейнером:

use App\Services\AlertCreator;
 
/**
* Создание экземпляра компонента.
*/
public function __construct(
public AlertCreator $creator,
public string $type,
public string $message,
) {}

Скрытие Атрибутов / Методов

Если вы хотите предотвратить предоставление некоторых общедоступных методов или свойств в виде переменных в вашем компонентном шаблоне, вы можете добавить их в массив $except свойства вашего компонента:

<?php
 
namespace App\View\Components;
 
use Illuminate\View\Component;
 
class Alert extends Component
{
/**
* Свойства / методы, которые не должны быть доступны в шаблоне компонента.
*
* @var array
*/
protected $except = ['type'];
 
/**
* Создание экземпляра компонента.
*/
public function __construct(
public string $type,
) {}
}

Атрибуты Компонента

Мы уже рассмотрели, как передавать атрибуты данных в компонент; однако иногда вам может потребоваться указать дополнительные HTML-атрибуты, такие как class, которые не являются частью данных, необходимых для функционирования компонента. Обычно вы хотите передать эти дополнительные атрибуты вниз к корневому элементу шаблона компонента. Например, представьте, что мы хотим отобразить компонент alert следующим образом:

<x-alert type="error" :message="$message" class="mt-4"/>

Все атрибуты, которые не являются частью конструктора компонента, автоматически добавляются в "мешок атрибутов" компонента. Этот мешок атрибутов автоматически становится доступным компоненту через переменную $attributes. Все атрибуты можно отобразить внутри компонента, выведя эту переменную:

<div {{ $attributes }}>
<!-- Component content -->
</div>

Внимание Использование директив, таких как @env внутри тегов компонента в настоящее время не поддерживается. Например, <x-alert :live=\"@env('production')\"/> не будет скомпилировано.

Атрибуты по Умолчанию / Объединение

Иногда вам может потребоваться указать значения по умолчанию для атрибутов или объединить дополнительные значения в некоторые атрибуты компонента. Для этого можно использовать метод merge мешка атрибутов. Этот метод особенно полезен для определения набора значений CSS-классов по умолчанию, которые всегда должны применяться к компоненту:

<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
{{ $message }}
</div>

Если мы предположим, что этот компонент используется следующим образом:

<x-alert type="error" :message="$message" class="mb-4"/>

Финальный HTML компонента будет выглядеть следующим образом:

<div class="alert alert-error mb-4">
<!-- Содержимое переменной $message -->
</div>

Условное Объединение Классов

Иногда вы можете захотеть объединить классы, если заданное условие истинно. Это можно сделать с помощью метода class, который принимает массив классов, где ключ массива содержит класс или классы, которые вы хотите добавить, а значение - логическое выражение. Если элемент массива имеет числовой ключ, его всегда будут включать в отображенный список классов:

<div {{ $attributes->class(['p-4', 'bg-red' => $hasError]) }}>
{{ $message }}
</div>

Если вам нужно объединить другие атрибуты в ваш компонент, вы можете цеплять метод merge на метод class:

<button {{ $attributes->class(['p-4'])->merge(['type' => 'button']) }}>
{{ $slot }}
</button>

Примечание Если вам нужно условно компилировать классы на других HTML-элементах, которые не должны получать объединенные атрибуты, вы можете использовать директиву @class.

Объединение Атрибутов, Не Являющихся Классами

При объединении атрибутов, не являющихся атрибутами class, предоставленные методу merge значения будут считаться значениями атрибута "по умолчанию". Однако, в отличие от атрибута class, эти атрибуты не будут сливаться с внедренными значениями атрибута. Вместо этого они будут перезаписаны. Например, реализация компонента button может выглядеть следующим образом:

<button {{ $attributes->merge(['type' => 'button']) }}>
{{ $slot }}
</button>

Чтобы отобразить компонент кнопки с пользовательским type, его можно указать при использовании компонента. Если тип не указан, будет использован тип button:

<x-button type="submit">
Submit
</x-button>

В данном примере отображаемый HTML компонента button будет следующим:

<button type="submit">
Submit
</button>

Если вы хотите, чтобы атрибут, отличный от class, объединял свое значение по умолчанию и внедренные значения, вы можете использовать метод prepends. В этом примере атрибут data-controller всегда начинается с profile-controller, а любые дополнительные внедренные значения data-controller будут помещены после этого значения по умолчанию:

<div {{ $attributes->merge(['data-controller' => $attributes->prepends('profile-controller')]) }}>
{{ $slot }}
</div>

Извлечение и фильтрация атрибутов

Вы можете фильтровать атрибуты с помощью метода filter. Этот метод принимает замыкание, которое должно возвращать true, если вы хотите сохранить атрибут в мешке атрибутов:

{{ $attributes->filter(fn (string $value, string $key) => $key == 'foo') }}

Для удобства вы можете использовать метод whereStartsWith, чтобы получить все атрибуты, ключи которых начинаются с заданной строки:

{{ $attributes->whereStartsWith('wire:model') }}

Напротив, метод whereDoesntStartWith можно использовать для исключения всех атрибутов, ключи которых начинаются с заданной строки:

{{ $attributes->whereDoesntStartWith('wire:model') }}

Используя метод first, вы можете отрендерить первый атрибут в данном мешке атрибутов:

{{ $attributes->whereStartsWith('wire:model')->first() }}

Если вы хотите проверить, присутствует ли атрибут на компоненте, вы можете использовать метод has. Этот метод принимает имя атрибута в качестве единственного аргумента и возвращает булево значение, указывающее, присутствует ли атрибут:

@if ($attributes->has('class'))
<div>Присутствует атрибут class</div>
@endif

Если методу has передан массив, он определит, присутствуют ли все указанные атрибуты на компоненте:

@if ($attributes->has(['name', 'class']))
<div>Все атрибуты присутствуют</div>
@endif

Метод hasAny можно использовать для определения, присутствует ли хотя бы один из указанных атрибутов на компоненте:

@if ($attributes->hasAny(['href', ':href', 'v-bind:href']))
<div>Один из атрибутов присутствует</div>
@endif

Вы можете получить значение конкретного атрибута, используя метод get:

{{ $attributes->get('class') }}

Зарезервированные Ключевые Слова

По умолчанию некоторые ключевые слова зарезервированы для внутреннего использования Blade для рендеринга компонентов. Следующие ключевые слова не могут быть определены как общедоступные свойства или имена методов ваших компонентов:

  • data
  • render
  • resolveView
  • shouldRender
  • view
  • withAttributes
  • withName

Слоты

Часто вам нужно будет передать дополнительное содержимое в ваш компонент через "слоты". Слоты компонента рендерятся путем вывода переменной $slot. Чтобы изучить эту концепцию, давайте представим, что у компонента alert есть следующая разметка:

<!-- /resources/views/components/alert.blade.php -->
 
<div class="alert alert-danger">
{{ $slot }}
</div>

Мы можем передать содержимое в slot, внедрив содержимое в компонент:

<x-alert>
<strong>Упс!</strong> Что-то пошло не так!
</x-alert>

Иногда компоненту может потребоваться отрендерить несколько разных слотов в разных местах компонента. Давайте модифицируем наш компонент alert, чтобы позволить внедрение слота "title":

<!-- /resources/views/components/alert.blade.php -->
 
<span class="alert-title">{{ $title }}</span>
 
<div class="alert alert-danger">
{{ $slot }}
</div>

Вы можете определить содержимое именованного слота, используя тег x-slot. Любое содержимое, не находящееся в явном теге x-slot, будет передано компоненту в переменной $slot:

<x-alert>
<x-slot:title>
Server Error
</x-slot>
 
<strong>Упс!</strong> Что-то пошло не так!
</x-alert>

Scoped Slots

Если вы использовали JavaScript-фреймворк, такой как Vue, вы, возможно, знакомы со "scoped slots", которые позволяют вам получить доступ к данным или методам компонента в вашем слоте. Вы можете добиться похожего поведения в Laravel, определив публичные методы или свойства на вашем компоненте и обращаясь к компоненту в вашем слоте через переменную $component. В этом примере мы предполагаем, что компонент x-alert имеет публичный метод formatAlert, определенный в классе компонента:

<x-alert>
<x-slot:title>
{{ $component->formatAlert('Ошибка сервера') }}
</x-slot>
 
<strong>Упс!</strong> Что-то пошло не так!
</x-alert>

Атрибуты Слотов

Как и компоненты Blade, вы можете назначить дополнительные атрибуты слотам, такие как имена CSS-классов:

<x-card class="shadow-sm">
<x-slot:heading class="font-bold">
Заголовок
</x-slot>
 
Контент
 
<x-slot:footer class="text-sm">
Футер
</x-slot>
</x-card>

Чтобы взаимодействовать с атрибутами слота, вы можете обратиться к свойству attributes переменной слота. Для получения дополнительной информации о взаимодействии с атрибутами, пожалуйста, ознакомьтесь с документацией по атрибутам компонентов:

@props([
'heading',
'footer',
])
 
<div {{ $attributes->class(['border']) }}>
<h1 {{ $heading->attributes->class(['text-lg']) }}>
{{ $heading }}
</h1>
 
{{ $slot }}
 
<footer {{ $footer->attributes->class(['text-gray-700']) }}>
{{ $footer }}
</footer>
</div>

Встраиваемые Представления Компонентов

Для очень маленьких компонентов управление классом компонента и шаблоном представления компонента может показаться обременительным. Поэтому вы можете непосредственно из метода render вернуть разметку компонента:

/**
* Получить представление / содержимое, которое представляет компонент.
*/
public function render(): string
{
return <<<'blade'
<div class="alert alert-danger">
{{ $slot }}
</div>
blade;
}

Генерация Встраиваемых Компонентов Представления

Чтобы создать компонент, который рендерит встроенное представление, вы можете использовать опцию inline при выполнении команды make:component:

php artisan make:component Alert --inline

Динамические Компоненты

Иногда вам может потребоваться отрендерить компонент, но не знать, какой компонент должен быть отрендерен до времени выполнения. В этой ситуации вы можете использовать встроенный в Laravel компонент dynamic-component для рендеринга компонента на основе значения или переменной во время выполнения:

// $componentName = "secondary-button";
 
<x-dynamic-component :component="$componentName" class="mt-4" />

Ручная Регистрация Компонентов

Внимание Документация по ручной регистрации компонентов в основном применима к тем, кто пишет пакеты Laravel, включающие компоненты представлений. Если вы не пишете пакет, эта часть документации по компонентам может быть неактуальной для вас.

При написании компонентов для вашего собственного приложения, компоненты автоматически обнаруживаются в директориях app/View/Components и resources/views/components.

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

use Illuminate\Support\Facades\Blade;
use VendorPackage\View\Components\AlertComponent;
 
/**
* Инициализация сервисов вашего пакета.
*/
public function boot(): void
{
Blade::component('package-alert', AlertComponent::class);
}

После регистрации вашего компонента, он может быть отрендерен с использованием его псевдонима тега:

<x-package-alert/>

Автозагрузка Компонентов Пакета

Как альтернатива, вы можете использовать метод componentNamespace для автозагрузки классов компонентов по соглашению. Например, пакет Nightshade может иметь компоненты Calendar и ColorPicker, находящиеся в пространстве имен Package\Views\Components:

use Illuminate\Support\Facades\Blade;
 
/**
* Инициализация сервисов вашего пакета.
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}

Это позволит использовать компоненты пакета с использованием синтаксиса package-name:::

<x-nightshade::calendar />
<x-nightshade::color-picker />

Blade автоматически определяет класс, связанный с этим компонентом, используя стиль PascalCase для имени компонента. Поддерживаются также поддиректории с использованием "точечной" нотации.

Анонимные Компоненты

Похоже на встроенные компоненты, анонимные компоненты предоставляют механизм управления компонентом через один файл. Однако анонимные компоненты используют один файл представления и не имеют связанного класса. Чтобы определить анонимный компонент, вам нужно только разместить шаблон Blade в вашем каталоге resources/views/components. Например, предполагая, что вы определили компонент в resources/views/components/alert.blade.php, вы можете просто отрендерить его так:

<x-alert/>

Вы можете использовать символ . для указания, если компонент расположен глубже в каталоге components. Например, предполагая, что компонент определен в resources/views/components/inputs/button.blade.php, вы можете отрендерить его так:

<x-inputs.button/>

Анонимные Индексные Компоненты

Иногда, когда компонент состоит из многих шаблонов Blade, вы можете захотеть сгруппировать данные шаблоны компонента в одном каталоге. Например, представьте компонент "аккордеон" со следующей структурой каталога:

/resources/views/components/accordion.blade.php
/resources/views/components/accordion/item.blade.php

Эта структура каталога позволяет вам отрендерить компонент аккордеона и его элемент так:

<x-accordion>
<x-accordion.item>
...
</x-accordion.item>
</x-accordion>

Однако, чтобы отрендерить компонент аккордеона через x-accordion, мы были вынуждены поместить шаблон компонента "индекс" аккордеона в каталог resources/views/components, вместо того чтобы разместить его в каталоге accordion вместе с другими связанными с аккордеоном шаблонами.

К счастью, Blade позволяет разместить файл index.blade.php в каталоге шаблонов компонента. Когда файл шаблона index.blade.php существует для компонента, он будет отрендерен как "корневой" узел компонента. Таким образом, мы можем продолжить использовать тот же синтаксис Blade, что и в приведенном выше примере; однако, мы скорректируем нашу структуру каталога следующим образом:

/resources/views/components/accordion/index.blade.php
/resources/views/components/accordion/item.blade.php

Свойства Данных / Атрибуты

Поскольку анонимные компоненты не имеют связанного класса, вы можете задаться вопросом, как вы можете различать, какие данные должны быть переданы компоненту в виде переменных и какие атрибуты должны быть помещены в мешок атрибутов компонента.

Вы можете указать, какие атрибуты должны рассматриваться как переменные данных, используя директиву @props в верхней части шаблона Blade компонента. Все остальные атрибуты компонента будут доступны через мешок атрибутов компонента. Если вы хотите дать переменной данных значение по умолчанию, вы можете указать имя переменной в качестве ключа массива и значение по умолчанию в качестве значения массива:

<!-- /resources/views/components/alert.blade.php -->
 
@props(['type' => 'info', 'message'])
 
<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
{{ $message }}
</div>

Учитывая определение компонента выше, мы можем отрендерить компонент так:

<x-alert type="error" :message="$message" class="mb-4"/>

Доступ к Данным Родителя

Иногда вам может потребоваться получить доступ к данным из родительского компонента внутри дочернего компонента. В этих случаях вы можете использовать директиву @aware. Например, представьте, что мы создаем сложный компонент меню, состоящий из родительского <x-menu> и дочернего <x-menu.item>:

<x-menu color="purple">
<x-menu.item>...</x-menu.item>
<x-menu.item>...</x-menu.item>
</x-menu>

Компонент <x-menu> может иметь реализацию, наподобие следующей:

<!-- /resources/views/components/menu/index.blade.php -->
 
@props(['color' => 'gray'])
 
<ul {{ $attributes->merge(['class' => 'bg-'.$color.'-200']) }}>
{{ $slot }}
</ul>

Поскольку свойство color было передано только в родительский компонент (<x-menu>), оно не будет доступно внутри <x-menu.item>. Однако, если мы используем директиву @aware, мы можем сделать его доступным также внутри <x-menu.item>:

<!-- /resources/views/components/menu/item.blade.php -->
 
@aware(['color' => 'gray'])
 
<li {{ $attributes->merge(['class' => 'text-'.$color.'-800']) }}>
{{ $slot }}
</li>

Внимание Директива @aware не может получить доступ к данным родительского компонента, которые не были явно переданы родительскому компоненту через атрибуты HTML. Значения @props, установленные по умолчанию и не явно переданные родительскому компоненту, не могут быть доступны директивой @aware.

Пути Анонимных Компонентов

Как уже обсуждалось, анонимные компоненты обычно определяются, помещая шаблон Blade в ваш каталог resources/views/components. Однако иногда вы можете захотеть зарегистрировать другие пути для анонимных компонентов в Laravel в дополнение к пути по умолчанию.

Метод anonymousComponentPath принимает "путь" к местоположению анонимного компонента в качестве первого аргумента и необязательное "пространство имен", под которым следует размещать компоненты, в качестве второго аргумента. Обычно этот метод следует вызывать из метода boot одного из поставщиков услуг вашего приложения:

/**
* Инициализация любых сервисов приложения.
*/
public function boot(): void
{
Blade::anonymousComponentPath(__DIR__.'/../components');
}

Когда пути компонентов регистрируются без указания префикса, как в приведенном выше примере, их также можно рендерить в ваших Blade-компонентах без соответствующего префикса. Например, если существует компонент panel.blade.php в зарегистрированном пути, его можно рендерить так:

<x-panel />

Префикс "пространств имен" можно указать вторым аргументом метода anonymousComponentPath:

Blade::anonymousComponentPath(__DIR__.'/../components', 'dashboard');

Когда предоставляется префикс, компоненты внутри этого "пространства имен" можно рендерить, добавляя к имени компонента префикс пространства имен при рендеринге компонента:

<x-dashboard::panel />

Создание Макетов

Макеты с Использованием Компонентов

Большинство веб-приложений сохраняют одинаковый общий макет на различных страницах. Было бы чрезвычайно неудобно и трудно поддерживать наше приложение, если бы нам пришлось повторять весь HTML-макет в каждом представлении, которое мы создаем. К счастью, удобно определить этот макет как единый компонент Blade, а затем использовать его в нашем приложении.

Определение Компонента Макета

Например, представьте, что мы создаем приложение для списка задач. Мы могли бы определить компонент layout, который выглядит следующим образом:

<!-- resources/views/components/layout.blade.php -->
 
<html>
<head>
<title>{{ $title ?? 'Менеджер задач' }}</title>
</head>
<body>
<h1>Задача</h1>
<hr/>
{{ $slot }}
</body>
</html>

Применение Компонента Макета

После того как компонент layout был определен, мы можем создать Blade-представление, использующее этот компонент. В этом примере мы определим простое представление, отображающее наш список задач:

<!-- resources/views/tasks.blade.php -->
 
<x-layout>
@foreach ($tasks as $task)
{{ $task }}
@endforeach
</x-layout>

Помните, что контент, внедренный в компонент, будет предоставлен переменной $slot по умолчанию внутри нашего компонента layout. Как вы могли заметить, наш layout также уважает слот $title, если он предоставлен; в противном случае отображается заголовок по умолчанию. Мы можем внедрить пользовательский заголовок из нашего представления списка задач, используя стандартный синтаксис слота, обсуждаемый в документации по компонентам:

<!-- resources/views/tasks.blade.php -->
 
<x-layout>
<x-slot:title>
Пользовательский заголовок
</x-slot>
 
@foreach ($tasks as $task)
{{ $task }}
@endforeach
</x-layout>

Теперь, когда мы определили наши представления макета и списка задач, нам просто нужно вернуть представление task из маршрута:

use App\Models\Task;
 
Route::get('/tasks', function () {
return view('tasks', ['tasks' => Task::all()]);
});

Макеты с Использованием Наследования Шаблонов

Определение Макета

Макеты также могут быть созданы с использованием "наследования шаблонов". Это был основной способ построения приложений до введения компонентов.

Для начала давайте рассмотрим простой пример. Сначала давайте рассмотрим макет страницы. Поскольку большинство веб-приложений поддерживают одинаковый общий макет на различных страницах, удобно определить этот макет как единое Blade-представление:

<!-- resources/views/layouts/app.blade.php -->
 
<html>
<head>
<title>Имя приложения - @yield('title')</title>
</head>
<body>
@section('sidebar')
Это главное боковое меню.
@show
 
<div class="container">
@yield('content')
</div>
</body>
</html>

Как видите, этот файл содержит типичную разметку HTML. Однако обратите внимание на директивы @section и @yield. Директива @section, как следует из названия, определяет раздел контента, а директива @yield используется для отображения содержимого данного раздела.

Теперь, когда мы определили макет для нашего приложения, давайте определим дочернюю страницу, которая наследует этот макет.

Расширение Макета

При определении дочернего представления используйте директиву Blade @extends, чтобы указать, какой макет должно "наследовать" дочернее представление. Представления, которые расширяют макет Blade, могут внедрять контент в разделы макета с использованием директив @section. Помните, как видно в приведенном выше примере, содержимое этих разделов будет отображаться в макете с использованием @yield:

<!-- resources/views/child.blade.php -->
 
@extends('layouts.app')
 
@section('title', 'Page Title')
 
@section('sidebar')
@parent
 
<p>Это добавится ко главному боковому меню.</p>
@endsection
 
@section('content')
<p>Это содержимое моего тела.</p>
@endsection

В этом примере раздел sidebar использует директиву @parent для добавления (а не перезаписи) контента в боковую панель макета. Директива @parent будет заменена содержимым макета при рендеринге представления.

Примечание В отличие от предыдущего примера, этот раздел sidebar заканчивается на @endsection, а не на @show. Директива @endsection только определяет секцию, в то время как @show определяет и немедленно выводит секцию.

Директива @yield также принимает вторым параметром значение по умолчанию. Это значение будет отображаться, если раздел, который следует выдавать, не определен:

@yield('content', 'Содержимое по умолчанию')

Формы

Поле CSRF

Всякий раз, когда вы создаете HTML-форму в своем приложении, вы должны включить скрытое поле токена CSRF в форму, чтобы промежуточное ПО защиты CSRF могло проверить запрос. Вы можете использовать директиву Blade @csrf для создания поля токена:

<form method="POST" action="/profile">
@csrf
 
...
</form>

Поле Метода

Поскольку HTML-формы не могут отправлять запросы PUT, PATCH или DELETE, вам придется добавить скрытое поле _method для подделки этих HTTP-глаголов. Директива Blade @method может создать это поле для вас:

<form action="/foo/bar" method="POST">
@method('PUT')
 
...
</form>

Ошибки Валидации

Директива @error можно использовать для быстрой проверки наличия сообщений об ошибках валидации для заданного атрибута. В пределах директивы @error вы можете вывести переменную $message, чтобы отобразить сообщение об ошибке:

<!-- /resources/views/post/create.blade.php -->
 
<label for="title">Заголовок поста</label>
 
<input id="title"
type="text"
class="@error('title') is-invalid @enderror">
 
@error('title')
<div class="alert alert-danger">{{ $message }}</div>
@enderror

Поскольку директива @error компилируется в оператор "if", вы можете использовать директиву @else для отображения содержимого, когда нет ошибки для атрибута:

<!-- /resources/views/auth.blade.php -->
 
<label for="email">Адрес электронной почты</label>
 
<input id="email"
type="email"
class="@error('email') is-invalid @else is-valid @enderror">

Вы можете передать название конкретной корзины ошибок вторым параметром директиве @error, чтобы получить сообщения об ошибках валидации на страницах, содержащих несколько форм:

<!-- /resources/views/auth.blade.php -->
 
<label for="email">Адрес электронной почты</label>
 
<input id="email"
type="email"
class="@error('email', 'login') is-invalid @enderror">
 
@error('email', 'login')
<div class="alert alert-danger">{{ $message }}</div>
@enderror

Стеки

Blade позволяет добавлять элементы в именованные стеки, которые можно отобразить в другом месте в другом представлении или макете. Это может быть особенно полезно для указания любых библиотек JavaScript, необходимых вашим дочерним представлениям:

@push('scripts')
<script src="/example.js"></script>
@endpush

Если вы хотите @push контент, если заданное булево выражение вычисляется в true, вы можете использовать директиву @pushIf:

@pushIf($shouldPush, 'scripts')
<script src="/example.js"></script>
@endPushIf

Вы можете добавлять элементы в стек столько раз, сколько необходимо. Чтобы отобразить полное содержимое стека, передайте имя стека директиве @stack:

<head>
<!-- Содержимое заголовка -->
 
@stack('scripts')
</head>

Если вы хотите добавить контент в начало стека, вы должны использовать директиву @prepend:

@push('scripts')
Это будет вторым...
@endpush
 
// Это будет первым...
 
@prepend('scripts')
Это будет первым...
@endprepend

Инъекция Сервисов

Директива @inject может использоваться для извлечения сервиса из контейнера служб Laravel. Первый аргумент, передаваемый в @inject, - это имя переменной, в которую будет помещен сервис, в то время как второй аргумент - это имя класса или интерфейса службы, которую вы хотите разрешить:

@inject('metrics', 'App\Services\MetricsService')
 
<div>
Ежемесячный доход:: {{ $metrics->monthlyRevenue() }}.
</div>

Рендеринг Встроенных Шаблонов Blade

Иногда вам может потребоваться преобразовать необработанную строку шаблона Blade в допустимый HTML. Вы можете сделать это, используя метод render предоставляемый фасадом Blade. Метод render принимает строку шаблона Blade и необязательный массив данных для предоставления шаблону:

use Illuminate\Support\Facades\Blade;
 
return Blade::render('Привет, {{ $name }}', ['name' => 'Julian Bashir']);

Laravel рендерит встроенные шаблоны Blade, записывая их в каталог storage/framework/views. Если вы хотите, чтобы Laravel удалил эти временные файлы после рендеринга шаблона Blade, вы можете предоставить аргумент deleteCachedView для метода:

return Blade::render(
'Привет, {{ $name }}',
['name' => 'Julian Bashir'],
deleteCachedView: true
);

Рендеринг Фрагментов Blade

При использовании фронтенд-фреймворков, таких как Turbo и htmx, вам иногда может потребоваться возвращать только часть шаблона Blade в вашем HTTP-ответе. Blade "фрагменты" позволяют вам сделать именно это. Для начала поместите часть вашего шаблона Blade в директивы @fragment и @endfragment:

@fragment('user-list')
<ul>
@foreach ($users as $user)
<li>{{ $user->name }}</li>
@endforeach
</ul>
@endfragment

Затем, при рендеринге представления, использующего этот шаблон, вы можете вызвать метод fragment для указания, что в исходящем HTTP-ответе должен быть включен только указанный фрагмент:

return view('dashboard', ['users' => $users])->fragment('user-list');

Метод fragmentIf позволяет условно возвращать фрагмент представления в зависимости от заданного условия. В противном случае будет возвращено целое представление:

return view('dashboard', ['users' => $users])
->fragmentIf($request->hasHeader('HX-Request'), 'user-list');

Методы fragments и fragmentIf позволяют вам возвращать несколько фрагментов представления в ответе. Фрагменты будут объединены вместе:

view('dashboard', ['users' => $users])
->fragments(['user-list', 'comment-list']);
 
view('dashboard', ['users' => $users])
->fragmentsIf(
$request->hasHeader('HX-Request'),
['user-list', 'comment-list']
);

Расширение Blade

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

В следующем примере создается директива @datetime($var), которая форматирует заданную переменную $var, которая должна быть экземпляром DateTime:

<?php
 
namespace App\Providers;
 
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
 
class AppServiceProvider extends ServiceProvider
{
/**
* Регистрация любых сервисов приложения.
*/
public function register(): void
{
// ...
}
 
/**
* Инициализация любых сервисов приложения.
*/
public function boot(): void
{
Blade::directive('datetime', function (string $expression) {
return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
});
}
}

Как видите, мы будем использовать метод format для любого выражения, переданного в директиву. Таким образом, в этом примере окончательный PHP-код, сгенерированный этой директивой, будет следующим:

<?php echo ($var)->format('m/d/Y H:i'); ?>

Внимание После обновления логики директивы Blade вам нужно удалить все кешированные представления Blade. Кешированные представления Blade можно удалить с помощью команды Artisan view:clear.

Пользовательские Обработчики Echo

Если вы пытаетесь «вывести» объект с использованием Blade, будет вызван метод __toString объекта. Метод __toString является одним из встроенных «магических методов» PHP. Однако иногда у вас может не быть контроля над методом __toString данного класса, например, когда класс, с которым вы взаимодействуете, принадлежит сторонней библиотеке.

В таких случаях Blade позволяет зарегистрировать собственный обработчик вывода для этого конкретного типа объекта. Для этого вы должны вызвать метод stringable Blade. Метод stringable принимает замыкание. Это замыкание должно указывать тип объекта, за который оно отвечает. Обычно метод stringable следует вызывать в методе boot класса AppServiceProvider вашего приложения:

use Illuminate\Support\Facades\Blade;
use Money\Money;
 
/**
* Инициализация любых сервисов приложения.
*/
public function boot(): void
{
Blade::stringable(function (Money $money) {
return $money->formatTo('en_GB');
});
}

Программирование собственной директивы иногда бывает более сложным, чем необходимо при определении простых условных операторов. По этой причине Blade предоставляет метод Blade::if, который позволяет быстро определять собственные условные директивы с использованием замыканий. Например, давайте определим собственное условие, которое проверяет настроенный по умолчанию «диск» для приложения. Мы можем сделать это в методе boot нашего AppServiceProvider:

Cost: {{ $money }}

Пользовательские Условные Выражения

Иногда программирование собственной директивы бывает более сложным, чем необходимо, при определении простых условных операторов. По этой причине Blade предоставляет метод Blade::if, который позволяет быстро определить собственные условные директивы с использованием замыканий. Например, давайте определим собственное условное выражение, которое проверяет настроенный "диск" по умолчанию для приложения. Мы можем сделать это в методе boot нашего AppServiceProvider:

use Illuminate\Support\Facades\Blade;
 
/**
* Инициализация любых сервисов приложения.
*/
public function boot(): void
{
Blade::if('disk', function (string $value) {
return config('filesystems.default') === $value;
});
}

После того как собственное условие будет определено, вы можете использовать его в своих шаблонах:

@disk('local')
<!-- Приложение использует локальный диск... -->
@elsedisk('s3')
<!-- Приложение использует диск s3... -->
@else
<!-- Приложение использует какой-то другой диск... -->
@enddisk
 
@unlessdisk('local')
<!-- Приложение не использует локальный диск... -->
@enddisk