Nette Documentation Preview

syntax
Șabloane
********

.[perex]
Nette utilizează sistemul de șabloane [Latte |latte:]. Latte este utilizat deoarece este cel mai sigur sistem de șabloane pentru PHP și, în același timp, cel mai intuitiv sistem. Nu trebuie să învățați prea multe lucruri noi, trebuie doar să cunoașteți PHP și câteva etichete Latte.

Este obișnuit ca pagina să fie completată din șablonul layout + șablonul de acțiune. Iată cum ar putea arăta un șablon layout, observați blocurile `{block}` și tag-ul `{include}`:

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

Iar acesta ar putea fi șablonul de acțiune:

```latte
{block title}Homepage{/block}

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

Acesta definește blocul `content`, care este inserat în locul lui `{include content}` în machetă și, de asemenea, redefinește blocul `title`, care suprascrie `{block title}` în machetă. Încercați să vă imaginați rezultatul.


Căutarea șablonului .[#toc-template-lookup]
-------------------------------------------

În prezentări, nu trebuie să specificați ce șablon trebuie redat; cadrul va determina automat calea, ceea ce vă ușurează codificarea.

Dacă utilizați o structură de directoare în care fiecare prezentator are propriul director, plasați pur și simplu șablonul în acest director sub numele acțiunii (de exemplu, view). De exemplu, pentru acțiunea `default`, utilizați șablonul `default.latte`:

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

Dacă utilizați o structură în care prezentatorii sunt împreună într-un singur director, iar șabloanele într-un dosar `templates`, salvați-l fie într-un fișier `<Presenter>.<view>.latte` sau `<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
\--

Directorul `templates` poate fi, de asemenea, plasat un nivel mai sus, la același nivel cu directorul cu clasele de prezentatori.

