Vývojářské postupy

Instalace

Nejlepší způsob, jak nainstalovat Latte, je pomocí Composeru:

composer require latte/latte

Podporované verze PHP (platí pro poslední setinkové verze Latte):

verze kompatibilní s PHP
Latte 3.0 PHP 8.0 – 8.2

Jak vykreslit šablonu

Jak vykreslit šablonu? Stačí k tomu tento jednoduchý kód:

$latte = new Latte\Engine;
// adresář pro cache
$latte->setTempDirectory('/path/to/tempdir');

$params = [ /* proměnné šablony */ ];
// or $params = new TemplateParameters(/* ... */);

// kresli na výstup
$latte->render('template.latte', $params);
// kresli do proměnné
$output = $latte->renderToString('template.latte', $params);

Parametry mohou být pole nebo ještě lépe objekt, který zajistí typovou kontrolu a napovídání v editorech.

Ukázky použití najdete také v repozitáři Latte examples.

Výkon a cache

Šablony v Latte jsou nesmírně rychlé, Latte je totiž kompiluje přímo do PHP kódu a ukládá do cache na disk. Nemají tedy žádnou režii navíc oproti šablonám psaným v čistém PHP.

Cache se automaticky regeneruje pokaždé, když změníte zdrojový soubor. Během vývoje si tedy pohodlně editujete šablony v Latte a změny okamžitě vidíte v prohlížeči. Tuto funkci můžete v produkčním prostředí vypnout a ušetřit tím malinko výkonu:

$latte->setAutoRefresh(false);

Při nasazení na produkčním serveru může prvotní vygenerování cache, zejména u rozsáhlejších aplikací, pochopitelně chviličku trvat. Latte má vestavěnou prevenci před cache stampede. Jde o situaci, kdy se sejde větší počet souběžných požadavků, které spustí Latte, a protože cache ještě neexistuje, začaly by ji všechny generovat současně. Což by neúměrně zatížilo server. Latte je chytré a při více souběžných požadavcích generuje cache pouze první vlákno, ostatní čekají a následně ji využíjí.

Parametry jako třída

Lepší než předávat proměnné do šablony jako pole je vytvořit si třídu. Získáte tak typově bezpečný zápis, příjemné napovídání v IDE a cestu pro registraci filtrů a funkcí.

class MailTemplateParameters
{
	public function __construct(
		public string $lang,
		public Address $address,
		public string $subject,
		public array $items,
		public ?float $price = null,
	) {}
}

$latte->render('mail.latte', new MailTemplateParameters(
	lang: $this->lang,
	subject: $title,
	price: $this->getPrice(),
	items: [],
	address: $userAddress,
));

Vypnutí auto-escapování proměnné

Pokud proměnná obsahuje řetězec v HTML, můžete ji označit tak, aby ji Latte automaticky (a tedy dvojitě) neescapovalo. Vyhnete se tak potřebě uvádět v šabloně |noescape.

Nejjednodušší cestou je řetězec zabalit do objektu Latte\Runtime\Html:

$params = [
	'articleBody' => new Latte\Runtime\Html($article->htmlBody),
];

Latte dále neescapuje všechny objekty, které implementují rozhraní Latte\HtmlStringable. Můžete si tak vytvořit vlastní třídu, jejíž metoda __toString() bude vracet HTML kód, který se nebude automaticky escapovat:

class Emphasis extends Latte\HtmlStringable
{
	public function __construct(
		private string $str,
	) {
	}

	public function __toString(): string
	{
		return '<em>' . htmlspecialchars($this->str) . '</em>';
	}
}

$params = [
	'foo' => new Emphasis('hello'),
];

Metoda __toString musí vracet korektní HTML a zajistit escapování parametrů, jinak může dojít ke zranitelnosti XSS!

Jak rozšířit Latte o filtry, značky atd.

