Şablonlar

Nette, Latte şablon sistemini kullanır. Latte kullanılır, çünkü PHP için en güvenli ve aynı zamanda en sezgisel şablon sistemidir. Yeni çok şey öğrenmeniz gerekmez; PHP bilgisi ve birkaç etiket yeterlidir.

Bir sayfanın layout şablonu + somut eylemin şablonundan oluşması yaygındır. Bir layout şablonu şöyle görünebilir; {block} bloklarına ve {include} etiketine dikkat edin:

<!DOCTYPE html>
<html>
<head>
	<title>{block title}Uygulamam{/block}</title>
</head>
<body>
	<header>...</header>
	{include content}
	<footer>...</footer>
</body>
</html>

Eylem şablonu ise şöyle olurdu:

{block title}Ana sayfa{/block}

{block content}
<h1>Ana sayfa</h1>
...
{/block}

Layout'ta {include content} yerine eklenen content bloğunu tanımlar ve ayrıca layout'taki {block title}'ın üzerine yazan title bloğunu yeniden tanımlar. Sonucu gözünüzde canlandırmaya çalışın.

Şablon arama

Presenter'larda hangi şablonun render edileceğini belirtmeniz gerekmez; framework yolu kendiliğinden çıkarır ve sizi yazmaktan kurtarır.

Her presenter'ın kendi dizinine sahip olduğu bir dizin yapısı kullanıyorsanız, şablonu bu dizine eylemin (yani görünümün) adıyla koymanız yeterlidir. Örneğin default eylemi için default.latte şablonunu kullanın:

app/
└── Presentation/
    └── Home/
        ├── HomePresenter.php
        └── default.latte

Presenter'ların tek bir dizinde bir arada olduğu ve şablonların bir templates klasöründe bulunduğu bir yapı kullanıyorsanız, onu ya <Presenter>.<görünüm>.latte ya da <Presenter>/<görünüm>.latte dosyasına kaydedin:

app/
└── Presenters/
    ├── HomePresenter.php
    └── templates/
        ├── Home/
        │   └── default.latte   ← 1. seçenek
        └── Home.default.latte  ← 2. seçenek

templates dizini bir düzey yukarıya, yani presenter sınıflarının bulunduğu dizinle aynı düzeye de konabilir.

Şablon bulunamazsa presenter 404 – sayfa bulunamadı hatasıyla yanıt verir.

Görünümü $this->setView('digerGorunum') ile değiştirebilirsiniz. Şablon dosyasını $this->template->setFile('/path/to/template.latte') ile doğrudan belirtmek de mümkündür.

Şablonların arandığı dosyalar, olası dosya adlarının dizisini döndüren formatTemplateFiles() metodu ezilerek değiştirilebilir.

Layout şablonu arama

Nette layout dosyasını da otomatik arar.

Her presenter'ın kendi dizinine sahip olduğu bir dizin yapısı kullanıyorsanız, layout'u yalnızca ona özgüyse presenter'ın klasörüne, birden fazla presenter için ortaksa bir düzey yukarıya koyun:

app/
└── Presentation/
    ├── @layout.latte           ← ortak layout
    └── Home/
        ├── @layout.latte       ← yalnızca Home presenter'ı için
        ├── HomePresenter.php
        └── default.latte

Presenter'ların tek bir dizinde toplandığı ve şablonların bir templates klasöründe bulunduğu bir yapı kullanıyorsanız, layout şu konumlarda beklenir:

app/
└── Presenters/
    ├── HomePresenter.php
    └── templates/
        ├── @layout.latte       ← ortak layout
        ├── Home/
        │   └── @layout.latte   ← yalnızca Home için, 1. seçenek
        └── Home.@layout.latte  ← yalnızca Home için, 2. seçenek

Presenter bir modülde yer alıyorsa, modül iç içeliğine göre dizin düzeylerinde daha yukarıya doğru da arama yapılır.

