Πρότυπα

Η Nette χρησιμοποιεί το σύστημα προτύπων Latte. Το Latte χρησιμοποιείται επειδή είναι το πιο ασφαλές σύστημα προτύπων για την PHP και ταυτόχρονα το πιο διαισθητικό σύστημα. Δεν χρειάζεται να μάθετε πολλά καινούργια, αρκεί να γνωρίζετε PHP και μερικές ετικέτες Latte.

Συνήθως η σελίδα ολοκληρώνεται από το πρότυπο διάταξης + το πρότυπο δράσης. Έτσι μπορεί να μοιάζει ένα πρότυπο διάταξης, προσέξτε τα μπλοκ {block} και την ετικέτα {include}:

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

Και αυτό μπορεί να είναι το πρότυπο δράσης:

{block title}Homepage{/block}

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

Ορίζει το μπλοκ content, το οποίο εισάγεται στη θέση του {include content} στη διάταξη, και επίσης επαναπροσδιορίζει το μπλοκ title, το οποίο αντικαθιστά το {block title} στη διάταξη. Προσπαθήστε να φανταστείτε το αποτέλεσμα.

Αναζήτηση προτύπου

Στους παρουσιαστές, δεν χρειάζεται να καθορίσετε ποιο πρότυπο πρέπει να αποδοθεί- το πλαίσιο θα καθορίσει αυτόματα τη διαδρομή, διευκολύνοντας την κωδικοποίηση για εσάς.

Αν χρησιμοποιείτε μια δομή καταλόγου όπου κάθε παρουσιαστής έχει το δικό του κατάλογο, απλά τοποθετήστε το πρότυπο σε αυτόν τον κατάλογο κάτω από το όνομα της ενέργειας (π.χ. προβολή). Για παράδειγμα, για τη δράση default, χρησιμοποιήστε το πρότυπο default.latte:

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

Εάν χρησιμοποιείτε μια δομή όπου οι παρουσιαστές βρίσκονται μαζί σε έναν κατάλογο και τα πρότυπα σε έναν φάκελο templates, αποθηκεύστε το είτε σε ένα αρχείο <Presenter>.<view>.latte είτε στο <Presenter>/<view>.latte:

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

Ο κατάλογος templates μπορεί επίσης να τοποθετηθεί ένα επίπεδο ψηλότερα, στο ίδιο επίπεδο με τον κατάλογο με τις κλάσεις παρουσιαστών.

Εάν το πρότυπο δεν βρεθεί, ο παρουσιαστής απαντά με το σφάλμα 404 – σελίδα δεν βρέθηκε.

Μπορείτε να αλλάξετε την προβολή χρησιμοποιώντας το $this->setView('anotherView'). Είναι επίσης δυνατό να καθορίσετε απευθείας το αρχείο προτύπου με το $this->template->setFile('/path/to/template.latte').

Τα αρχεία στα οποία αναζητούνται τα πρότυπα μπορούν να αλλάξουν με την παράκαμψη της μεθόδου formatTemplateFiles(), η οποία επιστρέφει έναν πίνακα πιθανών ονομάτων αρχείων.

Αναζήτηση προτύπων διάταξης

Η Nette αναζητά επίσης αυτόματα το αρχείο διάταξης.

Εάν χρησιμοποιείτε μια δομή καταλόγου όπου κάθε παρουσιαστής έχει το δικό του κατάλογο, τοποθετήστε τη διάταξη είτε στο φάκελο με τον παρουσιαστή, εάν αφορά μόνο αυτόν, είτε ένα επίπεδο ψηλότερα εάν είναι κοινή για πολλούς παρουσιαστές:

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

Εάν χρησιμοποιείτε μια δομή όπου οι παρουσιαστές είναι ομαδοποιημένοι σε έναν κατάλογο και τα πρότυπα βρίσκονται σε έναν φάκελο templates, η διάταξη αναμένεται στις ακόλουθες θέσεις:

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

Εάν ο παρουσιαστής βρίσκεται σε μια ενότητα, θα αναζητήσει επίσης πιο πάνω στο δέντρο καταλόγων σύμφωνα με την ένθεση της ενότητας.

Το όνομα της διάταξης μπορεί να αλλάξει χρησιμοποιώντας το $this->setLayout('layoutAdmin') και τότε θα αναμένεται στο αρχείο @layoutAdmin.latte. Μπορείτε επίσης να καθορίσετε απευθείας το αρχείο προτύπου διάταξης χρησιμοποιώντας το $this->setLayout('/path/to/template.latte').

