URL-Rewriting wie in Rails

Im Entwickler-Forum können Implementierungsdetails sowie Alternativen der Umsetzung diskutiert werden. // Here, developers can discuss implementation details of features of their projects.
fritz07
Beiträge: 5
Registriert: 22.04.2009, 17:29:53

URL-Rewriting wie in Rails

Beitrag von fritz07 » 31.01.2010, 07:28:44

Guten Morgen!

In letzter Zeit habe ich mich mit dem bekannten MVC-Framework Rails beschäftigt, nun möchte ich jedoch wieder ein wenig mit dem APF arbeiten. Ich plane nämlich, für das APF das URL-Rewriting von Rails zu implementieren, da ich das URL-Rewriting von APF einfach als "hässlich" empfinde und in Rails die Möglichkeit gegeben ist, das URL-Rewriting beliebig zu konfigurieren.

Ich werde jetzt das URL-Rewriting bzw. Routing von Rails erklären, damit klar wird, warum ich das so machen möchte, wie weiter unten dann erklärt wird.

In Rails hängen das URL-Rewriting und das Routing sehr stark miteinander zusammen, da Rails ein MVC-Framework ist und anhand der URL zu einer Action und zu einem Controller verwiesen werden muss. Bei jedem Aufruf versucht Rails, zum Pfad-Teil der URL einen Routing-Eintrag zu finden. Ein Routing-Eintrag wird in einer Konfigurationsdatei eingetragen. Der Routing-Eintrag wird anhand eines Pfades,welcher Platzhalter enthält, spezifiziert. Diese Platzhalter werden dann dem Controller als Parameter mitgeteilt. Ein Beispiel für einen Routing-Eintrag ist :controller/:action/:id. Dieser bedeutet, dass der Platzhalter :controller den Parameter "controller" enthält; dies gilt auch analog für :action und :id. Ein solcher Routing-Eintrag wäre im APF natürlich aufgrund der HMVC-Architektur nicht anzutreffen.

Aber in Rails gibt es auch die Möglichkeit, dass ein Platzhalter in einem Routing-Eintrag mit einem regulären Ausdruck verbunden werden kann. Das bedeutet geschlussfolgert, dass ein Routing-Eintrag nur angewendet wird, wenn ein Platzhalter auf den dazugehörigen regulären Ausdruck passt. Und nun kommt das letzte: Ein Routing-Eintrag kann weiterhin feste, also statische Parameter, besitzen, welche dem Controller zusätzlich mitgeteilt werden, wenn der Routing-Eintrag anhand des Pfades der URL angenommen wurde.

Hier ist die Standardkonfiguration für das Routing von Rails:

Code: Alles auswählen

ActionController::Routing::Routes.draw do |map|
  map.connect ':controller/:action/:id.:format'
  map.connect ':controller/:action/:id'
end
Wer mehr darüber erfahren möchte oder meinen Beitrag dazu nicht versteht, dem kann ich das hier empfehlen.

Nun zur Umsetzung im APF:

Im APF werden Konfigurationen als INI-Dateien abgelegt, während dies in Rails unterschiedlich ist. Ich schlage daher vor, für jede Regel einen Abschnitt anzulegen. Der Name des Abschnittes soll der Pfad mit den Platzhaltern sein. Weiterhin wird immer die als erstes zutreffende Regel angewandt. Dies soll wie folgt aussehen:

Code: Alles auswählen

[:param1/:param2/:param3.:param4]

[:param1/:param2/:param3]
Man kann beliebig viele Einstellungen erstellen. Wenn der Name der Einstellung einem Platzhalter im Pfad entspricht, so wird ein regulärer Ausdruck erwartet, wenn der Wert mit einem "/" beginnt. Sonstige Einstellungen werden einfach zu GET-Parametern. Dabei haben die Einstellungen Vorrang bezogen zu den Platzhaltern.

Beispiel

Eine APF-Applikation von uns erwartet folgenden Parameter: page oder id
Weiterhin werden folgende optionale Parameter akzeptiert: mark, subpage
Der optionale Parameter subpage kann nur verwendet werden, wenn page als Parameter verwendet wird.
Die Parameter page und subpage dürfen weiterhin nur alphanumerisch sein.
Der Parameter id darf nur numerisch sein.
Wenn jedoch keine Parameter angegeben werden, so ist page immer "home"

