Ustvarjanje lastnih filtrov

Filtri so zmogljiva orodja za formatiranje in urejanje podatkov neposredno v predlogah Latte. Ponujajo čisto sintakso s simbolom cevi (|) za transformacijo spremenljivk ali rezultatov izrazov v želeni izhodni format.

Kaj so filtri?

Filtri v Latte so v bistvu PHP funkcije, zasnovane posebej za transformacijo vhodne vrednosti v izhodno vrednost. Uporabljajo se s pomočjo zapisa s cevjo (|) znotraj izrazov predloge ({...}).

Priročnost: Filtri vam omogočajo zapiranje pogostih nalog formatiranja (kot je formatiranje datumov, sprememba velikosti črk, krajšanje) ali manipulacije s podatki v ponovno uporabne enote. Namesto ponavljanja zapletene PHP kode v vaših predlogah lahko preprosto uporabite filter:

{* Namesto zapletenega PHP za krajšanje: *}
{$article->text|truncate:100}

{* Namesto kode za formatiranje datuma: *}
{$event->startTime|date:'Y-m-d H:i'}

{* Uporaba več transformacij: *}
{$product->name|lower|capitalize}

Čitljivost: Uporaba filtrov naredi predloge preglednejše in bolj osredotočene na predstavitev, saj je transformacijska logika premaknjena v definicijo filtra.

Kontekstna občutljivost: Ključna prednost filtrov v Latte je njihova sposobnost biti kontekstno občutljivi. To pomeni, da lahko filter prepozna tip vsebine, s katero dela (HTML, JavaScript, navaden tekst itd.), in uporabi ustrezno logiko ali ubežanje znakov, kar je ključno za varnost in pravilnost, še posebej pri generiranju HTML.

Integracija z aplikacijsko logiko: Enako kot lastne funkcije je lahko PHP klicni objekt za filtrom zaprtje (closure), statična metoda ali metoda instance. To omogoča filtrom dostop do aplikacijskih storitev ali podatkov, če je potrebno, čeprav njihov glavni namen ostaja transformacija vhodne vrednosti.

Latte privzeto ponuja bogat nabor standardnih filtrov. Lastni filtri vam omogočajo razširitev tega nabora s formatiranjem in transformacijami, specifičnimi za vaš projekt.

Če potrebujete izvajati logiko, temelječo na več vhodih, ali nimate primarne vrednosti za transformacijo, je verjetno primernejše uporabiti lastno funkcijo. Če potrebujete generirati zapleten markup ali nadzorovati tok predloge, razmislite o lastni znački.

Ustvarjanje in registracija filtrov

Obstaja več načinov, kako definirati in registrirati lastne filtre v Latte.

Neposredna registracija s pomočjo addFilter()

Najenostavnejši način za dodajanje filtra je uporaba metode addFilter() neposredno na objektu Latte\Engine. Določite ime filtra (kot bo uporabljen v predlogi) in ustrezen PHP klicni objekt.

$latte = new Latte\Engine;

// Preprost filter brez argumentov
$latte->addFilter('initial', fn(string $s): string => mb_substr($s, 0, 1) . '.');

// Filter z neobveznim argumentom
$latte->addFilter('shortify', function (string $s, int $len = 10): string {
	return mb_substr($s, 0, $len);
});

// Filter, ki obdeluje polja
$latte->addFilter('sum', fn(array $numbers): int|float => array_sum($numbers));

Uporaba v predlogi:

{$name|initial}                 {* Izpiše 'J.' če je $name 'John' *}
{$description|shortify}         {* Uporabi privzeto dolžino 10 *}
{$description|shortify:50}      {* Uporabi dolžino 50 *}
{$prices|sum}                   {* Izpiše vsoto elementov v polju $prices *}

Posredovanje argumentov:

Vrednost levo od cevi (|) je vedno posredovana kot prvi argument funkciji filtra. Kakršnikoli parametri, navedeni za dvopičjem (:) v predlogi, so posredovani kot naslednji argumenti.

{$text|shortify:30}
// Kliče PHP funkcijo shortify($text, 30)

Registracija s pomočjo razširitve

Za boljšo organizacijo, še posebej pri ustvarjanju ponovno uporabnih naborov filtrov ali njihovem deljenju kot paketi, je priporočen način registracija znotraj razširitve Latte:

namespace App\Latte;

use Latte\Extension;

class MyLatteExtension extends Extension
{
	public function getFilters(): array
	{
		return [
			'initial' => $this->initial(...),
			'shortify' => $this->shortify(...),
		];
	}

	public function initial(string $s): string
	{
		return mb_substr($s, 0, 1) . '.';
	}

	public function shortify(string $s, int $len = 10): string
	{
		return mb_substr($s, 0, $len);
	}
}

// Registracija
$latte = new Latte\Engine;
$latte->addExtension(new App\Latte\MyLatteExtension);

Ta pristop ohranja logiko vašega filtra zaprto in registracijo enostavno.

Uporaba nalagalnika filtrov

Latte omogoča registracijo nalagalnika filtrov s pomočjo addFilterLoader(). Gre za en sam klicni objekt, ki ga Latte vpraša za katerokoli neznano ime filtra med kompilacijo. Nalagalnik vrne PHP klicni objekt filtra ali null.

$latte = new Latte\Engine;

