Presenter
Esamineremo come si scrivono i presenter e i template in Nette. Dopo la lettura capirete:
- come funzionano i presenter
- cosa sono i parametri persistenti
- come vengono disegnati i template
Sappiamo già che un presenter è una classe che rappresenta una determinata pagina di un'applicazione web, per esempio la home page, un prodotto di un e-shop, un form di login, un feed sitemap e così via. Un'applicazione può avere da uno a migliaia di presenter. In altri framework sono noti anche come controller.
Di norma con il termine presenter si intende un discendente della classe Nette\Application\UI\Presenter, adatta a generare interfacce web e alla quale sarà dedicato il resto di questo capitolo. In senso generale, un presenter è qualsiasi oggetto che implementi l'interfaccia Nette\Application\IPresenter.
Ciclo di vita del presenter
Il compito del presenter è gestire una richiesta e restituire una risposta (che può essere una pagina HTML, un'immagine, un redirect ecc.).
All'inizio, quindi, gli viene passata una richiesta. Non è la richiesta HTTP diretta, ma un oggetto Nette\Application\Request, nel quale la richiesta HTTP è stata trasformata con l'aiuto del router. Di norma non interagiamo direttamente con questo oggetto, perché il presenter delega abilmente l'elaborazione della richiesta ad altri metodi, che esamineremo ora.
Lo schema mostra l'elenco dei metodi che vengono chiamati in sequenza dall'alto verso il basso, se esistono. Nessuno di essi è obbligatorio: potete avere un presenter completamente vuoto, senza un solo metodo, e costruirci sopra un semplice sito statico.
__construct()
Il costruttore non appartiene in senso stretto al ciclo di vita del presenter, perché viene chiamato nel momento in cui l'oggetto viene creato. Lo menzioniamo però per la sua importanza. Il costruttore (insieme al metodo inject) serve a passare le dipendenze.
Il presenter non deve occuparsi della logica di business dell'applicazione, non deve scrivere sul database o leggerne, non
deve eseguire calcoli e così via. È compito delle classi dello strato che chiamiamo model. Per esempio, una classe
ArticleRepository può occuparsi di caricare e salvare gli articoli. Perché il presenter possa lavorarci, deve
farsela passare tramite dependency injection:
class ArticlePresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private ArticleRepository $articles,
) {
}
}
startup()
Subito dopo aver ricevuto la richiesta viene richiamato il metodo startup(). Potete usarlo per inizializzare le
proprietà, controllare i permessi dell'utente e così via. È obbligatorio che questo metodo chiami sempre il metodo genitore:
parent::startup().
action<Azione>(args...)
È simile al metodo render<Vista>(). Mentre render<Vista>() serve a preparare i dati per
un determinato template che verrà poi disegnato, action<Azione>() elabora una richiesta senza per forza
disegnare poi un template. Per esempio può elaborare dei dati, autenticare o disconnettere un utente e così via, per poi reindirizzare altrove.
È importante che action<Azione>() venga chiamato prima di render<Vista>(). Questo
ci permette eventualmente di cambiare il corso della richiesta dentro il metodo action, per esempio cambiando il template che
verrà disegnato o perfino il metodo render<Vista>() che verrà chiamato, con
setView('otherView').
Potete perfino passare a un'azione completamente diversa con il metodo switch('otherAction').
Interrompe il metodo corrente ed esegue invece i metodi action<Azione>() e render<Vista>()
della nuova azione (e disattiva la canonizzazione automatica). La richiesta in sé prosegue;
viene interrotto solo il metodo attualmente in esecuzione.
Al metodo vengono passati i parametri della richiesta. È possibile, e consigliato, indicare i tipi di questi parametri, per
esempio actionShow(int $id, ?string $slug = null). Se il parametro id manca o non è un intero, il
presenter restituisce un errore 404 e termina.
handle<Segnale>(args...)
Questo metodo elabora i cosiddetti segnali, di cui parleremo nel capitolo dedicato ai componenti. È destinato soprattutto ai componenti e alla gestione delle richieste AJAX.
Al metodo vengono passati i parametri della richiesta, come per action<Azione>(), compreso il controllo
dei tipi.
beforeRender()
Il metodo beforeRender, come suggerisce il nome, viene chiamato prima di ogni metodo
render<Vista>(). Serve per la configurazione comune del template, per passare variabili al layout e per compiti
simili.
render<Vista>(args...)
È qui che prepariamo il template per il successivo rendering, gli passiamo i dati e così via.
Al metodo vengono passati i parametri della richiesta, come per action<Azione>(), compreso il controllo
dei tipi.
public function renderShow(int $id): void
{
// ottiene i dati dal modello e li passa al template
$this->template->article = $this->articles->getById($id);
}
afterRender()
Il metodo afterRender, come suggerisce di nuovo il nome, viene chiamato dopo ogni metodo
render<Vista>(). Si usa piuttosto di rado.
shutdown()
Viene chiamato alla fine del ciclo di vita del presenter.
Eventi
Oltre ai metodi startup(), beforeRender() e shutdown(), chiamati nell'ambito del ciclo
di vita del presenter, si possono definire altre funzioni da chiamare automaticamente. Il presenter definisce i cosiddetti eventi e voi aggiungete i loro gestori negli array
$onStartup, $onRender e $onShutdown.
class ArticlePresenter extends Nette\Application\UI\Presenter
{
public function __construct()
{
$this->onStartup[] = function () {
// ...
};
}
}
I gestori dell'array $onStartup vengono chiamati subito prima del metodo startup(), quelli di
$onRender tra beforeRender() e render<Vista>() e infine quelli di
$onShutdown subito prima di shutdown().
Un consiglio prima di proseguire: come vedete, un presenter può gestire più azioni/viste, può cioè avere più metodi
render<Vista>(). Consigliamo però di progettare i presenter con una sola azione o comunque con il minor
numero possibile di azioni.
Inviare una risposta
La risposta del presenter è di norma il rendering di un template in una pagina HTML, ma può essere anche l'invio di un file, di un JSON o perfino un redirect a un'altra pagina.
In qualsiasi momento del ciclo di vita possiamo usare uno dei metodi seguenti per inviare una risposta e terminare contemporaneamente il presenter:
redirect(),redirectPermanent(),redirectUrl()eforward()eseguono un redirecterror()termina il presenter a causa di un erroresendJson($data)termina il presenter e invia i dati in formato JSONsendTemplate()termina il presenter e disegna subito il templatesendResponse($response)termina il presenter e invia una risposta personalizzataterminate()termina il presenter senza alcuna risposta
Ognuno di questi metodi termina immediatamente il presenter sollevando l'eccezione di terminazione silenziosa
Nette\Application\AbortException.
Se non chiamate nessuno di questi metodi, il presenter passa automaticamente al rendering del template. Perché? Perché nel 99% dei casi vogliamo disegnare un template, quindi il presenter adotta questo comportamento come predefinito per semplificarci il lavoro.
Creare i link
Il presenter ha un metodo link() che serve a creare link URL verso altri presenter. Il primo parametro è il
presenter e l'azione di destinazione, seguiti dagli argomenti, che si possono passare come array:
$url = $this->link('Product:show', $id);
$url = $this->link('Product:show', [$id, 'lang' => 'en']);
Nel template i link verso altri presenter e azioni si creano così:
<a n:href="Product:show $id">dettaglio del prodotto</a>
Basta scrivere la familiare coppia Presenter:azione al posto dell'URL vero e proprio e aggiungere gli eventuali
parametri necessari. Il trucco sta in n:href, che dice a Latte di elaborare questo attributo e di generare l'URL
reale. In Nette non dovete pensare affatto agli URL, solo ai presenter e alle azioni.
Maggiori informazioni si trovano nel capitolo Creazione di link URL.
Redirect
Per passare a un altro presenter si usano i metodi redirect() e forward(). Hanno una sintassi molto
simile a quella del metodo link().
Il metodo forward() passa subito al nuovo presenter, senza un redirect HTTP:
$this->forward('Product:show');
Esempio di redirect temporaneo con codice HTTP 302 (o 303 se il metodo della richiesta corrente è POST):
$this->redirect('Product:show', $id);
Per ottenere un redirect permanente con codice HTTP 301, usate questo:
$this->redirectPermanent('Product:show', $id);
Potete reindirizzare a un altro URL fuori dall'applicazione con il metodo redirectUrl(). Il codice HTTP si può
indicare come secondo parametro; il valore predefinito è 302 (o 303 se il metodo della richiesta corrente è POST):
$this->redirectUrl('https://nette.org');
Il redirect termina immediatamente l'attività del presenter sollevando la cosiddetta eccezione di terminazione silenziosa,
Nette\Application\AbortException.
Prima del redirect è possibile inviare messaggi flash, cioè messaggi che verranno mostrati nel template dopo il redirect.
Messaggi flash
Sono messaggi che di norma informano sull'esito di qualche operazione. Una caratteristica importante dei messaggi flash è che restano disponibili nel template anche dopo un redirect. Una volta mostrati restano attivi per altri 30 secondi: se per esempio l'utente ricarica la pagina per un errore di trasmissione, il messaggio non sparisce subito.
Basta chiamare il metodo flashMessage() e il
presenter si occupa di passarlo al template. Il primo parametro è il testo del messaggio, il secondo, facoltativo, è il suo tipo
(per esempio error, warning, info). Il metodo flashMessage() restituisce un'istanza del messaggio flash, alla quale
si possono aggiungere altre informazioni.
$this->flashMessage('L\'elemento è stato eliminato.');
$this->redirect(/* ... */); // e reindirizza
Nel template questi messaggi sono disponibili nella variabile $flashes come oggetti stdClass, che
contengono le proprietà message (il testo del messaggio), type (il tipo del messaggio) ed eventualmente
le informazioni aggiunte dall'utente già menzionate. Li disegniamo così:
{foreach $flashes as $flash}
<div class="flash {$flash->type}">{$flash->message}</div>
{/foreach}
Errore 404 e simili
Se la richiesta non si può soddisfare, per esempio perché l'articolo che vogliamo mostrare non esiste nel database,
solleviamo un errore 404 con il metodo error(string $message = '', int $httpCode = 404).
public function renderShow(int $id): void
{
$article = $this->articles->getById($id);
if (!$article) {
$this->error();
}
// ...
}
Il codice di errore HTTP si può passare come secondo parametro; il valore predefinito è 404. Il metodo funziona sollevando
una Nette\Application\BadRequestException, dopo la quale Application passa il controllo all'error
presenter. È un presenter il cui compito è mostrare una pagina che informa dell'errore avvenuto. L'error presenter si imposta
nella configurazione dell'applicazione.
Inviare JSON
Il metodo sendJson($data) codifica i dati indicati in JSON, li invia come risposta HTTP e termina il presenter.
Esempio:
public function actionData(): void
{
$data = ['hello' => 'nette'];
$this->sendJson($data);
}
Parametri della richiesta
Il presenter, e anche ogni componente, ottiene i propri parametri dalla richiesta HTTP. Potete leggerne i valori con
i metodi getParameter($name) o getParameters(). I valori sono stringhe o array di stringhe, in
sostanza dati grezzi ottenuti direttamente dall'URL.
Per maggiore comodità consigliamo di accedere ai parametri tramite le proprietà. Basta contrassegnarle con l'attributo
#[Parameter]:
use Nette\Application\Attributes\Parameter; // questa riga è importante
class HomePresenter extends Nette\Application\UI\Presenter
{
#[Parameter]
public string $theme; // deve essere public
}
Per la proprietà consigliamo di indicare il tipo di dato (per esempio string) e Nette convertirà automaticamente
il valore di conseguenza. I valori dei parametri si possono anche validare.
Quando create un link potete impostare direttamente il valore del parametro:
<a n:href="Home:default theme: dark">clicca</a>
Parametri persistenti
I parametri persistenti servono a mantenere lo stato tra richieste diverse. Il loro valore resta lo stesso anche dopo aver
cliccato un link. A differenza dei dati di sessione, vengono trasmessi nell'URL. E questo avviene in modo completamente
automatico, quindi non c'è bisogno di indicarli esplicitamente in link() o in n:href.
Un esempio d'uso? Immaginate di avere un'applicazione multilingue. La lingua corrente è un parametro che deve sempre far parte
dell'URL. Ma sarebbe incredibilmente noioso indicarlo in ogni link. Lo rendete quindi un parametro persistente lang e
verrà trascinato automaticamente. Comodo!
Creare un parametro persistente in Nette è estremamente semplice. Basta creare una proprietà pubblica e contrassegnarla con
l'attributo: (in precedenza si usava /** @persistent */)
use Nette\Application\Attributes\Persistent; // questa riga è importante
class ProductPresenter extends Nette\Application\UI\Presenter
{
#[Persistent]
public string $lang; // deve essere public
}
Se $this->lang ha un valore come 'en', allora anche i link creati con link() o
n:href conterranno il parametro lang=en. E dopo aver cliccato il link, $this->lang sarà
di nuovo 'en'.
Per la proprietà consigliamo di indicare il tipo di dato (per esempio string) e potete anche fornire un valore
predefinito. I valori dei parametri si possono validare.
I parametri persistenti vengono di norma trasferiti tra tutte le azioni di un determinato presenter. Per trasferirli anche tra più presenter, vanno definiti:
- in un antenato comune dal quale i presenter ereditano
- oppure in un trait che i presenter usano:
trait LanguageAware
{
#[Persistent]
public string $lang;
}
class ProductPresenter extends Nette\Application\UI\Presenter
{
use LanguageAware;
}
Quando si crea un link, il valore di un parametro persistente si può cambiare:
<a n:href="Product:show $id, lang: cs">dettaglio in ceco</a>
In alternativa lo si può azzerare, cioè rimuovere dall'URL. Assumerà allora il proprio valore predefinito:
<a n:href="Product:show $id, lang: null">clicca</a>
Spazio condiviso dei parametri
I parametri della richiesta, i parametri persistenti e i parametri dei metodi
action, render e handle (segnale) condividono un unico spazio, in cui ognuno è
identificato dal proprio nome. Se lo stesso nome compare in più di uno di essi, si riferiscono a uno stesso e identico
valore.
Spesso lo si sfrutta a proprio vantaggio. Per esempio, il parametro persistente lang e l'argomento
$lang di un metodo di azione o di segnale sono la stessa cosa: potete leggere il valore corrente di un parametro
persistente semplicemente elencandolo nella firma del metodo:
#[Persistent]
public string $lang;
public function handleSearch(string $query, string $lang): void
{
// $lang contiene il valore corrente del parametro persistente lang
}
Poiché questo spazio è condiviso, tenete unici i nomi dei parametri, a meno che non vogliate deliberatamente che condividano un valore. Questo vale anche per i segnali, che in più leggono i parametri dal corpo POST della richiesta, vedi I segnali in profondità.
Componenti interattivi
I presenter hanno un sistema di componenti integrato. I componenti sono unità riutilizzabili autonome che incorporiamo nei presenter. Possono essere form, datagrid, menu, in pratica tutto ciò che ha senso usare più volte.
Come si incorporano i componenti nei presenter e come li si usa poi? Lo imparerete nel capitolo Componenti. Scoprirete perfino cosa hanno in comune con Hollywood.
E dove trovo i componenti? Su Componette trovate componenti open source e molte altre estensioni per Nette, offerte da volontari della comunità del framework.
Andiamo più a fondo
Quello che abbiamo trattato finora in questo capitolo basterà probabilmente per la maggior parte degli usi. Le sezioni seguenti sono destinate a chi vuole approfondire i presenter e sapere assolutamente tutto.
Validazione dei parametri
I valori dei parametri della richiesta e dei parametri persistenti ricevuti dagli URL vengono scritti nelle proprietà dal metodo
loadState(). Esso controlla anche che il tipo di dato indicato nella proprietà corrisponda; in caso contrario
risponde con un errore 404 e la pagina non viene mostrata.
Non fidatevi mai ciecamente dei parametri ricevuti dall'URL, perché l'utente può sovrascriverli facilmente. Ecco per esempio
come verificheremmo che la lingua $this->lang sia tra quelle supportate. Un modo adatto è sovrascrivere il metodo
loadState() già menzionato:
class ProductPresenter extends Nette\Application\UI\Presenter
{
#[Persistent]
public string $lang;
public function loadState(array $params): void
{
parent::loadState($params); // qui viene impostato $this->lang
// segue il controllo personalizzato del valore:
if (!in_array($this->lang, ['en', 'cs'])) {
$this->error();
}
}
}
Salvare e ripristinare la richiesta
La richiesta gestita dal presenter è un oggetto Nette\Application\Request, restituito dal
metodo getRequest() del presenter.
La richiesta corrente si può salvare nella sessione oppure, al contrario, ripristinarla da essa e farla eseguire di nuovo al
presenter. È utile, per esempio, quando un utente sta compilando un form e la sua sessione di login scade. Per non perdere
i dati, prima di reindirizzare alla pagina di login salviamo la richiesta corrente nella sessione con
$reqId = $this->storeRequest(). Questo restituisce il suo identificatore come stringa breve, che passiamo poi come
parametro al presenter di login.
Dopo il login chiamiamo il metodo $this->restoreRequest($reqId), che recupera la richiesta dalla sessione. Le
richieste POST le vengono inoltrate, mentre le altre (GET) vengono reindirizzate all'URL della richiesta. Il metodo verifica che
la richiesta sia stata creata dallo stesso utente ora connesso. Se accede un utente diverso o se la chiave non è valida, non fa
nulla e il programma prosegue come al solito.
Vedi la guida Come tornare a una pagina precedente.
Canonizzazione
I presenter hanno una funzionalità davvero eccellente, che contribuisce a una migliore SEO (Search Engine Optimization).
Impediscono automaticamente l'esistenza di contenuto duplicato su URL diversi. Se più URL portano a una determinata destinazione,
per esempio /index e /index?page=1, il framework ne designa uno come principale (canonico) e vi
reindirizza gli altri con il codice HTTP 301. Grazie a questo i motori di ricerca non indicizzano le vostre pagine due volte e
non ne diluiscono il page rank.
Questo processo si chiama canonizzazione. L'URL canonico è quello generato dal router, di norma la prima route corrispondente della collezione.
La canonizzazione è attiva per impostazione predefinita e si può disattivare con
$this->autoCanonicalize = false.
Il redirect non avviene durante le richieste AJAX o POST, perché potrebbe portare a una perdita di dati o non offrirebbe alcun valore aggiunto in termini di SEO.
Potete anche avviare la canonizzazione manualmente con il metodo canonicalize(). Come per il metodo
link(), gli passate il presenter, l'azione e i parametri. Genera un link e lo confronta con l'indirizzo URL
corrente. Se differiscono, reindirizza al link generato.
public function actionShow(int $id, ?string $slug = null): void
{
$realSlug = $this->facade->getSlugForId($id);
// reindirizza se $slug è diverso da $realSlug
$this->canonicalize('Product:show', [$id, $realSlug]);
}
Per uno schema completo che combina i filtri delle route con canonicalize() per produrre URL adatti alla SEO,
vedi URL leggibili con gli slug.
Risposte
La risposta restituita dal presenter è un oggetto che implementa l'interfaccia Nette\Application\Response. Sono disponibili diverse risposte già pronte:
- Nette\Application\Responses\CallbackResponse – invia una callback
- Nette\Application\Responses\FileResponse – invia il file
- Nette\Application\Responses\ForwardResponse – forward()
- Nette\Application\Responses\JsonResponse – invia JSON
- Nette\Application\Responses\RedirectResponse – redirect
- Nette\Application\Responses\TextResponse – invia testo
- Nette\Application\Responses\VoidResponse – risposta vuota
Le risposte si inviano con il metodo sendResponse():
use Nette\Application\Responses;
// testo semplice
$this->sendResponse(new Responses\TextResponse('Hello Nette!'));
// invia un file
$this->sendResponse(new Responses\FileResponse(__DIR__ . '/invoice.pdf', 'Invoice13.pdf'));
// invia una callback
$callback = function (Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse) {
if ($httpResponse->getHeader('Content-Type') === 'text/html') {
echo '<h1>Hello</h1>';
}
};
$this->sendResponse(new Responses\CallbackResponse($callback));
Potete anche scrivere una vostra risposta. Basta implementare l'interfaccia Nette\Application\Response, che ha un
unico metodo send(), il quale riceve la richiesta e la risposta HTTP. È utile, per esempio, quando si trasmettono in
streaming dati che non volete tenere in memoria:
class CsvResponse implements Nette\Application\Response
{
public function __construct(
private string $fileName,
private iterable $rows,
) {
}
public function send(Nette\Http\IRequest $request, Nette\Http\IResponse $response): void
{
$response->setContentType('text/csv', 'utf-8');
$response->sendAsFile($this->fileName);
$handle = fopen('php://output', 'w');
foreach ($this->rows as $row) {
fputcsv($handle, $row);
}
fclose($handle);
}
}
La inviate poi nel presenter come al solito: $this->sendResponse(new CsvResponse('export.csv', $rows));
Caching HTTP
Il metodo lastModified() rende semplice sfruttare il caching HTTP. Gli passate la data e l'ora dell'ultima
modifica del contenuto (come timestamp, stringa oppure oggetto DateTimeInterface) e, facoltativamente, un validatore
ETag (una breve stringa che identifica la versione corrente del contenuto, per esempio un suo hash) e un tempo di scadenza. Se il
browser possiede già una versione corrispondente, il presenter invia una risposta 304 Not Modified e termina, così
la pagina non viene disegnata né trasferita inutilmente:
public function renderArticle(int $id): void
{
$article = $this->articles->getById($id);
$this->lastModified($article->updatedAt);
// ...
}
Completare il template
Quando il presenter disegna un template, il metodo sendTemplate() chiama completeTemplate() subito
prima del rendering. Questo metodo riempie le variabili contrassegnate con l'attributo #[TemplateVariable] e
individua il file del template (le variabili predefinite sono già impostate dal TemplateFactory al momento della
creazione del template). Potete sovrascrivere questo metodo protected per aggiungere variabili condivise da tutte le viste o per
impostare un file diverso:
protected function completeTemplate(Nette\Application\UI\Template $template): void
{
parent::completeTemplate($template);
$template->siteName = 'My App';
}
Limitare l'accesso con #[Requires]
L'attributo #[Requires] offre possibilità avanzate per limitare l'accesso ai presenter e ai loro metodi. Si può
usare per indicare i metodi HTTP, per richiedere una richiesta AJAX, per limitare alla stessa origine e per consentire l'accesso
solo tramite forwarding. L'attributo si può applicare sia alle classi dei presenter sia ai singoli metodi come
action<Azione>(), render<Vista>(), handle<Segnale>() e
createComponent<Nome>().
Potete indicare queste restrizioni:
- sui metodi HTTP:
#[Requires(methods: ['GET', 'POST'])] - richiedere una richiesta AJAX:
#[Requires(ajax: true)] - accesso solo dalla stessa origine:
#[Requires(sameOrigin: true)] - accesso solo tramite forwarding:
#[Requires(forward: true)] - restrizioni su azioni specifiche:
#[Requires(actions: 'default')]
Dalla versione 3.3 la corrispondenza della stessa origine è verificata tramite l'header
Sec-Fetch-Site del browser (prima tramite un cookie SameSite), il che è più affidabile e controlla la
corrispondenza esatta di schema, dominio e porta.
I dettagli si trovano nella guida Come usare l'attributo Requires.
Controllo del metodo HTTP
I presenter in Nette verificano automaticamente il metodo HTTP di ogni richiesta in arrivo, soprattutto per motivi di
sicurezza. Per impostazione predefinita sono ammessi i metodi GET, POST, HEAD,
PUT, DELETE, PATCH.
Se volete ammettere in più, per esempio, il metodo OPTIONS, usate l'attributo #[Requires] (da Nette
Application v3.2.3):
#[Requires(methods: ['GET', 'POST', 'HEAD', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'])]
class MyPresenter extends Nette\Application\UI\Presenter
{
}
Dalla versione 3.1.13 la verifica avviene in checkHttpMethod(), che controlla se il metodo indicato nella
richiesta è presente nell'array $presenter->allowedMethods. Dalla versione 3.2.3 questo approccio è deprecato
in favore di #[Requires]. Potete sovrascrivere il metodo così:
class MyPresenter extends Nette\Application\UI\Presenter
{
protected function checkHttpMethod(): void
{
$this->allowedMethods[] = 'OPTIONS';
parent::checkHttpMethod();
}
}
È importante sottolineare che, se attivate il metodo OPTIONS, dovete poi gestirlo in modo appropriato nel vostro
presenter. Questo metodo è spesso usato come cosiddetta richiesta preflight, che il browser invia automaticamente prima della
richiesta vera e propria quando è necessario stabilire se la richiesta è ammissibile secondo la policy CORS (Cross-Origin
Resource Sharing). Se attivate il metodo ma non implementate la risposta corretta, si possono creare incoerenze e potenziali
problemi di sicurezza.
Contrassegnare le azioni deprecate
L'attributo #[Deprecated] contrassegna azioni, segnali o interi presenter come deprecati e destinati alla
rimozione futura. Generando link verso parti deprecate dell'applicazione, Nette emette un avviso per allertare gli
sviluppatori.
Potete applicare l'attributo all'intera classe del presenter oppure ai singoli metodi action<Azione>(),
render<Vista>() e handle<Segnale>().