Die passende Konfiguration wäre dann:

Code: Alles auswählen

page="home"

[:id.:mark]
id="/^[0-9]+$/"

[:id]
id="/^[0-9]+$/"

[:page/:subpage.:mark]
page="/^[a-zA-Z0-9]+$/"
subpage="/^[a-zA-Z0-9]+$/"

[:page/:subpage]
page="/^[a-zA-Z0-9]+$/"
subpage="/^[a-zA-Z0-9]+$/"

[:page.:mark]
page="/^[a-zA-Z0-9]+$/"

[:page]
page="/^[a-zA-Z0-9]+$/"
Diese Regeln bedeuten einfach, dass beim Aufruf des Pfades
a) "1.suchbegriff" die Parameter id und mark die Werte 1 und "suchbegriff" haben,
b) "1" der Parameter id den Wert 1 hat,
c) "dokumentation/einleitung.suchbegriff" die Parameter page, subpage und mark die Werte "dokumentation", "einleitung" und "suchbegriff" haben,
d) "dokumentation/einleitung" die Parameter page und subpage die Werte "dokumentation" und "einleitung" haben,
e) "dokumentation.suchbegriff" die Parameter page und mark die Werte "dokumentation" und "suchbegriff" haben und
f) "dokumentation" der Parameter page den Wert "dokumentation" hat.

Und sollte kein Pfad angegeben werden, so hat der Parameter page den Wert "home"

Ich hoffe, dass ich das alles verständlich erklärt habe. Ich werde mich jetzt an die Entwicklung machen. Sollte es Neuigkeiten geben, so werde ich die hier bekanntgeben. Verbesserungsvorschläge wären schön.

Viele Grüße,
fritz07.

P.S.: Jetzt habe ich erstmal Kopfschmerzen. :|

Benutzeravatar
MrNiceGuy
Beiträge: 749
Registriert: 03.02.2009, 16:49:42
Wohnort: Nienburg / Weser

Re: URL-Rewriting wie in Rails

Beitrag von MrNiceGuy » 31.01.2010, 10:52:29

Eine derartige Umsetzung habe ich mir auch schon überlegt, allerdings noch nicht, wie ich diese realisieren sollte. Das APF bietet aber die Möglichkeit Input-Filter selber zu definieren, was den Vorteil hat, dass man bereits "dynamisch" ist, was die Parameter-Verarbeitung angeht. Einziges Manko hierbei: Man muss einen entsprechenden Input-Filter schreiben.

Deine Erweiterung kann also relativ leicht als Input-Filter bestehen. Ich glaube allerdings, dass die Verwendung von derart vielen RegEx' je Seitenaufruf die Performance enorm in die Knie' zwängt!?
There are only 10 Types of people in the world:
Those who understand binary and those who don't.

fritz07
Beiträge: 5
Registriert: 22.04.2009, 17:29:53

Re: URL-Rewriting wie in Rails

Beitrag von fritz07 » 31.01.2010, 12:04:42

MrNiceGuy hat geschrieben:Ich glaube allerdings, dass die Verwendung von derart vielen RegEx' je Seitenaufruf die Performance enorm in die Knie' zwängt!?
Ich glaube, dass man sich um RegEx weniger Sorgen machen muss. Trotzdem habe ich für jede Regel im oben genannten Beispiel die Dauer in Millisekunden für das Extrahieren der Parameter berechnet:
a) 0.155
b) 0.172
c) 0.295
d) 0.315
e) 0.369
f) 0.359

Und nun das ohne Pfad: 0.337

Scheint schnell genug für ein Routing zu sein, da es auch nach zweitasundmal Ausführen nicht länger als eineinhalb Sekunden dauert.

Benutzeravatar
MrNiceGuy
Beiträge: 749
Registriert: 03.02.2009, 16:49:42
Wohnort: Nienburg / Weser

Re: URL-Rewriting wie in Rails