Jak do Latte přidat vlastní filtr, funkci, značku atd? O tom pojednává kapitola rozšiřujeme Latte. Pokud chcete své úpravy znovu použít v různých projektech nebo je sdílet s ostatními, měli byste vytvořit rozšíření.

Libovolný kód v šabloně {php ...}

Uvnitř značky {do} lze zapisovat pouze PHP výrazy, nemůžete tak třeba vložit konstrukce jako if ... else nebo statementy ukončené středníkem.

Můžete si však zaregistrovat rozšíření RawPhpExtension, které přidává značku {php ...}. Pomocí té lze vkládat jakýkoliv PHP kód. Nevztahují se na něj žádná pravidla sandbox režimu, použití je tedy na zodpovědnost autora šablony.

$latte->addExtension(new Latte\Essential\RawPhpExtension);

Kontrola vygenerovaného kódu

Latte kompiluje šablony do PHP kódu. Samozřejmě dbá na to, aby vygenerovaný kód byl syntakticky validní. Nicméně při použítí rozšíření třetích stran nebo RawPhpExtension nemůže Latte zaručit správnost vygenerovaného souboru. Také lze v PHP zapsat kód, který je sice syntakticky správný, ale je zakázaný (například přiřazení hodnoty do proměnné $this) a způsobí PHP Compile Error. Pokud takovou operaci zapíšete v šabloně, dostane se i do vygenerovaného PHP kódu. Jelikož v PHP existují na dvě stovky různých zakázaných operací, nemá Latte ambici je odhalovat. Upozorní na ně až samotné PHP při vykreslení, což obvykle ničemu nevadí.

Jsou ale situace, kdy chcete vědět už v době kompilace šablony, že žádný PHP Compile Error neobsahuje. Zejména tehdy, pokud šablony mohou editovat uživatelé, nebo používáte Sandbox. V takovém případě si nechte šablony kontrolovat už v době kompilace. Tuto funkčnost zapnete metodou Engine::enablePhpLint(). Jelikož ke kontrole potřebuje volat binárku PHP, cestu k ní předejte jako parametr:

$latte = new Latte\Engine;
$latte->enablePhpLinter('/path/to/php');

try {
	$latte->compile('home.latte');
} catch (Latte\CompileException $e) {
	// zachytí chyby v Latte a také Compile Error v PHP
	echo 'Error: ' . $e->getMessage();
}

Striktní režim

Ve striktním režimu parsování Latte kontroluje, zda nechybí uzavírací HTML značky a také zakazuje používání proměnné $this. Zapnete jej takto:

$latte = new Latte\Engine;
$latte->setStrictParsing();

Generování šablon s hlavičkou declare(strict_types=1) zapnete takto:

$latte = new Latte\Engine;
$latte->setStrictTypes();

Překládání v šablonách

Pomocí rozšíření TranslatorExtension přidáte do šablony značky {_...}, {translate} a filtr translate. Slouží k překládání hodnot nebo částí šablony do jiných jazyků. Jako parametr uvedeme metodu (PHP callable) provádějící překlad:

class MyTranslator
{
	public function __construct(private string $lang)
	{}

	public function translate(string $original): string
	{
		// z $original vytvoříme $translated dle $this->lang
		return $translated;
	}
}

$translator = new MyTranslator($lang);
$extension = new Latte\Essential\TranslatorExtension(
	$translator->translate(...), // [$translator, 'translate'] v PHP 8.0
);
$latte->addExtension($extension);

Translator se volá za běhu při vykreslování šablony. Latte ovšem umí všechny statické texty překládat už během kompilace šablony. Tím se ušetří výkon, protože každý řetězec se přeloží jen jednou a výsledný překlad se zapíše do zkompilované podoby. V adresáři s cache tak vznikne více zkompilovaných verzí šablony, jedna pro každý jazyk. K tomu stačí pouze uvést jazyk jako druhý parametr:

$extension = new Latte\Essential\TranslatorExtension(
	$translator->translate(...),
	$lang,
);

