Загрузчики
Загрузчики – это механизм, с помощью которого Latte получает исходный код ваших шаблонов. Чаще всего шаблоны представляют собой файлы на диске, но гибкая система загрузчиков Latte позволяет загружать их практически откуда угодно и даже генерировать динамически.
Что такое загрузчик?
Обычно, работая с шаблонами, вы представляете себе файлы .latte,
лежащие в структуре каталогов вашего проекта. Этим занимается
стандартный FileLoader из состава Latte. Однако связь между
именем шаблона (например, 'main.latte' или 'components/card.latte') и его
настоящим исходным кодом не обязана быть прямым соответствием
пути к файлу.
Вот здесь и вступают в игру загрузчики. Загрузчик – это объект,
который получает имя шаблона (строку-идентификатор) и предоставляет
Latte его исходный код. В этой задаче Latte полностью полагается на
настроенный загрузчик. Это относится не только к исходному шаблону,
запрошенному через $latte->render('main.latte'), но и к каждому шаблону,
на который есть ссылка внутри, через теги вроде {include ...},
{layout ...}, {embed ...} или {import ...}.
Зачем нужен собственный загрузчик?
- Загрузка из других источников: получение шаблонов, хранящихся в базе данных, в кеше (например, Redis или Memcached), в системе контроля версий (например, в Git, по конкретному коммиту) или генерируемых динамически.
- Собственные соглашения об именовании: вы можете захотеть использовать более короткие псевдонимы шаблонов или реализовать особую логику поиска (например, сначала искать в каталоге темы, а потом возвращаться к каталогу по умолчанию).
- Добавление безопасности или контроля доступа: собственный загрузчик может проверять права пользователя перед загрузкой определённых шаблонов.
- Предобработка: хотя это в целом не рекомендуется (проходы компилятора подходят лучше), загрузчик теоретически может предобработать содержимое шаблона, прежде чем передать его Latte.
Загрузчик для экземпляра Latte\Engine устанавливается методом
setLoader():
$latte = new Latte\Engine;
// Используем стандартный FileLoader для файлов в '/path/to/templates'
$loader = new Latte\Loaders\FileLoader('/path/to/templates');
$latte->setLoader($loader);
Загрузчик должен реализовывать интерфейс Latte\Loader.
Встроенные загрузчики
Latte предлагает несколько стандартных загрузчиков:
FileLoader
Это загрузчик по умолчанию, который использует класс
Latte\Engine, если не указан другой. Он загружает шаблоны прямо из
файловой системы.
При желании можно задать корневой каталог, чтобы ограничить доступ:
use Latte\Loaders\FileLoader;
// Следующий код разрешит загружать шаблоны только из каталога /var/www/html/templates
$loader = new FileLoader('/var/www/html/templates');
$latte->setLoader($loader);
// $latte->render('../../../etc/passwd'); // Это выбросило бы исключение
// Отрисовка шаблона, расположенного в /var/www/html/templates/pages/contact.latte
$latte->render('pages/contact.latte');
При использовании тегов вроде {include} или {layout} он
разрешает имена шаблонов относительно текущего шаблона, если не
указан абсолютный путь. Однако, если задан корневой каталог, все имена
разрешаются относительно текущего шаблона.
StringLoader
Этот загрузчик получает содержимое шаблонов из ассоциативного массива, где ключи – это имена (идентификаторы) шаблонов, а значения – строки с их исходным кодом. Он особенно удобен для тестирования или небольших приложений, где шаблоны могут храниться прямо в PHP-коде.
use Latte\Loaders\StringLoader;
$loader = new StringLoader([
'main.latte' => 'Hello {$name}, include is below:{include helper.latte}',
'helper.latte' => '{var $x = 10}Included content: {$x}',
// Добавьте столько шаблонов, сколько нужно
]);
$latte->setLoader($loader);
$latte->render('main.latte', ['name' => 'World']);
// Вывод: Hello World, include is below:Included content: 10
Если вам нужно отрисовать всего один шаблон прямо из строки и при
этом не нужны подключения или наследование со ссылками на другие
именованные строковые шаблоны, вы можете передать строку прямо в метод
render() или renderToString(), используя StringLoader без
массива:
$loader = new StringLoader;
$latte->setLoader($loader);
$templateString = 'Hello {$name}!';
$output = $latte->renderToString($templateString, ['name' => 'Alice']);
// $output содержит 'Hello Alice!'
Создание собственного загрузчика
Чтобы создать свой загрузчик (например, для загрузки шаблонов из базы данных, кеша, системы контроля версий или другого источника), нужно создать класс, реализующий интерфейс Latte\Loader.
Посмотрим, что должен делать каждый метод.
getContent (string $name): string
Это основной метод загрузчика. Его задача – получить и вернуть
полный исходный код шаблона, обозначенного именем $name (в том
виде, в каком оно передано в метод $latte->render() или возвращено
методом getReferredName()).
Если шаблон не удаётся найти или получить к нему доступ, этот метод
должен выбросить исключение Latte\TemplateNotFoundException.
public function getContent(string $name): string
{
// Пример: загрузка из гипотетического внутреннего хранилища
$content = $this->storage->read($name);
if ($content === null) {
throw new Latte\TemplateNotFoundException("Template '$name' cannot be loaded.");
}
return $content;
}
getReferredName (string $name, string $referringName): string
Этот метод отвечает за разрешение имён шаблонов, используемых внутри
тегов вроде {include}, {layout} и так далее. Когда Latte встречает,
например, {include 'partial.latte'} внутри main.latte, он вызывает этот
метод с $name = 'partial.latte' и $referringName = 'main.latte'.
Задача метода – разрешить $name в канонический идентификатор
(например, абсолютный путь или уникальный ключ в базе данных), который
будет использоваться при вызове остальных методов загрузчика,
опираясь на контекст из $referringName.
public function getReferredName(string $name, string $referringName): string
{
return ...;
}
getUniqueId (string $name): string
Для повышения производительности Latte использует кеш
скомпилированных шаблонов. Каждому файлу скомпилированного шаблона
нужно уникальное имя, производное от идентификатора исходного
шаблона. Этот метод возвращает строку, которая однозначно
определяет шаблон $name.
Для файловых шаблонов для этого годится абсолютный путь. Для шаблонов в базе данных обычно используется сочетание префикса и идентификатора записи.
public function getUniqueId(string $name): string
{
return ...;
}
Пример: простой загрузчик из базы данных
Этот пример показывает базовую структуру загрузчика, который берёт
шаблоны из таблицы базы данных templates со столбцами name
(уникальный идентификатор), content и updated_at.
use Latte;
class DatabaseLoader implements Latte\Loader
{
public function __construct(
private \PDO $db,
) {
}
public function getContent(string $name): string
{
$stmt = $this->db->prepare('SELECT content FROM templates WHERE name = ?');
$stmt->execute([$name]);
$content = $stmt->fetchColumn();
if ($content === false) {
throw new Latte\TemplateNotFoundException("Template '$name' not found in database.");
}
return $content;
}
// В этом простом примере предполагается, что имена шаблонов ('homepage', 'article' и т. д.)
// уникальны и шаблоны не ссылаются друг на друга относительными путями.
public function getReferredName(string $name, string $referringName): string
{
return $name;
}
public function getUniqueId(string $name): string
{
// Здесь достаточно префикса и самого имени, это уникально
return 'db_' . $name;
}
}
// Использование:
$pdo = new \PDO(/* connection details */);
$loader = new DatabaseLoader($pdo);
$latte->setLoader($loader);
$latte->render('homepage'); // Загружает шаблон с именем 'homepage' из БД
Собственные загрузчики дают вам полный контроль над тем, откуда берутся шаблоны Latte, и позволяют интегрироваться с самыми разными хранилищами и рабочими процессами.