Özel filtreler oluşturma

Filtreler, veriyi doğrudan Latte şablonlarının içinde biçimlendirmek ve değiştirmek için güçlü araçlardır. Değişkenleri veya ifade sonuçlarını istenen çıktı biçimine dönüştürmek için boru simgesini (|) kullanan temiz bir sözdizimi sunarlar.

Filtreler nedir?

Latte'deki filtreler aslında bir girdi değerini bir çıktı değerine dönüştürmek için özel olarak tasarlanmış PHP fonksiyonlarıdır. Şablon ifadelerinin ({...}) içinde boru (|) gösterimiyle uygulanırlar.

Rahatlık: Filtreler, yaygın biçimlendirme işlerini (tarih biçimlendirme, harf dönüşümü, kısaltma gibi) veya veri işlemlerini yeniden kullanılabilir birimlere kapsüllemenizi sağlar. Şablonlarınızda karmaşık PHP kodunu yinelemek yerine bir filtreyi uygulamanız yeterlidir:

{* Kısaltma için karmaşık PHP yerine: *}
{$article->text|truncate:100}

{* Tarih biçimlendirme kodu yerine: *}
{$event->startTime|date:'Y-m-d H:i'}

{* Birden fazla dönüşümü uygulama: *}
{$product->name|lower|capitalize}

Okunabilirlik: Filtre kullanmak, şablonları daha temiz ve daha çok sunuma odaklı kılar; dönüşüm mantığını filtrenin tanımına taşır.

Bağlam duyarlılığı: Latte filtrelerinin önemli bir gücü, bağlama duyarlı olabilmeleridir. Yani bir filtre, üzerinde çalıştığı içeriğin tipini (HTML, JavaScript, düz metin vb.) anlayabilir ve uygun mantığı ya da kaçışı uygulayabilir; bu, özellikle HTML üretimiyle uğraşırken güvenlik ve doğruluk açısından çok önemlidir.

Uygulama mantığıyla entegrasyon: Tıpkı özel fonksiyonlarda olduğu gibi, bir filtrenin arkasındaki PHP callable bir closure, bir statik metot veya bir örnek metodu olabilir. Bu, filtrelerin gerekirse uygulama servislerine veya verisine erişmesine olanak tanır; ancak temel amaçları girdi değerini dönüştürmek olarak kalır.

Latte, varsayılan olarak zengin bir standart filtre kümesi sunar. Özel filtreler, bu kümeyi projenize özgü biçimlendirme ve dönüştürme ihtiyaçlarıyla genişletmenizi sağlar.

Birden fazla girdiye dayalı bir mantık uygulamanız gerekiyorsa ya da dönüştürülecek birincil bir değeriniz yoksa, büyük olasılıkla bir özel fonksiyon daha uygundur. Karmaşık işaretleme üretmeniz veya şablon akışını denetlemeniz gerekiyorsa, bir özel etiketi düşünün.

Filtrelerin oluşturulması ve kaydı

Latte'de özel filtreleri tanımlamanın ve kaydetmenin birkaç yolu vardır.

addFilter() ile doğrudan kayıt

Filtre eklemenin en basit yolu, addFilter() metodunu doğrudan Latte\Engine nesnesi üzerinde kullanmaktır. Filtre adını (şablonda nasıl kullanılacağını) ve karşılık gelen PHP callable'ı verirsiniz.

$latte = new Latte\Engine;

// Argümansız basit filtre
$latte->addFilter('initial', fn(string $s): string => mb_substr($s, 0, 1) . '.');

// İsteğe bağlı argümanı olan filtre
$latte->addFilter('shortify', function (string $s, int $len = 10): string {
	return mb_substr($s, 0, $len);
});

// Bir diziyi işleyen filtre
$latte->addFilter('sum', fn(array $numbers): int|float => array_sum($numbers));

Şablonda kullanımı:

{$name|initial}                 {* $name 'John' ise 'J.' yazdırır *}
{$description|shortify}         {* Varsayılan 10 uzunluğunu kullanır *}
{$description|shortify:50}      {* 50 uzunluğunu kullanır *}
{$prices|sum}                   {* $prices dizisindeki öğelerin toplamını yazdırır *}

Argüman aktarımı:

Borunun (|) sol yanındaki değer, filtre fonksiyonuna her zaman ilk argüman olarak aktarılır. Şablonda iki nokta üst üstenin (:) ardından belirtilen parametreler, sonraki argümanlar olarak aktarılır.

{$text|shortify:30}
// shortify($text, 30) PHP fonksiyonunu çağırır

Uzantı ile kayıt