Layout'un adı $this->setLayout('layoutAdmin') ile değiştirilebilir, o zaman @layoutAdmin.latte dosyasında beklenir. Layout şablonu dosyasını $this->setLayout('/path/to/template.latte') ile doğrudan da belirtebilirsiniz.

$this->setLayout(false) veya şablonun içindeki {layout none} etiketi, layout aramasını kapatır.

Layout şablonlarının arandığı dosyalar, olası dosya adlarının dizisini döndüren formatLayoutTemplateFiles() metodu ezilerek değiştirilebilir.

Şablon değişkenleri

Değişkenler şablonlara $this->template'e yazılarak aktarılır. Şablonda yerel değişken olarak erişilebilir olurlar:

$this->template->article = $this->articles->getById($id);

Bir özelliğin değerini şablona otomatik olarak değişken şeklinde aktarmak için onu #[TemplateVariable] niteliğiyle ve public görünürlükle işaretleyin:

use Nette\Application\Attributes\TemplateVariable;

class ArticlePresenter extends Nette\Application\UI\Presenter
{
	#[TemplateVariable]
	public string $siteName = 'Blogum';
}

Şablona aynı adlı bir değişken aktarırsanız, #[TemplateVariable] onun üzerine yazmaz.

Varsayılan değişkenler

Presenter'lar ve bileşenler şablonlara birkaç yararlı değişkeni otomatik aktarır:

  • $basePath, kök dizine giden mutlak URL yoludur (örneğin /eshop)
  • $baseUrl, kök dizine giden mutlak URL'dir (örneğin http://localhost/eshop)
  • $user, kullanıcıyı temsil eden bir nesnedir
  • $presenter, geçerli presenter'dır
  • $control, geçerli bileşen veya presenter'dır
  • $flashes, flashMessage() fonksiyonuyla gönderilen mesajların dizisidir

Kendi şablon sınıfınızı kullanıyorsanız, bu değişkenler onlar için bir özellik oluşturursanız aktarılır.

Tip güvenli şablonlar

Sağlam uygulamalar geliştirirken, şablonun hangi değişkenleri beklediğini ve bunların tiplerini açıkça tanımlamak yararlıdır. Bu, PHP'de tip denetimi, IDE'nizde akıllı ipuçları sağlar ve statik analizin hataları yakalamasını mümkün kılar.

Böyle bir listeyi nasıl tanımlarsınız? Basitçe, şablon değişkenlerini temsil eden özelliklere sahip bir sınıf olarak. Onu presenter'a benzer şekilde, sonuna Template ekleyerek adlandırın:

/**
 * @property-read ArticleTemplate $template
 */
class ArticlePresenter extends Nette\Application\UI\Presenter
{
}

class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template
{
	public Model\Article $article;
	public Nette\Security\User $user;

	// ve diğer değişkenler
}

Presenter'daki $this->template nesnesi artık ArticleTemplate sınıfının bir örneği olacaktır. Böylece PHP, yazma sırasında bildirilen tipleri denetler.

Nette şablon sınıfını otomatik seçer. Önce <Presenter><Eylem>Template adlı bir sınıf arar, örneğin edit eylemi için ArticleEditTemplate, ve ancak o yoksa <Presenter>Template'e geri döner.

@property-read anotasyonu IDE ve statik analiz içindir, kod tamamlamayı sağlar; bkz. PhpStorm ve $this⁠-⁠>⁠template için kod tamamlama.

Kod tamamlamayı doğrudan şablonlarda da kullanabilirsiniz. PhpStorm için Latte eklentisini kurmanız ve şablonun başında şablon parametre sınıfının adını belirtmeniz yeterlidir; ayrıntılar Latte: tip sistemi bölümünde:

{templateType App\Presentation\Article\ArticleTemplate}
...

Aynısı bileşenler için de geçerlidir. Adlandırma kuralına uyun ve FifteenControl gibi bir bileşen için FifteenTemplate parametre sınıfını oluşturun.