În cazul în care șablonul nu este găsit, prezentatorul răspunde cu [eroarea 404 - page not found |presenters#Error 404 etc].

Puteți schimba vizualizarea folosind `$this->setView('anotherView')`. De asemenea, este posibilă specificarea directă a fișierului șablon cu `$this->template->setFile('/path/to/template.latte')`.

.[note]
Fișierele în care sunt căutate șabloanele pot fi modificate prin suprascrierea metodei [formatTemplateFiles() |api:Nette\Application\UI\Presenter::formatTemplateFiles()], care returnează o matrice de nume de fișiere posibile.


Căutarea șabloanelor de prezentare .[#toc-layout-template-lookup]
-----------------------------------------------------------------

De asemenea, Nette caută automat fișierul de machetare.

Dacă folosiți o structură de directoare în care fiecare prezentator are propriul director, plasați macheta fie în folderul cu prezentatorul, dacă este specifică doar acestuia, fie la un nivel superior, dacă este comună mai multor prezentatori:

/--pre
app/
└── UI/
    ├── <b>@layout.latte</b>           ← common layout
    └── Home/
        ├── <b>@layout.latte</b>       ← only for Home presenter
        ├── HomePresenter.php
        └── default.latte
\--

Dacă utilizați o structură în care prezentatorii sunt grupați într-un singur director, iar șabloanele se află într-un dosar `templates`, macheta va fi așteptată în următoarele locuri:

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

Dacă prezentatorul se află într-un [modul |modules], se va căuta și mai sus în arborele de directoare, în funcție de structura de anvelopare a modulului.

Numele prezentării poate fi schimbat folosind `$this->setLayout('layoutAdmin')` și apoi va fi așteptat în fișierul `@layoutAdmin.latte`. De asemenea, puteți specifica direct fișierul șablon de prezentare folosind `$this->setLayout('/path/to/template.latte')`.

Utilizarea `$this->setLayout(false)` sau a etichetei `{layout none}` în interiorul șablonului dezactivează căutarea de layout.

.[note]
Fișierele în care sunt căutate șabloanele de prezentare pot fi modificate prin suprascrierea metodei [formatLayoutTemplateFiles() |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()], care returnează o matrice de nume de fișiere posibile.


Variabilele din șablon .[#toc-variables-in-the-template]
--------------------------------------------------------

Variabilele sunt transmise șablonului prin scrierea lor pe `$this->template` și apoi sunt disponibile în șablon ca variabile locale:

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

În acest fel, putem trece cu ușurință orice variabile în șabloane. Cu toate acestea, atunci când dezvoltăm aplicații robuste, este adesea mai util să ne limităm. De exemplu, prin definirea explicită a unei liste de variabile pe care șablonul le așteaptă și a tipurilor acestora. Acest lucru va permite PHP să verifice tipul, IDE-ului să se autocompleteze corect, iar analizei statice să detecteze erorile.

Și cum definim o astfel de enumerare? Pur și simplu sub forma unei clase și a proprietăților sale. O denumim în mod similar cu presenter, dar cu `Template` la sfârșit:

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

	// și alte variabile
}
```

Obiectul `$this->template` din prezentator va fi acum o instanță a clasei `ArticleTemplate`. Astfel, PHP va verifica tipurile declarate atunci când acestea sunt scrise. Începând cu PHP 8.2, PHP va avertiza, de asemenea, în cazul în care se scrie pe o variabilă inexistentă; în versiunile anterioare, același lucru poate fi realizat cu ajutorul trăsăturii [Nette\SmartObject |utils:smartobject].

Adnotarea `@property-read` este pentru IDE și analiza statică, va face ca autocompletarea să funcționeze, a se vedea "PhpStorm și finalizarea codului pentru $this->template":https://blog.nette.org/en/phpstorm-and-code-completion-for-this-template.

[* phpstorm-completion.webp *]

Vă puteți permite și luxul de a șopti în șabloane, trebuie doar să instalați pluginul în PhpStorm și să specificați numele clasei la începutul șablonului, consultați articolul "Latte: cum se tastează sistemul":https://blog.nette.org/ro/latte-cum-se-utilizeaza-sistemul-de-tipuri:

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

Acesta este, de asemenea, modul în care funcționează șabloanele în componente, trebuie doar să urmați convenția de denumire și să creați o clasă șablon `FifteenTemplate` pentru componentă, de exemplu `FifteenControl`.

Dacă aveți nevoie să creați un `$template` ca instanță a unei alte clase, utilizați metoda `createTemplate()`:

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


Variabile implicite .[#toc-default-variables]
---------------------------------------------

Prezentatorii și componentele transmit automat mai multe variabile utile către șabloane:

- `$basePath` este o cale URL absolută către directorul rădăcină (de exemplu, `/CD-collection`)
- `$baseUrl` este o adresă URL absolută către directorul rădăcină (de exemplu `http://localhost/CD-collection`)
- `$user` este un obiect [care reprezintă utilizatorul |security:authentication]
- `$presenter` este prezentatorul curent
- `$control` este componenta sau prezentatorul curent
- `$flashes` lista [mesajelor |presenters#flash-messages] trimise prin metoda `flashMessage()`

Dacă utilizați o clasă de șablon personalizată, aceste variabile sunt transmise dacă creați o proprietate pentru ele.


Crearea legăturilor .[#toc-creating-links]
------------------------------------------

În șablon, creăm legături către alți prezentatori și acțiuni după cum urmează:

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

Atributul `n:href` este foarte util pentru etichetele HTML `<a>`. Dacă dorim să imprimăm link-ul în altă parte, de exemplu în text, folosim `{link}`:

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

Pentru mai multe informații, consultați [Crearea de linkuri |Creating Links].


Filtre personalizate, etichete etc. .[#toc-custom-filters-tags-etc]
-------------------------------------------------------------------

Sistemul de modelare Latte poate fi extins cu filtre, funcții, etichete etc. personalizate. Acest lucru se poate face direct în `render<View>` sau `beforeRender()`:

```php
public function beforeRender(): void
{
	// adăugarea unui filtru
	$this->template->addFilter('foo', /* ... */);

	// sau configurați direct obiectul Latte\Engine
	$latte = $this->template->getLatte();
	$latte->addFilterLoader(/* ... */);
}
```

Latte versiunea 3 oferă o metodă mai avansată prin crearea unei [extensii |latte:creating-extension] pentru fiecare proiect web. Iată un exemplu aproximativ al unei astfel de clase:

```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()),
			// ...
		];
	}

	// ...
}
```

O înregistrăm folosind [configuration#Latte]:

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


Traducerea .[#toc-translating]
------------------------------

Dacă programați o aplicație multilingvă, probabil că va trebui să scoateți o parte din textul din șablon în diferite limbi. Pentru a face acest lucru, Nette Framework definește o interfață de traducere [api:Nette\Localization\Translator], care are o singură metodă `translate()`. Aceasta acceptă mesajul `$message`, care este de obicei un șir de caractere, și orice alți parametri. Sarcina este de a returna șirul tradus.
Nu există o implementare implicită în Nette, puteți alege în funcție de nevoile dumneavoastră din mai multe soluții gata făcute care pot fi găsite pe [Componette |https://componette.org/search/localization]. Documentația acestora vă spune cum să configurați traducătorul.

Șabloanele pot fi configurate cu un traducător, pe care ni-l [vom trece |dependency-injection:passing-dependencies], folosind metoda `setTranslator()`:

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

Alternativ, traducătorul poate fi setat cu ajutorul [configurației |configuration#Latte]:

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

Traducătorul poate fi apoi utilizat, de exemplu, ca filtru `|translate`, cu parametri suplimentari trecuți la metoda `translate()` (a se vedea `foo, bar`):

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

Sau ca o etichetă de subliniere:

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

Pentru traducerea secțiunii de șablon, există o etichetă pereche `{translate}` (de la Latte 2.11, anterior se folosea eticheta `{_}` ):

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

Traducătorul este apelat în mod implicit în timpul execuției la redarea șablonului. Cu toate acestea, versiunea 3 a Latte poate traduce tot textul static în timpul compilării șablonului. Acest lucru economisește performanță, deoarece fiecare șir de caractere este tradus o singură dată, iar traducerea rezultată este scrisă în formularul compilat. Astfel, se creează mai multe versiuni compilate ale șablonului în directorul cache, una pentru fiecare limbă. Pentru a face acest lucru, trebuie doar să specificați limba ca al doilea parametru:

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

Prin text static înțelegem, de exemplu, `{_'hello'}` sau `{translate}hello{/translate}`. Textul nestatic, cum ar fi `{_$foo}`, va continua să fie compilat din mers.

Șabloane

Nette utilizează sistemul de șabloane Latte. Latte este utilizat deoarece este cel mai sigur sistem de șabloane pentru PHP și, în același timp, cel mai intuitiv sistem. Nu trebuie să învățați prea multe lucruri noi, trebuie doar să cunoașteți PHP și câteva etichete Latte.

Este obișnuit ca pagina să fie completată din șablonul layout + șablonul de acțiune. Iată cum ar putea arăta un șablon layout, observați blocurile {block} și tag-ul {include}:

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

Iar acesta ar putea fi șablonul de acțiune:

{block title}Homepage{/block}

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

Acesta definește blocul content, care este inserat în locul lui {include content} în machetă și, de asemenea, redefinește blocul title, care suprascrie {block title} în machetă. Încercați să vă imaginați rezultatul.

Căutarea șablonului

În prezentări, nu trebuie să specificați ce șablon trebuie redat; cadrul va determina automat calea, ceea ce vă ușurează codificarea.

Dacă utilizați o structură de directoare în care fiecare prezentator are propriul director, plasați pur și simplu șablonul în acest director sub numele acțiunii (de exemplu, view). De exemplu, pentru acțiunea default, utilizați șablonul default.latte:

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

Dacă utilizați o structură în care prezentatorii sunt împreună într-un singur director, iar șabloanele într-un dosar templates, salvați-l fie într-un fișier <Presenter>.<view>.latte sau <Presenter>/<view>.latte:

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

Directorul templates poate fi, de asemenea, plasat un nivel mai sus, la același nivel cu directorul cu clasele de prezentatori.

În cazul în care șablonul nu este găsit, prezentatorul răspunde cu eroarea 404 – page not found.

Puteți schimba vizualizarea folosind $this->setView('anotherView'). De asemenea, este posibilă specificarea directă a fișierului șablon cu $this->template->setFile('/path/to/template.latte').

Fișierele în care sunt căutate șabloanele pot fi modificate prin suprascrierea metodei formatTemplateFiles(), care returnează o matrice de nume de fișiere posibile.

Căutarea șabloanelor de prezentare

De asemenea, Nette caută automat fișierul de machetare.

Dacă folosiți o structură de directoare în care fiecare prezentator are propriul director, plasați macheta fie în folderul cu prezentatorul, dacă este specifică doar acestuia, fie la un nivel superior, dacă este comună mai multor prezentatori:

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

Dacă utilizați o structură în care prezentatorii sunt grupați într-un singur director, iar șabloanele se află într-un dosar templates, macheta va fi așteptată în următoarele locuri:

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

Dacă prezentatorul se află într-un modul, se va căuta și mai sus în arborele de directoare, în funcție de structura de anvelopare a modulului.

Numele prezentării poate fi schimbat folosind $this->setLayout('layoutAdmin') și apoi va fi așteptat în fișierul @layoutAdmin.latte. De asemenea, puteți specifica direct fișierul șablon de prezentare folosind $this->setLayout('/path/to/template.latte').

Utilizarea $this->setLayout(false) sau a etichetei {layout none} în interiorul șablonului dezactivează căutarea de layout.

Fișierele în care sunt căutate șabloanele de prezentare pot fi modificate prin suprascrierea metodei formatLayoutTemplateFiles(), care returnează o matrice de nume de fișiere posibile.

Variabilele din șablon

Variabilele sunt transmise șablonului prin scrierea lor pe $this->template și apoi sunt disponibile în șablon ca variabile locale:

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

În acest fel, putem trece cu ușurință orice variabile în șabloane. Cu toate acestea, atunci când dezvoltăm aplicații robuste, este adesea mai util să ne limităm. De exemplu, prin definirea explicită a unei liste de variabile pe care șablonul le așteaptă și a tipurilor acestora. Acest lucru va permite PHP să verifice tipul, IDE-ului să se autocompleteze corect, iar analizei statice să detecteze erorile.

Și cum definim o astfel de enumerare? Pur și simplu sub forma unei clase și a proprietăților sale. O denumim în mod similar cu presenter, dar cu Template la sfârșit:

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

	// și alte variabile
}

Obiectul $this->template din prezentator va fi acum o instanță a clasei ArticleTemplate. Astfel, PHP va verifica tipurile declarate atunci când acestea sunt scrise. Începând cu PHP 8.2, PHP va avertiza, de asemenea, în cazul în care se scrie pe o variabilă inexistentă; în versiunile anterioare, același lucru poate fi realizat cu ajutorul trăsăturii Nette\SmartObject.

Adnotarea @property-read este pentru IDE și analiza statică, va face ca autocompletarea să funcționeze, a se vedea PhpStorm și finalizarea codului pentru $this->template.

Vă puteți permite și luxul de a șopti în șabloane, trebuie doar să instalați pluginul în PhpStorm și să specificați numele clasei la începutul șablonului, consultați articolul Latte: cum se tastează sistemul:

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

Acesta este, de asemenea, modul în care funcționează șabloanele în componente, trebuie doar să urmați convenția de denumire și să creați o clasă șablon FifteenTemplate pentru componentă, de exemplu FifteenControl.

Dacă aveți nevoie să creați un $template ca instanță a unei alte clase, utilizați metoda createTemplate():

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

Variabile implicite

Prezentatorii și componentele transmit automat mai multe variabile utile către șabloane:

  • $basePath este o cale URL absolută către directorul rădăcină (de exemplu, /CD-collection)
  • $baseUrl este o adresă URL absolută către directorul rădăcină (de exemplu http://localhost/CD-collection)
  • $user este un obiect care reprezintă utilizatorul
  • $presenter este prezentatorul curent
  • $control este componenta sau prezentatorul curent
  • $flashes lista mesajelor trimise prin metoda flashMessage()

Dacă utilizați o clasă de șablon personalizată, aceste variabile sunt transmise dacă creați o proprietate pentru ele.

În șablon, creăm legături către alți prezentatori și acțiuni după cum urmează:

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

Atributul n:href este foarte util pentru etichetele HTML <a>. Dacă dorim să imprimăm link-ul în altă parte, de exemplu în text, folosim {link}:

URL is: {link Home:default}

Pentru mai multe informații, consultați Crearea de linkuri.

Filtre personalizate, etichete etc.

Sistemul de modelare Latte poate fi extins cu filtre, funcții, etichete etc. personalizate. Acest lucru se poate face direct în render<View> sau beforeRender():

public function beforeRender(): void
{
	// adăugarea unui filtru
	$this->template->addFilter('foo', /* ... */);

	// sau configurați direct obiectul Latte\Engine
	$latte = $this->template->getLatte();
	$latte->addFilterLoader(/* ... */);
}

Latte versiunea 3 oferă o metodă mai avansată prin crearea unei extensii pentru fiecare proiect web. Iată un exemplu aproximativ al unei astfel de clase:

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

	// ...
}

O înregistrăm folosind configuration:

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

Traducerea

Dacă programați o aplicație multilingvă, probabil că va trebui să scoateți o parte din textul din șablon în diferite limbi. Pentru a face acest lucru, Nette Framework definește o interfață de traducere Nette\Localization\Translator, care are o singură metodă translate(). Aceasta acceptă mesajul $message, care este de obicei un șir de caractere, și orice alți parametri. Sarcina este de a returna șirul tradus. Nu există o implementare implicită în Nette, puteți alege în funcție de nevoile dumneavoastră din mai multe soluții gata făcute care pot fi găsite pe Componette. Documentația acestora vă spune cum să configurați traducătorul.

Șabloanele pot fi configurate cu un traducător, pe care ni-l vom trece, folosind metoda setTranslator():

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

Alternativ, traducătorul poate fi setat cu ajutorul configurației:

latte:
	extensions:
		- Latte\Essential\TranslatorExtension

Traducătorul poate fi apoi utilizat, de exemplu, ca filtru |translate, cu parametri suplimentari trecuți la metoda translate() (a se vedea foo, bar):

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

Sau ca o etichetă de subliniere:

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

Pentru traducerea secțiunii de șablon, există o etichetă pereche {translate} (de la Latte 2.11, anterior se folosea eticheta {_} ):

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

Traducătorul este apelat în mod implicit în timpul execuției la redarea șablonului. Cu toate acestea, versiunea 3 a Latte poate traduce tot textul static în timpul compilării șablonului. Acest lucru economisește performanță, deoarece fiecare șir de caractere este tradus o singură dată, iar traducerea rezultată este scrisă în formularul compilat. Astfel, se creează mai multe versiuni compilate ale șablonului în directorul cache, una pentru fiecare limbă. Pentru a face acest lucru, trebuie doar să specificați limba ca al doilea parametru:

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

Prin text static înțelegem, de exemplu, {_'hello'} sau {translate}hello{/translate}. Textul nestatic, cum ar fi {_$foo}, va continua să fie compilat din mers.