Beitrag von MrNiceGuy » 31.01.2010, 13:03:40

Es ist auch nur eine Vermutung. Allerdings fände ich eine Abfrage von 1,5 Sekunden schon relativ langsam. Man muss ja auch bedenken, was passiert, wenn auf die Seite nicht nur 20-30 Leute pro Sekunde zugreifen sondern 2000-3000. Dann könnten RegEx durchaus mal zu einem Problem werden.

Das ist aber reine Spekulation und nich weiß nicht, wie man das messen kann. Auffällig ist halt, dass bei jedem Seitenaufruf eine Reihenfolge bestimmter RegEx nötig ist, um den Inhalt der Seite darzustellen. Möglicherweise gibt es eine einfachere Möglichkeit die Daten entsprechend zu filtern!?
There are only 10 Types of people in the world:
Those who understand binary and those who don't.

Benutzeravatar
dr.e.
Administrator
Beiträge: 4555
Registriert: 04.11.2007, 16:13:53

Re: URL-Rewriting wie in Rails

Beitrag von dr.e. » 31.01.2010, 13:26:10

Hallo ihr beiden,

ich bin grade auf dem Sprung, werde nachher ausführlich antworten.
Viele Grüße,
Christian

Benutzeravatar
dr.e.
Administrator
Beiträge: 4555
Registriert: 04.11.2007, 16:13:53

Re: URL-Rewriting wie in Rails

Beitrag von dr.e. » 31.01.2010, 22:18:45

Hallo fritz07,

nun hatte ich Zeit, deinen Baitrag im Detail zu lesen. Was mir Kopfzerbrechen macht ist, warum du das URL-Design von Rails so nachahmenswert findest. Es ist im Grunde gegenüber dem URL-Layout das im APF enthalten ist ein Rückschritt an Flexibilität. Sicher kannst du dann über die URL einen expliziten Controller mit seiner expliziten Action adressieren, nur in komplexeren Applikationen brauchst du oft mehrer solcher Adressierungen und kannst die Applikation nicht mit einem einzigen Controller/einer einzigen Action abhandeln. Du sprachst bereits an, dass Rails kein HMVC beherrscht. Das ist IMHO auch der Grund, warum Rails damit auskommt, bzw. umgekehrt das APF damit nicht auskommen darf, weil man sich sonst den Vorteil des APF hinsichtlich GUI-Gestaltung zunichte macht.

Ich denke ich sollte nochmal ein paar Worte zur Umsetzung des APF-URL-Layouts sagen: das APF beherrscht 4 unterschiedliche URL-Layouts. Ein "normales" URL-Layout mit Request-Parameter wie sie jeder kennt, eine umgeschriebene Form mit der Syntax

Code: Alles auswählen

/param1/value1/param2/value2
, eine Form, wie Front-Controller-Actions in einer "normalen" URL adressiert werden und eine in Rewrite-Form. All diese werden über einen Input-Filter so umgeschrieben, dass die Applikation selbst davon nichts mitbekommt. Sie greift wie bei PHP üblich auf das $_REQUEST-Array zu und bezieht von dort die gewünschten Werte. Ob die Applikation dann in einem Rewrite-Modus ausgeführt wird oder nicht, ist dabei dann völlig transparent. Mit dem generischen URL-Layout ist es Anwendern des APF möglich, beliebig viele Parameter und beliebig viele Action-Anweisungen in die URL zu "codieren". Das unterstützt den Ansatz, dass das APF für das Erstellen von generischen und über die URL entkoppelten Anwendungen geschaffen ist.

Sofern das Standard-URL-Layout nicht gefällt, hat der Entwickler über die Registry die Möglichkeit, eigene Input- und Output-Filter zu definieren. Diese können dann ein eigenes URL-Layout in das $_REQUEST-Array übersetzen um das Format gegenüber der Anwendung transparent zu halten.

