Nette Documentation Preview

syntax
Predloge
********

.[perex]
Nette uporablja sistem predlog [Latte |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}`:

```latte
<!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:

```latte
{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 predlog .[#toc-search-for-templates]
--------------------------------------------

Pot do predlog se določi po preprosti logiki. Poskusi preveriti, ali obstaja ena od teh datotek s predlogami glede na imenik, v katerem se nahaja razred presenter, kjer `<Presenter>` je ime trenutnega predstavnika in `<view>` je ime trenutnega dejanja:

- `templates/<Presenter>/<view>.latte`
- `templates/<Presenter>.<view>.latte`

Če predloge ne najde, jo poskuša poiskati v imeniku `templates` eno raven višje, tj. na isti ravni kot imenik z razredom predstavnika.

Če predloge ne najde niti tam, se kot odgovor prikaže [napaka 404 |presenters#Error 404 etc.].

Pogled lahko spremenite tudi z uporabo `$this->setView('otherView')`. Lahko pa namesto iskanja neposredno določite ime datoteke s predlogo z uporabo `$this->template->setFile('/path/to/template.latte')`.

.[note]
Poti, po katerih se iščejo predloge, lahko spremenite tako, da nadgradite metodo [formatTemplateFiles |api:Nette\Application\UI\Presenter::formatTemplateFiles()], ki vrne polje možnih poti do datotek.

Postavitev se pričakuje v naslednjih datotekah:

- `templates/<Presenter>/@<layout>.latte`
- `templates/<Presenter>.@<layout>.latte`
- `templates/@<layout>.latte` postavitev, ki je skupna več predstavnikom

`<Presenter>` je ime trenutnega predavatelja in `<layout>` je ime postavitve, ki je privzeto `'layout'`. Ime lahko spremenite s `$this->setLayout('otherLayout')`, tako da se bodo poskušale uporabiti datoteke `@otherLayout.latte`.

Ime datoteke za predlogo postavitve lahko določite tudi neposredno z uporabo `$this->setLayout('/path/to/template.latte')`. Z uporabo spletne strani `$this->setLayout(false)` bo iskanje postavitve onemogočeno.

.[note]
Poti, po katerih se iščejo predloge, lahko spremenite tako, da nadgradite metodo [formatLayoutTemplateFiles |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()], ki vrne polje možnih poti do datotek.


Spremenljivke v predlogi .[#toc-variables-in-the-template]
----------------------------------------------------------

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

```php
$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:

```php
/**
 * @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 |utils: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":https://blog.nette.org/en/phpstorm-and-code-completion-for-this-template.

[* phpstorm-completion.webp *]

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":https://blog.nette.org/sl/latte-kako-uporabljati-sistem-tipov:

```latte
{templateType App\Presenters\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()`:

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


Privzete spremenljivke .[#toc-default-variables]
------------------------------------------------

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 |security:authentication]
- `$presenter` je trenutni predavatelj
- `$control` je trenutna komponenta ali predvajalnik
- `$flashes` seznam [sporočil, |presenters#flash-messages] poslanih z metodo `flashMessage()`

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


Ustvarjanje povezav .[#toc-creating-links]
------------------------------------------

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

```latte
<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}`:

```latte
URL is: {link Home:default}
```

Za več informacij glejte [Ustvarjanje povezav |Creating Links].


Filtri po meri, oznake itd. .[#toc-custom-filters-tags-etc]
-----------------------------------------------------------

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

```php
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 |latte:creating-extension] za vsak spletni projekt. Tukaj je približni primer takega razreda:

```php
namespace App\Templating;

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|configuration#Latte]:

```neon
latte:
	extensions:
		- App\Templating\LatteExtension
```


Prevajanje .[#toc-translating]
------------------------------

Č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 [api: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 |https://componette.org/search/localization]. V njihovi dokumentaciji je opisano, kako konfigurirati prevajalnik.

Predloge lahko nastavimo s prevajalnikom, ki nam ga [bomo posredovali |dependency-injection:passing-dependencies], s pomočjo metode `setTranslator()`:

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

Prevajalnik lahko nastavimo tudi s [konfiguracijo |configuration#Latte]:

```neon
latte:
	extensions:
		- Latte\Essential\TranslatorExtension
```

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

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

ali kot podčrtanka:

```latte
<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 `{_}` ):

```latte
<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:

```php
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.

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 predlog

Pot do predlog se določi po preprosti logiki. Poskusi preveriti, ali obstaja ena od teh datotek s predlogami glede na imenik, v katerem se nahaja razred presenter, kjer <Presenter> je ime trenutnega predstavnika in <view> je ime trenutnega dejanja:

  • templates/<Presenter>/<view>.latte
  • templates/<Presenter>.<view>.latte

Če predloge ne najde, jo poskuša poiskati v imeniku templates eno raven višje, tj. na isti ravni kot imenik z razredom predstavnika.

Če predloge ne najde niti tam, se kot odgovor prikaže napaka 404.

Pogled lahko spremenite tudi z uporabo $this->setView('otherView'). Lahko pa namesto iskanja neposredno določite ime datoteke s predlogo z uporabo $this->template->setFile('/path/to/template.latte').

Poti, po katerih se iščejo predloge, lahko spremenite tako, da nadgradite metodo formatTemplateFiles, ki vrne polje možnih poti do datotek.

Postavitev se pričakuje v naslednjih datotekah:

  • templates/<Presenter>/@<layout>.latte
  • templates/<Presenter>.@<layout>.latte
  • templates/@<layout>.latte postavitev, ki je skupna več predstavnikom

<Presenter> je ime trenutnega predavatelja in <layout> je ime postavitve, ki je privzeto 'layout'. Ime lahko spremenite s $this->setLayout('otherLayout'), tako da se bodo poskušale uporabiti datoteke @otherLayout.latte.

Ime datoteke za predlogo postavitve lahko določite tudi neposredno z uporabo $this->setLayout('/path/to/template.latte'). Z uporabo spletne strani $this->setLayout(false) bo iskanje postavitve onemogočeno.

Poti, po katerih se iščejo predloge, lahko spremenite tako, da nadgradite metodo formatLayoutTemplateFiles, ki vrne polje možnih poti do 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\Presenters\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\Templating;

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\Templating\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

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.