Шаблоны Twig
До сих пор HTML собирался строками внутри действий. Это неудобно и опасно: легко забыть обезвредить чужой текст. Шаблон — отдельный файл с разметкой, в который действие передаёт данные. В Slim шаблонизатора нет; обычно подключают Twig.
Установка
composer require slim/twig-viewГде лежат шаблоны
Создайте вручную папку templates в корне проекта — рядом с config и src. Файлы шаблонов имеют расширение .twig.
Twig в контейнере
Объект шаблонизатора описывают в config/container.php, чтобы действия получали его через конструктор:
// config/container.php
use Slim\Views\Twig;
return [
// ... прежние записи
Twig::class => fn () => Twig::create(__DIR__ . '/../templates', ['cache' => false]),
];Первый аргумент — папка с шаблонами. Кеш пока выключен; его включают при размещении на сервере.
Затем добавьте посредник пакета в config/middleware.php, выше трёх встроенных:
// config/middleware.php
use Slim\Views\Twig;
use Slim\Views\TwigMiddleware;
$app->add(TwigMiddleware::createFromContainer($app, Twig::class));Посредник нужен, чтобы в шаблонах работали функции для ссылок на маршруты.
Первый шаблон
{# templates/home.twig #}
<h1>{{ title }}</h1>
<p>Сайт работает на Slim.</p>Двойные фигурные скобки выводят значение переменной. Первая строка — комментарий Twig, на страницу он не попадает.
Вывод из действия
// src/Action/HomeAction.php
namespace App\Action;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Views\Twig;
final class HomeAction
{
public function __construct(private Twig $twig) {}
public function __invoke(Request $request, Response $response): Response
{
return $this->twig->render($response, 'home.twig', [
'title' => 'Мой блог',
]);
}
}Метод render() принимает ответ, имя файла относительно папки templates и массив данных. Он записывает готовую страницу в ответ и возвращает его. Описание HomeAction::class из урока о настройках удалите из config/container.php: теперь действие создаётся автосвязыванием. Откройте главную страницу — на ней заголовок «Мой блог».
Синтаксис Twig
| Запись | Назначение |
|---|---|
{{ title }} | Вывести значение |
{{ post.title }} | Элемент массива или свойство объекта |
{% if ... %}, {% for ... %} | Условие и цикл |
{# ... #} | Комментарий |
Список в шаблоне
Перенесём в шаблон список статей. Создайте папку templates/posts и файл в ней:
{# templates/posts/index.twig #}
<h1>Статьи</h1>
{% for post in posts %}
<p>{{ post.title }}</p>
{% else %}
<p>Статей пока нет.</p>
{% endfor %}// src/Action/ListPostsAction.php
public function __invoke(Request $request, Response $response): Response
{
return $this->twig->render($response, 'posts/index.twig', [
'posts' => $this->posts->all(),
]);
}В конструктор действия добавляется private Twig $twig. По адресу /posts появится список; ветка else у цикла сработает, если массив пуст.
Частая ошибка
Twig сам обезвреживает HTML в выводимых значениях — это защита от чужих скриптов. Фильтр raw её отключает: {{ comment.text|raw }} выведет чужой тег <script> как есть. Применяйте raw только к разметке, которую создали сами.