Der Ansatz von Rails ist - verglichen mit dem APF - eine Mischung aus Front-Controller und einem MVC-View-Controller. Er wird direkt adressiert - wie beim APF eine Front-Controller-Action und in der Action wird auch gleich die Logik verpackt, wie die Ausgabe der Seite stattfindet. Da du beim Rendering der Seite also keine weiteren Struktur-Elemente mehr hast (das APF bietet hier den Page-Controller an, der eine HMVC-Struktur verwalten kann, mit dem eine beliebig komplexe Oberfläche gestaltet werden kann), bist du auf "Hacks" wie View-Helper, Layout-Rendering &Co. angewiesen. Das ist meiner Meinung nach nicht besonders generisch und führt oft dazu, dass man hier und dort eine Funktionalität reinfrickelt, die man sicher einfacher und wiederverwendbarer in einer Taglib oder einem eigenen Template mit Controller untergebracht und in den DOM-Baum eingehangen hätte.

Summa summarum verstehe ich deine Motivation also nicht ganz, denn ich finde, dass du dich damit einen Schritt von der Flexibilität des APF zurückbewegst. Es wäre daher schön, die Motivation ein bischen näher zu verstehen, dann kann ich vielleicht eine "einfachere" oder "flexiblere" Lösung vorschlagen.

Was deinen Ansatz angeht, müsste man nun noch festlegen, ob du mit dieser URL-Logik Front-Controller-Actions oder explizite Page-Controller adressieren möchtest. Hinsichtlich eines sauberen Software-Designs wäre es nur konsequent Front-Controller-Actions zu adressieren, die dann eine Business-Logik ausführen, vielleicht ein Model und/oder ein Domänen-Objekt/Domänen-Objekte zu füllen und dann eine GUI zu erzeugen, die sich dieser Informationen bedient. Das ist jedoch aus Sicht des Software-Designs nichts anderes als eine Front-Controller-basierte Lösung einer Applikation mit einem anderen URL-Layout.

Technisch kannst du dir den FrontControllerInputFilter, bzw. genauer den FrontcontrollerRewriteRequestFilter als Vorlage nehmen und das gewünschte Layout mit einer Routing-Konfiguration auf Front-Controller-Actions mappen. Wichtig hierbei ist, dass du die Methode addAction() des Frontcontroller nutzt um die gewünschten Actions zum Stack hinzuzufügen. Strend genommen könntest du im Input-Filter auch deinen eigenen Frontcontroller implementieren, das halte ich aber für nicht besonders clever, da du sonst das Rendering der GUI - das der APF-Frontcontroller auch für dich erledigt - auch selbst implementieren müsstest.
Viele Grüße,
Christian

Benutzeravatar
MrNiceGuy
Beiträge: 749
Registriert: 03.02.2009, 16:49:42
Wohnort: Nienburg / Weser

Re: URL-Rewriting wie in Rails

Beitrag von MrNiceGuy » 02.02.2010, 18:34:17

Ich kann ihn schon ein wenig verstehen, was das URL-Layout angeht. Ich selber bin auch schon am überlegen, wie man das anders handeln könnte, allerdings wollte ich nicht unbedingt auf statische Formatierungen der URL zurückgreifen. Was glaube ich das "Hauptproblem" darstellt sind die enorm langen Links, die teilweise entstehen, wenn man das APF benutzt. Ich selber bin ja eigentlich ein Freund von langen Variablennamen, sofern der Variablenname einigermaßen wiedergibt, welchen Inhalt er hat. Ebenso halte ich es mit Funktionsnamen, was bei Frontcontroller-Actions schonmal sehr nachteilig wird.
Daher war meine Überlegung, ob man auf irgendeine fuchsige Weise die Parameter-Namen weglassen kann. Hierbei wäre es dann nötig, eine Komponente zu haben, die der URL-Struktur entnimmt, welche Inhalte was sein sollen, die Parameter numerisch in der Reihenfolge adressiert oder jeder Komponente, die aufgerufen wird eine gewisse Struktur mitzugeben. Ich denke, dass es genau das war, was er damit erreichen möchte, eine entsprechende Extension zu entwickeln.

