Creazione di link URL
Creare link in Nette è semplice come puntare il dito. Basta mirare e il framework farà tutto il lavoro per voi. Vi mostreremo:
- come creare link nei template e altrove
- come riconoscere un link alla pagina corrente
- cosa fare con i link non validi
Grazie al routing bidirezionale non dovrete mai scrivere a mano nei template o nel codice gli URL della vostra applicazione, che potrebbero cambiare in seguito o essere complicati da comporre. Nel link basta indicare il presenter e l'azione, passare eventuali parametri, e il framework genererà l'URL da sé. In realtà è molto simile a chiamare una funzione. Vi piacerà.
Nel template del presenter
Il più delle volte creiamo i link nei template, e l'attributo n:href è un ottimo aiuto:
<a n:href="Product:show">dettaglio</a>
Notate che al posto dell'attributo HTML href abbiamo usato l'n:attributo n:href. Il suo valore non è un URL, come
sarebbe per l'attributo href, ma il nome del presenter e dell'azione.
Cliccare su un link è, detta semplicemente, un po' come chiamare il metodo ProductPresenter::renderShow(). E se
questo ha dei parametri nella propria firma, possiamo chiamarlo con degli argomenti:
<a n:href="Product:show $product->id, $product->slug">dettaglio del prodotto</a>
È possibile passare anche parametri nominali. Il link seguente passa il parametro lang con il valore
en:
<a n:href="Product:show $product->id, lang: en">dettaglio del prodotto</a>
Se il metodo ProductPresenter::renderShow() non ha $lang nella propria firma, può ottenere il valore
del parametro con $lang = $this->getParameter('lang') oppure da una proprietà.
Se i parametri sono salvati in un array, si possono espandere con l'operatore ...:
{var $args = [$product->id, lang => en]}
<a n:href="Product:show, ...$args">dettaglio del prodotto</a>
Nei link vengono passati automaticamente anche i cosiddetti parametri persistenti.
L'attributo n:href è molto comodo per i tag HTML <a>. Se vogliamo stampare il link altrove,
per esempio nel testo, usiamo {link}:
L'URL è: {link Home:default}
Nel codice
Per creare un link nel presenter si usa il metodo link():
$url = $this->link('Product:show', $product->id);
I parametri si possono passare anche come array, in cui si possono indicare anche parametri nominali:
$url = $this->link('Product:show', [$product->id, 'lang' => 'en']);
I link si possono creare anche senza un presenter, con il LinkGenerator e il suo metodo
link().
A volte vi serve creare un link subito, ma generare l'URL vero e proprio solo più tardi. A questo serve il metodo
lazyLink(), che restituisce un oggetto Nette\Application\UI\Link. Il vantaggio è che potete passare
questo oggetto, per esempio a un template, e prima che venga disegnato potete ancora modificarne i parametri con il metodo
setParameter(). L'URL viene composto solo quando l'oggetto viene convertito in stringa:
$link = $this->lazyLink('Product:show', $id);
// ...
echo $link; // l'URL viene generato solo qui
Link a un presenter
Se la destinazione del link è un presenter con un'azione, la sintassi è questa:
[//] [[[[:]module:]presenter:]action | this] [#fragment]
Questo formato è supportato da tutti i tag di Latte e da tutti i metodi del presenter che lavorano con i link, cioè
n:href, {link}, {plink}, link(), lazyLink(),
isLinkCurrent(), redirect(), redirectPermanent(), forward(),
canonicalize() e anche dal LinkGenerator. Quindi, anche se negli esempi si usa
n:href, al suo posto potrebbe esserci una qualsiasi di queste funzioni.
La forma di base è dunque Presenter:azione:
<a n:href="Home:default">home page</a>
Se colleghiamo a un'azione del presenter corrente, possiamo ometterne il nome:
<a n:href="default">home page</a>
Se l'azione di destinazione è default, possiamo ometterla, ma i due punti devono restare:
<a n:href="Home:">home page</a>
I link possono puntare anche ad altri moduli. Qui si distingue tra link
relativi a un sottomodulo annidato e link assoluti. Il principio è analogo a quello dei percorsi su disco, solo che al posto
delle barre si usano i due punti. Supponendo che il presenter corrente faccia parte del modulo Front,
scriveremmo:
<a n:href="Shop:Product:show">link a Front:Shop:Product:show</a>
<a n:href=":Admin:Product:show">link a Admin:Product:show</a>
Un caso particolare è il link a sé stessi, dove indichiamo come destinazione
this.
<a n:href="this">aggiorna</a>
Possiamo collegare a una parte precisa della pagina tramite il cosiddetto frammento dopo il cancelletto #:
<a n:href="Home:#main">link a Home:default e al frammento #main</a>
Il frammento si può impostare anche dinamicamente, come argomento con la chiave #. Il suo
valore viene codificato automaticamente e ha la precedenza sul frammento indicato nella destinazione:
$this->link('Home:default', ['#' => $fragment]);
Percorsi assoluti
I link generati con link() o n:href sono sempre percorsi assoluti (cioè iniziano con
/), ma non URL assoluti con protocollo e dominio, come https://domain.
Per generare un URL assoluto aggiungete due barre all'inizio (per esempio n:href="//Home:"). In alternativa potete
far generare al presenter solo link assoluti impostando $this->absoluteUrls = true.
Nel template si può usare anche il filtro |absoluteUrl per convertire un percorso relativo in uno assoluto.
Link alla pagina corrente
La destinazione this crea un link alla pagina corrente:
<a n:href="this">aggiorna</a>
Allo stesso tempo vengono trasferiti tutti i parametri indicati nella firma del metodo action<Azione>() o
render<Vista>() (se action<Azione>() non è definito). Se quindi ci troviamo sulla pagina
Product:show con id: 123, anche il link a this passerà questo parametro.
Naturalmente è possibile indicare i parametri direttamente:
<a n:href="this refresh: 1">aggiorna</a>
La funzione isLinkCurrent() controlla se la destinazione del link coincide con la pagina corrente. Si può usare
per esempio in un template per distinguere i link e simili.
I parametri sono gli stessi del metodo link(), ma al posto di un'azione specifica si può usare anche il
carattere jolly *, che indica una qualsiasi azione del presenter indicato.
{if !isLinkCurrent('Admin:login')}
<a n:href="Admin:login">Accedi</a>
{/if}
<li n:class="isLinkCurrent('Product:*') ? active">
<a n:href="Product:">...</a>
</li>
In combinazione con n:href su un unico elemento si può usare una forma abbreviata:
<a n:class="isLinkCurrent() ? active" n:href="Home:">...</a>
Il carattere jolly * si può usare solo al posto dell'azione, non del presenter.
Per stabilire se ci troviamo in un determinato modulo o in un suo sottomodulo, usate il metodo
isModuleCurrent(moduleName).
<li n:class="isModuleCurrent('Forum:Users') ? active">
<a n:href="Product:">...</a>
</li>
Cambiare la base dei link
Per impostazione predefinita i link relativi sono derivati dal presenter corrente. Lo si può cambiare con
{linkBase}:
{linkBase Admin:Dashboard}
<a n:href="Product:show">dettaglio del prodotto</a>
Il link porterà a Admin:Dashboard:Product:show. Ne sono interessati solo i link relativi: i link assoluti che
iniziano con i due punti e i link al presenter corrente (this, show) restano invariati.
{linkBase} vale per l'intero template ed è particolarmente utile nei template di layout, dove garantisce link
coerenti indipendentemente dal presenter chiamante. Il tag va collocato all'inizio del template, altrimenti solleva una
CompileException.
Link a un segnale
La destinazione di un link non deve essere per forza un presenter con un'azione: può essere anche un segnale (che chiama il metodo
handle<Segnale>()). La sintassi è allora questa:
[//] [sotto-componente:]segnale! [#fragment]
Il segnale si distingue quindi per il punto esclamativo:
<a n:href="click!">segnale</a>
Potete creare anche un link a un segnale di un sottocomponente (o di un sotto-sottocomponente):
<a n:href="componentName:click!">segnale</a>
Link in un componente
Poiché i componenti sono unità riutilizzabili autonome, che
non dovrebbero avere alcun legame con i presenter circostanti, qui i link funzionano in modo un po' diverso. L'attributo Latte
n:href e il tag {link}, così come i metodi del componente come link() e altri,
considerano sempre la destinazione del link come il nome di un segnale. Non è quindi nemmeno necessario indicare il punto
esclamativo:
<a n:href="click">segnale, non un'azione</a>
Se volessimo collegare ai presenter nel template di un componente, useremmo il tag {plink}:
<a href={plink Home:default}>home</a>
oppure nel codice
$this->getPresenter()->link('Home:default')
Alias
A volte può essere utile assegnare a una coppia Presenter:azione un alias facile da ricordare. Per esempio chiamare la home
page Front:Home:default semplicemente home, oppure Admin:Dashboard:default come
admin.
Gli alias si definiscono nella configurazione, sotto la chiave
application › aliases:
application:
aliases:
home: Front:Home:default
admin: Admin:Dashboard:default
sign: Front:Sign:in
Nei link si scrivono poi con la chiocciola, per esempio:
<a n:href="@admin">amministrazione</a>
Sono supportati anche in tutti i metodi che lavorano con i link, come redirect() e simili.
Link non validi
Può capitare di creare un link non valido: perché porta a un presenter inesistente, perché passa più parametri di quanti ne
accetti il metodo di destinazione nella propria firma, oppure perché per l'azione di destinazione non è possibile generare un
URL. Come gestire i link non validi si imposta nel presenter con $this->invalidLinkMode. Può assumere una
combinazione di questi valori (costanti):
Presenter::InvalidLinkSilent– modalità silenziosa, restituisce come URL il carattere #Presenter::InvalidLinkWarning– viene emesso un avviso E_USER_WARNING, che in modalità di produzione verrà registrato nel log ma non interromperà l'esecuzione dello scriptPresenter::InvalidLinkTextual– avviso visivo, stampa l'errore direttamente nel linkPresenter::InvalidLinkException– solleva InvalidLinkException
L'impostazione predefinita è InvalidLinkWarning in modalità di produzione e
InvalidLinkWarning | InvalidLinkTextual in modalità di sviluppo. In ambiente di produzione
InvalidLinkWarning non provoca l'interruzione dello script, ma l'avviso verrà registrato nel log. In ambiente di
sviluppo lo intercetta Tracy e mostra una schermata blu. InvalidLinkTextual
funziona restituendo come URL un messaggio di errore che inizia con i caratteri #error:. Perché link del genere si
notino a colpo d'occhio, aggiungete al vostro CSS:
a[href^="#error:"] {
background: red;
color: white;
}
Se non vogliamo che in ambiente di sviluppo vengano emessi avvisi, possiamo silenziarli direttamente nella configurazione.
application:
silentLinks: true
LinkGenerator
Come creare link con la stessa comodità del metodo link(), ma senza la presenza di un presenter? A questo serve
Nette\Application\LinkGenerator.
LinkGenerator è un servizio che potete farvi passare tramite il costruttore e con cui potete poi creare link usandone il
metodo link().
C'è una differenza rispetto ai presenter. LinkGenerator crea tutti i link direttamente come URL assoluti. Inoltre non esiste
un “presenter corrente”, quindi non è possibile indicare come destinazione solo il nome dell'azione,
link('default'), né usare percorsi relativi ai moduli.
I link non validi sollevano sempre Nette\Application\UI\InvalidLinkException.