Podaljšanje Latte
Latte je zelo prilagodljiv in ga je mogoče razširiti na več načinov: dodajate lahko filtre, funkcije, oznake, nalagalnike itd. Pokazali vam bomo, kako to storiti.
V tem poglavju so opisani različni načini razširitve sistema Latte. Če želite svoje spremembe ponovno uporabiti v različnih projektih ali če jih želite deliti z drugimi, morate nato ustvariti tako imenovano razširitev.
Koliko poti vodi v Rim?
Ker se lahko nekateri načini podaljševanja latte mešajo, poskušajmo najprej razložiti razlike med njimi. Kot primer poskusimo implementirati generator Lorem ipsum, ki mu posredujemo število besed za generiranje.
Glavni konstrukt jezika Latte je oznaka. Generator lahko implementiramo tako, da razširimo program Latte z novo značko:
{lipsum 40}
Oznaka bo delovala odlično. Vendar generator v obliki oznake morda ne bo dovolj prilagodljiv, saj ga ne bo mogoče uporabiti v izrazu. Mimogrede, v praksi redko potrebujete generiranje značk; in to je dobra novica, saj so značke bolj zapleten način razširjanja.
Ok, poskusite ustvariti filter namesto oznake:
{=40|lipsum}
Tudi to je veljavna možnost. Toda filter mora posredovano vrednost spremeniti v nekaj drugega. V tem primeru uporabimo
vrednost 40
, ki označuje število ustvarjenih besed, kot argument filtra in ne kot vrednost, ki jo želimo
pretvoriti.
Zato poskusimo uporabiti funkcijo:
{lipsum(40)}
To je to! Za ta primer je ustvarjanje funkcije idealna razširitvena točka, ki jo lahko uporabimo. Pokličete jo lahko povsod, kjer je na primer sprejet izraz:
{var $text = lipsum(40)}
Filtri
Filter ustvarite tako, da registrirate njegovo ime in katerikoli klic PHP, na primer funkcijo:
$latte = new Latte\Engine;
$latte->addFilter('shortify', fn(string $s) => mb_substr($s, 0, 10)); // skrajša besedilo na 10 znakov
V tem primeru bi bilo bolje, če bi filter dobil dodaten parameter:
$latte->addFilter('shortify', fn(string $s, int $len = 10) => mb_substr($s, 0, $len));
Uporabljamo ga v predlogi, kot je ta:
<p>{$text|shortify}</p>
<p>{$text|shortify:100}</p>
Kot lahko vidite, funkcija kot naslednje argumente prejme levo stran filtra pred cevjo |
as the first argument and
the arguments passed to the filter after :
.
Seveda lahko funkcija, ki predstavlja filter, sprejme poljubno število parametrov, podprti pa so tudi variabilni parametri.
Če filter vrne niz HTML, ga lahko označite, da ga Latte ne bo samodejno (in zato dvojno) eskapiral. S tem se izognete
potrebi, da bi v predlogi določili |noescape
. Najlažji način je, da niz zapakirate v objekt
Latte\Runtime\Html
, drugi način pa so kontekstualni filtri.
$latte->addFilter('money', fn(float $amount) => new Latte\Runtime\Html("<i>$amount EUR</i>"));
V tem primeru mora filter zagotoviti pravilno izpisovanje podatkov.
Filtri z uporabo razreda
Drugi način za opredelitev filtra je uporaba
razreda. Ustvarimo metodo z atributom TemplateFilter
:
class TemplateParameters
{
public function __construct(
// parametri
) {}
#[Latte\Attributes\TemplateFilter]
public function shortify(string $s, int $len = 10): string
{
return mb_substr($s, 0, $len);
}
}
$params = new TemplateParameters(/* ... */);
$latte->render('template.latte', $params);
Nalaganje filtrov
Namesto registracije posameznih filtrov lahko ustvarite tako imenovani nalagalnik, ki je funkcija, ki se pokliče z imenom filtra kot argumentom in vrne njegov klicni parameter PHP ali nič.
$latte->addFilterLoader([new Filters, 'load']);
class Filters
{
public function load(string $filter): ?callable
{
if (in_array($filter, get_class_methods($this))) {
return [$this, $filter];
}
return null;
}
public function shortify($s, $len = 10)
{
return mb_substr($s, 0, $len);
}
// ...
}
Kontekstualni filtri
Kontekstualni filter je filter, ki v prvem parametru sprejme predmet Latte\Runtime\FilterInfo, nato pa mu sledijo drugi parametri kot pri klasičnih filtrih. Registrira se na enak način, Latte sam prepozna, da je filter kontekstualen:
use Latte\Runtime\FilterInfo;
$latte->addFilter('foo', function (FilterInfo $info, string $str): string {
// ...
});
Kontekstni filtri lahko zaznajo in spremenijo vrsto vsebine, ki jo prejmejo v spremenljivki
$info->contentType
. Če je filter klican klasično nad spremenljivko (npr. {$var|foo}
), bo
$info->contentType
vsebovala ničlo.
Filter mora najprej preveriti, ali je vrsta vsebine vhodnega niza podprta. Lahko ga tudi spremeni. Primer filtra, ki sprejme besedilo (ali ničlo) in vrne HTML:
use Latte\Runtime\FilterInfo;
$latte->addFilter('money', function (FilterInfo $info, float $amount): string {
// najprej preverimo, ali je tip vsebine vnosa besedilo.
if (!in_array($info->contentType, [null, ContentType::Text])) {
throw new Exception("Filter |money used in incompatible content type $info->contentType.");
}
// spremenimo tip vsebine v HTML
$info->contentType = ContentType::Html;
return "<i>$amount EUR</i>";
});
V tem primeru mora filter zagotoviti pravilno escapiranje podatkov.
Vsi filtri, ki se uporabljajo nad bloki (npr. kot
{block|foo}...{/block}
) morajo biti kontekstualni.
Funkcije
Privzeto lahko v Latte uporabljate vse izvorne funkcije PHP, razen če je to v peskovniku onemogočeno. Lahko pa določite tudi lastne funkcije. Te lahko prekrijejo izvorne funkcije.
Funkcijo ustvarite tako, da vpišete njeno ime in kateri koli klic PHP:
$latte = new Latte\Engine;
$latte->addFunction('random', function (...$args) {
return $args[array_rand($args)];
});
Uporaba je nato enaka kot pri klicanju funkcije PHP:
{random(apple, orange, lemon)} // prints for example: apple
Funkcije, ki uporabljajo razred
Drugi način opredelitve funkcije je uporaba
razreda. Ustvarimo metodo z atributom TemplateFunction
:
class TemplateParameters
{
public function __construct(
// parametri
) {}
#[Latte\Attributes\TemplateFunction]
public function random(...$args)
{
return $args[array_rand($args)];
}
}
$params = new TemplateParameters(/* ... */);
$latte->render('template.latte', $params);
Nalagalniki
Nalagalniki so odgovorni za nalaganje predlog iz vira, kot je datotečni sistem. Nastavijo se z metodo
setLoader()
:
$latte->setLoader(new MyLoader);
Vgrajeni nalagalniki so:
FileLoader
Privzeta naprava za nalaganje. Naloži predloge iz datotečnega sistema.
Dostop do datotek lahko omejite z nastavitvijo osnovnega imenika:
$latte->setLoader(new Latte\Loaders\FileLoader($templateDir));
$latte->render('test.latte');
StringLoader
Naloži predloge iz nizov. Ta nalagalnik je zelo uporaben za testiranje enot. Uporablja se lahko tudi pri manjših projektih, kjer je morda smiselno vse predloge shraniti v eno samo datoteko PHP.
$latte->setLoader(new Latte\Loaders\StringLoader([
'main.file' => '{include other.file}',
'other.file' => '{if true} {$var} {/if}',
]));
$latte->render('main.file');
Poenostavljena uporaba:
$template = '{if true} {$var} {/if}';
$latte->setLoader(new Latte\Loaders\StringLoader);
$latte->render($template);
Ustvarjanje polnilnika po meri
Loader je razred, ki implementira vmesnik Latte\Loader.
Oznake
Ena od najzanimivejših funkcij mehanizma za oblikovanje predlog je možnost opredelitve novih jezikovnih konstrukcij z uporabo oznak. To je tudi bolj zapletena funkcionalnost, zato morate razumeti, kako Latte notranje deluje.
Vendar pa v večini primerov uporaba značk ni potrebna:
- Če naj bi ustvarila kakšen izhod, namesto tega uporabite funkcijo
- če naj bi spremenila nek vhodni podatek in ga vrnila, namesto tega uporabite filter
- če naj bi urejala območje besedila, ga ovijte z
{block}
in uporabite filter - če ne bi smel ničesar izpisati, ampak samo poklicati funkcijo, jo pokličite z
{do}
Če še vedno želite ustvariti oznako, odlično! Vse bistvene informacije so na voljo v poglavju Ustvarjanje razširitve.
Prehodi za prevajalnik
Prehodi za prevajalnik so funkcije, ki spreminjajo AST ali v njih zbirajo informacije. V programu Latte je na primer peskovnik izveden na ta način: prečka vsa vozlišča AST, poišče klice funkcij in metod ter jih nadomesti z nadzorovanimi klici.
Tako kot pri oznakah gre za bolj zapleteno funkcionalnost, zato morate razumeti, kako Latte deluje pod pokrovom. Vse bistvene informacije najdete v poglavju Ustvarjanje razširitve.