Meine Idee ging dann allerdings eher in die Richtung, dass ich die Parameter weglasse und innerhalb meines CMS, das ich bauen möchte z.B. fix den ersten Parameter als aufzurufende Seite zu deuten und alle folgenden Parameter entsprechend dem der Seite zugewiesenen Modul die Parameter verfügbar zu machen. Hierbei würde sich die Konfiguration auf das URL-Layout "lediglich" nach dem verwendeten Modul richten und nicht auf die komplette Seite. Allerdings bin ich noch nicht sicher, ob ich das auch wirklich so machen möchte...
There are only 10 Types of people in the world:
Those who understand binary and those who don't.

Benutzeravatar
dr.e.
Administrator
Beiträge: 4555
Registriert: 04.11.2007, 16:13:53

Re: URL-Rewriting wie in Rails

Beitrag von dr.e. » 02.02.2010, 19:07:59

Hallo Lutz,

den Ansatz verstehe ich - keine Frage. Das Problem - bzw. anders formuliert - die Herausforderung bei um Parameter gekürzte URLs ist immer das Mapping. Man muss sich quasi per Konvention darauf verlassen, dass die Parameter immer in der gewünschten Reihenfolge angeordnet werden. Weiter ist es schwieriger, mehrere Applikationen zu adressieren und man muss quasi für jedes Modul eine dynamische Link-Generierung schreiben. Möglich ist, eine Komponente zu schreiben, die LinkFormatter pro Model einer Anwendung entgegen nimmt und daraus einen Link generiert, nur dann ist die Abbildung von Model zu URL quasi 1:1 und man entfernt sich von sauberem (H)MVC.

Umsetzungstechnisch kann man sicher andenken, pro "Modul" jeweils ein Model zu erzeugen und dort die Parameter zu injizieren. Das lässt sich sicher auch mit verhältnismäßig wenig Aufwand generisch lösen. Mein erster Ansatz dazu ist die "Module" per "/~/" zu trennen und innerhalb eines Moduls den Namespace und den Namen der Action zu kodieren, sowie die Parameter zu verpacken. Per ReqExp entscheidet sich dann, welcher setter des Models (das auch in der Action definiert sein muss) mit welchem Wert der URL befüllt wird. Schwieriger gestaltet sich dann aber die Zuordnung von Parametern gleichen Typs.

Aber wir warten mal auf fritz07's Antwort - ich bin gespannt! :)
Viele Grüße,
Christian

fritz07
Beiträge: 5
Registriert: 22.04.2009, 17:29:53

Re: URL-Rewriting wie in Rails

Beitrag von fritz07 » 11.02.2010, 09:05:07

Ich habe derzeit wenig Zeit zum Antworten. Daher kann eine Antwort noch etwas länger dauern ...

Benutzeravatar
dr.e.
Administrator
Beiträge: 4555
Registriert: 04.11.2007, 16:13:53

Re: URL-Rewriting wie in Rails

Beitrag von dr.e. » 10.04.2010, 13:32:57

Hallo fritz07,

gibt es schon Ergebnisse oder kann ich dir irgendwie helfen?
Viele Grüße,
Christian

Benutzeravatar
MrNiceGuy
Beiträge: 749
Registriert: 03.02.2009, 16:49:42
Wohnort: Nienburg / Weser

Re: URL-Rewriting wie in Rails

Beitrag von MrNiceGuy » 17.05.2010, 18:17:24

Christian, ich verstehe deine Einwände. Ich weiß selber, dass das nicht die sauberste Lösung ist - chicer finde ich es dennoch ;) Aber das ist geschmackssache.

Jedenfalls habe ich mir ja auch schon vor diesem Thread mal ein paar Gedanken gemacht, wie man das realisieren könnte und bin dabei den Weg über nummerische Attribute gegangen. Sprich: Statt namensbezogene Attribute verwende ich einfach die numerischen Bezeichner. Das ändert zwar nichts daran, dass ich intern immernoch irgendwie wissen muss, welcher Parameter unter welcher "Nummer" verfügbar ist, jedoch kann ich auf diese Weise relativ einfach die URL in Parameter wandeln. Was dann das Tool nachher aus dem numerischen Array macht ist dann eine vollkommen andere Sache.

Nachteil hierbei ist halt ganz klar, dass es für mich als Programmierer nicht mehr so schön nachvollziehbar ist, wie es vorher mit Attribut-Namen war.

