Blade usage инструкция на русском

Blade это мощный движок для компиляции шаблонов, который встроен в Laravel. В прошлой статье о видах мы лишь упомянули его, теперь же стоит разобраться подробно с его возможностями. Хотя Blade не запрещает использование обычных php-конструкций (<?php ... ?>) в шаблонах, в этом едва ли возникнет нужда, так как шаблонизатор делает работу с видами гораздо более приятной. Файлы видов, которые подлежат обработке шаблонизатором, должны иметь расширение .blade.php.

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

Visual Studio Code расширение для работы с Blade

Немного оффтопа для начала. Если вы используете редактор Visual Studio Code, то можно установить расширение Laravel Blade Snippets, которое добавит подсветку синтаксиса шаблонизатора и сделает работу с blade-файлами гораздо более удобной.

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

Вывод данных

Шаблонизатор Blade предлагает выводить данные в двойных фигурных скобках (похожим образом данные выводятся в JS-фреймворке Vue и многих других). Вот пример базового вывода:

Hello, {{ $name }}.

Всё, что распечатывается в Blade-шаблонах внутри {{ }} автоматически проходит обработку через php- функцию htmlspecialchars что позволяет избежать XSS-атак.

Двойные фигурные скобки обрабатывают не только готовые переменные. На самом деле вы можете написать внутри вызов какого-либо метода или выражение.

Кол-во секунд с 1 января 1970: {{ time() }}.

Html-сущности

По умолчанию Blade применяет двойное кодирование к html-сущностям. Такое поведение можно отключить, вызвав метод withoutDoubleEncoding у фасада Blade внутри сервис-провайдера.

// внутри класса AppServiceProvider
public function boot() {
  Blade::withoutDoubleEncoding();
}

Чтобы вывести необработанные данные можно использовать синтаксис {!! $data !!}. То есть одна фигурная скобка и 2 восклицательных знака по бокам, без пробелов. В этом случае данные не будут пропущены через функцию htmlspecialchars.

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

Комментарии в Blade

Вы наверняка знаете, как делать комментарии в html и php. Blade же предлагает свой собственный синтаксис для комментариев — {{-- comment --}}:

{{-- Это комментарий и он не попадет в итоговый HTML --}}

Важно не допускать пробелов между дефисами и фигурными скобками, иначе синтаксис станет невалидным. Заметьте, что в отличие от html комментариев, которые попадают в разметку и просто там не отображаются, разметка закомментированная blade-комментарием не попадет в финальный код в принципе.

Также помните, что html комментарий не влияет на Blade. Если вы закомментируете что-то через <!-- --> то Blade продолжит выполнят свои расчеты в этом куске кода, если там присутствует динамический шаблон.

Символ @ и экранирование

Другое применение символа @ это экранирование директив самого Blade. К примеру, вам нужно вывести в шаблоне @if, но чтобы это было обработано как строка, а не как директива шаблонизатора. Дополнительный @ как раз проведет экранирование.

@@if()

Это похоже на то, как в регулярных выражениях вы экранируете слэш и прочие спецсимволы.

Blade и JS-фреймворки

В случае если php-шаблонизатор используется вместе с шаблонизатором какого-нибудь JS фреймворка (например, Vue) можно заставить Blade игнорировать определенные участки шаблона, чтобы их обработкой смог заняться шаблонизатор js-фреймворка. Для этого используется символ @ перед двойными фигурными скобками.

Hello, @{{ name }}.

В данном примере очевидно, что name это не php-переменная. Так как поставлен символ @, php-шаблонизатор проигнорирует эту область.

Однако если js-переменных в виде очень много, использовать везде символ @ неудобно. В этом случае удобнее воспользоваться директивой verbatim. Весь код, помещенный внутрь директивы, будет проигнорирован шаблонизатором.

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

Рендеринг JSON

Стандартный способ пробросить JSON в js-переменную может выглядеть так:

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

Laravel однако предлагает более удобный способ с использованием класса IlluminateSupportJs и его метода from. В этом случае выполнится дополнительная валидация json на момент правильного экранирования а также преобразование в js-объект через использование JSON.parse.

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

В последней версии Laravel добавлен фасад Js, который позволяет использовать этот способ еще более удобно.

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

Директивы являются удобными шорт-кодами для основных управляющих php-структур, таких как условные выражения и циклы. Вместо того, чтобы писать, к примеру, <?php if($condition) : ?> ... <?php endif; ?> с директивами шаблонизатора можно писать гораздо короче и проще. Более того, разработчиками Blade дополнительно учтен ряд кейсов, которые сильно упрощает и сокращают код и делают разработку видов более приятной.

Директивы для условных выражений

Базовыми директивами здесь являются @if, @elseif, @else и @endif.

@if (count($users) === 1)
  Один пользователь
@elseif (count($users) > 1)
  Несколько пользователей
@else
  Нет пользователей
@endif

Для удобства Blade предлагает даже директиву @unless которая является противоположной по смыслу @if и ее можно представить как @if(!$condition):

@unless (count($users) > 0)
  Нет пользователей
@endunless

Тут вопрос удобства и читаемости. Лично автору материала (мне) директива @unless не нравится, а @if с отрицанием кажется более коротким и читабельным вариантом.

Blade предлагает дополнительные директивы @isset/@empty, которые реализуют проверки через нативные php-функции с аналогичными именами. isset вернет true если переменная объявлена и не является null, а empty проверит переменную на пустоту и вернет true если ее либо вообще нет, либо значением переменной является falsy-значение.

@isset($user)
  переменная $user объявлена и не равна null
@endisset

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

Директивы @auth и @guest позволяют проверяют, является пользователь аутентифицируемым или же он гость.

@auth
  Юзер залогинен
@endauth
 
@guest
  Юзер является гостем
@endguest

Laravel также позволяет указать кастомное название guard-прослойки при использовании этих директив:

@auth('admin')
  Юзер прошел проверку на логин через guard admin
@endauth

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

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

@production
  Мы на продакшене
@endproduction
@env(['staging', 'production'])
  Мы на продакшене или в среде staging
@endenv

Директивы проверки секций

Директивы @hasSection и @sectionMissing принимают название секции и выводят определенные фрагменты если секция присутствует или отсутствует.

@hasSection('navigation')
  Секция навигации есть
  @yield('navigation')
@endif

@sectionMissing('navigation')
  @include('default-navigation')
@endif

Заметьте важное отличие от предыдущих директив. Эти две закрываются просто через @endif.

Директива switch

Позволяет описать все то же самое, что и обычный оператор switch в php.

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

Директива once

Директива once позволяет указать порцию шаблона, которая будет рассчитана только 1 раз за цикл рендеринга. Это может быть полезно при генерации какого-то шаблона в цикле, когда добавить что-либо нужно единожды. Например, при добавлении какого-то javascript в шапку страницы.

@once
  @push('scripts')
    <script>
      // ваш кастомный javascript
    </script>
  @endpush
@endonce

Также для удобства добавлена более короткая директива pushOnce, которая объединяет 2 в 1.

@pushOnce('scripts')
  <script>
    // ваш кастомный javascript
  </script>
@endPushOnce

Директива PHP

В некоторых случаях может быть полезно произвести какие-либо вычисления прямо в виде. Тут будет полезна директива @php внутри которой можно выполнять любой php-код.

@php
  $sum = $a + $b;
@endphp

Если php-код очень короткий и состоит из одного выражения, можно описать его в 1 строку и опустить @endphp. Также можно опустить точку с запятой.

@php $sum = $a + $b

Директивы циклов

В Blade присутствуют директивы для всех циклов в php — for, while, foreach. Вот как может выглядеть использование цикла for через директиву @for:

@for ($i = 0; $i < 10; $i++)
  Текущее значение {{ $i }}
@endfor

Foreach удобен для итеративного вывода значений в массивах и коллекциях:

@foreach ($users as $user)
  <p>ID текущего юзера {{ $user->id }}</p>
@endforeach

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

Давайте рассмотрим самую интересную директиву из циклов — @forelse. Здесь по сути разработчики реализовали за нас простую но полезную идею. Часто при использовании foreach мы проверяем, а есть ли вообще элементы в массиве, и если нет, выполняется какая-то другая логика. @forelse позволяет сократить эту проверку:

@forelse ($users as $user)
  <li>Имя юзера {{ $user->name }}</li>
@empty
  <p>Нет юзеров</p>
@endforelse

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

Внутри циклов вам доступны такие ключевые слова, как continue и break. Пример использования:

@foreach ($users as $user)
  @if ($user->role_id === 1)
    @continue
  @endif
 
  <li>Юзер {{ $user->name }}</li>
 
  @if ($user->id > 10)
    @break
  @endif
@endforeach

Однако Blade позволяет существенно сократить подобный кусок шаблона, передав условия прямо как аргументы в директивы @continue/@break:

@foreach ($users as $user)
  @continue ($user->role_id === 1)
 
  <li>Юзер {{ $user->name }}</li>
 
  @break($user->id > 10)
@endforeach

Сокращение получается очень впечатляющее, учитывая, что данные директивы не нуждаются в закрывающей части.

Переменная $loop в циклах

Используя директивы @foreach/@forelse вы можете получить доступ к переменной $loop в теле цикла, которая содержит различную полезную информацию. Это упрощает такие типичные проверки, как проверка на первую или последнюю итерацию, проверка на чет/нечет, номер итерации, вложенность цикла.

@foreach ($users as $user)
  @if ($loop->first)
    Это первая итерация
  @endif
 
  @if ($loop->last)
    Это последняя итерация
  @endif
@endforeach

Находясь во вложенном цикле можно получить значения переменной $loop внешнего цикла через свойство parent.

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

Помимо first/last, переменная $loop имеет ряд других полезных свойств:

  • index — индекс цикла, начинается с 0
  • iteration — номер итерации, начинается с 1
  • remaining — bool-флаг, в цикле еще остались итерации
  • count — кол-во элементов в итерируемом массиве
  • even — четная итерация или нет
  • odd — нечетная или нет
  • depth — глубина вложенности текущего цикла
  • parent — переменная внешнего цикла, если текущий является вложенным

Как видим, использование шаблонизатора Blade значительно упрощает работу с циклами.

Добавление классов по условию

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

@php
  $isActive = false;
  $hasError = true;
@endphp

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

Такая работа с классами очень сильно напоминает js-фреймворк Vue. Вы просто передаете массив, где ключами выступают названия классов, а значениями — условия. При этом последние являются необязательными.

Дополнительные html-атрибуты

Работая с html можно столкнуться с рядом атрибутов, у которых нет значений. Это такие атрибуты как checked, selected, disabled, readonly и required. Собственно, для всех этих атрибутов Blade предлагает директивы для удобного присвоения этих атрибутов по условию. Если вы знакомы с нативным синтаксисом php касательно этих атрибутов, там это далеко не так коротко и красиво.

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

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

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

Подключение видов (@include)

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

<main>
  @include('article.pre-content')
 
  <article>
    <!-- Article Contents -->
  </article>
</main>

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

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

@includeIf('view.name', ['key' => 'val'])

Директивы includeWhen и includeUnless подключают вид в случае, если он соответствует или не соответствует условию.

@includeWhen($boolean, 'view.name', ['key' => 'val'])
@includeUnless($bool, 'view.name', ['key' => 'val'])

Чтобы подключить первый вид из существующих в переданном массиве, используется директива @includeFirst.

@includeFirst(['custom.admin', 'admin'], ['key' => 'val'])

Не следует использовать php-константы __DIR__ и __FILE__ в шаблонах Blade, так как они компилируются, а значениями этих констант становится адрес скомпилированных видов.