Farklı bir parametre sınıfı kullanmanız gerekirse createTemplate() metodunu kullanın:

public function renderDefault(): void
{
	$template = $this->createTemplate(SpecialTemplate::class);
	$template->foo = 123;
	// ...
	$this->sendTemplate($template);
}

Şablonun render edilmeden önce nasıl tamamlanacağını etkilemeniz gerekirse, örneğin tüm eylemlerde ortak değişkenler eklemek için, presenter'da completeTemplate() metodunu ezebilirsiniz. Şablon render edilmeden hemen önce çağrılır:

protected function completeTemplate(Nette\Application\UI\Template $template): void
{
	parent::completeTemplate($template);
	$template->siteName = 'Blogum';
}

Bağlantı oluşturma

Şablonda başka presenter'lara ve eylemlere bağlantılar şöyle oluşturulur:

<a n:href="Product:show">ürün detayı</a>

n:href niteliği HTML <a> etiketleri için çok kullanışlıdır. Bağlantıyı başka bir yerde, örneğin metin içinde yazdırmak istersek {link} kullanırız:

URL şudur: {link Home:default}

Daha fazla bilgiyi URL bağlantıları oluşturma bölümünde bulabilirsiniz.

Özel filtreler, etiketler vb.

Latte şablon sistemi özel filtreler, fonksiyonlar, etiketler ve başka öğelerle genişletilebilir. Hızlı geçici çözümlerden tüm uygulamalar için mimari kalıplara uzanan üç yaklaşım vardır.

Presenter metotlarında geçici olarak

En hızlı yaklaşım, filtreleri veya fonksiyonları doğrudan presenter ya da bileşen kodunda eklemektir. Presenter'larda bunun için beforeRender() veya render<Görünüm>() metotları uygundur:

protected function beforeRender(): void
{
	// filtre ekleme
	$this->template->addFilter('money', fn($val) => '$' . number_format($val, 2));

	// fonksiyon ekleme
	$this->template->addFunction('isWeekend', fn($date) => $date->format('N') >= 6);
}

Şablonda:

<p>Fiyat: {$price|money}</p>

{if isWeekend($now)} ... {/if}

Daha karmaşık mantık için Latte\Engine nesnesini doğrudan yapılandırabilirsiniz:

protected function beforeRender(): void
{
	$latte = $this->template->getLatte();
	$latte->setFeature(Latte\Feature::MigrationWarnings);
}

Nitelikleri kullanarak

Daha zarif bir yaklaşım, filtreleri ve fonksiyonları doğrudan presenter'ın veya bileşenin şablon parametre sınıfında metot olarak tanımlamak ve niteliklerle işaretlemektir:

class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template
{
	#[Latte\Attributes\TemplateFilter]
	public function money(float $val): string
	{
		return '$' . number_format($val, 2);
	}

	#[Latte\Attributes\TemplateFunction]
	public function isWeekend(DateTimeInterface $date): bool
	{
		return $date->format('N') >= 6;
	}
}

Latte, bu niteliklerle işaretlenmiş metotları otomatik bulur ve kaydeder. Şablonlardaki filtre veya fonksiyon adı metot adıyla aynıdır. Bu metotlar public olmalıdır.

Uzantılarla genel olarak

Önceki yaklaşımlar, yalnızca belirli presenter'larda veya bileşenlerde gereken filtre ve fonksiyonlar için uygundur, uygulama geneli için değil. Tüm uygulama için bir uzantı oluşturmak en iyi sonucu verir. Bu sınıf, projenizdeki tüm Latte uzantılarını tek yerde toplar. Kısa bir örnek:

namespace App\Presentation\Accessory;

final class LatteExtension extends Latte\Extension
{
	public function __construct(
		private App\Model\Facade $facade,
		private Nette\Security\User $user,
		// ...
	) {
	}