Statickým textem je myšleno třeba {_'hello'} nebo {translate}hello{/translate}. Nestatické texty, jako třeba {_$foo}, se nadále budou překládat za běhu.

Překladači lze ze šablony předávat i doplňující parametry pomocí {_$original, foo: bar} nebo {translate foo: bar}, které získá jako pole $params:

public function translate(string $original, ...$params): string
{
	// $params['foo'] === 'bar'
}

Debuggování a Tracy

Latte se vám snaží vývoj co nejvíce zpříjemnit. Přímo pro účely debugování existuje trojice značek {dump}, {debugbreak} a {trace}.

Největší komfort získáte, když ještě si nainstalujete skvělý ladicí nástroj Tracy a aktivujete doplněk pro Latte:

// zapne Tracy
Tracy\Debugger::enable();

$latte = new Latte\Engine;
// aktivuje rozšíření pro Tracy
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);

Nyní se vám budou všechny chyby zobrazovat v přehledné červené obrazovce, včetně chyb v šablonách se zvýrazněním řádku a sloupce (video). Zároveň v pravém dolním rohu v tzv. Tracy Baru se objeví záložka pro Latte, kde jsou přehledně vidět všechny vykreslované šablony a jejich vzájemné vztahy (včetně možnosti se do šablony nebo zkompilovaného kódu prokliknout) a také proměnné:

Jelikož Latte kompiluje šablony do přehledného PHP kódu, můžete je pohodlně ve svém IDE krokovat.

Linter: validace syntaxe šablon

Projít všechny šablony a zkontrolovat, zda neobsahují syntaktické chyby, vám pomůže nástroj Linter. Spouští se z konzole:

vendor/bin/latte-lint <cesta>

Parametrem --strict aktivujete striktní režim.

Pokud používáte vlastní značky, vytvořte si také vlastní verzi Linteru, např. custom-latte-lint:

#!/usr/bin/env php
<?php

// zadejte skutečnou cestu k soubor autoload.php
require __DIR__ . '/vendor/autoload.php';

$path = $argv[1] ?? '.';

$linter = new Latte\Tools\Linter;
$latte = $linter->getEngine();
// tady přidejte jednotlivá svá rozšíření
$latte->addExtension(/* ... */);

$ok = $linter->scanDirectory($path);
exit($ok ? 0 : 1);

Alternativně můžete vlastní objekt Latte\Engine předat do Linteru:

$latte = new Latte\Engine;
// tady nakonfigurujeme objekt $latte
$linter = new Latte\Tools\Linter(engine: $latte);

Načítání šablon z řetězce

Potřebujete načítat šablony z řetězců místo souborů, třeba pro účely testování? Pomůže vám StringLoader:

$latte->setLoader(new Latte\Loaders\StringLoader([
	'main.file' => '{include other.file}',
	'other.file' => '{if true} {$var} {/if}',
]));

$latte->render('main.file', $params);

Exception handler

Můžete si definovat vlastní obslužný handler pro očekávané výjimky. Předají se mu výjimky vzniklé uvnitř {try} a v sandboxu.

$loggingHandler = function (Throwable $e, Latte\Runtime\Template $template) use ($logger) {
	$logger->log($e);
};

$latte = new Latte\Engine;
$latte->setExceptionHandler($loggingHandler);

Automatické dohledávání layoutu

Pomocí značky {layout} šablona určuje svou rodičovskou šablonu. Je taky možné nechat dohledávat layout automaticky, což zjednoduší psaní šablon, neboť v nich nebude nutné značku {layout} uvádět.

Dosáhne se toho následujícím způsobem:

$finder = function (Latte\Runtime\Template $template) {
	if (!$template->getReferenceType()) {
		// vrací cestu k souboru s layoutem
		return 'automatic.layout.latte';
	}
};

$latte = new Latte\Engine;
$latte->addProvider('coreParentFinder', $finder);

Pokud šablona nemá mít layout, oznámí to značkou {layout none}.

verze: 3.0 2.x