Predloge

Nette uporablja sistem predlog Latte. Latte se uporablja, ker je najbolj varen sistem predlog za PHP in hkrati najbolj intuitiven. Ni se vam treba naučiti veliko novega, poznati morate le PHP in nekaj oznak Latte.

Običajno je stran dokončana iz predloge za postavitev + predloge za akcijo. Tako je lahko videti predloga za postavitev, opazite bloke {block} in oznake {include}:

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

To pa je lahko predloga za dejanja:

{block title}Homepage{/block}

{block content}
<h1>Homepage</h1>
...
{/block}

V njej je opredeljen blok content, ki se v postavitev vstavi namesto bloka {include content}, prav tako pa je na novo opredeljen blok title, ki v postavitvi prepiše blok {block title}. Poskusite si predstavljati rezultat.

Iskanje predloge

V predstavitvenih programih vam ni treba določiti, katera predloga naj se prikaže; ogrodje samodejno določi pot, kar vam olajša kodiranje.

Če uporabljate imeniško strukturo, v kateri ima vsak predstavnik svoj imenik, preprosto postavite predlogo v ta imenik pod ime dejanja (npr. pogleda). Na primer, za dejanje default uporabite predlogo default.latte:

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

Če uporabljate strukturo, v kateri so predstavniki skupaj v enem imeniku, predloge pa v mapi templates, jo shranite bodisi v datoteko <Presenter>.<view>.latte ali . <Presenter>/<view>.latte:

app/
└── Presenters/
    ├── HomePresenter.php
    └── templates/
        ├── Home.default.latte  ← 1st variant
        └── Home/
            └── default.latte   ← 2nd variant

Imenik templates lahko postavite tudi eno raven višje, na isto raven kot imenik z razredi predavateljev.

Če predloge ni mogoče najti, se predstavitveni program odzove z napako 404 – stran ni najdena.

Prikaz lahko spremenite z uporabo spletne strani $this->setView('anotherView'). Datoteko s predlogo lahko določite tudi neposredno z uporabo $this->template->setFile('/path/to/template.latte').

Datoteke, v katerih se iščejo predloge, lahko spremenite tako, da nadgradite metodo formatTemplateFiles(), ki vrne polje možnih imen datotek.

Iskanje predlog za postavitev

Nette samodejno poišče tudi datoteko z maketo.

Če uporabljate imeniško strukturo, v kateri ima vsak predavatelj svoj imenik, postavite postavitev bodisi v mapo s predavateljem, če je namenjena samo njemu, bodisi za stopnjo višje, če je skupna več predavateljem:

app/
└── UI/
    ├── @layout.latte           ← common layout
    └── Home/
        ├── @layout.latte       ← only for Home presenter
        ├── HomePresenter.php
        └── default.latte

Če uporabljate strukturo, v kateri so predstavniki združeni v enem imeniku, predloge pa so v mapi templates, bo postavitev pričakovana na naslednjih mestih:

app/
└── Presenters/
    ├── HomePresenter.php
    └── templates/
        ├── @layout.latte       ← common layout
        ├── Home.@layout.latte  ← only for Home, 1st variant
        └── Home/
            └── @layout.latte   ← only for Home, 2nd variant

Če je predstavnik v modulu, se bo poiskal tudi naprej po drevesu imenika v skladu z gnezdenjem modula.

Ime postavitve lahko spremenite z uporabo spletne strani $this->setLayout('layoutAdmin'), nato pa jo boste pričakali v datoteki @layoutAdmin.latte. Datoteko s predlogo postavitve lahko določite tudi neposredno z uporabo $this->setLayout('/path/to/template.latte').

Uporaba $this->setLayout(false) ali oznake {layout none} znotraj predloge onemogoči iskanje postavitve.

Datoteke, v katerih se iščejo predloge postavitve, lahko spremenite tako, da nadgradite metodo formatLayoutTemplateFiles(), ki vrne polje možnih imen datotek.

Spremenljivke v predlogi

Spremenljivke posredujemo predlogi tako, da jih zapišemo na naslov $this->template, nato pa so v predlogi na voljo kot lokalne spremenljivke:

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

Na ta način lahko predlogi enostavno posredujemo poljubne spremenljivke. Vendar je pri razvoju robustnih aplikacij pogosto bolj koristno, da se omejimo. Na primer tako, da izrecno določimo seznam spremenljivk, ki jih predloga pričakuje, in njihove vrste. To bo PHP omogočilo preverjanje tipov, IDE pravilno samodejno dopolnjevanje, statična analiza pa odkrivanje napak.

In kako definiramo takšen seznam? Preprosto v obliki razreda in njegovih lastnosti. Poimenujemo ga podobno kot presenter, vendar s Template na koncu:

/**
 * @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;

	// in druge spremenljivke
}

Objekt $this->template v predstavniku bo zdaj primerek razreda ArticleTemplate. PHP bo torej preveril deklarirane tipe, ko bodo zapisani. Od različice PHP 8.2 pa bo tudi opozoril na zapisovanje v neobstoječo spremenljivko; v prejšnjih različicah lahko enako dosežemo z uporabo lastnosti Nette\SmartObject.

Opomba @property-read je namenjena IDE in statični analizi, zaradi nje bo delovalo samodejno dokončanje, glejte PhpStorm and code completion for $this->template.

Privoščite si lahko tudi razkošje šepetanja v predlogah, samo namestite vtičnik Latte v PhpStorm in na začetku predloge navedite ime razreda, glejte članek Latte: kako vtipkati sistem:

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

Tako delujejo tudi predloge v komponentah, samo upoštevajte konvencijo poimenovanja in ustvarite razred predloge FifteenTemplate za komponento, npr. FifteenControl.

Če morate ustvariti $template kot primerek drugega razreda, uporabite metodo createTemplate():

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

Privzete spremenljivke

Predstavniki in komponente predlogam samodejno posredujejo več uporabnih spremenljivk:

  • $basePath je absolutna pot URL do korenskega dirja (na primer /CD-collection)
  • $baseUrl je absolutna pot URL do korenskega dirja (na primer http://localhost/CD-collection)
  • $user je objekt, ki predstavlja uporabnika
  • $presenter je trenutni predavatelj
  • $control je trenutna komponenta ali predvajalnik
  • $flashes seznam sporočil, poslanih z metodo flashMessage()

Če uporabljate razred predloge po meri, se te spremenljivke posredujejo, če zanje ustvarite lastnost.

V predlogi ustvarimo povezave do drugih predstavnikov in akcij na naslednji način:

<a n:href="Product:show">detail</a>

Atribut n:href je zelo priročen za oznake HTML <a>. Če želimo povezavo natisniti drugje, na primer v besedilu, uporabimo {link}:

URL is: {link Home:default}

Za več informacij glejte Ustvarjanje povezav.

Filtri po meri, oznake itd.

Sistem predlog Latte je mogoče razširiti s filtri po meri, funkcijami, oznakami itd. To lahko storite neposredno v render<View> ali beforeRender():

public function beforeRender(): void
{
	// dodajanje filtra
	$this->template->addFilter('foo', /* ... */);

	// ali neposredno konfigurirajte objekt Latte\Engine
	$latte = $this->template->getLatte();
	$latte->addFilterLoader(/* ... */);
}

Različica Latte 3 ponuja naprednejši način z ustvarjanjem razširitve za vsak spletni projekt. Tukaj je približni primer takega razreda:

namespace App\UI\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()),
			// ...
		];
	}

	// ...
}

Registriramo ga z uporabo konfiguracije:

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

Prevajanje

Če programirate večjezično aplikacijo, boste verjetno morali del besedila v predlogi izpisati v različnih jezikih. V ta namen je v ogrodju Nette opredeljen vmesnik za prevajanje Nette\Localization\Translator, ki ima eno samo metodo translate(). Ta sprejme sporočilo $message, ki je običajno niz, in morebitne druge parametre. Naloga je vrniti prevedeni niz. Privzete implementacije v Nette ni, glede na svoje potrebe lahko izbirate med več pripravljenimi rešitvami, ki jih najdete na Componette. V njihovi dokumentaciji je opisano, kako konfigurirati prevajalnik.

Predloge lahko nastavimo s prevajalnikom, ki nam ga bomo posredovali, s pomočjo metode setTranslator():

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

Prevajalnik lahko nastavimo tudi s konfiguracijo:

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

Prevajalnik lahko nato uporabimo na primer kot filter |translate, pri čemer metodi translate() posredujemo dodatne parametre (glej foo, bar):

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

ali kot podčrtanka:

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

Za prevajanje razdelkov predlog je na voljo parna oznaka {translate} (od različice Latte 2.11, prej se je uporabljala oznaka {_} ):

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

Prevajalnik se privzeto prikliče med izvajanjem, ko se izrisuje predloga. Različica Latte 3 pa lahko prevede vse statično besedilo med sestavljanjem predloge. To prihrani zmogljivost, saj se vsak niz prevede samo enkrat, dobljeni prevod pa se zapiše v sestavljeno obliko. Tako se v imeniku predpomnilnika ustvari več sestavljenih različic predloge, po ena za vsak jezik. Za to morate kot drugi parameter navesti le jezik:

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

S statičnim besedilom mislimo na primer na {_'hello'} ali {translate}hello{/translate}. Nestatično besedilo, kot je {_$foo}, se bo še naprej sestavljalo sproti.

različica: 4.0