Η χρήση του $this->setLayout(false) ή της ετικέτας {layout none} μέσα στο πρότυπο απενεργοποιεί την αναζήτηση διάταξης.

Τα αρχεία στα οποία αναζητούνται τα πρότυπα διάταξης μπορούν να αλλάξουν με την παράκαμψη της μεθόδου formatLayoutTemplateFiles(), η οποία επιστρέφει έναν πίνακα πιθανών ονομάτων αρχείων.

Μεταβλητές στο πρότυπο

Οι μεταβλητές περνούν στο πρότυπο γράφοντάς τες στο $this->template και στη συνέχεια είναι διαθέσιμες στο πρότυπο ως τοπικές μεταβλητές:

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

Με αυτόν τον τρόπο μπορούμε εύκολα να περάσουμε οποιεσδήποτε μεταβλητές στα πρότυπα. Ωστόσο, κατά την ανάπτυξη εύρωστων εφαρμογών, είναι συχνά πιο χρήσιμο να περιοριστούμε. Για παράδειγμα, ορίζοντας ρητά μια λίστα με τις μεταβλητές που αναμένει το πρότυπο και τους τύπους τους. Αυτό θα επιτρέψει στην PHP να κάνει έλεγχο τύπου, στο IDE να συμπληρώσει σωστά την αυτόματη συμπλήρωση και στη στατική ανάλυση να εντοπίσει σφάλματα.

Και πώς ορίζουμε μια τέτοια απαρίθμηση; Απλά με τη μορφή μιας κλάσης και των ιδιοτήτων της. Την ονομάζουμε παρόμοια με την presenter, αλλά με Template στο τέλος:

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

	// και άλλες μεταβλητές
}

Το αντικείμενο $this->template στον παρουσιαστή θα είναι τώρα μια περίπτωση της κλάσης ArticleTemplate. Έτσι, η PHP θα ελέγχει τους δηλωμένους τύπους όταν γράφονται. Και ξεκινώντας από την PHP 8.2 θα προειδοποιεί επίσης για εγγραφή σε μη υπάρχουσα μεταβλητή, στις προηγούμενες εκδόσεις το ίδιο μπορεί να επιτευχθεί με τη χρήση του γνωρίσματος Nette\SmartObject.

Το σχόλιο @property-read είναι για το IDE και τη στατική ανάλυση, θα κάνει την αυτόματη συμπλήρωση να λειτουργεί, δείτε PhpStorm και συμπλήρωση κώδικα για $this->template.

Μπορείτε επίσης να αφεθείτε στην πολυτέλεια του ψιθυρίσματος στα πρότυπα, απλά εγκαταστήστε το πρόσθετο Latte στο PhpStorm και καθορίστε το όνομα της κλάσης στην αρχή του προτύπου, δείτε το άρθρο Latte: πώς να πληκτρολογήσετε το σύστημα:

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

Έτσι λειτουργούν τα πρότυπα και στα συστατικά, απλά ακολουθήστε τη σύμβαση ονοματοδοσίας και δημιουργήστε μια κλάση προτύπου FifteenTemplate για το συστατικό π.χ. FifteenControl.

Εάν πρέπει να δημιουργήσετε ένα $template ως παράδειγμα μιας άλλης κλάσης, χρησιμοποιήστε τη μέθοδο createTemplate():

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

Default Variables