Daha iyi bir düzen için, özellikle yeniden kullanılabilir filtre kümeleri oluştururken veya onları paket olarak paylaşırken, önerilen yol onları bir Latte uzantısında kaydetmektir:

namespace App\Templating;

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

// Kayıt
$latte = new Latte\Engine;
$latte->addExtension(new MyLatteExtension);

Bu yaklaşım filtre mantığınızı kapsüllü tutar ve kaydı basitleştirir.

Nitelikli bir sınıf kullanan filtreler

Filtreleri tanımlamanın bir başka zarif yolu, şablon parametreleri sınıfınızdaki metotları kullanmaktır. Metoda #[Latte\Attributes\TemplateFilter] niteliğini eklemeniz yeterlidir.

use Latte\Attributes\TemplateFilter;

class TemplateParameters
{
	public function __construct(
		public string $description,
		// diğer parametreler...
	) {}

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

// Nesneyi şablona aktar
$params = new TemplateParameters(description: '...');
$latte->render('template.latte', $params);

Latte, TemplateParameters nesnesi şablona aktarıldığında bu nitelikle işaretlenmiş metotları otomatik saptar ve kaydeder. Şablondaki filtre adı metot adıyla aynı olacaktır (bu durumda shortify).

{* Parametreler sınıfında tanımlanan filtreyi kullan *}
{$description|shortify:50}

Bağlamsal filtreler

Bazen bir filtrenin, yalnızca girdi değerinden fazlasına ihtiyacı olur. İşlediği dizenin içerik tipini (örneğin HTML, JavaScript, düz metin) bilmesi, hatta onu değiştirmesi gerekebilir. İşte bağlamsal filtreler burada devreye girer.

Bağlamsal bir filtre, tıpkı olağan bir filtre gibi tanımlanır, ama ilk parametresinin tür bildirimi Latte\Runtime\FilterInfo olmalıdır. Latte bu imzayı otomatik tanır ve filtreyi çağırırken FilterInfo nesnesini aktarır. Sonraki parametreler filtre argümanlarını her zamanki gibi alır.

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

$latte->addFilter('money', function (FilterInfo $info, float $amount): string {
	// 1. Girdi içerik tipini denetle (isteğe bağlı ama önerilir)
	//    null (değişken girdisi) veya düz metne izin ver. HTML vb. üzerinde uygulanırsa reddet.
	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. Dönüşümü gerçekleştir
	$formatted = number_format($amount, 2, '.', ',') . ' EUR';
	$htmlOutput = '<i>' . htmlspecialchars($formatted) . '</i>'; // Doğru kaçışı sağla!

	// 3. Çıktı içerik tipini bildir
	$info->contentType = ContentType::Html;

	// 4. Sonucu döndür
	return $htmlOutput;
});

$info->contentType, Latte\ContentType sınıfından bir dize sabitidir (örneğin ContentType::Html, ContentType::Text, ContentType::JavaScript vb.), ya da filtre bir değişkene uygulanıyorsa ({$var|filter}) null'dır. Girdi bağlamını denetlemek için bunu okuyabilir, çıktı bağlam tipini bildirmek için ona yazabilirsiniz.

İçerik tipini HTML yaparak Latte'ye filtrenizin döndürdüğü dizenin güvenli HTML olduğunu söylemiş olursunuz. Latte o zaman bu sonuç üzerinde varsayılan otomatik kaçışını uygulamaz. Filtreniz HTML işaretlemesi üretiyorsa bu çok önemlidir.

Filtreniz HTML üretiyorsa, o HTML'in içinde kullanılan girdi verisini doğru kaçırmaktan siz sorumlusunuz (yukarıdaki htmlspecialchars($formatted) çağrısında olduğu gibi). Bunu yapmamak XSS güvenlik açıkları yaratabilir. Filtreniz yalnızca düz metin döndürüyorsa $info->contentType ayarlamanız gerekmez.

Bloklardaki filtreler

İçerik tipi metin dışında (genellikle HTML) olan bloklara uygulanan filtreler bağlamsal olmak zorundadır. Bunun nedeni, bloğun içeriğinin, filtrenin bilmesi gereken tanımlı bir içerik tipine sahip olmasıdır. Klasik, bağlamsal olmayan bir filtre yalnızca içeriği düz metin olan bir bloğa uygulanabilir.

{block heading|money}1000{/block}
{* 'money' filtresi ikinci argüman olarak '1000' alır
   ve $info->contentType ContentType::Html olur *}

Bağlamsal filtreler, verinin bağlamına göre nasıl işleneceği üzerinde güçlü bir denetim sağlar; gelişmiş özellikleri mümkün kılar ve özellikle HTML içerik üretirken doğru kaçış davranışını güvence altına alır.

versiyon: 3.x