Crearea filtrelor personalizate

Filtrele sunt instrumente puternice pentru formatarea și modificarea datelor direct în șabloanele Latte. Oferă o sintaxă curată folosind simbolul pipe (|) pentru a transforma variabilele sau rezultatele expresiilor în formatul de ieșire dorit.

Ce sunt filtrele?

Filtrele în Latte sunt în esență funcții PHP concepute special pentru a transforma o valoare de intrare într-o valoare de ieșire. Se aplică folosind notația cu pipe (|) în interiorul expresiilor șablonului ({...}).

Comoditate: Filtrele vă permit să încapsulați sarcini comune de formatare (cum ar fi formatarea datelor, schimbarea majusculelor/minusculelor, trunchierea) sau manipularea datelor în unități reutilizabile. În loc să repetați cod PHP complex în șabloanele dvs., puteți aplica pur și simplu un filtru:

{* În loc de PHP complex pentru trunchiere: *}
{$article->text|truncate:100}

{* În loc de cod pentru formatarea datei: *}
{$event->startTime|date:'Y-m-d H:i'}

{* Aplicarea mai multor transformări: *}
{$product->name|lower|capitalize}

Lizibilitate: Utilizarea filtrelor face șabloanele mai clare și mai concentrate pe prezentare, deoarece logica de transformare este mutată în definiția filtrului.

Sensibilitate la context: Un avantaj cheie al filtrelor în Latte este capacitatea lor de a fi sensibile la context. Acest lucru înseamnă că un filtru poate recunoaște tipul de conținut cu care lucrează (HTML, JavaScript, text simplu etc.) și poate aplica logica sau escaparea corespunzătoare, ceea ce este crucial pentru securitate și corectitudine, în special la generarea HTML.

Integrare cu logica aplicației: La fel ca funcțiile personalizate, PHP callable din spatele unui filtru poate fi o închidere (closure), o metodă statică sau o metodă de instanță. Acest lucru permite filtrelor să acceseze serviciile sau datele aplicației, dacă este necesar, deși scopul lor principal rămâne transformarea valorii de intrare.

Latte oferă implicit un set bogat de filtre standard. Filtrele personalizate vă permit să extindeți acest set cu formatări și transformări specifice proiectului dvs.

Dacă trebuie să efectuați logică bazată pe mai multe intrări sau nu aveți o valoare primară de transformat, este probabil mai potrivit să utilizați o funcție personalizată. Dacă trebuie să generați markup complex sau să controlați fluxul șablonului, luați în considerare un tag personalizat.

Crearea și înregistrarea filtrelor

Există mai multe moduri de a defini și înregistra filtre personalizate în Latte.

Înregistrare directă folosind addFilter()

Cel mai simplu mod de a adăuga un filtru este utilizarea metodei addFilter() direct pe obiectul Latte\Engine. Specificați numele filtrului (cum va fi utilizat în șablon) și PHP callable corespunzător.

$latte = new Latte\Engine;

// Filtru simplu fără argumente
$latte->addFilter('initial', fn(string $s): string => mb_substr($s, 0, 1) . '.');

// Filtru cu argument opțional
$latte->addFilter('shortify', function (string $s, int $len = 10): string {
	return mb_substr($s, 0, $len);
});

// Filtru care procesează array-uri
$latte->addFilter('sum', fn(array $numbers): int|float => array_sum($numbers));

Utilizare în șablon:

{$name|initial}                 {* Afișează 'I.' dacă $name este 'Ion' *}
{$description|shortify}         {* Utilizează lungimea implicită 10 *}
{$description|shortify:50}      {* Utilizează lungimea 50 *}
{$prices|sum}                   {* Afișează suma elementelor din array-ul $prices *}

Transmiterea argumentelor:

Valoarea din stânga pipe-ului (|) este întotdeauna transmisă ca primul argument funcției filtrului. Orice parametri specificați după două puncte (:) în șablon sunt transmiși ca argumente următoare.

{$text|shortify:30}
// Apelează funcția PHP shortify($text, 30)

Înregistrare prin extensie

Pentru o mai bună organizare, în special la crearea de seturi reutilizabile de filtre sau partajarea lor ca pachete, modul recomandat este să le înregistrați în cadrul unei extensii 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);
	}
}

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

Această abordare menține logica filtrului dvs. încapsulată și înregistrarea simplă.

Utilizarea încărcătorului de filtre

Latte permite înregistrarea unui încărcător de filtre folosind addFilterLoader(). Acesta este un singur callable pe care Latte îl va solicita pentru orice nume de filtru necunoscut în timpul compilării. Încărcătorul returnează PHP callable al filtrului sau null.

$latte = new Latte\Engine;

