Unetway

Laravel - Blade Templates

Вступление

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

 

Наследование шаблонов

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

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

<!-- Stored in resources/views/layouts/app.blade.php -->

<html>
    <head>
        <title>App Name - @yield('title')</title>
    </head>
    <body>
        @section('sidebar')
            This is the master sidebar.
        @show

        <div class="container">
            @yield('content')
        </div>
    </body>
</html>

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

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

 

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

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

<!-- Stored in resources/views/child.blade.php -->

@extends('layouts.app')

@section('title', 'Page Title')

@section('sidebar')
    @parent

    <p>This is appended to the master sidebar.</p>
@endsection

@section('content')
    <p>This is my body content.</p>
@endsection

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

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

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

@yield('content', View::make('view.name'))

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

Route::get('blade', function () {
    return view('child');
});

 

Компоненты и слоты

Компоненты и слоты обеспечивают аналогичные преимущества для разделов и макетов; однако, некоторые могут найти ментальную модель компонентов и слотов более легкой для понимания. Во-первых, давайте представим повторно используемый компонент «оповещения», который мы хотели бы использовать в нашем приложении:

<!-- /resources/views/alert.blade.php -->

<div class="alert alert-danger">
    {{ $slot }}
</div>

Переменная будет содержать контент мы хотим ввести в компонент. Теперь, чтобы построить этот компонент, мы можем использовать директиву Blade:{{ $slot }}@component

@component('alert')
    <strong>Whoops!</strong> Something went wrong!
@endcomponent

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

<!-- /resources/views/alert.blade.php -->

<div class="alert alert-danger">
    <div class="alert-title">{{ $title }}</div>

    {{ $slot }}
</div>

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

@component('alert')
    @slot('title')
        Forbidden
    @endslot

    You are not allowed to access this resource!
@endcomponent

Передача дополнительных данных в компоненты

Иногда вам может потребоваться передать дополнительные данные компоненту. По этой причине вы можете передать массив данных в качестве второго аргумента @componentдирективе. Все данные будут доступны для шаблона компонента в виде переменных:

@component('alert', ['foo' => 'bar'])
    ...
@endcomponent

Алиасинг компонентов

Если ваши компоненты Blade хранятся в подкаталоге, вы можете использовать псевдонимы для более легкого доступа. Например, представьте компонент Blade, который хранится в . Вы можете использовать метод для псевдонима компонента из в . Как правило, это должно быть сделано в методе вашего :resources/views/components/alert.blade.phpcomponentcomponents.alertalertbootAppServiceProvider

use Illuminate\Support\Facades\Blade;

Blade::component('components.alert', 'alert');

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

@alert(['type' => 'danger'])
    You are not allowed to access this resource!
@endalert

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

@alert
    You are not allowed to access this resource!
@endalert

 

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

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

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

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

Hello, {{ $name }}.

Операторы Blade автоматически отправляются через функцию PHP, чтобы предотвратить атаки XSS.{{ }}htmlspecialchars

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

The current UNIX timestamp is {{ time() }}.

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

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

Hello, {!! $name !!}.

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

Рендеринг JSON

Иногда вы можете передать массив вашему представлению с намерением отобразить его как JSON, чтобы инициализировать переменную JavaScript. Например:

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

Однако вместо ручного вызова json_encodeвы можете использовать @jsonдирективу Blade. @jsonДиректива принимает те же аргументы, что и в PHP json_encodeфункции:

<script>
    var app = @json($array);

    var app = @json($array, JSON_PRETTY_PRINT);
</script>

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

@jsonДиректива также полезна для высева компонентов Vue или атрибутов:data-*

<example-component :some-prop='@json($array)'></example-component>

Использование @jsonатрибутов in требует, чтобы он был заключен в одинарные кавычки.

HTML Entity Encoding

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

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Blade::withoutDoubleEncoding();
    }
}

 

Blade & JavaScript Framework

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

<h1>Laravel</h1>

Hello, @{{ name }}.

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

@verbatimДиректива

Если вы отображаете переменные JavaScript в большой части вашего шаблона, вы можете заключить HTML-код в @verbatimдирективу, чтобы вам не приходилось ставить перед каждым оператором Blade echo префикс @:

@verbatim
    <div class="container">
        Hello, {{ name }}.
    </div>
@endverbatim

 

Управляющие структуры

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

 

IF

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

@if (count($records) === 1)
    I have one record!
@elseif (count($records) > 1)
    I have multiple records!
@else
    I don't have any records!
@endif

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

@unless (Auth::check())
    You are not signed in.
@endunless

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

@isset($records)
    // $records is defined and is not null...
@endisset

@empty($records)
    // $records is "empty"...
@endempty

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

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

@auth
    // The user is authenticated...
@endauth

@guest
    // The user is not authenticated...
@endguest

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

@auth('admin')
    // The user is authenticated...
@endauth

@guest('admin')
    // The user is not authenticated...
@endguest

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

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

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

    <div class="clearfix"></div>
@endif

 

Переключение операторов

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

@switch($i)
    @case(1)
        First case...
        @break

    @case(2)
        Second case...
        @break

    @default
        Default case...
@endswitch

 

Loops

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

@for ($i = 0; $i < 10; $i++)
    The current value is {{ $i }}
@endfor

@foreach ($users as $user)
    <p>This is user {{ $user->id }}</p>
@endforeach

@forelse ($users as $user)
    <li>{{ $user->name }}</li>
@empty
    <p>No users</p>
@endforelse

@while (true)
    <p>I'm looping forever.</p>
@endwhile

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

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

@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

 

Переменная Loop

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

@foreach ($users as $user)
    @if ($loop->first)
        This is the first iteration.
    @endif

    @if ($loop->last)
        This is the last iteration.
    @endif

    <p>This is user {{ $user->id }}</p>
@endforeach

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

@foreach ($users as $user)
    @foreach ($user->posts as $post)
        @if ($loop->parent->first)
            This is first iteration of the parent loop.
        @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 Находясь во вложенном цикле, родительская переменная цикла.

 

Комментарии

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

{{-- This comment will not be present in the rendered HTML --}}

 

PHP

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

@php
    //
@endphp

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

 

Формы

CSRF Field

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

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

    ...
</form>

 

Поле метода

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

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

    ...
</form>

 

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

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

<!-- /resources/views/post/create.blade.php -->

<label for="title">Post Title</label>

<input id="title" type="text" class="@error('title') is-invalid @enderror">

@error('title')
    <div class="alert alert-danger">{{ $message }}</div>
@enderror

 

Включая подвиды

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

<div>
    @include('shared.errors')

    <form>
        <!-- Form Contents -->
    </form>
</div>

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

@include('view.name', ['some' => 'data'])

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

@includeIf('view.name', ['some' => 'data'])

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

@includeWhen($boolean, 'view.name', ['some' => 'data'])

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

@includeFirst(['custom.admin', 'admin'], ['some' => 'data'])

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

Псевдоним включает

Если ваши Blade-файлы хранятся в подкаталоге, вы можете создать псевдонимы для более легкого доступа. Например, представьте, что Blade- содержимое хранится со следующим содержимым:resources/views/includes/input.blade.php

<input type="{{ $type ?? 'text' }}">

Вы можете использовать includeметод для псевдонима включения из в . Как правило, это должно быть сделано в методе вашего :includes.inputinputbootAppServiceProvider

use Illuminate\Support\Facades\Blade;

Blade::include('includes.input', 'input');

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

@input(['type' => 'email'])

 

Визуализация представлений для коллекций

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

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

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

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

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

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

 

Стеки

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

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

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

<head>
    <!-- Head Contents -->

    @stack('scripts')
</head>

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

@push('scripts')
    This will be second...
@endpush

// Later...

@prepend('scripts')
    This will be first...
@endprepend

 

Сервисная инъекция

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

@inject('metrics', 'App\Services\MetricsService')

<div>
    Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
</div>

 

Удлиняющий Blade

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

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

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Blade::directive('datetime', function ($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

 

Пользовательские заявления If

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

use Illuminate\Support\Facades\Blade;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Blade::if('env', function ($environment) {
        return app()->environment($environment);
    });
}

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

@env('local')
    // The application is in the local environment...
@elseenv('testing')
    // The application is in the testing environment...
@else
    // The application is not in the local or testing environment...
@endenv