Fejlesztői eljárások

Telepítés

A Latte telepítésének legjobb módja a Composer használata:

composer require latte/latte

Támogatott PHP verziók (a Latte legutolsó alverzióira vonatkozik):

verzió kompatibilis PHP-vel
Latte 3.0 PHP 8.0 – 8.2

Hogyan rendereljünk sablont

Hogyan rendereljünk sablont? Ehhez elég ez az egyszerű kód:

$latte = new Latte\Engine;
// könyvtár a gyorsítótárhoz
$latte->setTempDirectory('/path/to/tempdir');

$params = [ /* sablon változók */ ];
// vagy $params = new TemplateParameters(/* ... */);

// rajzolás a kimenetre
$latte->render('template.latte', $params);
// rajzolás változóba
$output = $latte->renderToString('template.latte', $params);

A paraméterek lehetnek tömbök vagy még jobb egy objektum, amely biztosítja a típusellenőrzést és a súgást a szerkesztőkben.

Használati példákat a Latte examples repozitóriumban is találhat.

Teljesítmény és gyorsítótár

A Latte sablonok rendkívül gyorsak, mivel a Latte közvetlenül PHP kódra fordítja őket, és a lemezen lévő gyorsítótárban tárolja. Így nincs többlet terhelésük a tiszta PHP-ban írt sablonokhoz képest.

A gyorsítótár automatikusan újragenerálódik minden alkalommal, amikor megváltoztatja a forrásfájlt. Így a fejlesztés során kényelmesen szerkesztheti a Latte sablonokat, és a változásokat azonnal láthatja a böngészőben. Ezt a funkciót a produkciós környezetben kikapcsolhatja, hogy egy kis teljesítményt spóroljon:

$latte->setAutoRefresh(false);

A produkciós szerverre történő telepítéskor a gyorsítótár kezdeti generálása, különösen nagyobb alkalmazások esetén, természetesen eltarthat egy ideig. A Latte beépített védelemmel rendelkezik a cache stampede ellen. Ez egy olyan helyzet, amikor nagyobb számú párhuzamos kérés érkezik, amelyek elindítják a Latte-t, és mivel a gyorsítótár még nem létezik, mindegyik egyszerre kezdené el generálni. Ez aránytalanul megterhelné a szervert. A Latte okos, és több párhuzamos kérés esetén csak az első szál generálja a gyorsítótárat, a többiek várnak, majd azt használják.

Paraméterek osztályként

Jobb, mint a változókat tömbként átadni a sablonnak, ha létrehozunk egy osztályt. Így típusbiztos írást, kellemes súgást az IDE-ben és utat kapunk a szűrők és függvények regisztrálásához.

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,
));

Változó automatikus escapelésének kikapcsolása

Ha egy változó HTML stringet tartalmaz, megjelölheti úgy, hogy a Latte ne escapelje automatikusan (és így duplán). Ezzel elkerülheti a |noescape használatának szükségességét a sablonban.

A legegyszerűbb módja, ha a stringet egy Latte\Runtime\Html objektumba csomagolja:

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

A Latte továbbá nem escapeli az összes olyan objektumot, amely implementálja a Latte\HtmlStringable interfészt. Így létrehozhat saját osztályt, amelynek __toString() metódusa olyan HTML kódot ad vissza, amely nem lesz automatikusan escapelve:

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'),
];

A __toString metódusnak korrekt HTML-t kell visszaadnia, és biztosítania kell a paraméterek escapelését, különben XSS sebezhetőség léphet fel!

Hogyan bővítsük a Latte-t szűrőkkel, tagekkel stb.

Hogyan adjunk hozzá saját szűrőt, függvényt, taget stb. a Latte-hoz? Erről szól a Latte bővítése fejezet. Ha a módosításait különböző projektekben szeretné újra felhasználni, vagy megosztani másokkal, akkor hozzon létre egy kiterjesztést.

Tetszőleges kód a sablonban {php ...}

A {do} tag belsejében csak PHP kifejezéseket lehet írni, így például nem illeszthet be olyan konstrukciókat, mint if ... else vagy pontosvesszővel lezárt utasításokat.

Azonban regisztrálhatja a RawPhpExtension kiterjesztést, amely hozzáadja a {php ...} taget. Ezzel bármilyen PHP kódot beilleszthet. Rá nem vonatkoznak a sandbox mód szabályai, így a használata a sablon szerzőjének felelőssége.

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

Generált kód ellenőrzése

A Latte a sablonokat PHP kódra fordítja. Természetesen ügyel arra, hogy a generált kód szintaktikailag érvényes legyen. Azonban harmadik féltől származó kiterjesztések vagy a RawPhpExtension használata esetén a Latte nem tudja garantálni a generált fájl helyességét. Továbbá PHP-ban lehet olyan kódot írni, amely bár szintaktikailag helyes, de tiltott (például érték hozzárendelése a $this változóhoz), és PHP Compile Errort okoz. Ha ilyen műveletet ír a sablonba, az bekerül a generált PHP kódba is. Mivel a PHP-ban több mint kétszáz különböző tiltott művelet létezik, a Latte-nak nincs ambíciója ezeket felderíteni. Ezekre csak maga a PHP hívja fel a figyelmet a rendereléskor, ami általában nem okoz problémát.

Vannak azonban helyzetek, amikor már a sablon fordításakor tudni szeretné, hogy nem tartalmaz PHP Compile Errort. Különösen akkor, ha a sablonokat a felhasználók szerkeszthetik, vagy Sandboxot használ. Ebben az esetben ellenőriztesse a sablonokat már a fordításkor. Ezt a funkcionalitást az Engine::enablePhpLint() metódussal kapcsolhatja be. Mivel az ellenőrzéshez PHP bináris fájlt kell hívnia, adja át annak elérési útját paraméterként:

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