// Nalagalnik lahko dinamično ustvarja/pridobiva klicne objekte filtrov
$latte->addFilterLoader(function (string $name): ?callable {
	if ($name === 'myLazyFilter') {
		// Predstavljajte si tu zahtevno inicializacijo...
		$service = get_some_expensive_service();
		return fn($value) => $service->process($value);
	}
	return null;
});

Ta metoda je bila primarno namenjena za leno nalaganje filtrov z zelo zahtevno inicializacijo. Vendar sodobne prakse vstavljanja odvisnosti (dependency injection) običajno upravljajo lene storitve učinkoviteje.

Nalagalniki filtrov dodajajo kompleksnost in se na splošno ne priporočajo v korist neposredne registracije s pomočjo addFilter() ali znotraj razširitve s pomočjo getFilters(). Uporabljajte nalagalnike samo, če imate resen, specifičen razlog, povezan z zmogljivostnimi težavami pri inicializaciji filtrov, ki jih ni mogoče rešiti drugače.

Filtri, ki uporabljajo razred z atributi

Še en eleganten način za definiranje filtrov je uporaba metod v vašem razredu parametrov predloge. Dovolj je dodati atribut #[Latte\Attributes\TemplateFilter] k metodi.

use Latte\Attributes\TemplateFilter;

class TemplateParameters
{
	public function __construct(
		public string $description,
		// nadaljnji parametri...
	) {}

	#[TemplateFilter]
	public function shortify(string $s, int $len = 10): string
	{
		return mb_substr($s, 0, $len);
	}
}

// Posredovanje objekta v predlogo
$params = new TemplateParameters(description: '...');
$latte->render('template.latte', $params);

Latte samodejno prepozna in registrira metode, označene s tem atributom, ko je objekt TemplateParameters posredovan v predlogo. Ime filtra v predlogi bo enako imenu metode (shortify v tem primeru).

{* Uporaba filtra, definiranega v razredu parametrov *}
{$description|shortify:50}

Kontekstni filtri

Včasih filter potrebuje več informacij kot samo vhodno vrednost. Morda mora poznati tip vsebine niza, s katerim dela (npr. HTML, JavaScript, navaden tekst) ali ga celo spremeniti. To je situacija za kontekstne filtre.

Kontekstni filter je definiran enako kot običajen filter, vendar mora biti njegov prvi parameter tipsko označen kot Latte\Runtime\FilterInfo. Latte samodejno prepozna ta podpis in pri klicu filtra posreduje objekt FilterInfo. Naslednji parametri prejmejo argumente filtra kot običajno.

use Latte\Runtime\FilterInfo;
use Latte\ContentType;

$latte->addFilter('money', function (FilterInfo $info, float $amount): string {
	// 1. Preverite vhodni tip vsebine (neobvezno, a priporočljivo)
	//    Dovolite null (spremenljiv vhod) ali navaden tekst. Zavrnite, če je uporabljen na HTML itd.
	if (!in_array($info->contentType, [null, ContentType::Text], true)) {
		$actualType = $info->contentType ?? 'mixed';
		throw new \RuntimeException(
			"Filter |money used in incompatible content type $actualType. Expected text or null."
		);
	}

	// 2. Izvedite transformacijo
	$formatted = number_format($amount, 2, '.', ',') . ' EUR';
	$htmlOutput = '<i>' . htmlspecialchars($formatted) . '</i>'; // Zagotovite pravilno ubežanje znakov!

	// 3. Deklarirajte izhodni tip vsebine
	$info->contentType = ContentType::Html;

	// 4. Vrnite rezultat
	return $htmlOutput;
});

$info->contentType je nizovna konstanta iz Latte\ContentType (npr. ContentType::Html, ContentType::Text, ContentType::JavaScript, itd.) ali null, če je filter uporabljen na spremenljivki ({$var|filter}). To vrednost lahko berete, da preverite vhodni kontekst, in pišete vanjo, da deklarirate tip izhodnega konteksta.

Z nastavitvijo tipa vsebine na HTML sporočate Latte, da je niz, vrnjen s strani vašega filtra, varen HTML. Latte potem na ta rezultat ne bo uporabil svojega privzetega samodejnega ubežanja znakov. To je ključno, če vaš filter generira HTML markup.

Če vaš filter generira HTML, ste odgovorni za pravilno ubežanje znakov kakršnihkoli vhodnih podatkov, uporabljenih v tem HTML (kot v primeru klica htmlspecialchars($formatted) zgoraj). Opustitev lahko ustvari XSS ranljivosti. Če vaš filter vrača samo navaden tekst, vam ni treba nastavljati $info->contentType.

Filtri na blokih

Vsi filtri, uporabljeni na blokih morajo biti kontekstni. To je zato, ker ima vsebina bloka definiran tip vsebine (običajno HTML), katerega se mora filter zavedati.

{block heading|money}1000{/block}
{* Filter 'money' prejme '1000' kot drugi argument
   in $info->contentType bo ContentType::Html *}

Kontekstni filtri zagotavljajo močan nadzor nad tem, kako so podatki obdelani na podlagi njihovega konteksta, omogočajo napredne funkcije in zagotavljajo pravilno vedenje ubežanja znakov, še posebej pri generiranju HTML vsebine.

različica: 3.0