Symfony 3 – Hinzufügen dynamischer Routen

Heute habe ich mich mit dem Thema dynamische Routen (zum Beispiel aus einer Datenbank) in Symfony 3 beschäftigt. Dabei ist mir aufgefallen, dass derzeit verfügbare Bundles noch nicht mit Symfony 3.0 kompatibel sind – ich musste also selbst ran.


Symfony bietet bereits sehr angenehme Möglichkeiten die eigenen URLs mit Routen zu verwalten – zum Beispiel mit Annotations. Wir wollen hier das Rad nicht neu erfinden, sondern lediglich ein paar dynamische Routen aus der Datenbank hinzufügen.

Für dieses Ziel müssen wir keinen neuen Router implementieren, sondern nur die vorhanden Lademechanismen für Routen erweitern.

Struktur der Routen

Die Struktur der Routen ist denkbar einfach und spiegelt das wider was ein Basis-CMS benötigt:

  • URL (z. B. /symfony-3-hinzufuegen-dynamischer-routen)
  • Definition von Titel und Inhalt der Zielseite

DynamicRouteLoader – Wie wir die Routen aus der Datenbank laden

Alles was wir benötigen ist ein Loader, der unsere Routen beim Erstellen des Routen-Caches aus der Datenbank holt.

Der Loader

Entscheidend ist, das wir LoaderInterface implementieren – andernfalls würde Symfony den Loader nicht erkennen. Als Typ definieren wir passenderweise dynamic.

Innerhalb der foreach erstellen wir für jeden Eintrag in der Datenbank eine Route. Der erste Parameter für Route() ist die URL. Im zweiten (defaults) definieren wir Controller und Action mit dem Platzhalter _controller. In meinem Fall wird immer die selbe Kombination verwendet. Es steht euch natürlich frei, hier ebenfalls dynamische Werte einzusetzen.

Mit templateId fügen wir noch eine Verbindung zum Template ein. Nennen wir später im Controller einen Parameter $templateId, wird er entsprechend gefüllt. Hier könnt ihr beliebig viele weitere Parameter festlegen.

Konfiguration als Service

Obiger Loader muss nun als Service in der entsprechenden Konfigurationsdatei hinterlegt werden. Den Namen könnt ihr frei wählen. Genauso ist es unerheblich ob ihr ihn im user space haben wollt oder nicht (public true/false).

Wichtig ist der Tag routing.loader. Damit sagt ihr Symfony, dass es diesen Service beim Laden der Routen berücksichtigen soll. Er wird zwar immer noch nicht tatsächlich verwendet, aber immerhin ist er jetzt in der Liste.

Als Parameter für den Konstruktor (arguments) benötigen wir noch den Datenbankzugang in Form des Entity Managers.

Aufruf des Loaders

Die Konfiguration für’s Routing ergänzen wir um obigen Eintrag.

Für resource definieren wir nur einen Platzhalter. Wir benötigen diesen Parameter nicht, er ist aber eine Pflichtangabe.

Als Typ verwenden wir den vom Loader in der supports() Methode definierten Typ dynamic.

Entität zur Definition der dynamischen Routen

Der Vollständigkeit halber noch das Model (mit Doctrine) zur Definition der Routen.

Weiterverarbeitung im Controller

Alles bisher passiert beim Warm-Up der Seite (bzw. Cache). Wir haben lediglich einen Loader, keinen echten Router eingebunden.

Die zur Laufzeit notwendige weitere Verarbeitung übernimmt der zugehörige Controller. Dieser ist bis auf den zusätzlichen Parameter aber unspektakulär.


tl;dr

  • Loader erstellen der \Symfony\Component\Config\Loader\LoaderInterface implementiert
  • Loader als Service mit tag routing.loader definieren
  • Notwendige Infos automatisch an Controller/Action übergeben lassen