Erstellen von URL-Links
Das Erstellen von Links in Nette ist so einfach wie mit dem Finger zu zeigen. Sie müssen nur zielen, und das Framework erledigt die ganze Arbeit für Sie. Wir zeigen Ihnen:
- wie man Links in Templates und anderswo erstellt
- wie man einen Link zur aktuellen Seite unterscheidet
- was mit ungültigen Links zu tun ist
Dank bidirektionalem Routing müssen Sie niemals fest codierte URL-Adressen Ihrer Anwendung in Templates oder Code schreiben, die sich später ändern könnten, oder sie kompliziert zusammensetzen. Im Link genügt es, den Presenter und die Aktion anzugeben, eventuelle Parameter zu übergeben, und das Framework generiert die URL selbst. Eigentlich ist es sehr ähnlich wie der Aufruf einer Funktion. Das wird Ihnen gefallen.
Im Presenter-Template
Am häufigsten erstellen wir Links in Templates, und ein großartiger Helfer ist das Attribut n:href
:
<a n:href="Product:show">Detail</a>
Beachten Sie, dass wir anstelle des HTML-Attributs href
das n:Attribut n:href
verwendet haben. Sein Wert ist dann
nicht eine URL, wie es beim href
-Attribut der Fall wäre, sondern der Name des Presenters und der Aktion.
Ein Klick auf den Link ist, vereinfacht gesagt, so etwas wie der Aufruf der Methode
ProductPresenter::renderShow()
. Und wenn diese Parameter in ihrer Signatur hat, können wir sie mit Argumenten
aufrufen:
<a n:href="Product:show $product->id, $product->slug">Produktdetail</a>
Es ist auch möglich, benannte Parameter zu übergeben. Der folgende Link übergibt den Parameter lang
mit dem
Wert cs
:
<a n:href="Product:show $product->id, lang: cs">Produktdetail</a>
Wenn die Methode ProductPresenter::renderShow()
$lang
nicht in ihrer Signatur hat, kann sie den Wert
des Parameters mit $lang = $this->getParameter('lang')
oder aus der Property ermitteln.
Wenn die Parameter in einem Array gespeichert sind, können sie mit dem Operator ...
(in Latte 2.x mit dem
Operator (expand)
) erweitert werden:
{var $args = [$product->id, lang => cs]}
<a n:href="Product:show ...$args">Produktdetail</a>
In Links werden auch automatisch sogenannte persistente Parameter übergeben.
Das Attribut n:href
ist sehr praktisch für HTML-Tags <a>
. Wenn wir einen Link an anderer
Stelle ausgeben möchten, zum Beispiel im Text, verwenden wir {link}
:
Die Adresse lautet: {link Home:default}
Im Code
Zum Erstellen eines Links im Presenter dient die Methode link()
:
$url = $this->link('Product:show', $product->id);
Parameter können auch über ein Array übergeben werden, wo auch benannte Parameter angegeben werden können:
$url = $this->link('Product:show', [$product->id, 'lang' => 'cs']);
Links können auch ohne Presenter erstellt werden, dafür gibt es den LinkGenerator und seine
Methode link()
.
Links zu Presentern
Wenn das Ziel des Links ein Presenter und eine Aktion ist, hat er diese Syntax:
[//] [[[[:]module:]presenter:]action | this] [#fragment]
Das Format wird von allen Latte-Tags und allen Presenter-Methoden unterstützt, die mit Links arbeiten, also
n:href
, {link}
, {plink}
, link()
, lazyLink()
,
isLinkCurrent()
, redirect()
, redirectPermanent()
, forward()
,
canonicalize()
und auch dem LinkGenerator. Auch wenn in den Beispielen
n:href
verwendet wird, könnte dort jede dieser Funktionen stehen.
Die Grundform ist also Presenter:action
:
<a n:href="Home:default">Startseite</a>
Wenn wir auf eine Aktion des aktuellen Presenters verlinken, können wir seinen Namen weglassen:
<a n:href="default">Startseite</a>
Wenn das Ziel die Aktion default
ist, können wir sie weglassen, aber der Doppelpunkt muss bleiben:
<a n:href="Home:">Startseite</a>
Links können auch zu anderen Modulen führen. Hier werden Links in
relative zu verschachtelten Submodulen oder absolute unterschieden. Das Prinzip ist analog zu Pfaden auf der Festplatte, nur dass
anstelle von Schrägstrichen Doppelpunkte verwendet werden. Angenommen, der aktuelle Presenter ist Teil des Moduls
Front
, dann schreiben wir:
<a n:href="Shop:Product:show">Link zu Front:Shop:Product:show</a>
<a n:href=":Admin:Product:show">Link zu Admin:Product:show</a>
Ein Sonderfall ist der Link auf sich selbst, bei dem wir als Ziel
this
angeben.
<a n:href="this">aktualisieren</a>
Wir können auf einen bestimmten Teil der Seite über das sogenannte Fragment nach dem Rautezeichen #
verlinken:
<a n:href="Home:#main">Link zu Home:default und Fragment #main</a>
Absolute Pfade
Links, die mit link()
oder n:href
generiert werden, sind immer absolute Pfade (d. h. sie beginnen mit
einem /
), aber keine absoluten URLs mit Protokoll und Domain wie https://domain
.
Um eine absolute URL zu generieren, fügen Sie am Anfang zwei Schrägstriche hinzu (z. B. n:href="//Home:"
). Oder
Sie können den Presenter so umschalten, dass er nur absolute Links generiert, indem Sie
$this->absoluteUrls = true
setzen.
Link zur aktuellen Seite
Das Ziel this
erstellt einen Link zur aktuellen Seite:
<a n:href="this">aktualisieren</a>
Gleichzeitig werden auch alle Parameter übertragen, die in der Signatur der Methode action<Action>()
oder
render<View>()
angegeben sind, falls action<Action>()
nicht definiert ist. Wenn wir also auf
der Seite Product:show
mit id: 123
sind, übergibt der Link auf this
auch diesen
Parameter.
Natürlich ist es möglich, Parameter direkt anzugeben:
<a n:href="this refresh: 1">aktualisieren</a>
Die Funktion isLinkCurrent()
prüft, ob das Ziel des Links mit der aktuellen Seite übereinstimmt. Dies kann
beispielsweise in einem Template verwendet werden, um Links zu unterscheiden usw.
Die Parameter sind die gleichen wie bei der Methode link()
, zusätzlich ist es jedoch möglich, anstelle einer
konkreten Aktion den Platzhalter *
anzugeben, der jede Aktion des gegebenen Presenters bedeutet.
{if !isLinkCurrent('Admin:login')}
<a n:href="Admin:login">Anmelden</a>
{/if}
<li n:class="isLinkCurrent('Product:*') ? active">
<a n:href="Product:">...</a>
</li>
In Kombination mit n:href
in einem Element kann eine verkürzte Form verwendet werden:
<a n:class="isLinkCurrent() ? active" n:href="Home:">...</a>
Der Platzhalter *
kann nur anstelle der Aktion verwendet werden, nicht für den Presenter.
Um festzustellen, ob wir uns in einem bestimmten Modul oder dessen Submodul befinden, verwenden wir die Methode
isModuleCurrent(moduleName)
.
<li n:class="isModuleCurrent('Forum:Users') ? active">
<a n:href="Product:">...</a>
</li>
Links zu Signalen
Das Ziel eines Links muss nicht nur ein Presenter und eine Aktion sein, sondern auch ein Signal (sie rufen die Methode
handle<Signal>()
auf). Dann lautet die Syntax wie folgt:
[//] [sub-component:]signal! [#fragment]
Das Signal wird also durch ein Ausrufezeichen unterschieden:
<a n:href="click!">Signal</a>
Es kann auch ein Link zum Signal einer Subkomponente (oder Sub-Subkomponente) erstellt werden:
<a n:href="componentName:click!">Signal</a>
Links in einer Komponente
Da Komponenten separate wiederverwendbare Einheiten sind, die
keine Bindungen an umgebende Presenter haben sollten, funktionieren Links hier etwas anders. Das Latte-Attribut
n:href
und der Tag {link}
sowie Komponentenmethoden wie link()
und andere betrachten das
Linkziel immer als den Namen des Signals. Daher ist es nicht notwendig, ein Ausrufezeichen anzugeben:
<a n:href="click">Signal, nicht Aktion</a>
Wenn wir im Template einer Komponente auf Presenter verlinken möchten, verwenden wir dazu den Tag {plink}
:
<a href={plink Home:default}>Startseite</a>
oder im Code
$this->getPresenter()->link('Home:default')
Aliase
Manchmal kann es nützlich sein, dem Paar Presenter:Aktion einen leicht zu merkenden Alias zuzuordnen. Zum Beispiel die
Startseite Front:Home:default
einfach als home
benennen oder Admin:Dashboard:default
als
admin
.
Aliase werden in der Konfiguration unter dem Schlüssel
application › aliases
definiert:
application:
aliases:
home: Front:Home:default
admin: Admin:Dashboard:default
sign: Front:Sign:in
In Links werden sie dann mit einem At-Zeichen geschrieben, zum Beispiel:
<a n:href="@admin">Administration</a>
Sie werden auch in allen Methoden unterstützt, die mit Links arbeiten, wie redirect()
und ähnliche.
Ungültige Links
Es kann vorkommen, dass wir einen ungültigen Link erstellen – entweder weil er auf einen nicht existierenden Presenter
verweist, oder weil er mehr Parameter übergibt, als die Zielmethode in ihrer Signatur akzeptiert, oder wenn für die Zielaktion
keine URL generiert werden kann. Wie mit ungültigen Links umgegangen wird, bestimmt die statische Variable
Presenter::$invalidLinkMode
. Diese kann eine Kombination der folgenden Werte (Konstanten) annehmen:
Presenter::InvalidLinkSilent
– stiller Modus, als URL wird das Zeichen # zurückgegebenPresenter::InvalidLinkWarning
– es wird eine E_USER_WARNING-Warnung ausgegeben, die im Produktionsmodus protokolliert wird, aber die Skriptausführung nicht unterbrichtPresenter::InvalidLinkTextual
– visuelle Warnung, gibt den Fehler direkt im Link ausPresenter::InvalidLinkException
– es wird eine InvalidLinkException-Ausnahme ausgelöst
Die Standardeinstellung ist InvalidLinkWarning
im Produktionsmodus und
InvalidLinkWarning | InvalidLinkTextual
im Entwicklungsmodus. InvalidLinkWarning
im Produktionsmodus
führt nicht zur Unterbrechung des Skripts, aber die Warnung wird protokolliert. Im Entwicklungsmodus wird sie von Tracy abgefangen und zeigt einen Bluescreen an. InvalidLinkTextual
funktioniert so, dass als URL eine Fehlermeldung zurückgegeben wird, die mit den Zeichen #error:
beginnt. Damit
solche Links auf den ersten Blick erkennbar sind, ergänzen wir unser CSS:
a[href^="#error:"] {
background: red;
color: white;
}
Wenn wir nicht möchten, dass im Entwicklungsmodus Warnungen erzeugt werden, können wir den stillen Modus direkt in der Konfiguration einstellen.
application:
silentLinks: true
LinkGenerator
Wie erstellt man Links mit ähnlichem Komfort wie die Methode link()
, aber ohne die Anwesenheit eines Presenters?
Dafür gibt es den Nette\Application\LinkGenerator.
Der LinkGenerator ist ein Dienst, den Sie sich über den Konstruktor übergeben lassen und dann Links mit seiner Methode
link()
erstellen können.
Im Vergleich zu Presentern gibt es hier einen Unterschied. Der LinkGenerator erstellt alle Links direkt als absolute URLs.
Außerdem gibt es keinen “aktuellen Presenter”, sodass man als Ziel nicht nur den Aktionsnamen link('default')
angeben oder relative Pfade zu Modulen verwenden kann.
Ungültige Links lösen immer eine Nette\Application\UI\InvalidLinkException
aus.