try {
	$latte->compile('home.latte');
} catch (Latte\CompileException $e) {
	// elkapja a Latte hibáit és a PHP Compile Error-t is
	echo 'Hiba: ' . $e->getMessage();
}

Nemzeti beállítások

A Latte lehetővé teszi a nemzeti beállítások megadását, amelyek befolyásolják a számok, dátumok formázását és a rendezést. Ezt a setLocale() metódussal állíthatja be. A környezet azonosítója az IETF language tag szabványt követi, amelyet a PHP intl kiterjesztése használ. A nyelv kódjából és adott esetben az ország kódjából áll, pl. en_US az angolhoz az Egyesült Államokban, de_DE a némethez Németországban stb.

$latte = new Latte\Engine;
$latte->setLocale('hu');

A környezet beállítása befolyásolja a localDate, sort, number és bytes szűrőket.

Szükséges a PHP intl kiterjesztés. A Latte beállítása nem befolyásolja a PHP globális locale beállításait.

Szigorú mód

Szigorú parzolási módban a Latte ellenőrzi, hogy hiányoznak-e a záró HTML tagek, és letiltja a $this változó használatát is. Így kapcsolhatja be:

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

A sablonok generálását declare(strict_types=1) fejléccel így kapcsolhatja be:

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

Fordítás sablonokban

A TranslatorExtension kiterjesztés segítségével hozzáadhatja a sablonhoz a {_...}, {translate} tageket és a translate szűrőt. Ezek értékek vagy sablonrészek más nyelvekre történő fordítására szolgálnak. Paraméterként megadjuk a fordítást végző metódust (PHP callable):

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

	public function translate(string $original): string
	{
		// az $original alapján létrehozzuk a $translated-et a $this->lang szerint
		return $translated;
	}
}

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

A fordító futásidőben hívódik meg a sablon renderelésekor. A Latte azonban képes az összes statikus szöveget már a sablon fordítása során lefordítani. Ezzel teljesítményt takarítunk meg, mivel minden string csak egyszer fordítódik le, és az eredményül kapott fordítás beíródik a lefordított formába. Így a gyorsítótár könyvtárában több lefordított sablonverzió jön létre, minden nyelvhez egy. Ehhez elég csak a nyelvet megadni második paraméterként:

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

Statikus szöveg alatt például a {_'hello'} vagy {translate}hello{/translate} értendő. A nem statikus szövegek, mint például {_$foo}, továbbra is futásidőben kerülnek fordításra.

A fordítónak a sablonból kiegészítő paramétereket is átadhatunk a {_$original, foo: bar} vagy {translate foo: bar} segítségével, amelyeket $params tömbként kap meg:

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

Debuggolás és Tracy

A Latte igyekszik a fejlesztést a lehető legkellemesebbé tenni. Közvetlenül a debuggolás céljára létezik három tag: {dump}, {debugbreak} és {trace}.

A legnagyobb kényelmet akkor éri el, ha még telepíti a kiváló Tracy hibakereső eszközt és aktiválja a Latte kiegészítőt:

// bekapcsolja a Tracy-t
Tracy\Debugger::enable();

$latte = new Latte\Engine;
// aktiválja a Tracy kiterjesztést
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);

Mostantól minden hiba áttekinthető piros képernyőn jelenik meg, beleértve a sablonhibákat is a sor és oszlop kiemelésével (videó). Ugyanakkor a jobb alsó sarokban, az ún. Tracy Barban megjelenik egy fül a Latte számára, ahol áttekinthetően láthatók az összes renderelt sablon és azok kölcsönös kapcsolatai (beleértve a sablonba vagy a lefordított kódba való átkattintás lehetőségét is), valamint a változók:

Mivel a Latte a sablonokat áttekinthető PHP kódra fordítja, kényelmesen lépésenként végigkövetheti őket az IDE-jében.

Linter: sablonok szintaxisának validálása

Az összes sablon átnézéséhez és annak ellenőrzéséhez, hogy nem tartalmaznak-e szintaktikai hibákat, a Linter eszköz segít. Konzolból indítható:

vendor/bin/latte-lint <útvonal>

A --strict paraméterrel aktiválhatja a szigorú módot.

Ha saját tageket használ, hozzon létre saját Linter verziót is, pl. custom-latte-lint:

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

// adja meg az autoload.php fájl tényleges elérési útját
require __DIR__ . '/vendor/autoload.php';

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

$linter = new Latte\Tools\Linter;
$latte = $linter->getEngine();
// itt adja hozzá az egyes saját kiterjesztéseit
$latte->addExtension(/* ... */);

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

Alternatívaként átadhatja a saját Latte\Engine objektumát a Linternek:

$latte = new Latte\Engine;
// itt konfiguráljuk a $latte objektumot
$linter = new Latte\Tools\Linter(engine: $latte);

Sablonok betöltése stringből

Szüksége van sablonok betöltésére stringekből fájlok helyett, például tesztelési célokra? Segít a 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

Definiálhat saját kezelőt a várt kivételekhez. Átadódnak neki a {try} belsejében és a sandboxban keletkezett kivételek.

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

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

Layout automatikus keresése

A {layout} tag segítségével a sablon meghatározza a szülő sablonját. Lehetőség van a layout automatikus keresésére is, ami leegyszerűsíti a sablonok írását, mivel nem lesz szükség bennük a {layout} tag megadására.

Ezt a következő módon érhetjük el:

$finder = function (Latte\Runtime\Template $template) {
	if (!$template->getReferenceType()) {
		// visszaadja a layout fájl elérési útját
		return 'automatic.layout.latte';
	}
};

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

Ha a sablonnak nem kell layout, azt a {layout none} taggal jelzi.

verzió: 3.0