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().

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.

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>

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>

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.

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ückgegeben
  • Presenter::InvalidLinkWarning – es wird eine E_USER_WARNING-Warnung ausgegeben, die im Produktionsmodus protokolliert wird, aber die Skriptausführung nicht unterbricht
  • Presenter::InvalidLinkTextual – visuelle Warnung, gibt den Fehler direkt im Link aus
  • Presenter::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.

Version: 4.0