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}veyan: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:
- Yeni çıktı kullanım durumunuz için doğruysa (örneğin
nulliken niteliğin kaybolmasını yeğliyorsanız),|acceptfiltresini ekleyerek uyarıyı bastırın - Değişken
nulliken niteliğin düşürülmesi yerine boş render edilmesini istiyorsanız (örneğintitle=""), yedek olarak boş bir dize verin:title={$val ?? ''} - Kesinlikle eski davranışı istiyorsanız (örneğin
trueiç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.