Laravel. Blade. Изучаем более тщательно

screenshot-laravel com 2016-03-28 10-36-38 В предыдущем посте я немного касался создания представлений с использованием шаблонизатора Blade. Ну и теперь можно уже изучить вопрос глубже.

Вставка PHP кода
———————————
Blade позволяет использовать PHP код внутри шаблонов.

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

Хотя я подозреваю, что если в коде встретится что-то, похожее на Blade инструкцию, он скорее всего попытается её выполнить. Надо как-нибудь попробовать…

Видимо поэтому существует специальная инструкция для вставки PHP

@php
//
@endphp

Ну и для завершения этой секции, помните, что если в вашем шаблоне слишком много PHP, о это у вас какой-то неправильный шаблон

Вывод переменной
——————————

Вывод переменной

{{ $var }} 
Эквивалентно
<?php echo $var; ?>

Вывод переменной с вариантом по-умолчанию

{{ $var or 'default' }}
Эквивалентно тернарной операции
{{ isset($var) ? $var: 'default' }}

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

Hello, {!! $name !!}.

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

@{{ This will not be processed by Blade }}

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

@verbatim
    
Hello, {{ name }}.
@endverbatim

Ну и наконец, какой же язык без комментариев?

{{-- Comment --}}

Условия
————————————
Условия пишутся почти так же как и на PHP

@if(condition) 
    Условие выполняется
@elseif(condition)
    Или может другое условие?
@else
    Иначе вот тут
@endif

Ключевое слово unless тоже своего рода условие, только с отрицанием

@unless ($age >= 18)
    Вам нельзя продавать алкоголь
@endunless

Циклы
—————————
Тут тоже всё почти так же как в PHP
Цикл foreach

@foreach($list as $key => $val)
    то, что выводится в цикле
@endforeach

Цикл for

@for($i = 0; $i < 10; $i++)
    то, что выводится в цикле
@endfor

Цикл while

@while(condition)
    то, что выводится в цикле
@endwhile

Включение другого шаблона
————————————-
Самый прямолинейный просто способ вставить другой шаблон:

@include(file)

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

@include(file, ['var' => $val,...])

А теперь представьте типичную задачку — вам надо вывести шаблон в цикле для каждого элемента массива. Что-то вроде такого:

@if (count($records))
    @foreach ($records as $record)
        @include('record.item', $record)
    @endforeach
@else
    Записей нет
@endif

Так вот, это можно было записать проще:

@each('record.item', $records, 'record', 'record.no-items')

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

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

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

И назовём его к примеру layout.blade.php.
Обратите внимание на инструкцию

@yield('section')

Она указывает куда и какие секции будут вставлены.

Теперь создадим сам файл шаблона

@extends('layouts')
Это мы подключили наш шаблон

@section('title', 'Тут мы задали секцию title')

@section('content')
    <p>
    А тут мы задаём секцию content. 
    Обратите внимание, что эта секция может не поместиться в одну строку
    Поэтому использован другой ситнаксис
    </p>
@endsection

В результате будет подключен шаблон и вставлено содержание секций! Всё работает.

Перечислим ключевые слова, которые работают с секциями

Начать секцию

@section('name') 

Закончить секцию. Тут два равнозначных варианта

@stop
@endsection

Закончить секцию и тут же её показать.

@show 

Это можно делать в базовом шаблоне, в котором можно задать дефолтное содержание секции Например так

@section('content')
     Это дефолтное содержание секции
@show

Если сделать так, то появляются два описания секции — шаблоне конкретной страницы и в общем, базовом шаблоне. Это даёт неоднозначность в ожидаемом поведении. Что должно произойти, если определены оба? Частное должно перекрыть общее? Или дополнить?

В древнем манускрипте я нашёл старые заклинания
В старой документации я нашёл ключевые слова

@append 
Закрыть секцию и добавить её содержимое к предыдущей секции с таким же именем
@overwrite
Закрыть секцию и перезаписать предыдующую секцию с таким же именем

Но эти слова в Laravel 5.3 не работают. Секция просто закрывается и содержимое переписывается. Чтобы сохранить значение предыдущей секции надо использовать ключевое слово

@parent

При чём предыдущее значение секции можно оставить в начале, можно задвинуть в конец или середину

@section('content')
   Новое содержимое секции
@parent
   продоление нового содержимого секции
@stop

Резюме
———————————————
Мне кажется, этим постом я закрыл 99% случаев использования Blade. По мере обнаружения ошибок и чего-то важного этот пост может незначительно корректироваться.

Если я что-то забыл или напутал — пишите.