Blade: директива для отображения выбранного пункта в списке

Blade директива selectedWhen

Что касается моей работы с HTML и PHP, то чаще всего я работаю со списками (select). Кто не помнит, то это тег, отображающий выпадающий список с возможностью выбора пунктов.

<select id="category-list">
    <option value="sports">Sports</option>
    <option value="politics">Politics</option>
    <option value="entertainment">Entertainment</option>
    <option value="technology">Technology</option>
</select>

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

Редактирование Podcast

Когда один из редакторов решает отредактировать подкаст, то ему показывается HTML-форма с кучей input’ов. Каждый из них заполняется свойствами подкаста, такими как title, abstract, tags и category.

Category выбирается из списка, кодом, который я показал выше. Например, подкаст может принадлежать к категории «Спорт». Это позволит подкасту появляться на сайте в разделе «Спорт».

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

<select id="category-list">
  <option value="sports"
     @if($article->category === 'sports') selected @endif>
       Sports</option>
  <option value="politics"
     @if($article->category === 'politics') selected @endif>
       Politics</option>
  <option value="entertainment"
     @if($article->category === 'entertainment') selected @endif>
       Entertainment</option>
  <option value="technology"
     @if($article->category === 'technology') selected @endif>
       Technology</option>
</select>

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

Директива selectedWhen

Наша новая blade-директива будет отвечать за две вещи: вывод value и добавление свойства selected, если значение равно тому, что мы передаем. Итак, эта директива будет принимать два аргумента.

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

<select id="category-list">
  <option @selectedWhen('sports', $article->category)>
    Sports</option>
  <option @selectedWhen('politics', $article->category)>
    Politics</option>
  <option @selectedWhen('entertainment', $article->category)>
    Entertainment</option>
  <option @selectedWhen('technology', $article->category)>
    Technology</option>
</select>

Хорошо, директива будет очень простой: мы выдаем значение, затем сравниваемое значение, и все. Значение будет напечатано в любом случае, но, если оба значения равны, то в опцию добавится selected.

Теперь нужно создать директиву.

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

Для начала очистим скомпилированные шаблоны командой php artisan view:clear

Дело в том, что каждый раз, когда блейд-шаблон компилируется, он кэшируется как чистый php-код в хранилище вашего приложения. Если вы что-то измените в шаблоне, то он будет скомпилирован снова. А если вы измените код директивы, то не будет, ведь шаблоны не менялись. Поэтому очистка кэша скомпилированных шаблонов обязательна при каждом изменении кода директив.

Давайте перейдем в AppServiceProvider@boot и зарегистрируем директиву:

Blade::directive('selectedWhen', function ($parameters) {
    dd($parameters); // От этого избавимся позже
});

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

"'sports', $article->category"

Как видите, двойные кавычки означают, что директива получила строку, а не массив из нескольких параметров. Мы можем просто разобрать (explode) строку на параметры.

Blade::directive('selectedWhen', function ($parameters) {
    [$value, $expected] = explode(',', $parameters);
    
    dd([$value, $expected]);
});

Теперь получим:

[
  0 => "'sports'",
  1 => " $article->category"
]

Нужно убрать одинарные кавычки из первого параметра. Можно использовать для этого удобный метод trim() и повторно объявить переменную после разделения. Если вы используете в качестве первого параметра строку без кавычек, то нет проблем, будут обрезаться только кавычки.

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

Blade::directive('selectedWhen', function ($parameters) {
    [$value, $expected] = explode(',', $parameters);
    $value = trim($value, '\'');    
    return "value=\"$value\" <?php if ('$value' === $expected) {
        echo 'selected';
    }";
});

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

Автор: Italo Baeza
Перевод: Алексей Широков

Наш Телеграм-канал — следите за новостями о Laravel.