Loadery
Loadery to mechanizm, za pomocą którego Latte pobiera kod źródłowy Twoich szablonów. Najczęściej szablony są plikami na dysku, ale elastyczny system loaderów w Latte pozwala wczytywać je praktycznie skądkolwiek, a nawet generować je dynamicznie.
Czym jest loader?
Zwykle, pracując z szablonami, myślisz o plikach .latte leżących w strukturze katalogów Twojego projektu.
Zajmuje się tym domyślny FileLoader Latte. Powiązanie między nazwą szablonu (jak
'main.latte' czy 'components/card.latte') a jego rzeczywistym kodem źródłowym nie musi
jednak być bezpośrednim odwzorowaniem na ścieżkę pliku.
I tu wkraczają loadery. Loader to obiekt odpowiedzialny za to, aby na podstawie nazwy szablonu (łańcucha identyfikującego)
dostarczyć Latte jego kod źródłowy. Latte polega w tym zadaniu całkowicie na skonfigurowanym loaderze. Dotyczy to nie tylko
początkowego szablonu żądanego przez $latte->render('main.latte'), ale też każdego szablonu
przywoływanego wewnątrz tagami takimi jak {include ...}, {layout ...}, {embed ...}
czy {import ...}.
Po co własny loader?
- Wczytywanie z innych źródeł: pobieranie szablonów przechowywanych w bazie danych, w cache (jak Redis czy Memcached), w systemie kontroli wersji (jak Git, na podstawie konkretnego commita) albo generowanych dynamicznie.
- Wprowadzenie własnych konwencji nazewniczych: możesz chcieć używać krótszych aliasów szablonów albo zaimplementować własną logikę wyszukiwania ścieżek (np. najpierw szukać w katalogu motywu, a potem sięgnąć do katalogu domyślnego).
- Dodanie zabezpieczeń lub kontroli dostępu: własny loader mógłby przed wczytaniem pewnych szablonów sprawdzać uprawnienia użytkownika.
- Wstępne przetwarzanie: choć ogólnie się to odradza (compiler passy są lepsze), loader mógłby teoretycznie wstępnie przetworzyć treść szablonu, zanim przekaże ją Latte.
Loader dla instancji Latte\Engine ustawiasz metodą setLoader():
$latte = new Latte\Engine;
// używamy domyślnego FileLoadera dla plików w '/path/to/templates'
$loader = new Latte\Loaders\FileLoader('/path/to/templates');
$latte->setLoader($loader);
Loader musi implementować interfejs Latte\Loader.
Wbudowane loadery
Latte oferuje kilka standardowych loaderów:
FileLoader
To domyślny loader używany przez klasę Latte\Engine, jeśli nie podano innego. Wczytuje szablony
bezpośrednio z systemu plików.
Opcjonalnie możesz ustawić katalog główny, aby ograniczyć dostęp:
use Latte\Loaders\FileLoader;
// poniższe pozwoli wczytywać szablony tylko z katalogu /var/www/html/templates
$loader = new FileLoader('/var/www/html/templates');
$latte->setLoader($loader);
// $latte->render('../../../etc/passwd'); // to zgłosiłoby wyjątek
// renderowanie szablonu leżącego w /var/www/html/templates/pages/contact.latte
$latte->render('pages/contact.latte');
Przy użyciu tagów takich jak {include} czy {layout} rozwiązuje nazwy szablonów względem
bieżącego szablonu, o ile nie podano ścieżki bezwzględnej. Jeśli jednak ustawiono katalog główny, wszystkie nazwy są
rozwiązywane względem bieżącego szablonu.
StringLoader
Ten loader pobiera treść szablonów z tablicy asocjacyjnej, w której kluczami są nazwy szablonów (identyfikatory), a wartościami łańcuchy z kodem źródłowym szablonu. Przydaje się zwłaszcza przy testach albo w niewielkich aplikacjach, w których szablony mogą być przechowywane bezpośrednio w kodzie 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}',
// w razie potrzeby dodaj kolejne szablony
]);
$latte->setLoader($loader);
$latte->render('main.latte', ['name' => 'World']);
// wynik: Hello World, include is below:Included content: 10
Jeśli potrzebujesz wyrenderować tylko jeden szablon bezpośrednio z łańcucha, bez includów ani dziedziczenia
odwołującego się do innych nazwanych szablonów tekstowych, możesz przy użyciu StringLoader bez tablicy
przekazać łańcuch bezpośrednio do metody render() albo renderToString():
$loader = new StringLoader;
$latte->setLoader($loader);
$templateString = 'Hello {$name}!';
$output = $latte->renderToString($templateString, ['name' => 'Alice']);
// $output zawiera 'Hello Alice!'
Tworzenie własnego loadera
Aby utworzyć własny loader (np. do wczytywania szablonów z bazy danych, cache, systemu kontroli wersji albo innego źródła), musisz stworzyć klasę implementującą interfejs Latte\Loader.
Zobaczmy, co ma robić każda z metod.
getContent (string $name): string
To główna metoda loadera. Jej zadaniem jest pobranie i zwrócenie pełnego kodu źródłowego szablonu identyfikowanego
przez $name (przekazanego do metody $latte->render() albo zwróconego przez metodę getReferredName()).
Jeśli szablonu nie da się znaleźć ani do niego sięgnąć, ta metoda musi zgłosić
Latte\TemplateNotFoundException.
public function getContent(string $name): string
{
// przykład: wczytanie z hipotetycznego magazynu wewnętrznego
$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
Ta metoda obsługuje rozwiązywanie nazw szablonów używanych w tagach takich jak {include},
{layout} itd. Gdy Latte napotka na przykład {include 'partial.latte'} wewnątrz
main.latte, wywoła tę metodę z $name = 'partial.latte' i
$referringName = 'main.latte'.
Zadaniem metody jest rozwiązanie $name w kanoniczny identyfikator (np. ścieżkę bezwzględną, unikalny klucz w
bazie danych), który zostanie użyty przy wywoływaniu pozostałych metod loadera, na podstawie kontekstu podanego w
$referringName.
public function getReferredName(string $name, string $referringName): string
{
return ...;
}
getUniqueId (string $name): string
Dla poprawy wydajności Latte korzysta z cache skompilowanych szablonów. Każdy plik skompilowanego szablonu potrzebuje
unikalnej nazwy wyprowadzonej z identyfikatora szablonu źródłowego. Ta metoda dostarcza łańcuch, który jednoznacznie
identyfikuje szablon $name.
Dla szablonów opartych na plikach może do tego posłużyć ścieżka bezwzględna. Dla szablonów w bazie danych typowa jest kombinacja prefiksu i identyfikatora w bazie.
public function getUniqueId(string $name): string
{
return ...;
}
Przykład: prosty loader bazodanowy
Ten przykład pokazuje podstawową strukturę loadera wczytującego szablony przechowywane w tabeli bazy danych
templates z kolumnami name (unikalny identyfikator), content i
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;
}
// ten prosty przykład zakłada, że nazwy szablonów ('homepage', 'article' itd.)
// są unikalnymi ID i że szablony nie odwołują się do siebie względnie
public function getReferredName(string $name, string $referringName): string
{
return $name;
}
public function getUniqueId(string $name): string
{
// prefiks razem z samą nazwą jest tu unikalny i wystarczający
return 'db_' . $name;
}
}
// użycie:
$pdo = new \PDO(/* connection details */);
$loader = new DatabaseLoader($pdo);
$latte->setLoader($loader);
$latte->render('homepage'); // wczyta z bazy szablon o nazwie 'homepage'
Własne loadery dają Ci pełną kontrolę nad tym, skąd pochodzą Twoje szablony Latte, i pozwalają na integrację z rozmaitymi systemami magazynowania i sposobami pracy.