Отрисовка видов для коллекций

Очень часто имея Eloquent-коллекцию данных необходимо в цикле подключить вид для каждого элемента коллекции, так как фрагмент шаблона для одного элемента может быть весьма сложным. Шаблонизатор предлагает способ сделать это вообще в 1 строчку, используя директиву @each.

@each('posts._post', $posts, 'post')

Первым параметром передается название вида, вторым — переменная с коллекцией, а третьим название переменной, по которому будет доступен конкретный элемент в виде. Теперь мы можем использовать переменную $post в виде posts._post и она будет указывать на текущий пост. Переменная $key тоже доступна в этом виде, она передается туда по умолчанию.

Директива @each принимает опциональный четвертый аргумент — название вида который будет использован, если в коллекции нет элементов.

@each('posts._post', $posts, 'post', 'posts.empty')

Таким образом, директива @each позволяет в 1 строке разместить столько логики, сколько обычно помещается в 5-10 строк.

Однако, виды подключенные через @each не наследуют автоматически переменные из родительского вида. Если вас не устраивает такое поведение, следует использовать foreach/forelse и include.

Компоненты

Компоненты предоставляют похожие преимущества, что и секции, шаблоны и директива @include, но предлагают другую идеологию, подсмотренную у фронтенд-фреймворков (в частности Vue). Компоненты также позволяют разбить куски шаблона более осмысленно и сделать код более документируемым.

Есть 2 подхода к созданию компонентов — компоненты-классы и анонимные. Компоненты-классы хранятся в папке app/View/Components (непосредственно сами классы), а их шаблоны в resources/views/components. Анонимные компоненты не содержат классов и состоят только из шаблонов, которые хранятся там же — resources/views/components. Здесь нет правильного или неправильного подхода, но анонимные компоненты создавать и использовать в целом проще.

Создание компонентов

Фреймворк предлагает использовать консольный помощник artisan для быстрого создания компонентов. Это особенно актуально, если вы собираетесь создавать компоненты-классы. К примеру, выполним такую команду:

php artisan make:component Alert

Если в проекте еще не было компонентов-классов, то будет создана папка View/Components в директории App. Там будет создан класс Alert.php примерно с таким содержимым:

<?php

namespace AppViewComponents;

use IlluminateViewComponent;

class Alert extends Component
{
  public function __construct() {
    //
  }

  public function render() {
    return view('components.alert');
  }
}

Внутри уже сгенерирован скелет компонента. За отрисовку, как несложно догадаться, отвечает метод render. Он уже возвращает вид, лежащий по адресу components/alert.blade.php если следовать от корня resources/views. Фреймворк создает за нас этот вид.

При создании компонентов очень часто появляется определенная структура папок. Например, вы можете захотеть разложить элементы форм, всплывающие окна, оповещения и т.д. по разным папкам. При создании компонента через консоль можно указать путь к компоненту и Laravel автоматически поместит его в нужные папки + правильно сгенерирует пространство имен. К примеру:

php artisan make:component Forms/Input

Фреймворк создаст нужную структуру в обоих местах. Класс будет помещен по адресу App/View/Components/Forms, а его вид по адресу resources/views/components/forms. Laravel учитывает даже регистр — где надо ставит верхний, где надо нижний.

Создание анонимных компонентов

Что касается создания анонимных компонентов, для этого нужно добавить флаг --view:

php artisan make:component forms.input --view

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

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

При создании и использовании компонентов в рамках своего веб-приложения, будь то классы или анонимные компоненты, вам не нужно вручную регистрировать компоненты. Достаточно придерживаться правил, что классы компонентов лежат в App/View/Components, а их виды в resources/views/components. Однако если вы создаете свой composer-пакет, вам придется регистрировать компоненты в сервис провайдере вашего пакета, используя фасад Blade.

use IlluminateSupportFacadesBlade;
 
// внутри сервис провайдера
public function boot() {
  Blade::component('package-alert', Alert::class);
}

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

public function boot() {
  Blade::componentNamespace('MyPackage\Views\Components', 'my-package');
}

В этом случае отрисовывать компоненты можно используя спец. синтакс (название-пакета::название-компонента):

<x-my-package::alert/>

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

Для отрисовки компонентов Blade предлагает префикс x-, после которого должно идти название компонента в кебаб-кейсе. Если компонент не принимает никакого контента/слота внутрь, можно использовать его как одинарный закрывающий тег, точно так же как и нативные html-теги вроде <br/>, <hr /> и подобных.

К примеру, если компонент называется small-alert, он выводится так:

<x-small-alert/>

Если класс компонента находится в структуре папок глубже корневой, можно использовать точку как разделитель для доступа к компоненту.

<x-inputs.button/>

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

Передавать данные в Blade-компоненты просто. Если это простые статические значения, их можно передавать как обычные html-атрибуты. Если же в качестве значения выступает php-переменная или даже php-выражение, следует использовать префикс : для таких атрибутов:

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

Передав данные в компонент, дальнейшие шаги зависят от того, каков тип компонента. Давайте пока разбираться с компонентами-классами, они в любом случае сложнее. Передав параметры, вы должны описать их в классе компонента, а также реализовать конструктор для объекта класса. Вот как может выглядеть такое описание (некоторые PHPDoc комментарии удалены, чтобы уменьшить размер кода):

<?php
 
namespace AppViewComponents;
 
use IlluminateViewComponent;
 
class Alert extends Component
{
  public $type;
  public $message;
 
  /**
   * Create the component instance.
   *
   * @param  string  $type
   * @param  string  $message
   * @return void
  */
  public function __construct($type, $message) {
    $this->type = $type;
    $this->message = $message;
  }
 
  public function render() {
    return view('components.alert');
  }
}

Как видим, класс позволяет очень подробно описать параметры, их типы, что может быть очень важно и полезно при разрастании проекта.Теперь, подготовив класс, мы можем описать сам вид (resources/views/components/alert.blade.php):

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