Οι παρουσιαστές και τα στοιχεία μεταβιβάζουν αυτόματα διάφορες χρήσιμες μεταβλητές στα πρότυπα:

  • $basePath είναι μια απόλυτη διαδρομή URL στο root dir (για παράδειγμα /CD-collection)
  • $baseUrl είναι μια απόλυτη διεύθυνση URL στο root dir (για παράδειγμα http://localhost/CD-collection)
  • $user είναι ένα αντικείμενο που αντιπροσωπεύει τον χρήστη
  • $presenter είναι ο τρέχων παρουσιαστής
  • $control είναι το τρέχον συστατικό ή ο παρουσιαστής
  • $flashes κατάλογος μηνυμάτων που αποστέλλονται από τη μέθοδο flashMessage()

Εάν χρησιμοποιείτε μια προσαρμοσμένη κλάση προτύπου, αυτές οι μεταβλητές μεταβιβάζονται εάν δημιουργήσετε μια ιδιότητα για αυτές.

Στο πρότυπο δημιουργούμε συνδέσμους προς άλλους παρουσιαστές & δράσεις ως εξής:

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

Το χαρακτηριστικό n:href είναι πολύ βολικό για τις ετικέτες HTML <a>. Αν θέλουμε να εκτυπώσουμε τον σύνδεσμο αλλού, για παράδειγμα στο κείμενο, χρησιμοποιούμε το {link}:

URL is: {link Home:default}

Για περισσότερες πληροφορίες, ανατρέξτε στην ενότητα Δημιουργία συνδέσμων.

Προσαρμοσμένα φίλτρα, ετικέτες κ.λπ.

Το σύστημα δημιουργίας προτύπων Latte μπορεί να επεκταθεί με προσαρμοσμένα φίλτρα, συναρτήσεις, ετικέτες κ.λπ. Αυτό μπορεί να γίνει απευθείας στο render<View> ή beforeRender() μέθοδο:

public function beforeRender(): void
{
	// προσθήκη φίλτρου
	$this->template->addFilter('foo', /* ... */);

	// ή να ρυθμίσετε απευθείας το αντικείμενο Latte\Engine
	$latte = $this->template->getLatte();
	$latte->addFilterLoader(/* ... */);
}

Latte έκδοση 3 προσφέρει έναν πιο προηγμένο τρόπο δημιουργώντας μια επέκταση για κάθε έργο ιστού. Εδώ είναι ένα πρόχειρο παράδειγμα μιας τέτοιας κλάσης:

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

	// ...
}

Την καταχωρούμε χρησιμοποιώντας την configuration:

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

Μετάφραση

Αν προγραμματίζετε μια πολύγλωσση εφαρμογή, πιθανόν να χρειαστεί να εκδώσετε κάποιο από το κείμενο του προτύπου σε διαφορετικές γλώσσες. Για να το κάνετε αυτό, το Nette Framework ορίζει μια διεπαφή μετάφρασης Nette\Localization\Translator, η οποία διαθέτει μια μόνο μέθοδο translate(). Αυτή δέχεται το μήνυμα $message, το οποίο είναι συνήθως μια συμβολοσειρά, και οποιεσδήποτε άλλες παραμέτρους. Η αποστολή της είναι να επιστρέψει το μεταφρασμένο αλφαριθμητικό. Δεν υπάρχει προεπιλεγμένη υλοποίηση στο Nette, μπορείτε να επιλέξετε ανάλογα με τις ανάγκες σας από διάφορες έτοιμες λύσεις που μπορείτε να βρείτε στο Componette. Η τεκμηρίωσή τους σας ενημερώνει για το πώς να ρυθμίσετε τον μεταφραστή.

Τα πρότυπα μπορούν να ρυθμιστούν με έναν μεταφραστή, τον οποίο θα μας έχει περάσει, χρησιμοποιώντας τη μέθοδο setTranslator():

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

Εναλλακτικά, ο μεταφραστής μπορεί να οριστεί χρησιμοποιώντας τη διαμόρφωση:

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

Ο μεταφραστής μπορεί στη συνέχεια να χρησιμοποιηθεί, για παράδειγμα, ως φίλτρο |translate, με πρόσθετες παραμέτρους που περνούν στη μέθοδο translate() (βλ. foo, bar):

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

Ή ως ετικέτα υπογράμμισης:

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

{translate} (από το Latte 2.11, προηγουμένως χρησιμοποιούνταν η ετικέτα {_} ):

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

Ο μεταφραστής καλείται από προεπιλογή κατά την εκτέλεση κατά την απόδοση του προτύπου. Η έκδοση 3 του Latte, ωστόσο, μπορεί να μεταφράσει όλο το στατικό κείμενο κατά τη διάρκεια της σύνταξης του προτύπου. Αυτό εξοικονομεί επιδόσεις επειδή κάθε συμβολοσειρά μεταφράζεται μόνο μία φορά και η προκύπτουσα μετάφραση εγγράφεται στη μεταγλωττισμένη φόρμα. Αυτό δημιουργεί πολλαπλές μεταγλωττισμένες εκδόσεις του προτύπου στον κατάλογο cache, μία για κάθε γλώσσα. Για να το κάνετε αυτό, χρειάζεται να καθορίσετε μόνο τη γλώσσα ως δεύτερη παράμετρο:

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

Με τον όρο στατικό κείμενο εννοούμε, για παράδειγμα, το {_'hello'} ή το {translate}hello{/translate}. Μη στατικό κείμενο, όπως το {_$foo}, θα συνεχίσει να μεταγλωττίζεται εν κινήσει.

έκδοση: 4.0