Загрузчики шаблонов

Загрузчики – это механизм, который Latte использует для получения исходного кода ваших шаблонов. Чаще всего шаблоны представляют собой файлы, хранящиеся на диске, но гибкая система загрузчиков Latte позволяет загружать их практически из любого места или даже генерировать их динамически.

Что такое загрузчик?

Обычно, когда вы работаете с шаблонами, вы думаете о файлах .latte, расположенных в структуре каталогов вашего проекта. За это отвечает стандартный загрузчик файлов 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 ниже:Включенное содержимое: 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\RuntimeException.

public function getContent(string $name): string
{
	// Пример: Выборка из гипотетического внутреннего хранилища
	$content = $this->storage->read($name);
	if ($content === null) {
		throw new Latte\RuntimeException("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\RuntimeException("Template '$name' not found in database.");
		}
		return $content;
	}

	// В этом простом примере предполагается, что имена шаблонов ("главная страница", "статья" и т. д.)
	// являются уникальными идентификаторами, и шаблоны не ссылаются друг на друга относительно.
	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, что позволяет интегрировать их с различными системами хранения и рабочими процессами.

версия: 3.0