Регистр

Аргументы в конструкторе класса следует указывать в camelCase, то есть в верблюжьем кейсе, в то время как передавать их в html следует в кебаб-кейсе.

// camelCase для аргументов в классе
public function __construct($alertType) {
  $this->alertType = $alertType;
}

В то время как в HTML:

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

Сокращенный синтаксис

Можно использовать короткий синтаксис для передачи атрибутов, если имена атрибута и переменной-значения атрибута совпадают.

{{-- короткий синтаксис --}}
<x-profile :$userId :$name />
 
{{-- пример выше эквивалентен --}}
<x-profile :user-id="$userId" :name="$name" />

Обратите внимание, что Blade автоматически учитывает разницу в регистре названий атрибутов и переменных. Таким образом, переменная $userId превращается в атрибут user-id. Фреймворк учитывает эту разницу в регистрах за вас.

Игнорирование атрибутов для JS фреймворков

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

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

Доп. возможности компонентов-классов

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

Методы компонентов

Используя классы можно не только описывать параметры, но и реализовывать собственные методы. К примеру, для такого html-элемента как select может быть разумным реализация метода isSelected, который вернет true для выбранной опции.

// в классе компонента
public function isSelected($option) {
  return $option === $this->selected;
}

Теперь можно вызвать этот метод прямо в виде компонента:

<option @selected($isSelected($value)) value="{{ $value }}">
  {{ $label }}
</option>

Здесь мы используем и директиву @selected и метод компонента чтобы сделать функционал очень простым и удобным. Заметьте, какой синтаксис используется для вызова метода $isSelected (знак $, потом название метода).

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

В методе render можно получить данные компонента в виде ассоциативного массива. Чтобы сделать это, нужно вернуть функцию-замыкание из метода. Функция получает единственный аргумент $data, который и будет массивом, содержащим необходимую информацию. По ключу componentName будет лежать имя компонента в кебаб-кейсе, attributes содержит массив атрибутов (свойств), а slot — слот.

public function render() {
  return function (array $data) {
    // $data['componentName'];
    // $data['attributes'];
    // $data['slot'];
 
    return '<div>Components content</div>';
  };
}

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

Доп. зависимости в конструкторе класса

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

use AppServicesAlertCreator;
 
/**
 * Create the component instance.
 *
 * @param  AppServicesAlertCreator  $creator
 * @param  string  $type
 * @param  string  $message
 * @return void
 */
public function __construct(AlertCreator $creator, $type, $message) {
  $this->creator = $creator;
  $this->type = $type;
  $this->message = $message;
}

Скрытие атрибутов и методов

Можно скрывать атрибуты или методы от доступа в виде, реализовав свойство except.

protected $except = ['type'];

Атрибуты компонентов

Бывают ситуации, когда не все из переданных атрибутов должны быть атрибутами компонента. Возможно, вы хотите чтобы они были обработаны как обычные html атрибуты. Рассмотрим пример с заданием атрибута class компоненту:

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

Здесь Laravel поступает так — если class не был объявлен как аргумент в конструкторе класса, то этот атрибут попадает в так называемый attribute bag или сумку аргументов. Подобные аргументы становятся автоматически доступны компоненту через переменную $attributes. Это позволяет отрендерить их в нужном месте.

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

Директивы вроде @env в данный момент не поддерживаются для использования внутри видов компонентов. Код вроде <x-alert :live="@env('production')"/> не будет скомпилирован.

Атрибуты по умолчанию/слияние

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

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

В примере мы указываем, что 2 класса всегда будут присваиваться нашему элементу. Если компонент используется так:

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

То в результате компиляции он превратится в следующий html:

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

Слияние по условию

Если вы хотите добавить определенные классы по условию, можно использовать метод class, который позволяет указать классы в формате ключ (название класса) — логическое выражение.

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

Если вам, помимо классов по условию, нужно добавить другие атрибуты, используйте merge и class вместе через цепочку вызовов.

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

Если требуется задать классы по условиям для других html-элементов, которые не являются корневыми в компоненте, можно использовать Blade-директиву @class.

Поведение атрибутов не-классов

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

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

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

<x-button>Кнопка</x-button>

Поскольку тип здесь не указан вообще, то будет использовано значение атрибута из метода merge. Однако если мы укажем так:

<x-button type="submit">
  Отправить
</x-button>

Атрибут в скомпилированной версии получит значение submit, так как прямое указание в атрибутах компонента имеет приоритет перед тем, что указано в merge. Еще раз напомним, что такое поведение касается всех атрибутов не-классов.

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

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

В данном примере у нас есть атрибут data-attr, у которого всегда начальным значением будет val. Если в компонент передать параметр data-attr="val2", то в скомпилированном виде значением атрибута будет "val val2".

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

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

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

Есть более короткие методы whereStartsWith и whereDoesntStartWith, которые позволяют быстро отфильтровать атрибуты, чье название ключа начинается или не начинается с определенной подстроки.

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

Метод first, вызванный на отфильтрованном списке атрибутов, позволяет вернуть первый из них.

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

Метод has позволяет проверить, существует ли атрибут у компонента.

@if ($attributes->has('type'))
  <div>Атрибут type присутствует</div>
@endif

Наконец, для получения значения атрибута по его названию, можно использовать метод get.

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

Зарезервированные ключевые слова

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

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

Слоты компонентов

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

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

В переменную $slot попадет все, что вы передадите внутрь тега компонента.

<x-alert>
  <b>Слот</b>
</x-alert>

В данном случае <b>Слот</b> это содержимое слота. Это так называемый слот по умолчанию, который всегда будет доступен в переменной $slot.

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

<x-alert>
  <x-slot:title>
    Слот с заголовком
  </x-slot>
 
  Слот по умолчанию
</x-alert>

Как видим, тег x-slot позволяет задать слот, а через двоеточие задается его имя. Теперь в исходном коде компонента можно этот слот обработать:

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

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

