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 predloge .[#toc-template-lookup]
----------------------------------------

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

/--pre
app/
└── UI/
    └── Home/
        ├── HomePresenter.php
        └── <b>default.latte</b>
\--

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

/--pre
app/
└── Presenters/
    ├── HomePresenter.php
    └── templates/
        ├── <b>Home.default.latte</b>  ← 1st variant
        └── <b>Home/</b>
            └── <b>default.latte</b>   ← 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 |presenters#Error 404 etc].

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')`.

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


Iskanje predlog za postavitev .[#toc-layout-template-lookup]
------------------------------------------------------------

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:

/--pre
app/
└── UI/
    ├── <b>@layout.latte</b>           ← common layout
    └── Home/
        ├── <b>@layout.latte</b>       ← 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:

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

Če je predstavnik v [modulu |modules], 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.

.[note]
Datoteke, v katerih se iščejo predloge postavitve, lahko spremenite tako, da nadgradite metodo [formatLayoutTemplateFiles() |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()], ki vrne polje možnih imen 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\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()`:

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

```neon
latte:
	extensions:
		- App\UI\Accessory\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(@Nette\Localization\Translator)
```

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