	public function getFilters(): array
	{
		return [
			'timeAgoInWords' => $this->filterTimeAgoInWords(...),
			'money' => $this->filterMoney(...),
			// ...
		];
	}

	public function getFunctions(): array
	{
		return [
			'canEditArticle' =>
				fn($article) => $this->facade->canEditArticle($article, $this->user->getId()),
			// ...
		];
	}

	private function filterTimeAgoInWords(DateTimeInterface $time): string
	{
		// ...
	}

	// ...
}

Uzantıyı yapılandırma üzerinden kaydedin:

latte:
	extensions:
		- App\Presentation\Accessory\LatteExtension

Uzantılar birkaç avantaj sunar: bağımlılık enjeksiyonu desteği, uygulamanızın model katmanına erişim ve tüm uzantıların tek yerden yönetimi. Ayrıca özel etiketleri, sağlayıcıları, compiler pass'leri ve daha fazlasını desteklerler.

Tüm şablonların ayarlanması

Tüm şablonları oluşturan TemplateFactory servisi, public bir $onCreate callback dizisi sunar. Bunlar herhangi bir şablon her oluşturulduğunda çağrılır, böylece uygulamadaki tüm şablonlar için filtreleri, fonksiyonları veya değişkenleri tek bir yerden ayarlayabilirsiniz. Her callback, yeni oluşturulan şablonu alır. TemplateFactory servisini enjekte ettirin ve callback'leri, örneğin uygulama başlarken kaydedin:

$templateFactory->onCreate[] = function (Nette\Bridges\ApplicationLatte\Template $template): void {
	$template->addFilter('money', fn($val) => '$' . number_format($val, 2));
};

Çeviri

Çok dilli bir uygulama programlıyorsanız, büyük olasılıkla şablondaki bazı metinleri farklı dillerde çıkarmanız gerekecek. Nette Framework bunun için tek bir translate() metoduna sahip Nette\Localization\Translator çeviri arayüzünü tanımlar. Genellikle bir dize olan $message mesajını ve başka parametreleri kabul eder. Görevi çevrilmiş dizeyi döndürmektir. Nette'in varsayılan bir uygulaması yoktur; ihtiyacınıza göre Componette üzerinde bulunan hazır çözümlerden seçebilirsiniz. Çevirmenin nasıl yapılandırılacağını dokümantasyonları anlatır.

Şablonlara, aktarılmasını sağladığımız çevirmen setTranslator() metoduyla ayarlanabilir:

protected function beforeRender(): void
{
	// ...
	$this->template->setTranslator($translator);
}

Alternatif olarak çevirmen yapılandırma ile ayarlanabilir:

latte:
	extensions:
		- Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)

Sonra çevirmen örneğin bir |translate filtresi olarak, translate() metoduna aktarılan ek parametrelerle birlikte kullanılabilir (bkz. foo, bar):

<a href="basket">{='Sepet'|translate}</a>
<span>{$item|translate}</span>
<span>{$item|translate, foo, bar}</span>

Ya da alt çizgi etiketi olarak:

<a href="basket">{_'Sepet'}</a>
<span>{_$item}</span>
<span>{_$item, foo, bar}</span>

Şablonun bir bölümünü çevirmek için {translate} çift etiketi vardır (Latte 2.11'den beri, önceden {_} etiketi kullanılıyordu):

<a href="order">{translate}Sipariş{/translate}</a>
<a href="order">{translate foo, bar}Sipariş{/translate}</a>

Çevirmen normalde şablon render edilirken, çalışma zamanında çağrılır. Ancak Latte 3 sürümü, tüm statik metinleri daha şablon derlenirken çevirebilir. Bu performanstan tasarruf sağlar, çünkü her dize yalnızca bir kez çevrilir ve elde edilen çeviri derlenmiş biçime 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 ikinci parametre olarak belirtmeniz yeterlidir:

protected function beforeRender(): void
{
	// ...
	$this->template->setTranslator($translator, $lang);
}

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

versiyon: 4.x