Доступ к компоненту в слоте

Через переменную $component можно получить доступ к свойствам и методам компонента, находясь в слоте. К примеру, если у класса компонента есть метод formatAlert, он может быть вызван прямо из слота.

<x-alert>
  <x-slot:title>
    {{ $component->formatAlert('Слот заголовок') }}
  </x-slot>
 
  Слот по умолчанию
</x-alert>

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

Как и Blade-компоненты, слоты могут получать свои собственные атрибуты.

<x-card class="shadow-sm">
  <x-slot:title class="font-bold">
    Заголовок
  </x-slot>
 
  Контент (слот по умолчанию)
 
  <x-slot:footer class="text-sm">
    Подвал
  </x-slot>
</x-card>

Чтобы обработать атрибуты слотов, нужно обращаться к переменной по имени слота, а у нее будет свойство attributes.

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

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

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

Строковые виды для компонентов

Когда речь идет о компонентах-классах, Laravel позволяет вернуть html-строку прямо в методе render. Это позволяет не создавать отдельный файл в папке resources/views/components. Работать с html в режиме строки очень неудобно, однако строковые виды могут быть использованы для очень простых компонентов, чей html занимает не более 3-5 строк.

public function render() {
  return <<<'blade'
    <div class="alert alert-danger">
      {{ $slot }}
    </div>
  blade;
}

Заметьте, какой в данном случае используется необычный синтаксис. Открывающая инструкция <<<'blade' и закрывающая blade; информируют о начале и конце строкового вида.

Создание компонентов со строковым видом

Если уже на этапе создания компонента вы уверены, что вам не потребуется отдельный файл вида для него, а весь код вида поместится в строку в методе render, то можно указать флаг --inline в artisan. Таким образом, будет создан только класс компонента, а файл вида создан не будет.

php artisan make:component Alert --inline

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

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

<x-dynamic-component :component="$componentName" />

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

Анонимные компоненты можно сравнить с компонентами-классами, в который вид возвращается прямо в виде строки в методе render. В обоих случаях для описания компонента используется 1 файл. Только в случае с компонентами-классами это класс, а в случае с анонимными это вид.

Анонимные компоненты в своем функционале не особо уступают классовым, но при этом реализовываются гораздо проще и быстрее, так как весь компонент описывается в одном файле вида.

Если компонент лежит в корне папки resources/views/components, то его можно использовать через тег x-название-компонента. Если вложенность более глубокая, следует использовать точку как разделитель. К примеру, компонент button лежащий в папке inputs можно использовать так:

<x-inputs.button/>

Корневые компоненты

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

К примеру, в папке components лежит accordion.blade.php, а в папке components/accordion есть файл item.blade.php. Используя такую структуру, где родительский компонент лежит наверху, а его дочерние в отдельной папке, можно использовать компоненты следующим образом:

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

Это первый вариант структуры. Второй вариант это положить родительский компонент в папку accordion и назвать его index.blade.php. Вы сможете использовать компоненты, точно так же, как и в первом случае.

Когда фреймворк видит во вложенной папке компонент index.blade.php, он догадывается, что это корневой компонент папки, поэтому вы можете обращаться к нему по имени x-folder-name, вместо x-folder-name.index.

Свойства и атрибуты

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

К примеру, укажем что компонент принимает свойство type, со значением info по умолчанию, а также свойство message без значения по дефолту.

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

Доступ к свойствам родителя

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

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

В данном примере мы передали цвет только родителю, но что, если он нам нужен и в дочерних компонентах. В этом случае поможет директива @aware, которая позволяет считать свойства родителя. Вот как может выглядеть код дочернего компонента:

@aware(['color' => 'gray'])
 
<li {{ $attributes->merge(['class' => 'text-'.$color.'-800']) }}>
  {{ $slot }}
</li>

Директива @aware способна достать только те свойства родителя, которые были явно указаны в @props и переданы родителю.

Пути анонимных компонентов

По умолчанию компоненты хранятся в директории resources/views/components. Если по каким-то причинам вы хотите изменить корневую папку для них, это можно сделать в сервис провайдере с помощью фасада Blade:

public function boot() {
  Blade::anonymousComponentPath(__DIR__.'/../components');
}

В этом примере меняем корневую папку для анонимных компонентов на resources/components. Вторым параметром можно передать «пространство имен» или общее название, которое будет ассоциироваться с компонентами.

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

Это позволяет использовать несколько другой синтаксис при использовании компонентов. Так, файл созданный по указанному пути с именем alert.blade.php, можно будет использовать следующим образом:

<x-dashboard::alert />

Создание общих шаблонов

В большинстве веб-приложений у многих страниц есть определенная часть html, которая не сильно меняется. Как правило, можно выделить какую-то явную изменяемую часть и статическую, неизменяемую часть. Вы же не начинаете описание каждого вида с тега !doctype, после чего последовательно пишите html, head, body… Очевидно, что для таких каркасов нужно использовать отдельные файлы — общие шаблоны.

Если приложение простое, то такой шаблон может быть вообще один — какой-нибудь layout.blade.php, лежащий прямо в корне папки видов. Иначе же создается как правило отдельная папка для таких шаблонов.

Сейчас мы рассмотрим 2 способа создания шаблонов — через компонентный подход и через секции.

Создание шаблонов через компоненты

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

<html>
  <head>
    <title>{{ $title ?? 'Заголовок по умолчанию' }}</title>
  </head>
  <body>
    <h1>Шаблон-компонент</h1>
    <hr/>
    {{ $slot }}
  </body>
</html>

К примеру, компонент назвали layout.blade.php. Как вы уже знаете, в $slot попадет все, что мы разместим между открывающим и закрывающим тегами компонента-шаблона. Это позволяет нам очень удобно и быстро применить шаблон к любому виду, просто описав сам вид как слот шаблона.

<x-layout>
  Файл вида
  @foreach ($items as $item)
    {{ $item}}
  @endforeach
</x-layout>

Используя именованные слоты, мы можем добавлять различные фрагменты html, которые станут в нужное место шаблона, и делать это из вида. Таким образом, мы сможем настроить каждый вид соответствующим образом — у каждой страницы будет свой заголовок, мета-теги и прочая информация.

<x-layout>
  Вид с именованными слотами
  Этот слот попадет в $title
  <x-slot:title>
    Пользовательский заголовок
  </x-slot>
 
  Слот по умолчанию, попадет в $slot
</x-layout>

Создание шаблонов через наследование и расширение вида

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

Старый способ основан на директивах @extends, @section, @show и @yield. В начале мы создаем сам шаблон, в котором размечаем, где какие секции должны находиться.

<html>
  <head>
    <title>Сайт - @yield('title')</title>
  </head>
  <body>
    @section('sidebar')
      Сайдбар
    @show
 
    <div class="container">
      @yield('content')
    </div>
  </body>
</html>

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

@extends('layout')
 
@section('title', 'Заголовок страницы')
 
@section('sidebar')
  @parent
  <p>Доп контент сайдбара</p>
@endsection
 
@section('content')
  <p>Основной контент</p>
@endsection

Первым делом в файле вида все начинается с директивы @extends. Если вы знакомы с ООП, то знаете что это означает расширение какого-либо класса, наследование от него. Здесь тот же концепт, только на уровне видов — мы указываем, что расширяем шаблон layout.blade.php.

Теперь секции. Каждая описывается с помощью директивы @section. Если описание влазит в одну строку, то можно опустить закрывающую @endsection.

В случае с секциями title и content, думаем, все понятно — мы их просто определяем и описываем. А вот в секции сайдбара, которую в данном случае даже необязательно было реализовывать, наблюдаем еще одну директиву @parent. И снова можете провести параллели с ООП и словом parent в конструкторе/методах класса. В случае с видами это означает, что мы берем родительский html-секции, и после него вставляем свой, расширяя секцию.

В общем, для понимания расширения шаблонов нужно понять, как работают директивы @section, @show, @parent, @yield и @extends.

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

@yield('content', 'Контент по умолчанию')

Итоги по шаблонам

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

Работа с формами

Blade предоставляет ряд удобных директив для работы с формами. Как вы знаете, Laravel предоставляет защиту от csrf-атак по умолчанию. Все что для этого нужно, это внедрить директиву @csrf в форму.

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

Иногда вам может потребоваться указать метод отправки формы, отличный от GET/POST. Здесь пригодится директива @method.

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

Показ ошибок

Blade предлагает директиву @error для удобного показа ошибок.

<input id="title"
  type="text"
  class="@error('title') is-invalid @enderror">
 
@error('title')
  <div class="alert alert-danger">{{ $message }}</div>
@enderror

По сути это упрощение кейса с if и проверкой на наличие ошибки. Поскольку @error превращается в if, можно использовать @else чтобы проверить отсутствие ошибки.

<!-- /resources/views/auth.blade.php -->
 
<label for="email">Email address</label>
 
<input id="email"
  type="email"
  class="@error('email') is-invalid @else is-valid @enderror">

Доп директивы

Blade предоставляет дополнительные удобные директивы для таких атрибутов, как required, disabled, selected, readonly и checked. Мы их уже рассмотрели выше, здесь лишь напоминаем о них, потому что все эти директивы прямо связано с формами.

Стэки

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

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

Директива @push принимает имя стэка, в который нужно отправить скрипт. Можно даже выполнить пуш (отправку) по условию:

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

Для отображения стэка в шаблона используется директива @stack.

<head>
  <!-- контент тега head -->
  @stack('scripts')
</head>

Директива @push добавит скрипт в конец стэка. Если вы хотите передать определенный скрипт, который должен занять свое место перед остальными, следует использовать директиву @prepend.

@prepend('scripts')
  <script src="/prepend.js"></script>
@endprepend

Внедрение сервиса

Директива @inject позволяет внедрить сервис из сервисного контейнера Laravel. Первым параметром принимается имя переменной, которая станет инстансом класса сервиса, а вторым пространство имен класса.

@inject('metrics', 'AppServicesMetricsService')
 
<div>
  Новые клиенты: {{ $metrics->newCustomers() }}.
</div>

Рендеринг Blade-шаблона из строки

Иногда может возникнуть необходимость скомпилировать Blade-шаблон из строки. Например, когда вы находитесь не в видах, а в другой части веб-приложения. Фасад Blade и его метод render позволяют добиться этого.

use IlluminateSupportFacadesBlade;
 
return Blade::render('Hello, {{ $name }}', ['name' => 'John Doe']);

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

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

Используя некоторые специфические js-фреймворки вроде Turbo или htmx, вам может потребоваться вернуть только фрагмент Blade шаблона в HTTP-ответе. Шаблонизатор позволяет это сделать с помощью директивы @fragment. На уровне вида это делается так:

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

Далее, при возврате ответа из обработчика роута, следует вызвать метод fragment, куда передать имя возвращаемого фрагмента. В итоге Laravel вернет только html, относящийся к этому фрагменту.

return view('manage', ['posts' => $posts])->fragment('post-list');

Расширение шаблонизатора Blade

Blade позволяет добавлять и описывать свои собственные директивы с любой пользовательской логикой. Когда Blade увидит директиву, которая является пользовательской, он будет искать функцию-замыкание, реализующую логику директивы.

Создать директиву можно с помощью фасада Blade, метода directive. Это делается в сервис-провайдере. Первый параметром принимается название директивы, а вторым функция для ее реализации. Название, конечно же, не должно конфликтовать с уже объявленными и встроенными в шаблонизатор директивами.

public function boot() {
  Blade::directive('datetime', function ($expression) {
    return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
  });
}

Функция принимает значение, переданное в директиву. В данном примере, будет выполняться форматирование даты к описанному формату. Учитывая, что Laravel способен автоматически переводить поля дат для Eloquent-моделей в Carbon-объекты, использование директивы может выглядеть так:

@datetime($post->created_at)

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

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

При попытке распечатать объект в Blade, шаблонизатор будет искать метод __toString у класса объекта, чтобы представить объект в виде строки. В ряде случаев, однако, может не быть доступа к методу __toString, потому что может возникнуть необходимость распечатать объект класса, чей код является недоступным для редактирования.

Для таких случаев фреймворк предлагает метод stringable фасада Blade, в котором можно реализовать функцию для печати нужного объекта. Обязательным является внедрение зависимости с экземпляром класса, который нуждается в правке логики распечатки. Типичное место для выполнение подобных операций это сервис-провайдер AppServiceProvider.

use IlluminateSupportFacadesBlade;
use MoneyMoney;

public function boot() {
  Blade::stringable(function (Money $money) {
    return $money->formatTo('en_GB');
  });
}

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

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

public function boot() {
  Blade::if('disk', function ($value) {
    return config('filesystems.default') === $value;
  });
}

Теперь, вместо того чтобы писать в шаблоне длинную проверку типа @if(config('filesystems.default') === 'local') можно использовать следующие записи:

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

Как видим, Blade::if не просто добавляет директиву для нового пользовательского условия, но и делает это с учетом разных вариантов, добавляя поддержку else и unless.

Итоги

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

UFS50 FLOOR SCRAPER

1.

Start with a narrow blade, then increase blade size to optimize cutting pass. Narrower blades

work easier than wider blades and usually clean the floor better. Wider is not always better or

faster.

2.

Proper blade size and placement, depending on material and sub-floor type, greatly affects

performance.

3.

Keep in mind, narrow width blades will make a cleaner floor surface.

4.

For wood or wood like floors, pound down or remove any nails or metal obstruction to avoid

blade damage.

5.

When working over plywood sub-floor, try to work in the direction of the wood grain.

6.

A new sharp blade being used on wood or alike sub floors may work better when slightly

dulled to avoid digging or gouging.

7.

When working over concrete, beware of expansion joints and sub-floor mounted receptacles.

8.

Keep your work area clean and clear of debris.

9.

After you have removed a portion of material, remove it out of the way. This will give the

machine maximum performance and help to keep the work area safe.

10. Dull blades greatly reduce cutting ability. Re-sharpen or replace as needed.

11. Use Sawtec

replacement blades.

®

(A)

Blades can be offset in cutting

head for easier access to toe

kicks or removal along the wall

15

BLADES

  • Introduction
  • Template Inheritance

    • Определение макета
    • Расширение макета
  • Displaying Data

    • Платформы Blade и JavaScript
  • Control Structures

    • If Statements
    • Switch Statements
    • Loops
    • Переменная Петля
    • Comments
    • PHP
    • @once Директива
  • Forms

    • CSRF Field
    • Method Field
    • Validation Errors
  • Components

    • Displaying Components
    • Передача данных компонентам
    • Managing Attributes
    • Slots
    • Представления встроенных компонентов
    • Anonymous Components
    • Dynamic Components
  • Including Subviews

    • Рендеринговые виды для коллекций
  • Stacks
  • Service Injection
  • Extending Blade

    • Выписки из таможни Если выписки из таможни

Introduction

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

Template Inheritance

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

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


<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 @extends , чтобы указать, какой макет дочернее представление должно «наследовать». Представления, которые расширяют макет Blade, могут вставлять контент в разделы макета с помощью директив @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'))

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

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

Displaying Data

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

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

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

Hello, {{ $name }}.

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

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

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

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

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

Hello, {!! $name !!}.

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

Rendering 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 основан на регулярных выражениях, и попытки передать сложное выражение в директиву могут вызвать неожиданные сбои.

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

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

<?php

namespace AppProviders;

use IlluminateSupportFacadesBlade;
use IlluminateSupportServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    
    public function boot()
    {
        Blade::withoutDoubleEncoding();
    }
}

43

Effective Date 07-01-06

Use only genuine Walker

®

 replacement parts.

BLADE USAGE CHART

Right hand and left hand orientated with operator on seat

All blade sets include 5706 (Blade Hub & Trash Guard), F002 & F202 unless otherwise specified

*

Blade set consists of three (3) blades

TWO BLADE DECKS

RH BLADE

LH BLADE

BLADE SET

DGHS36

5705-2

5705-0

5705-6

DSD36

5705-1

5705-1

5705-5

DGHS42

5705-4

5705-3

5705-8

DSD42

5705-3

5705-3

5705-7

DML42A

5705-28

5705-28

5705-19

DGHS48

7705-2

7705-1

7705-3

DSD48

7705-1

7705-1

7705-5

THREE & FOUR BLADE DECKS

SINGLE BLADE

BLADE SET

DSD52

5705-14

8738-7*

DSD52 MULCHING

UPPER BLADE

5705-15

8738-7*

DSD52 MULCHING

LOWER BLADE

5705-14

8738-8*

DSD56

5705-0

5705-9

DSD62

5705-3

5705-13

DSD74

5705-0

5705-16

F018

F056

F055

F202

Right-Hand Blade 

Left-Hand Blade 

F002

Refer to DGHS48
DECK ASSEMBLY,
Page 20

  1. 1. Введение
  2. 2. Наследование шаблонов

    1. 2.1. Определение макета
    2. 2.2. Наследование макета
  3. 3. Отображение данных

    1. 3.1. Blade и JavaScript-фреймворки
  4. 4. Управляющие конструкции

    1. 4.1. Оператор If
    2. 4.2. Циклы
    3. 4.3. Переменная Loop
    4. 4.4. Комментарии
    5. 4.5. PHP
  5. 5. Включение подшаблонов

    1. 5.1. Отрисовка представлений для коллекций
  6. 6. Стеки
  7. 7. Внедрение сервисов
  8. 8. Наследование Blade

Этот перевод актуален для англоязычной документации на

28.01.2017

(ветка

5.3) ,

08.12.2016

(ветка

5.2) и

19.06.2016

(ветка

5.1).
Опечатка? Выдели и нажми Ctrl+Enter.

Введение

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

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

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

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

PHP

<!-- Хранится в resources/views/layouts/app.blade.php -->

<

html>
  <
head>
    <
title>App Name - @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:

PHP

<!-- Хранится в 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 будет заменена содержимым макета при отрисовке представления.

Blade-представления могут быть возвращены из маршрутов при помощи глобальной вспомогательной функции PHPview():

PHP

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

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

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

PHP

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

Вы можете отобразить содержимое переменной name вот так:

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

PHP

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

Blade-оператор PHP{{ }} автоматически отправляется через PHP-функцию PHPhtmlentities() для предотвращения XSS-атак.

Вывод переменных после проверки на существование

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

PHP

{{ isset($name) ? $name 'Default' }}

Вместо написания тернарного оператора Blade позволяет вам использовать такое удобное сокращение, которое будет скомпилировано в тернарный оператор, приведённый ранее:

PHP

{{ $name or 'Default' }}

Если переменная $name имеет значение, то оно будет отображено, иначе будет выведено слово Default.

Вывод неэкранированных данных

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

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

Как показывает практика, вместо экранирования только пользовательских переменных безопаснее экранировать весь вывод, делая исключения только в редких случаях — прим. пер.

Blade и JavaScript-фреймворки

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

PHP

<h1>Laravel</h1>Hello, @{{ name }}.

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


+
5.3

добавлено в

5.3

(28.01.2017)

Директива PHP@verbatim

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

PHP

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

Управляющие конструкции

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

Оператор If

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

PHP

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

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

PHP

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


+
5.2

добавлено в

5.2

(08.12.2016)

Также вы можете определить, есть ли содержимое в данной секции макета, с помощью директивы PHP@hasSection:

PHP

<title>
  @
hasSection ('title')
    @yield(
'title') - Название приложения
  
@else
    
Название приложения
  
@endif
</
title>

Циклы

В дополнение к условным операторам Blade предоставляет простые директивы для работы с конструкциями циклов PHP. Данные директивы тоже идентичны их 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


+
5.3 5.2

добавлено в

5.3

(28.01.2017)

5.2

(08.12.2016)

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

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

PHP

@foreach ($users as $user)
  @if (
$user->type == 1)
    @continue
  @endif

  <

li>{{ $user->name }}</li>

  @if (

$user->number == 5)
    @break
  @endif
@endforeach

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

PHP

@foreach ($users as $user)
  @continue(
$user->type == 1)

  <

li>{{ $user->name }}</li>

  @break(

$user->number == 5)
@endforeach


+
5.3

добавлено в

5.3

(28.01.2017)

Переменная Loop

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

PHP

@foreach ($users as $user)
  @if (
$loop->first)
    
Это первая итерация.
  @endif

  @if (

$loop->last)
    
Это последняя итерация.
  @endif

  <

p>Это пользователь {{ $user->id }}</p>
@endforeach

Если вы во вложенном цикле, вы можете обратиться к переменной PHP$loop родительского цикла через свойство PHPparent:

PHP

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

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

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

Комментарии

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

PHP

{{-- Этого комментария не будет в итоговом HTML --}}

PHP

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

Несмотря на то, что в Blade есть эта возможность, её частое использование может быть сигналом того, что у вас слишком много логики, встроенной в шаблон.

Включение подшаблонов

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

PHP

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

  <

form>
    <!-- 
Содержимое формы -->
  </
form>
</
div>

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

PHP

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

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

PHP

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

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

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

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

PHP

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

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

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

PHP

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


+
5.3 5.2

добавлено в

5.3

(28.01.2017)

5.2

(08.12.2016)

Стеки

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

PHP

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

«Пушить» в стек можно сколько угодно раз. Для отрисовки всего содержимого стека передайте имя стека в директиву PHP@stack:

PHP

<head>
  <!-- 
Содержимое заголовка -->

  @

stack('scripts')
</
head>

Внедрение сервисов

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

PHP

@inject('metrics''AppServicesMetricsService')

<

div>
  
Месячный доход: {{ $metrics->monthlyRevenue() }}.
</
div>

Наследование Blade

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

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

PHP

<?phpnamespace AppProviders;

use 

IlluminateSupportFacadesBlade;
//для версии 5.2 и ранее:
//use Blade;
use IlluminateSupportServiceProvider;

class 

AppServiceProvider extends ServiceProvider
{
  
/**
   * Выполнение после-регистрационной загрузки сервисов.
   *
   * @return void
   */
  
public function boot()
  {
    
Blade::directive('datetime', function ($expression) {
      return 
"<?php echo ($expression)->format('m/d/Y H:i'); ?>";
    });
  }
/**
   * Регистрация привязок в контейнере.
   *
   * @return void
   */
  
public function register()
  {
    
//
  
}
}

Как видите, мы прицепили метод PHPformat() к тому выражению, которое передаётся в директиву. Поэтому финальный PHP-код, сгенерированный этой директивой, будет таким:

PHP

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


+
5.3 5.2

добавлено в

5.3

(28.01.2017)

5.2

(08.12.2016)

После изменения логики директивы Blade вам надо удалить все кешированные представления Blade. Это можно сделать Artisan-командой shview:clear.

Понравилась статья? Поделить с друзьями:
  • Blackvue fhd 60 fps инструкция
  • Bona forte от тли и гусениц инструкция по применению
  • Blackvue dr650gw 2ch инструкция на русском языке
  • Bona forte для цитрусовых инструкция по применению
  • Blackview solo 2 инструкция по эксплуатации