// Încărcătorul poate crea/obține dinamic callable-uri de filtre
$latte->addFilterLoader(function (string $name): ?callable {
	if ($name === 'myLazyFilter') {
		// Imaginați-vă aici o inițializare costisitoare...
		$service = get_some_expensive_service();
		return fn($value) => $service->process($value);
	}
	return null;
});

Această metodă a fost destinată în principal încărcării leneșe a filtrelor cu o inițializare foarte costisitoare. Cu toate acestea, practicile moderne de injectare a dependențelor (dependency injection) gestionează de obicei serviciile leneșe mai eficient.

Încărcătoarele de filtre adaugă complexitate și, în general, nu sunt recomandate în favoarea înregistrării directe folosind addFilter() sau în cadrul unei extensii folosind getFilters(). Utilizați încărcătoarele doar dacă aveți un motiv serios, specific, legat de probleme de performanță la inițializarea filtrelor, care nu pot fi rezolvate altfel.

Filtre care utilizează o clasă cu atribute

Un alt mod elegant de a defini filtre este utilizarea metodelor în clasa dvs. de parametri de șablon. Pur și simplu adăugați atributul #[Latte\Attributes\TemplateFilter] la metodă.

use Latte\Attributes\TemplateFilter;

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

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

// Transmiterea obiectului către șablon
$params = new TemplateParameters(description: '...');
$latte->render('template.latte', $params);

Latte va recunoaște și înregistra automat metodele marcate cu acest atribut atunci când obiectul TemplateParameters este transmis șablonului. Numele filtrului în șablon va fi același cu numele metodei (shortify în acest caz).

{* Utilizarea filtrului definit în clasa de parametri *}
{$description|shortify:50}

Filtre contextuale

Uneori, un filtru are nevoie de mai multe informații decât doar valoarea de intrare. Poate avea nevoie să cunoască tipul de conținut al șirului cu care lucrează (de exemplu, HTML, JavaScript, text simplu) sau chiar să îl modifice. Aceasta este situația pentru filtrele contextuale.

Un filtru contextual este definit la fel ca un filtru obișnuit, dar primul său parametru trebuie să fie tipat ca Latte\Runtime\FilterInfo. Latte recunoaște automat această semnătură și, la apelarea filtrului, transmite obiectul FilterInfo. Parametrii următori primesc argumentele filtrului ca de obicei.

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

$latte->addFilter('money', function (FilterInfo $info, float $amount): string {
	// 1. Verificați tipul de conținut de intrare (opțional, dar recomandat)
	//    Permiteți null (intrare variabilă) sau text simplu. Refuzați dacă este aplicat pe HTML etc.
	if (!in_array($info->contentType, [null, ContentType::Text], true)) {
		$actualType = $info->contentType ?? 'mixed';
		throw new \RuntimeException(
			"Filtrul |money utilizat într-un tip de conținut incompatibil $actualType. Se aștepta text sau null."
		);
	}

	// 2. Efectuați transformarea
	$formatted = number_format($amount, 2, '.', ',') . ' EUR';
	$htmlOutput = '<i>' . htmlspecialchars($formatted) . '</i>'; // Asigurați escaparea corectă!

	// 3. Declarați tipul de conținut de ieșire
	$info->contentType = ContentType::Html;

	// 4. Returnați rezultatul
	return $htmlOutput;
});

$info->contentType este o constantă de șir din Latte\ContentType (de exemplu, ContentType::Html, ContentType::Text, ContentType::JavaScript, etc.) sau null, dacă filtrul este aplicat pe o variabilă ({$var|filter}). Puteți citi această valoare pentru a verifica contextul de intrare și scrie în ea pentru a declara tipul contextului de ieșire.

Setând tipul de conținut la HTML, îi spuneți lui Latte că șirul returnat de filtrul dvs. este HTML sigur. Latte nu va aplica apoi escaparea sa automată implicită acestui rezultat. Acest lucru este crucial dacă filtrul dvs. generează markup HTML.

Dacă filtrul dvs. generează HTML, sunteți responsabil pentru escaparea corectă a oricăror date de intrare utilizate în acest HTML (ca în cazul apelului htmlspecialchars($formatted) de mai sus). Omiterea poate crea vulnerabilități XSS. Dacă filtrul dvs. returnează doar text simplu, nu trebuie să setați $info->contentType.

Filtre pe blocuri

Toate filtrele aplicate pe blocuri trebuie să fie contextuale. Acest lucru se datorează faptului că conținutul blocului are un tip de conținut definit (de obicei HTML), de care filtrul trebuie să fie conștient.

{block heading|money}1000{/block}
{* Filtrul 'money' primește '1000' ca al doilea argument
   și $info->contentType va fi ContentType::Html *}

Filtrele contextuale oferă un control puternic asupra modului în care datele sunt procesate în funcție de contextul lor, permit funcții avansate și asigură un comportament corect de escapare, în special la generarea de conținut HTML.

versiune: 3.0