Ich weiß selber noch nicht so genau, wie ich das umsetzen werden - bzw. ob überhaupt, aber ich lasse mir noch etwas einfallen :)
There are only 10 Types of people in the world:
Those who understand binary and those who don't.

Benutzeravatar
dr.e.
Administrator
Beiträge: 4555
Registriert: 04.11.2007, 16:13:53

Re: URL-Rewriting wie in Rails

Beitrag von dr.e. » 18.05.2010, 22:55:24

Hallo Lutz,

ich verstehe ja den Ansatz und will ihn auch garnicht wegdiskutieren. Ich wollte lediglich die Nachteile desselben aufzeigen. Die Umsetzung ist IMHO recht trivial, du mappst einfach die Werte in einem eigenen InputFilter auf die relevanten Parameter und stellst diese der Applikation zur Verfügung. Idealerweise sollte das mit einer Konfiguration verbunden sein, welcher Wert auf welchen Parameter gemappt werden sollte, dann kann man bisherige Applikationen auch nachher noch betreiben, da das Parameter-Mapping schon vor der Ausführung der Anwendung stattfindet.

Die Parametrisierung kann dann an Hand eines dedizierten Action-Kenners erfolgen, der auch gleichzeitig dazu dient, das Parameter-Mapping zu spezifizieren. Nehmen wir an, du hast eine URL wie

Code: Alles auswählen

/doku/einleitung/kinderhort
, dann kannst du in einer Konfiguration mit dem Abschnitt doku die auszuführende Action und das Parmeter-Mapping definieren:

Code: Alles auswählen

[doku]
1 = "view"
2 = "tag"
...
action = "EntryAction"
namespace = "..."
Der Input-Filter kann dann an Hand des ersten Pfad-Abschnittes - oder auch ab dem Keyword /doku die Werte der Parameter auslesen, diese im $_REQUEST bereitstellen und die benannte Action im Front-Controller registrieren. Das ist Implementierungs-technisch nicht besonders aufwendig, erfüllt aber IMHO schon die o.g. Anforderungen.
Viele Grüße,
Christian

Benutzeravatar
MrNiceGuy
Beiträge: 749
Registriert: 03.02.2009, 16:49:42
Wohnort: Nienburg / Weser

Re: URL-Rewriting wie in Rails

Beitrag von MrNiceGuy » 20.05.2010, 11:02:23

Das ist mir auch klar und so ähnlich habe ich es mir auch gedacht, nur geht dabei wiederum die Dynamik vor die Hunde - und genau das ist es ja, was eigentlich gefordert war. Nunja, ich bin wie gesagt auch noch nicht ganz durch mit meinen Überlegungen, aber wenn ich eine praktikable Lösung habe, die neben der Funktion auch noch dynamisch anwendbar ist, dann gebe ich nochmal laut. Aktuell bin ich jedoch noch etwas mit anderen Projekten gebunden :(
Zuletzt geändert von MrNiceGuy am 20.05.2010, 12:00:33, insgesamt 1-mal geändert.
There are only 10 Types of people in the world:
Those who understand binary and those who don't.

Megger
Beiträge: 1233
Registriert: 04.11.2008, 10:57:37

Re: URL-Rewriting wie in Rails

Beitrag von Megger » 20.05.2010, 11:51:57

...die dynamit vor die Hunde
Die armen Hunde




Tschuldigung das musste sein :D
Tutorial: Browsergame mit dem APF (Die ersten Parts handeln von Installation und Inbetriebnahme des APFs, deswegen sicherlich auch für alle Nicht-Browsergame-Programmierer interessant)

APF-Version
  • Entwicklung: 2.0
  • Produktiv: 1.15

Benutzeravatar
MrNiceGuy
Beiträge: 749
Registriert: 03.02.2009, 16:49:42
Wohnort: Nienburg / Weser

Re: URL-Rewriting wie in Rails

Beitrag von MrNiceGuy » 20.05.2010, 12:00:57

*hust* Ähm, habe ich doch garnicht geschrieben :oops:
There are only 10 Types of people in the world:
Those who understand binary and those who don't.

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste