Artikel: Blog
von
Dieser Artikel ist bereits über 2 Jahre alt. Das gezeigte Vorgehen ist vielleicht nicht mehr aktuell.
Copyright bei Patrick Froch und easy Solutions IT. Dieses Werk ist lizenziert unter Creative Commons BY-NC-SA.

Contao 4: Eigene Route erstellen

In diesem Artikel zeige ich, wie man eine eigene Route für Contao 4 erstellt. Ich werde nicht auf alle Möglichkeiten des Routings eingehen können, aber es sollen die Grundzüge erläutert werden. Wollte man unter Contao 2 oder 3 einen eigenen "Entry point" für den Zugriff von außen (z.B. für eine API), hat man einfach in seiner Erweiterung eine entsprechende Datei erstellt und dort losgelegt. Dies war genau so einfach, wie gefährlich. Symfony bietet hier mit den Routen eine wesentlich ausgereiftere Lösung.

Im Folgenden wollen wir eine einfache Route erstellen, die uns den Pfad zur Uuid einer Datei zurück gibt. Auf Sicherheitsprüfungen wird weitgehend verzichtet, da diese beim Laden der Datei sowieso noch berücksichtigt werden müssen. Der vorgestellte Code sollte also auf gar keinen Fall so verwendet werden!

Hinweis: Ich gehe auf die Grundlagen der Bundels nicht mehr ein, da diese hier im Blog schon zur Genüge erläutert wurden.

ManagerPlugin

Wie immer haben wir zwei ContaoManagerPlugins, eins für die Entwicklungsumgebung und eins, dass später mit dem Bundle ausgeliefert wird und dafür sorgt, dass unsere Dateien nach der Installation von Contao geladen werden können.

Das Plugin für die Entwicklungsumgebung liegt unter app/ContaoManagerPlugin.php:

Das Plugin des Bundles liegt im Ordner des Bundles unter src/Esit/Demo/Classes/Contao/Manger/Plugin.php:

Neu bei den Plugins ist die Methode getRouteCollection, die die Routingkonfiguration lädt. Damit dies funktioniert muss die Klasse das RoutingPluginInterface implementieren! (s. Zeile 13!)

routing.yml

Nun müssen wir noch die Datei erstellen, die wir im Plugin laden wollen. Die Routingkonfiguration steht in der Datei src/Esit/Demo/Resources/config/routing.yml:

In Zeile 2 legen wir den Pfad der Url fest, auf den unser Controller reagieren soll. In Zeile 4 steht unsere Klasse und die Methode, die als Controller aufgerufen werden soll. In Zeile 8 legen wir noch fest, dass der übergebene Parameter 32 Stellen haben muss und aus den Zeichen a-f, A-F und 0-9 bestehen darf, also die hexadezimale Darstellung einer Uuid.

Service

Nun erstellen wir für unseren Controller einen Serviceeintrag in der Datei src/Esit/Demo/Resources/config/services.yml:

Im Gegensatz zu den "normalen" Services geben wir hier keine Klasse an, benutzen aber den Namespace und Klassennamen als Schlüssel für den Service (s. Zeile 2). Wir legen die Konstruktorparameter fest, die wir benötigen und setzen den Tag controller.service_arguments, um den Service als Controller zu definieren. Die Datei src/Esit/Demo/Resources/config/services.yml wird wie immer über die Extension-Datei des Bundels geladen (src/Esit/Demo/DependencyInjection/EsitDemoExtension.php).

Controller

Als letztes benötigen wir noch einen Controller, der die Arbeit für uns verrichtet und für uns das gewünschte Ergebnis erzeugt. Der Controller liegt unter src/Esit/Demo/Classes/Controller/UuidController.php:

In Zeile 21 werden die Konstruktorparameter entgegengenommen. Die eigentliche Arbeit macht die Methode loadAction ab Zeile 28. Sie erhält eine Uuid, lädt über das FilesModel die Daten der Datei aus der DB und gibt ein JSON-Objekt mit dem Pfad zurück.

Das war schon die ganze Magie. Selbstverständlich ist das Routing wesentlich leistungsfähiger, aber als Einstieg soll dies reichen.

Zurück

Kommentare

Kommentar von Stefan Fischer |

Hi,

wie kann im Routing eine Contao-Seite laden mit Parametern? habs mit folgendem Befehl versucht:

$request = Request::create(
'index.html',
'GET',
array("sow" => "test54")
);
$kernel = ContaoKernel::fromRequest(\dirname(__DIR__), $request);
$response = $kernel->handle($request);
return $response;

Antwort von Patrick Froch

Hi,

ich weiß nicht genau was das Ziel ist. Bei mir ist das Routing in einer YAML-Datei, da kann man nichts laden. Vermutlich ist der Controller gemeint. In diesem Fall kann man einfach ein Redirect machen, oder wie hier beschrieben, die Anfrage weiterleiten. Mit Contao habe ich dies leider auch noch nicht verwendet, so dass ich ohne die Details zu kennen, keine sinnvolle Hilfestellung geben kann.

Viele Grüße,
Patrick Froch

Kommentar von Stefan Fischer |

Hi,

Ja das habe ich vergessen zu erwähnen, ich habe einen Frontend-Controller erstellt und will auf die Startseite zugreifen. Also kein Redirect machen. Der Startseite will ich zusätzlich einige Parameter übergeben. Mit den obigen Befehlen komme ich an einen Punkt wo er mir eine Exception wirft und das terminal42/contao-folderpage mich darauf verweist: Undefined index: save_callback.

Antwort von Patrick Froch

Dann liegt es aber wohl eher an der Erweiterung. Vielleicht wird ein DCA nicht geladen. Ich würde zu erst versuchen herauszufinden, welche save_callbacks die Erweiterung verarbeitet und dann das DCA manuell laden. Hast Du das Framework initialisiert? Soweit ich weiß, musst Du dies im Controller manuell machen.

Mehr als allgemeine Tipps kann ich leider nicht beisteuern, vielleicht weiß ja im Forum oder Slack jemand Rat.

Kommentar von stefan fischer |

Die Komponente ist Teil von contao

Antwort von Patrick Froch

Stimmt, die Erweiterung wird mit dem Contao-Core installiert. Das ändert aber nichts, am Vorgehen. ;)

Kommentar von stefan fischer |

Muss ich mal nachschauen. Ich hab den Controller in der yml deklariert. Aber ich konnte dem keine Argumente übergeben. Beim DCA weiß ich noch nicht. Ob ich da was manuell einfügen kann was sinnvoll ist. Wenn ich den FrontendIndex Controller aufrufe. Dann brauche ich das DCA zu befüllen aber ich kann dem keine Parameter übergeben. Ich werde die Tage mich nochmal dransetzen

Antwort von Patrick Froch

Ich meine nicht das DCA befüllen, sondern laden: \Contao\Controller::loadDataContainer('tl_example');. Es werden immer nur die benötigten DCAs geladen und der Controller weiß ja nicht, welcher gebraucht wird. Wenn kein DCA geladen wurde, steht auch kein save_callback zur Verfügung. Ich weiß aber nicht, welche Tabelle hier verarbeitet wird und ob es wirklich daran liegt. ISt halt nur ein beliebter Fehler, wenn man Contao von "außen" etwas unterschieben will.

Kommentar von stefan fischer |

Ich werde es mal testen

Kommentar von Stefan Fischer |

habe nachfolgenden Thread gefunden... vllt. ist das schon die Lösung:
https://community.contao.org/de/showthread.php?78094-Routing-in-Contao-4-4

ich weiß nur noch nicht ob domain.tld/index/show/test54.html so schön ist aber es wäre mal ne erste Lösung... was meinst du?

Antwort von Patrick Froch

Wie gesagt, ich weiß nicht was genau Dein Ziel ist. Ich würde die Parameter einfach als ?param1=foo&para2=bar anhängen. Geht natürlich nur, wenn Du GET-Parameter verwenden kannst. Man könnte es z.B. so lösen:

$objPage = \PageModel::findPublishedById($jumpTo);
$strUrl = \Controller::generateFrontendUrl(array('alias' => $objPage->alias));

Dabei muss $jumpTo durch die Id Deiner Zielseite ersetzt werden, aber die wirst Du ja kennen.

Die eigentliche Herausforderung ist ja nun, die Seite in Deinem Controller vollständig zu rendern. Damit habe ich mich lange nicht beschäftigt und weiß auf die Schnelle keine Lösung. Vielleicht hilft Dir dieser Eintrag weiter.

Kommentar von Stefan Fischer |

Hi,

also ich habe auf der Startseite einmal eine Übersichtsseite und je nachdem wenn Parameter vorhanden sind eine Detailseite. Da die detailseite ein Parameter show benötigt konnte ich die Seite mittels ?show=testuser anzeigen. Dies wollte ich allerdings ändern, da es ja für SEO nicht so gut ist. Deshalb wollte ich daraus eine sprechende URL machen.

Antwort von Patrick Froch

Okay, also geht es um das Umschreiben der Url und nicht das Rendern einer Seite. Dazu benötigst Du aber keinen eigenen Controller, sondern den getPageIdFromUrl-Hook. In diesem nimmst Du Deine angepasste Url und wandelst sie in etwas um, dass Contao versteht. Wenn Du Deine Urls automatisch nach Deinem Schema von Contao erstelle lassen willst, kannst Du dafür den generateFrontendUrl-Hook verwenden. Mit diesen beiden habe ich schön öfter SEO-freundliche URLs erstellt.

Kommentar von Stefan Fischer |

vielen Dank für die Info

Antwort von Patrick Froch

Immer gerne!

Einen Kommentar schreiben

Bitte rechnen Sie 8 plus 6.