Nette Documentation Preview

syntax
Geliştiriciler için pratikler
*****************************


Kurulum
=======

Latte'yi kurmanın en iyi yolu Composer'dır:

```shell
composer require latte/latte
```

Desteklenen PHP sürümleri (en son yama Latte sürümleri için geçerlidir):

| sürüm           | uyumlu olduğu PHP
|-----------------|-------------------
| Latte 3.1       | PHP 8.2 - 8.5
| Latte 3.0       | PHP 8.0 - 8.5


Bir şablon nasıl render edilir
==============================

Bir şablon nasıl render edilir? Şu basit kodu kullanmanız yeterli:

```php
$latte = new Latte\Engine;
// önbellek dizini
$latte->setCacheDirectory('/path/to/tempdir');

$params = [ /* şablon değişkenleri */ ];
// veya $params = new TemplateParameters(/* ... */);

// çıktıya render et
$latte->render('template.latte', $params);
// veya bir değişkene render et
$output = $latte->renderToString('template.latte', $params);
```

Parametreler dizi olabilir ya da daha iyisi, tip denetimi ve editörde öneri sağlayacak bir [nesne |#Parametreler bir sınıf olarak] olabilir.

.[note]
Kullanım örneklerini [Latte examples |https://github.com/nette-examples/latte] deposunda da bulabilirsiniz.


Performans ve önbellekleme
==========================

Latte şablonları son derece hızlıdır, çünkü Latte onları doğrudan PHP koduna derler ve diskte önbelleğe alır. Böylece saf PHP ile yazılmış şablonlara kıyasla ek bir yük getirmezler.

Kaynak dosyayı her değiştirdiğinizde önbellek otomatik yeniden üretilir. Böylece geliştirme sırasında Latte şablonlarınızı rahatça düzenleyip değişiklikleri tarayıcıda hemen görebilirsiniz. Bu özelliği üretim ortamında kapatıp biraz performans kazanabilirsiniz:

```php
$latte->setAutoRefresh(false);
```

Üretim sunucusuna dağıtım yapıldığında, özellikle daha büyük uygulamalarda ilk önbellek üretimi anlaşılır biçimde biraz zaman alabilir. Latte'de "önbellek stampedesine":https://en.wikipedia.org/wiki/Cache_stampede karşı yerleşik bir önlem vardır. Bu, sunucunun çok sayıda eşzamanlı istek aldığı ve Latte'nin önbelleği henüz var olmadığı için hepsinin aynı anda onu üreteceği durumdur. Bu da CPU'yu zıplatır. Latte akıllıdır; birden fazla eşzamanlı istek olduğunda önbelleği yalnızca ilk iş parçacığı üretir, diğerleri bekler ve sonra onu kullanır.

Önbelleği dağıtım sırasında (örneğin bir dağıtım betiğinde) `Engine::warmupCache()` metoduyla önceden de üretebilirsiniz. Verilen şablonu önbelleğe önceden derler, böylece ilk ziyaretçinin beklemesi gerekmez: `$latte->warmupCache('template.latte')`.


Latte'yi genişletme yolları
===========================

Latte, basit yardımcılardan tamamen yeni dil yapılarına kadar birkaç şekilde özelleştirilebilir. [Latte'yi genişletme |extending-latte] sayfası bunları ayrıntılı ele alır; işte hızlı bir bakış:

- **[Özel filtreler|custom-filters]:** şablon çıktısındaki veriyi biçimlendirmek veya dönüştürmek için (örneğin `{$var|myFilter}`).
- **[Özel fonksiyonlar|custom-functions]:** şablon ifadelerinin içinde çağırdığınız özel mantık için (örneğin `{myFunction($arg)}`).
- **[Özel etiketler|custom-tags]:** tamamen yeni dil yapıları için (`{mytag}...{/mytag}` veya `n:mytag`).
- **[Compiler pass'leri|compiler-passes]:** şablonun AST'sini ayrıştırma ile PHP kodu üretimi arasında değiştiren fonksiyonlar (örneğin iyileştirmeler veya güvenlik denetimleri).
- **[Özel loader'lar|loaders]:** Latte'nin şablon dosyalarını nasıl bulup yüklediğini değiştirmek için.

Uzantılarınızı projeler arasında yeniden kullanmak veya başkalarıyla paylaşmak isterseniz, onları bir [Latte uzantısı |extending-latte#Latte Extension] sınıfında toplayın.


Parametreler bir sınıf olarak
=============================

Değişkenleri şablona dizi olarak aktarmaktansa bir sınıf oluşturmak daha iyidir. [Tip güvenli yazım|type-system], [IDE'de güzel öneriler |recipes#Editörler ve IDE'ler] ve [filtre |custom-filters#Filters Using the Class] ile [fonksiyon |custom-functions#Functions Using the Class] kaydetme yolu elde edersiniz.

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


Bir değişkenin otomatik kaçışını kapatma
========================================

Değişken bir HTML dizesi içeriyorsa, Latte'nin onu otomatik (ve dolayısıyla iki kez) kaçırmaması için işaretleyebilirsiniz. Böylece şablonda `|noescape` belirtmeye gerek kalmaz.

En kolayı, dizeyi bir `Latte\Runtime\Html` nesnesine sarmaktır:

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

Latte, `Latte\Runtime\HtmlStringable` arayüzünü uygulayan tüm nesneleri de kaçırmaz. Yani `__toString()` metodu otomatik kaçırılmayacak HTML kodu döndüren kendi sınıfınızı oluşturabilirsiniz:

```php
class Emphasis implements Latte\Runtime\HtmlStringable
{
	public function __construct(
		private string $str,
	) {
	}

	public function __toString(): string
	{
		return '<em>' . htmlspecialchars($this->str) . '</em>';
	}
}

$params = [
	'foo' => new Emphasis('hello'),
];
```

.[warning]
`__toString` metodu doğru HTML döndürmeli ve parametre kaçışını sağlamalıdır, aksi halde bir XSS güvenlik açığı oluşabilir!


Latte filtrelerle, etiketlerle vb. nasıl genişletilir
=====================================================

Latte'ye özel bir filtre, fonksiyon, etiket vb. nasıl eklenir? [Latte'yi genişletme|extending-latte] bölümünde öğrenin. Değişikliklerinizi farklı projelerde yeniden kullanmak ya da başkalarıyla paylaşmak isterseniz, o zaman [bir uzantı oluşturmalısınız |extending-latte#Latte Extension].


Şablonda herhangi bir kod `{php ...}` .{toc: RawPhpExtension}
=============================================================

[`{do}` |tags#{do}] etiketinin içinde yalnızca PHP ifadeleri yazılabilir, bu yüzden örneğin `if ... else` gibi yapıları ya da noktalı virgülle biten deyimleri ekleyemezsiniz.

Ancak `{php ...}` etiketini ekleyen `RawPhpExtension` uzantısını kaydedebilirsiniz. Bunu herhangi bir PHP kodunu eklemek için kullanabilirsiniz. Hiçbir sandbox modu kuralına tabi değildir, bu yüzden kullanımı şablon yazarının sorumluluğundadır.

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


Üretilen kodun denetimi .{data-version:3.0.7}
=============================================

Latte şablonları PHP koduna derler. Elbette üretilen kodun sözdizimsel olarak geçerli olmasını sağlar. Ancak üçüncü taraf uzantılar veya `RawPhpExtension` kullanılırken Latte, üretilen dosyanın doğruluğunu garanti edemez. Ayrıca PHP'de, sözdizimsel olarak doğru ama yasak olan (örneğin `$this` değişkenine değer atamak) ve PHP Compile Error'a yol açan kod yazabilirsiniz. Böyle bir işlemi bir şablona yazarsanız, üretilen PHP koduna da girer. PHP'de iki yüzden fazla farklı yasak işlem olduğundan Latte, onları saptamayı hedeflemez. Render sırasında PHP'nin kendisi bunları bildirir; bu genellikle sorun değildir.

Ancak şablonun PHP Compile Error içermediğini derleme sırasında bilmek istediğiniz durumlar vardır. Özellikle şablonlar kullanıcılar tarafından düzenlenebiliyorsa ya da [Sandbox |sandbox] kullanıyorsanız. Böyle bir durumda şablonları derleme sırasında denetletin. Bu işlevselliği `Engine::enablePhpLinter()` metoduyla etkinleştirebilirsiniz. Denetim için PHP ikili dosyasını çağırması gerektiğinden, yolunu parametre olarak verin:

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

try {
	$latte->compile('home.latte');
} catch (Latte\CompileException $e) {
	// Latte hatalarını ve ayrıca PHP'deki Compile Error'ı yakalar
	echo 'Error: ' . $e->getMessage();
}
```


Yerel ayar .{data-version:3.0.18}
=================================

Latte, sayıların ve tarihlerin biçimlendirilmesini ve sıralamayı etkileyen yerel ayarı belirlemenize olanak tanır. `setLocale()` metoduyla ayarlanır. Yerel ayar tanımlayıcısı, PHP `intl` uzantısını kullanan IETF dil etiketi standardını izler. Bir dil kodundan ve gerekirse bir ülke kodundan oluşur; örneğin Amerika Birleşik Devletleri'ndeki İngilizce için `en_US`, Almanya'daki Almanca için `de_DE` vb.

```php
$latte = new Latte\Engine;
$latte->setLocale('en_US');
```

Yerel ayar; [localDate |filters#localDate], [sort |filters#sort], [number |filters#number] ve [bytes |filters#bytes] filtrelerini etkiler.

.[note]
PHP `intl` uzantısını gerektirir. Latte'deki ayar, PHP'deki genel yerel ayarı etkilemez.


Katı mod .{data-version:3.0.8}
==============================

Katı ayrıştırma modunda Latte, eksik kapanış HTML etiketlerini denetler ve ayrıca `$this` değişkeninin kullanımını kapatır. Onu açmak için:

```php
$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::StrictParsing);
```

Şablonları `declare(strict_types=1)` başlığıyla üretmek için şunu yapın:

```php
$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::StrictTypes);
```

.[note]
Latte 3.1'den beri katı tipler varsayılan olarak etkindir. Onları `$latte->setFeature(Latte\Feature::StrictTypes, false)` ile kapatabilirsiniz.


Geçiş uyarıları .{data-version:3.1.0}
=====================================

Latte 3.1, bazı [HTML niteliklerinin|html-attributes] davranışını değiştirir. Örneğin `null` değerler artık boş dize yazdırmak yerine niteliği düşürür. Bu değişikliğin şablonlarınızı etkilediği yerleri kolayca bulmak için geçiş uyarılarını etkinleştirebilirsiniz:

```php
$latte->setFeature(Latte\Feature::MigrationWarnings);
```

Etkinleştirildiğinde Latte, render edilen nitelikleri denetler ve çıktı Latte 3.0'ın üreteceğinden farklıysa bir kullanıcı uyarısı (`E_USER_WARNING`) tetikler. Bir uyarıyla karşılaştığınızda şu çözümlerden birini uygulayın:

1. Yeni çıktı kullanım durumunuz için doğruysa (örneğin `null` iken niteliğin kaybolmasını yeğliyorsanız), `|accept` filtresini ekleyerek uyarıyı bastırın
2. Değişken `null` iken niteliğin düşürülmesi yerine boş render edilmesini istiyorsanız (örneğin `title=""`), yedek olarak boş bir dize verin: `title={$val ?? ''}`
3. Kesinlikle eski davranışı istiyorsanız (örneğin `true` için `"true"` yerine `"1"` yazdırmak), değeri açıkça dizeye dönüştürün: `data-foo={(string) $val}`

Tüm uyarılar giderildiğinde geçiş uyarılarını kapatın ve artık gerekmediklerinden şablonlarınızdaki **tüm** `|accept` filtrelerini kaldırın.


Kapsamlı döngü değişkenleri .{data-version:3.1.3}
=================================================

Varsayılan olarak, bir `{foreach}` döngüsünde tanımlanan değişkenler (`$key` ve `$value` gibi) döngü bittikten sonra da erişilebilir kalır; tıpkı PHP'nin kendisinde olduğu gibi. Bir döngü değişkeni var olan bir şablon değişkeniyle aynı ada sahip olduğunda bu, istenmeyen değişken ezmelerine yol açabilir.

`ScopedLoopVariables` özelliği, döngü değişkenlerinin kapsamını döngü gövdesiyle sınırlar. Döngü bittikten sonra değişkenin özgün değeri geri yüklenir (daha önce varsa) ya da değişken kaldırılır:

```php
$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::ScopedLoopVariables);
```

Farkın bir örneği:

```latte
{var $item = 'original'}
{foreach [1, 2] as $item}{$item}, {/foreach}
{$item}
```

`ScopedLoopVariables` olmadan: `1, 2, 2` yazdırır (değişken ezilir)
`ScopedLoopVariables` ile: `1, 2, original` yazdırır (değişken geri yüklenir)

Bu, yapı bozma sözdizimiyle de çalışır, örneğin `{foreach $array as [$a, $b]}`.

.[note]
Referans kullanan döngü değişkenleri (`{foreach $array as &$value}`) veya özellik atamaları (`{foreach $array as $obj->prop}`) kapsamlandırılmaz, çünkü bu, amaçlarını bozar.


Otomatik girinti kaldırma .{toc: Dedent}{data-version:3.1.3}
============================================================

`{if}`, `{foreach}` veya `{block}` gibi çift etiketler kullanırken, okunabilirlik için iç içe içeriği sıklıkla girintilersiniz. Ancak bu girinti varsayılan olarak üretilen çıktıya dahil edilir. `Dedent` özelliği onu otomatik kaldırır, böylece Latte etiketlerinizi ne kadar derin iç içe geçirirseniz geçirin çıktı temiz kalır:

```php
$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::Dedent);
```

Örnek:

```latte
{if true}
	Hello
	World
{/if}
```

`Dedent` olmadan çıktı girintiyi içerirdi (`\tHello\n\tWorld\n`). `Dedent` ile girinti soyulur ve çıktı `Hello\nWorld\n` olur.

Bir bloğun içindeki daha derin girinti, temel girintiye göre korunur:

```latte
{if true}
	Hello
		Indented
{/if}
```

Çıktı: `Hello\n\tIndented\n`.

Bir bloğun içindeki girinti tutarlı olmalıdır (ya tabulatör ya boşluk). Karışırlarsa Latte bir `Inconsistent indentation` istisnası fırlatır.


Şablonlarda çeviri .{toc: TranslatorExtension}
==============================================

Şablona [`{_...}` |tags#], [`{translate}` |tags#{translate}] ve [`translate` |filters#translate] filtresini eklemek için `TranslatorExtension` uzantısını kullanın. Bunlar, değerleri ya da şablonun bölümlerini başka dillere çevirmeye yarar. Parametre, çeviriyi gerçekleştiren callable ya da `Nette\Localization\Translator` tipinde bir nesnedir (çevirileri kapatmak için `null` verin):

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

	public function translate(string $original): string
	{
		// $this->lang'a göre $original'dan $translated oluştur
		return $translated;
	}
}

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

Çevirmen, şablon render edilirken çalışma zamanında çağrılır. Ancak Latte tüm statik metinleri şablon derlenirken çevirebilir. Bu performanstan tasarruf sağlar, çünkü her dize yalnızca bir kez çevrilir ve elde edilen çeviri derlenmiş dosyaya yazılır. Böylece önbellek dizininde şablonun her dil için bir tane olmak üzere birden fazla derlenmiş sürümü oluşur. Bunun için dili yalnızca ikinci parametre olarak belirtmeniz gerekir:

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

Statik metin derken örneğin `{_'hello'}` veya `{translate}hello{/translate}` kastediyoruz. `{_$foo}` gibi statik olmayan metinler çalışma zamanında çevrilmeye devam eder.

Şablon, çevirmene `{_$original, foo: bar}` veya `{translate foo: bar}` ile ek parametreler de aktarabilir; çevirmen onları `$params` dizisi olarak alır:

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


Hata ayıklama ve Tracy
======================

Latte, geliştirmeyi olabildiğince keyifli kılmaya çalışır. Hata ayıklama amacıyla üç etiket vardır: [`{dump}` |tags#{dump}], [`{debugbreak}` |tags#{debugbreak}] ve [`{trace}` |tags#{trace}].

En çok rahatlığı, harika [hata ayıklama aracı Tracy'yi|tracy:] kurup Latte eklentisini etkinleştirerek elde edersiniz:

```php
// Tracy'yi etkinleştirir
Tracy\Debugger::enable();

$latte = new Latte\Engine;
// Tracy'nin uzantısını etkinleştirir
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);
```

Artık tüm hataları düzgün bir kırmızı ekranda göreceksiniz; şablonlardaki hatalar da satır ve sütun vurgusuyla dahil ([video|https://github.com/nette/tracy/releases/tag/v2.9.0]). Aynı zamanda sağ alt köşede, Tracy Bar denilen yerde, render edilen tüm şablonları ve ilişkilerini (şablona veya derlenmiş koda tıklama olanağı dahil) ve ayrıca değişkenleri açıkça görebileceğiniz bir Latte sekmesi belirir:

[* latte-debugging.webp *]

Latte şablonları okunabilir PHP koduna derlediğinden, IDE'nizde onların içinde rahatça adım adım ilerleyebilirsiniz.


Linter: şablon sözdiziminin doğrulanması .{toc: Linter}
=======================================================

**Linter** aracı, tüm şablonları doğrulamaya yarar. Amacı, belirtilen dosyaları taramak ve içlerinde sözdizimi hatası ile var olmayan etiketlere, filtrelere, fonksiyonlara, sınıflara veya benzer yapılara başvuru bulunmadığından emin olmaktır.

Linter komut satırından çalıştırılır:

```shell
vendor/bin/latte-lint <path>
```

[#Katı mod]'u etkinleştirmek için `--strict` parametresini kullanın. `--debug` parametresi, işlenen her dosyanın adını ve tam istisna ayrıntılarını yazdırır; bu, sorun giderirken yardımcı olur.

Özel etiketler, filtreler veya başka Latte uzantıları kullanıyorsanız, Linter'ın kendi varyantınızı oluşturmanız gerekir, örneğin `custom-latte-lint`. Bu betikte, asıl şablon doğrulaması yapılmadan önce gereken tüm uzantıları kaydedersiniz:

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

// autoload.php dosyasının gerçek yolunu girin
require __DIR__ . '/vendor/autoload.php';

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

$linter = new Latte\Tools\Linter;
$latte = $linter->getEngine();
// kendi uzantılarınızı buraya ekleyin
$latte->addExtension(/* ... */);

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

Alternatif olarak Linter'a kendi `Latte\Engine` nesnenizi verebilirsiniz:

```php
$latte = new Latte\Engine;
// $latte nesnesini burada yapılandırıyoruz
$linter = new Latte\Tools\Linter(engine: $latte);
```

Ortaya çıkan özelleştirilmiş linter, standart araçla aynı şekilde, ama tüm özel uzantılarınızı tam olarak bilerek kullanılabilir.


Şablonları bir dizeden yükleme
==============================

Şablonları, belki test amacıyla, dosyalar yerine dizelerden yüklemeniz mi gerekiyor? [StringLoader |loaders#StringLoader] size yardım eder:

```php
$latte->setLoader(new Latte\Loaders\StringLoader([
	'main.file' => '{include other.file}',
	'other.file' => '{if true} {$var} {/if}',
]));

$latte->render('main.file', $params);
```


İstisna işleyici
================

Beklenen istisnalar için kendi işleyicinizi tanımlayabilirsiniz. [`{try}` |tags#{try}] içinde ve [sandbox]'ta oluşan istisnalar ona aktarılır.

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

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


Otomatik layout arama
=====================

Şablon, [`{layout}` |template-inheritance#Layout Inheritance] etiketiyle üst şablonunu belirler. Layout'un otomatik aranmasını sağlamak da mümkündür; bu, şablonların `{layout}` etiketini içermesi gerekmeyeceğinden onları yazmayı kolaylaştırır.

Bu şöyle sağlanır:

```php
// üst şablon dosyasının yolunu döndürür
$finder = fn(Latte\Runtime\Template $template) => 'automatic.layout.latte';
$latte = new Latte\Engine;
$latte->addProvider('coreParentFinder', $finder);
```

Şablonun layout'u olmaması gerekiyorsa, bunu `{layout none}` etiketiyle belirtir.

Geliştiriciler için pratikler

Kurulum

Latte'yi kurmanın en iyi yolu Composer'dır:

composer require latte/latte

Desteklenen PHP sürümleri (en son yama Latte sürümleri için geçerlidir):

sürüm uyumlu olduğu PHP
Latte 3.1 PHP 8.2 – 8.5
Latte 3.0 PHP 8.0 – 8.5

Bir şablon nasıl render edilir

Bir şablon nasıl render edilir? Şu basit kodu kullanmanız yeterli:

$latte = new Latte\Engine;
// önbellek dizini
$latte->setCacheDirectory('/path/to/tempdir');

$params = [ /* şablon değişkenleri */ ];
// veya $params = new TemplateParameters(/* ... */);

// çıktıya render et
$latte->render('template.latte', $params);
// veya bir değişkene render et
$output = $latte->renderToString('template.latte', $params);

Parametreler dizi olabilir ya da daha iyisi, tip denetimi ve editörde öneri sağlayacak bir nesne olabilir.

Kullanım örneklerini Latte examples deposunda da bulabilirsiniz.

Performans ve önbellekleme

Latte şablonları son derece hızlıdır, çünkü Latte onları doğrudan PHP koduna derler ve diskte önbelleğe alır. Böylece saf PHP ile yazılmış şablonlara kıyasla ek bir yük getirmezler.

Kaynak dosyayı her değiştirdiğinizde önbellek otomatik yeniden üretilir. Böylece geliştirme sırasında Latte şablonlarınızı rahatça düzenleyip değişiklikleri tarayıcıda hemen görebilirsiniz. Bu özelliği üretim ortamında kapatıp biraz performans kazanabilirsiniz:

$latte->setAutoRefresh(false);

Üretim sunucusuna dağıtım yapıldığında, özellikle daha büyük uygulamalarda ilk önbellek üretimi anlaşılır biçimde biraz zaman alabilir. Latte'de önbellek stampedesine karşı yerleşik bir önlem vardır. Bu, sunucunun çok sayıda eşzamanlı istek aldığı ve Latte'nin önbelleği henüz var olmadığı için hepsinin aynı anda onu üreteceği durumdur. Bu da CPU'yu zıplatır. Latte akıllıdır; birden fazla eşzamanlı istek olduğunda önbelleği yalnızca ilk iş parçacığı üretir, diğerleri bekler ve sonra onu kullanır.

Önbelleği dağıtım sırasında (örneğin bir dağıtım betiğinde) Engine::warmupCache() metoduyla önceden de üretebilirsiniz. Verilen şablonu önbelleğe önceden derler, böylece ilk ziyaretçinin beklemesi gerekmez: $latte->warmupCache('template.latte').

Latte'yi genişletme yolları

Latte, basit yardımcılardan tamamen yeni dil yapılarına kadar birkaç şekilde özelleştirilebilir. Latte'yi genişletme sayfası bunları ayrıntılı ele alır; işte hızlı bir bakış:

  • Özel filtreler: şablon çıktısındaki veriyi biçimlendirmek veya dönüştürmek için (örneğin {$var|myFilter}).
  • Özel fonksiyonlar: şablon ifadelerinin içinde çağırdığınız özel mantık için (örneğin {myFunction($arg)}).
  • Özel etiketler: tamamen yeni dil yapıları için ({mytag}...{/mytag} veya n:mytag).
  • Compiler pass'leri: şablonun AST'sini ayrıştırma ile PHP kodu üretimi arasında değiştiren fonksiyonlar (örneğin iyileştirmeler veya güvenlik denetimleri).
  • Özel loader'lar: Latte'nin şablon dosyalarını nasıl bulup yüklediğini değiştirmek için.

Uzantılarınızı projeler arasında yeniden kullanmak veya başkalarıyla paylaşmak isterseniz, onları bir Latte uzantısı sınıfında toplayın.

Parametreler bir sınıf olarak

Değişkenleri şablona dizi olarak aktarmaktansa bir sınıf oluşturmak daha iyidir. Tip güvenli yazım, IDE'de güzel öneriler ve filtre ile fonksiyon kaydetme yolu elde edersiniz.

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

Bir değişkenin otomatik kaçışını kapatma

Değişken bir HTML dizesi içeriyorsa, Latte'nin onu otomatik (ve dolayısıyla iki kez) kaçırmaması için işaretleyebilirsiniz. Böylece şablonda |noescape belirtmeye gerek kalmaz.

En kolayı, dizeyi bir Latte\Runtime\Html nesnesine sarmaktır:

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

Latte, Latte\Runtime\HtmlStringable arayüzünü uygulayan tüm nesneleri de kaçırmaz. Yani __toString() metodu otomatik kaçırılmayacak HTML kodu döndüren kendi sınıfınızı oluşturabilirsiniz:

class Emphasis implements Latte\Runtime\HtmlStringable
{
	public function __construct(
		private string $str,
	) {
	}

	public function __toString(): string
	{
		return '<em>' . htmlspecialchars($this->str) . '</em>';
	}
}

$params = [
	'foo' => new Emphasis('hello'),
];

__toString metodu doğru HTML döndürmeli ve parametre kaçışını sağlamalıdır, aksi halde bir XSS güvenlik açığı oluşabilir!

Latte filtrelerle, etiketlerle vb. nasıl genişletilir

Latte'ye özel bir filtre, fonksiyon, etiket vb. nasıl eklenir? Latte'yi genişletme bölümünde öğrenin. Değişikliklerinizi farklı projelerde yeniden kullanmak ya da başkalarıyla paylaşmak isterseniz, o zaman bir uzantı oluşturmalısınız.

Şablonda herhangi bir kod {php ...}

{do} etiketinin içinde yalnızca PHP ifadeleri yazılabilir, bu yüzden örneğin if ... else gibi yapıları ya da noktalı virgülle biten deyimleri ekleyemezsiniz.

Ancak {php ...} etiketini ekleyen RawPhpExtension uzantısını kaydedebilirsiniz. Bunu herhangi bir PHP kodunu eklemek için kullanabilirsiniz. Hiçbir sandbox modu kuralına tabi değildir, bu yüzden kullanımı şablon yazarının sorumluluğundadır.

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

Üretilen kodun denetimi

Latte şablonları PHP koduna derler. Elbette üretilen kodun sözdizimsel olarak geçerli olmasını sağlar. Ancak üçüncü taraf uzantılar veya RawPhpExtension kullanılırken Latte, üretilen dosyanın doğruluğunu garanti edemez. Ayrıca PHP'de, sözdizimsel olarak doğru ama yasak olan (örneğin $this değişkenine değer atamak) ve PHP Compile Error'a yol açan kod yazabilirsiniz. Böyle bir işlemi bir şablona yazarsanız, üretilen PHP koduna da girer. PHP'de iki yüzden fazla farklı yasak işlem olduğundan Latte, onları saptamayı hedeflemez. Render sırasında PHP'nin kendisi bunları bildirir; bu genellikle sorun değildir.

Ancak şablonun PHP Compile Error içermediğini derleme sırasında bilmek istediğiniz durumlar vardır. Özellikle şablonlar kullanıcılar tarafından düzenlenebiliyorsa ya da Sandbox kullanıyorsanız. Böyle bir durumda şablonları derleme sırasında denetletin. Bu işlevselliği Engine::enablePhpLinter() metoduyla etkinleştirebilirsiniz. Denetim için PHP ikili dosyasını çağırması gerektiğinden, yolunu parametre olarak verin:

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

try {
	$latte->compile('home.latte');
} catch (Latte\CompileException $e) {
	// Latte hatalarını ve ayrıca PHP'deki Compile Error'ı yakalar
	echo 'Error: ' . $e->getMessage();
}

Yerel ayar

Latte, sayıların ve tarihlerin biçimlendirilmesini ve sıralamayı etkileyen yerel ayarı belirlemenize olanak tanır. setLocale() metoduyla ayarlanır. Yerel ayar tanımlayıcısı, PHP intl uzantısını kullanan IETF dil etiketi standardını izler. Bir dil kodundan ve gerekirse bir ülke kodundan oluşur; örneğin Amerika Birleşik Devletleri'ndeki İngilizce için en_US, Almanya'daki Almanca için de_DE vb.

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

Yerel ayar; localDate, sort, number ve bytes filtrelerini etkiler.

PHP intl uzantısını gerektirir. Latte'deki ayar, PHP'deki genel yerel ayarı etkilemez.

Katı mod

Katı ayrıştırma modunda Latte, eksik kapanış HTML etiketlerini denetler ve ayrıca $this değişkeninin kullanımını kapatır. Onu açmak için:

$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::StrictParsing);

Şablonları declare(strict_types=1) başlığıyla üretmek için şunu yapın:

$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::StrictTypes);

Latte 3.1'den beri katı tipler varsayılan olarak etkindir. Onları $latte->setFeature(Latte\Feature::StrictTypes, false) ile kapatabilirsiniz.

Geçiş uyarıları

Latte 3.1, bazı HTML niteliklerinin davranışını değiştirir. Örneğin null değerler artık boş dize yazdırmak yerine niteliği düşürür. Bu değişikliğin şablonlarınızı etkilediği yerleri kolayca bulmak için geçiş uyarılarını etkinleştirebilirsiniz:

$latte->setFeature(Latte\Feature::MigrationWarnings);

Etkinleştirildiğinde Latte, render edilen nitelikleri denetler ve çıktı Latte 3.0'ın üreteceğinden farklıysa bir kullanıcı uyarısı (E_USER_WARNING) tetikler. Bir uyarıyla karşılaştığınızda şu çözümlerden birini uygulayın:

  1. Yeni çıktı kullanım durumunuz için doğruysa (örneğin null iken niteliğin kaybolmasını yeğliyorsanız), |accept filtresini ekleyerek uyarıyı bastırın
  2. Değişken null iken niteliğin düşürülmesi yerine boş render edilmesini istiyorsanız (örneğin title=""), yedek olarak boş bir dize verin: title={$val ?? ''}
  3. Kesinlikle eski davranışı istiyorsanız (örneğin true için "true" yerine "1" yazdırmak), değeri açıkça dizeye dönüştürün: data-foo={(string) $val}

Tüm uyarılar giderildiğinde geçiş uyarılarını kapatın ve artık gerekmediklerinden şablonlarınızdaki tüm |accept filtrelerini kaldırın.

Kapsamlı döngü değişkenleri

Varsayılan olarak, bir {foreach} döngüsünde tanımlanan değişkenler ($key ve $value gibi) döngü bittikten sonra da erişilebilir kalır; tıpkı PHP'nin kendisinde olduğu gibi. Bir döngü değişkeni var olan bir şablon değişkeniyle aynı ada sahip olduğunda bu, istenmeyen değişken ezmelerine yol açabilir.

ScopedLoopVariables özelliği, döngü değişkenlerinin kapsamını döngü gövdesiyle sınırlar. Döngü bittikten sonra değişkenin özgün değeri geri yüklenir (daha önce varsa) ya da değişken kaldırılır:

$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::ScopedLoopVariables);

Farkın bir örneği:

{var $item = 'original'}
{foreach [1, 2] as $item}{$item}, {/foreach}
{$item}

ScopedLoopVariables olmadan: 1, 2, 2 yazdırır (değişken ezilir) ScopedLoopVariables ile: 1, 2, original yazdırır (değişken geri yüklenir)

Bu, yapı bozma sözdizimiyle de çalışır, örneğin {foreach $array as [$a, $b]}.

Referans kullanan döngü değişkenleri ({foreach $array as &$value}) veya özellik atamaları ({foreach $array as $obj->prop}) kapsamlandırılmaz, çünkü bu, amaçlarını bozar.

Otomatik girinti kaldırma

{if}, {foreach} veya {block} gibi çift etiketler kullanırken, okunabilirlik için iç içe içeriği sıklıkla girintilersiniz. Ancak bu girinti varsayılan olarak üretilen çıktıya dahil edilir. Dedent özelliği onu otomatik kaldırır, böylece Latte etiketlerinizi ne kadar derin iç içe geçirirseniz geçirin çıktı temiz kalır:

$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::Dedent);

Örnek:

{if true}
	Hello
	World
{/if}

Dedent olmadan çıktı girintiyi içerirdi (\tHello\n\tWorld\n). Dedent ile girinti soyulur ve çıktı Hello\nWorld\n olur.

Bir bloğun içindeki daha derin girinti, temel girintiye göre korunur:

{if true}
	Hello
		Indented
{/if}

Çıktı: Hello\n\tIndented\n.

Bir bloğun içindeki girinti tutarlı olmalıdır (ya tabulatör ya boşluk). Karışırlarsa Latte bir Inconsistent indentation istisnası fırlatır.

Şablonlarda çeviri

Şablona {_...}, {translate} ve translate filtresini eklemek için TranslatorExtension uzantısını kullanın. Bunlar, değerleri ya da şablonun bölümlerini başka dillere çevirmeye yarar. Parametre, çeviriyi gerçekleştiren callable ya da Nette\Localization\Translator tipinde bir nesnedir (çevirileri kapatmak için null verin):

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

	public function translate(string $original): string
	{
		// $this->lang'a göre $original'dan $translated oluştur
		return $translated;
	}
}

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

Çevirmen, şablon render edilirken çalışma zamanında çağrılır. Ancak Latte tüm statik metinleri şablon derlenirken çevirebilir. Bu performanstan tasarruf sağlar, çünkü her dize yalnızca bir kez çevrilir ve elde edilen çeviri derlenmiş dosyaya yazılır. Böylece önbellek dizininde şablonun her dil için bir tane olmak üzere birden fazla derlenmiş sürümü oluşur. Bunun için dili yalnızca ikinci parametre olarak belirtmeniz gerekir:

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

Statik metin derken örneğin {_'hello'} veya {translate}hello{/translate} kastediyoruz. {_$foo} gibi statik olmayan metinler çalışma zamanında çevrilmeye devam eder.

Şablon, çevirmene {_$original, foo: bar} veya {translate foo: bar} ile ek parametreler de aktarabilir; çevirmen onları $params dizisi olarak alır:

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

Hata ayıklama ve Tracy

Latte, geliştirmeyi olabildiğince keyifli kılmaya çalışır. Hata ayıklama amacıyla üç etiket vardır: {dump}, {debugbreak} ve {trace}.

En çok rahatlığı, harika hata ayıklama aracı Tracy'yi kurup Latte eklentisini etkinleştirerek elde edersiniz:

// Tracy'yi etkinleştirir
Tracy\Debugger::enable();

$latte = new Latte\Engine;
// Tracy'nin uzantısını etkinleştirir
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);

Artık tüm hataları düzgün bir kırmızı ekranda göreceksiniz; şablonlardaki hatalar da satır ve sütun vurgusuyla dahil (video). Aynı zamanda sağ alt köşede, Tracy Bar denilen yerde, render edilen tüm şablonları ve ilişkilerini (şablona veya derlenmiş koda tıklama olanağı dahil) ve ayrıca değişkenleri açıkça görebileceğiniz bir Latte sekmesi belirir:

Latte şablonları okunabilir PHP koduna derlediğinden, IDE'nizde onların içinde rahatça adım adım ilerleyebilirsiniz.

Linter: şablon sözdiziminin doğrulanması

Linter aracı, tüm şablonları doğrulamaya yarar. Amacı, belirtilen dosyaları taramak ve içlerinde sözdizimi hatası ile var olmayan etiketlere, filtrelere, fonksiyonlara, sınıflara veya benzer yapılara başvuru bulunmadığından emin olmaktır.

Linter komut satırından çalıştırılır:

vendor/bin/latte-lint <path>

Katı mod'u etkinleştirmek için --strict parametresini kullanın. --debug parametresi, işlenen her dosyanın adını ve tam istisna ayrıntılarını yazdırır; bu, sorun giderirken yardımcı olur.

Özel etiketler, filtreler veya başka Latte uzantıları kullanıyorsanız, Linter'ın kendi varyantınızı oluşturmanız gerekir, örneğin custom-latte-lint. Bu betikte, asıl şablon doğrulaması yapılmadan önce gereken tüm uzantıları kaydedersiniz:

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

// autoload.php dosyasının gerçek yolunu girin
require __DIR__ . '/vendor/autoload.php';

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

$linter = new Latte\Tools\Linter;
$latte = $linter->getEngine();
// kendi uzantılarınızı buraya ekleyin
$latte->addExtension(/* ... */);

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

Alternatif olarak Linter'a kendi Latte\Engine nesnenizi verebilirsiniz:

$latte = new Latte\Engine;
// $latte nesnesini burada yapılandırıyoruz
$linter = new Latte\Tools\Linter(engine: $latte);

Ortaya çıkan özelleştirilmiş linter, standart araçla aynı şekilde, ama tüm özel uzantılarınızı tam olarak bilerek kullanılabilir.

Şablonları bir dizeden yükleme

Şablonları, belki test amacıyla, dosyalar yerine dizelerden yüklemeniz mi gerekiyor? StringLoader size yardım eder:

$latte->setLoader(new Latte\Loaders\StringLoader([
	'main.file' => '{include other.file}',
	'other.file' => '{if true} {$var} {/if}',
]));

$latte->render('main.file', $params);

İstisna işleyici

Beklenen istisnalar için kendi işleyicinizi tanımlayabilirsiniz. {try} içinde ve sandbox'ta oluşan istisnalar ona aktarılır.

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

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

Otomatik layout arama

Şablon, {layout} etiketiyle üst şablonunu belirler. Layout'un otomatik aranmasını sağlamak da mümkündür; bu, şablonların {layout} etiketini içermesi gerekmeyeceğinden onları yazmayı kolaylaştırır.

Bu şöyle sağlanır:

// üst şablon dosyasının yolunu döndürür
$finder = fn(Latte\Runtime\Template $template) => 'automatic.layout.latte';
$latte = new Latte\Engine;
$latte->addProvider('coreParentFinder', $finder);

Şablonun layout'u olmaması gerekiyorsa, bunu {layout none} etiketiyle belirtir.