Clansuite Community Forum


 
Willkommen Gast. Bitte einloggen oder registrieren.
Haben Sie Ihre Aktivierungs E-Mail übersehen?

Einloggen mit Benutzername, Passwort und Sitzungslänge
 
Seiten: [1]   Nach unten
  Drucken  
Autor Thema: Route rewrite  (Gelesen 1198 mal)
0 Mitglieder und 1 Gast betrachten dieses Thema.
paulbr
Developer
*****
Offline Offline

Beiträge: 126


« am: Juni 21, 2011, 05:47:17 »

Hallo Jens,

ich habe das rewrite mal aktiviert und entsprchend änderungen gemacht damit dies
auch ausgeführt wird.

Also irgendwie steig ich bei dem rewrite im routing nicht durch!

Hier werden immer Äpfel mit Birnen abgeprüft, zumindest empfinde ich es so Smiley

Beispiel:  /pages/site/1
Sollte öffnen:  mod=pages&action=site&id=1

In public function mapMatchURI():

Clansuite_Debug::printR($route_values);
ergibt:
Array
(
    [regexp] => /^\/:controller\/?\/:action\/?\/:id\/?$/
    [number_of_segments] => 3
)

Clansuite_Debug::printR($this->uri);  ergibt:  pages/site/1

if (true === preg_match('/^:([a-zA-Z_]+)$/', $this->uri, $matches))
bzw:
elseif(true === preg_match( $route_values['regexp'], $this->uri, $matches))

hier wird in der uri nach ':controller' verglichen, d.h. das result ist immer false.

Clansuite_Debug::printR( $this->routes );
ergibt:
Array
(
    [:controller/:action/:id] => Array
        (
            [regexp] => /^\/:controller\/?\/:action\/?\/:id\/?$/
            [number_of_segments] => 3
        )
    [:controller/:subcontroller/:action] => Array
        (
            [regexp] => /^\/:controller\/?\/:subcontroller\/?\/:action\/?$/
            [number_of_segments] => 3
        )
)


abgeprüft wird hier nach:
if(isset($this->routes[$this->uri]))
also immer false, weil der key $this->uri nicht existiert.

Kannst du mir da mal auf die Sprünge helfen, wie das angedacht ist?


gruss
paul
Gespeichert
Jens-A. Koch
Maintainer
*
Offline Offline

Beiträge: 574

One-Man Team


« Antworten #1 am: Juni 21, 2011, 11:52:40 »

Hallo Paul,

Danke für die Ergänzungen. Eine schöne Übersicht über unsere Konstanten.
Das sieht dann doch sehr geordnet aus und ist ganz hilfreich Smiley

Abschließender Slash bei "WWW_"-Konstanten
Nachdem ich das so übersichtlcih gesehen hab, werd ich wohl an einer Stelle zurückrudern.
Wir benutzen im Viewbereich ja die "WWW_"-Konstanten und hatten uns mal drauf verständigt, alle Pfadkonstanten mit Slash abzuschließen.
Allerdings finde ich die Verwendung im View ohne nachfolgenden Slash irgendwie unschön.
Das ist sicher Geschmackssache und auch nur eine Kleinigkeit, aber es fällt mir jedesmal auf, wenn ich dort Pfade definiere. Also nur mal als Änderungsvorschlag:
Ich würde den Slash bei den WWW_ Konstanten wieder entfernen.
Code:
Aus:
{$www_root_themes_core}images/image.png
wird dann:
{$www_root_themes_core}/images/image.png

Routing

So.. nun zum Routing.

Defintiv Baustelle!
Ich hoffe ich hab mich weit genug vom Router entfernt, um daran wieder was zu machen.
Die Sache mit den zusammengesetzten Regular Expressions war zwischenzeitlich relativ nervig.
Groß testen kann ich es im Moment nicht, da ich auf einer Nginx Umgebung bin.
Aber eigentlich müsste es auch ein mod_rewrite ähnliches Plugin für Nginx geben...

Es gibt drei Dinge die für den Router angedacht sind.
1. feste 1:1 Routen (/index/about)
2. statische Routen (:controller/:subcontroller/:action)
3. dynamische Routen.
In dieser Reihenfolge arbeitet mapMatchURI() auch die Matching-Versuche ab.

Da werden nicht Äpfel mit Birnen verglichen ,)
Die Vergleiche sind "eigentlich" ok, soweit ich das sehe.
Was dort fehlt ist die Verwendung vom TargetRoute Objekt für Punkte 1 und 2.

Nun zur Methode mapMatchURI():

Zu 1. (feste Routen):
Zitat
/**
         * Do we have a direct match ?
         * URI = '/index/show' => Routes['/index/show']
         */
        if(isset($this->routes[$this->uri])) # does this check work?
        {
            $found_route = '';
            $found_route = $this->routes[$this->uri];
        }

Das ist der Versuch die URI direkt in den Routen zu finden (also ein 1:1 Mapping).
Dafür müsste $this->routes fest angegebene Routen beinhalten.
Zur Zeit sind keine definiert, daher ist das immer false und man landet in der URI-Segment Prüfung.

Selbst wenn 1:1 Routen definiert sind, läuft es derzeit leider leer, da $found_route gar nicht mehr genutzt wird. Ganz am Ende ist das ja auskommentiert.

Hier müsste die gefundene 1:1 Route in das Clansuite_TargetRoute Objekt überführt werden.
Dazu könnte man $found_route exploden und mit fester Reihenfolge (setController, setAction, setId) auf Clansuite_TargetRoute abbilden. Oder eine Definition (controller/action/id) mit in die Routing-Regel aufnehmen, um zu wissen, wie auf Target_Route abgebildet wird.

Für feste Routen entfällt auch die Clansuite_TargetRoute::dispatchable() Prüfung, also der Test, ob die gefundene Route auch ausführbar ist. Für feste Verdrahtungen unterstelle ich mal Stimmigkeit.

Zu 2. Routen mit statisch benannten Parametern
Hier beginnen die Routing-Parameter immer mit Doppelpunkt.
Die Doppelpunkt-Namen sind bekannte Platzhalter die mit Regular Expressions ersetzt werden.
Daher auch der preg_match:
if (true === preg_match('/^:([a-zA-Z_]+)$/', $this->uri, $matches))

Etwa [:controller/:action/:id] oder [:controller/:action/:year/:month].
Letztere Regel könnte man für ein mapping auf /calendar/show/2011/06 nehmen.
Dafür könnte man aber auch [calendar/show/:year/:month] schreiben... usw.

Hier fehlt ebenfalls die Abbildung auf TargetRoute mittels
entsprechender Abbildungsregel, bspw.
"&mod=calendar&action=show&date=(:year)-(:month)"

Zu 3. dynamische Routen
Im Unterschied zu den statisch benannten Routen, werden hier die Regular Expressions in der Route mitgeführt, die dann später für ein Matching verwendet werden.
Bei statischen Routen gibts ja nur einige wenige Platzhalter (:id) die mit Regular Expressions ersetzt werden ([0-9]+) - hierfür ist die Methode placeholdersToRegexp() wichtig.

Code:
elseif(true === preg_match( $route_values['regexp'], $this->uri, $matches))
Ergebnisse in $matches ,)

Evtl. noch hilfreich zu wissen ist, wenn "?P<ParameterName>" in dem RegExp auftaucht, dann bedeutet das, dass der preg_match Treffer im Array $matches[ParameterName] abgelegt wird.
Normalerweise hat man es ja mit $matches[1] etc. zu tun - hier mit einem benannten (Teil-)Suchmuster.

Insgesamt könnte man die benannten Parameter des Matches-Array nehmen um dynamische Methodenaufrufe auf TargetRoute abzubilden: Clansuite_TargetRoute::set{namedParameter}($matches[namedParameter]).

Insgesamt gibts da noch viel Arbeit... Tests, Beispiele, Routendefinitionen, Routenverwaltung, Routencaching, Routendebugging, usw.

Soviel erstmal,

Gruß Jens
Gespeichert

Keine Supportanfragen per PN oder Mail. Fragen bitte nur im Forum stellen (Wie man Fragen richtig stellt).
Jens-A. Koch
Maintainer
*
Offline Offline

Beiträge: 574

One-Man Team


« Antworten #2 am: Juni 22, 2011, 12:20:48 »

Kurz noch zur Methode isRewriteEngineOn().
Ursprunglich war das gedacht, um automatisch zu testen, ob htaccess "mod_rewrite on" enthält.
Später war mir das ständige Nachschauen in htaccess zuviel an Overhead.
Daher auch das sofortige "return true;", wenn $this->config['routing']['mod_rewrite'] ist.

Letztlich müsste in dieser Funktion nur "REWRITE_ENGINE_ON" und "return" entsprechend der Config erfolgen.
Der htaccess-Test kann dort raus, sollte aber im Router bleiben. Funktional gehört er schon da hin.

Von der Verwendung her wandert das allerdings in Richtung Konfigurationshilfe und damit in den Settingsdialog. Dort wird er dann nur einmal aufgerufen, um dem Nutzer entsprechenden Konfigurationshinweis zu geben. Bzw.kann man ein Schreiben der .htaccess andenken.
Damit sind wir dann den Overhead los.

Ohne den Check bleibt ein Fall übrig: Config rewrite 1, htaccess zwischenzeitlich off.
Diejenigen werden dann im Forum fragen kommen, wie man wieder ins System kommt... cfg mod_rewrite 0.
Evtl. wäre hier für den Notfall ein Config-Reset-Werkzeug für die Standardwerte denkbar...mod_rewrite 0, staging 0 etc. Da können wir gleich den Wartungstoken nochmal verwenden... nur ne Idee.

Gespeichert

Keine Supportanfragen per PN oder Mail. Fragen bitte nur im Forum stellen (Wie man Fragen richtig stellt).
paulbr
Developer
*****
Offline Offline

Beiträge: 126


« Antworten #3 am: Juni 22, 2011, 02:44:12 »

Hallo Jens,

danke für die Ausführliche Erklärung.

Zitat
Da werden nicht Äpfel mit Birnen verglichen ,)
Ja nach deiner Erklärung sehe ich das nun auch.
Für mich machte es irgendwie keinen Sinn das mittels preg_match ':controller' mit 'index/show'
abgeprüft wird Smiley

---

Die Masse wird wohl das feste 1:1 Routen sein.

Wenn irgendwann mal das Redaktionsmodul fertig ist (Block/Artikel) und die
Static Pages, dann werden diese irgendwo in menüs gelistet.
Überwiegend wird das immer 'mod/action/id' sein.

Zitat
Es gibt drei Dinge die für den Router angedacht sind.
1. feste 1:1 Routen (/index/about)
2. statische Routen (:controller/:subcontroller/:action)
3. dynamische Routen.
In dieser Reihenfolge arbeitet mapMatchURI() auch die Matching-Versuche ab.
Ich denke man könnte vorerst auf Punkt 1 anpassen.

1. feste nach art von:
    /index/about
    /news/showone/1
    /pages/site/23
    ...

Das ist überwiegend der fall und alle menüs und links auf der Clansuite verwenden ja
überwiegend diese form:
mod=...&action=...            (mod/action)
mod=...&action=...&id=...   (mod/action/id)

Zitat
Dazu könnte man $found_route exploden und mit fester Reihenfolge (setController, setAction, setId) auf Clansuite_TargetRoute abbilden. Oder eine Definition (controller/action/id) mit in die Routing-Regel aufnehmen, um zu wissen, wie auf Target_Route abgebildet wird.
ja das denke ich macht Sinn, nur was ist mit submodulen?

Gut man könnte hier auf den namen des 2. segmentes abprüfen:
   controller/action
   controller/action/id
   controller/subcontroller/action
   controller/subcontroller/action/id

Der subcontroller wird überwiegend 'admin' sein.
Hier kann man auch ein array mit namen der verwendeten subcontroller erstellen und
abprüfen ob der name des 2. segments in diesem array vorhanden ist.
So wäre dies auch jederzeit erweiterbar ohne die prüfungen abändern zu müssen.

Auch sollte man die Reihenfolge der Prüfung umdrehen, wenn Punkt 2 + 3 false sind, dann
kanns nur Punkt 1 sein.

Wenn wir mit den Punkt 1 anfangen, können alle bisher vorhandenen Links in der Clansuite
bereits mittels mod_rewrite verlinkt werden.

Gibt es den eigentlich links im aktuellen Stand der Clansuite, welche das statische oder dynamische routen benötigen?

gruss
paul

-----
EDIT:

Zitat
Für feste Routen entfällt auch die Clansuite_TargetRoute::dispatchable() Prüfung, also der Test, ob die gefundene Route auch ausführbar ist. Für feste Verdrahtungen unterstelle ich mal Stimmigkeit.
Nein habe ich ausprobiert.
In Clansuite_TargetRoute::dispatchable() wird unter anderem der filename gesetzt und includiert.
Der Frontcontroller findet die Class ansonsten nicht.

Gespeichert
Jens-A. Koch
Maintainer
*
Offline Offline

Beiträge: 574

One-Man Team


« Antworten #4 am: Juni 22, 2011, 08:49:53 »

Hallo Paul,

hier noch einige Ergänzungen:

Zitat
Die Masse wird wohl das feste 1:1 Routen sein.
Hmm..nein. Dann müssten wir ja alle Routen fest definieren (1.).
Das wäre einie riesige Liste mit Links...
Ich denke mal es wird darauf hinauslaufen, dass einige haufig genutzte Routen fest definiert sind,
rtwa "/login" und "/logout".

Die Masse der Anfragen wird über statische Routen (2.) abgewickelt.
:controller/:subcontroller/:action/:id
:controller/:action/:id
Wir du schon geschrieben hast, diese Muster sind definitiv sehr häufig.
Sie sind bereits in der Methode loadDefaultRoutes() als Standardrouten definiert.

Zitat
        /**
         * Connect some default fallback Routes
         *
         * With ArrayAccess: $r['/:controller'];
         */
        if(true === empty($this->routes))
        {
            $this->addRoute('/:controller');
            $this->addRoute('/:controller/:action');
            $this->addRoute('/:controller/:action/:id');
            $this->addRoute('/:controller/:action/:id/:format');

            $this->addRoute('/:controller/:subcontroller');
            $this->addRoute('/:controller/:subcontroller/:action');
            $this->addRoute('/:controller/:subcontroller/:action/:id');
            $this->addRoute('/:controller/:subcontroller/:action/:id/:format');
        }

Ein Verzeichnis mit festen Routen 1:1 zu pflegen macht hingegen richtig viel Arbeit.
Das sind grob geschätzt pro Modul bestimmt 10 Links.
Und das ist die zweitbeste Lösung, was die Performance angeht.
Beste Lösung ist gar kein rewriting zu verwenden!

(Hier liegt ein Vergleich zum Autoloader nahe....
schnellste Lösung: an Ort und Stelle einbinden
zweitbeste: manuelle ClassMap
dritte: dynamische Maperstellung)

Zur "internen" Linkverwendung
Code:
Gibt es den eigentlich links im aktuellen Stand der Clansuite, welche das statische oder dynamische routen benötigen?
Unsere Links sind hauptsächlich mit Get-Variablen hardcoded geschrieben (&mod &action &id).
In einigen Templates wird bereits {link_to} verwendet.
Auf link_to kann man jetzt schon zurückgreifen, wenn man Links hat die den Default-Regeln entsprechen. Alle Links mit abweichenden Get-Parametern fallen dann erstmal raus, bsp: "&file=" oder "&tpl=", weils noch keine Regeln dafür gibt.

Wenn mod_rewrite an ist, dann müssen die Links mit Slashes geschrieben werden.
Beispiel: /news/show/1
Wenn mod_rewrite aus ist, dann müssen die Get-Variablen mit in den Link.
Beispiel: &mod=news&action=show&id=1
Der {link_to} Smarty-Viewhelper nutzt intern Clansuite_Router::buildURL() und macht das dann automatisch.

Clansuite_Router::buildURL() ist, wie der Name schon sagt, die Methode zum Generieren der URLs bzw. Links, je nachdem ob mod_rewrite an oder aus ist.
Verwendungsbeispiel: {link_to href="/news/show"}
Die interne Schreibweise entspricht damit der mod_rewrite Schreibweise.

Normal:
{link_to href="/account/login"}
Rewrite aus: "&mod=account&action=login"
Rewrite an: "/account/login"

Naja, und dann gibts noch Spezialfälle, etwa abgekürzte Routen:
"/login"
{link_to href="/login"}

---

Code:
Auch sollte man die Reihenfolge der Prüfung umdrehen, wenn Punkt 2 + 3 false sind, dann
kanns nur Punkt 1 sein.
Hmm.. wenn genügend Routen definiert wurden, können wir das ja mal umstellen und die Zeiten vergleichen. Evtl. macht 2-1-3 Sinn, also statisch regexp, fest, dyn regexp.
Ist relativ schwierig das abzuschätzen, evtl. gibts ne Link-Verteilung von 30-300-30 auf 1-2-3.
Dann würde es Sinn machen 2 vorzuziehen. Kann ich ohne Benchmarks nicht beurteilen.

Subcontrollererkennung [subcontroller oder action]
Code:
Hier kann man auch ein array mit namen der verwendeten subcontroller erstellen und
abprüfen ob der name des 2. segments in diesem array vorhanden ist.
So wäre dies auch jederzeit erweiterbar ohne die prüfungen abändern zu müssen.
Ja, wird so eingebaut.

Gruß Jens
Gespeichert

Keine Supportanfragen per PN oder Mail. Fragen bitte nur im Forum stellen (Wie man Fragen richtig stellt).
paulbr
Developer
*****
Offline Offline

Beiträge: 126


« Antworten #5 am: Juli 19, 2011, 01:41:00 »

Hallo jens,

hab grad mal etwas Zeit und nochmal über dem Routing mit mod-rewrite nachgedacht.
Ich versuche mal nicht zu kompliziert zu denken und das ganze etwas einfacher zu sehen Smiley

Im Prinzip kann man ja vieles durch "feste definitionen" automatisieren.

Die URI schaut ja im Prinzip so aus:

   / controller [ / [supcontroller | action] [ / [action | id] ] [ / [id | params] ] [ / params ] ]

Ansatz:
Man könnte alle vorhandenen, oder besser nur die aktiven Module auslesen und damit
ein default_auto_route array erstellen. (z.B. aus Datenbank: modules)
Worin die default: action_show und die default: action_admin_show enthalten wären.

default_auto_routes[$segment[1]] => mod=$segment[1]&action=show
default_auto_routes[$segment[1]][$segment[2]] => mod=$segment[1]&sub=$segment[2]&action=admin_show'

bei:
/about              würde dann automatisch: mod=about&action=show
/about/admin     würde dann automatisch: mod=about&sub=admin&action=admin_show
/news               würde dann automatisch: mod=news&action=show
/news/admin      würde dann automatisch: mod=news&sub=admin&action=admin_show

im prinzip für alle Module standard: action=show und action=admin_show

Wenn also nur 1 segment angegeben wurde braucht man nur in die map schauen.
Wenn 2 segmente angegeben werden und das 2. segment in dem subcontroller named array vorhanden ist
braucht man ebenfalls nur in der map nachschlagen.
subNamedArray = { admin, ... }

Das subNamedArray ist jederzeit erweiterbar und wird somit automatisch bei der subcontroller prüfung mit einbezogen.
Könnte man auch Administrativ editierbar machen, wenn es nötig sein sollte.

Man kann nun auch noch Quicklinks definieren z.B.
   /login
   /lastnews

   quick_auto_routes["login"] => mod=account&action=login
   quick_auto_routes["lastnews"] => mod=news&action=lastnews

und diese in die default_auto_routes inkludieren, hier darf der quicklinkname allerdings nicht mit einem modulename kollidieren.
Im Falle der Quicklinks wäre der quicklinkname an der controller position und somit der Index in der Map.

Das kann alles automatisiert werden und bedarf keinerlei Pflege.

Wenn ein Modul disabled ist, gibt es 2 Möglichkeiten:
1. es existiert nicht in der Map und es wird eine Fehlerseite aufgerufen
2. es existiert in der Map, wird aufgerufen und dann erscheint eine Fehlerseite
    (setzt voraus, das in dem Modul geprüft wird ob es aktiviert ist)

Ich tendiere zu lösung 1 denn dann könnte man:
 - diese Map für die erstellung einer Google Sitemap heranziehen (nur gültige links)
 - alle dynamischen links brauchen nicht umgewandelt oder ausgeführt werden,
   wenn der controller nicht in der Map existiert.

Anmerkung:
Auch die Actions sind eigentlich schon definiert und bekannt.
Für das ACL sollen ja in der modulename.config.php alle actions für das Modul erfasst werden.

Man könnte also hier im Prinzip:
   /controller/action
   /controller/subcontroller/action
automatisch erfassen und in die Map ablegen

Dynamisch bliebe also nur das was danach kommt: id | params ..etc.

Ein Gedanke für die dynamischen Angaben:
 - Wenn es eine ID ist: z.b. <id>.html
 - Wenn es ein parameter array ist, diese Parameter Base64 verschlüsseln und als: <Base64 code>.phtml
benennen
Man ersieht dann aus der Kennung ob es sich um eine ID oder ein Param-Array handelt.
Für die Kennung kann man sich ja festlegen was was bedeuten soll.

Simple Beispiel:
bei Zeige news #1
/news/showone/1.html        würde dann automatisch: mod=news&action=showone&id=1

oder bei Zeige alle news von <datum> bis <datum> (z.B. aus einem Formular für die Eingrenzung der Anzeige von News)
param{vonDate => 01.07.2011, bisDate => 07.07.2011}

Base64 encode string
/news/showrange/cGFyYW17dm9uRGF0ZSA9PiAwMS4wNy4yMDExLCBiaXNEYXRlID0+IDA3LjA3LjIwMTF9.phtml

oder als MD5 hash encode string weil das kürzer ist.
/news/showrange/c855603fad1a5c8161a3c42d544ed6b4.phtml

Der Vorteil ist:
 - man brauch die parametern nicht auch noch wertepaar mässig mit / trennen.
 - der Link wird nicht zu lange und bleibt übersichtlich
 - in dem encode string können x-beliebige wertepaare als array abgelegt werden

Wenn die actions ebenfalls in der Map erfasst sind und man dynamische parameter hat,
kann man den link aus der Map holen und entsprechend um die dynamischen Parameter ergänzen.

Um nicht zuviel Last zu erzeugen könnte man die DB:modules um die in der modulname.config.php
angegebenen actions ergänzen (Textfeld mit actions komma separiert).
(Evtl. eine check routine erstellen welche die module auf neue oder geänderte actions, sowie
auf aktiv/inaktiv prüft und entsprechend die DB:modules aktualisiert.)

Im Prinzip strebe ich eine möglichst kurze User- und Suchmaschinenfreundliche URL an.
Meiner Meinung nach gibt es nichts schlimmeres als eine URL die ellenlang mit Parametern gespickt ist.

Sicher ist ein Base64 oder MD5 hash erzeugter name nicht gerade Userfreundlich.
Abhilfe könnte man mit einem Alias Array schaffen.
Beim Erzeugen des Hash strings für die URL kann man z.B.
HashAlias[irgendwassinnvolles] = 'c855603fad1a5c8161a3c42d544ed6b4';
erstellen. Als Link dann: /news/showrange/irgendwassinnvolles.phtml.
Da die Kennung .phtml ist, im Alias Array nachsehen und den Hash anschliessend decodieren
und an den querystring aus der Map anhängen.

Man kann das ganze unendlich weiter spinnen und auf verschiedene Arten lösen.
Ich möchte mit dem Post nur mal Gedanken zu unterschiedlichen möglichen Lösungsansätze geben.
Viele Unterschiedliche Ansätze/Gedanken führen meist schneller zu einem brauchbaren und
vielleicht einfacheren Resultat.

gruss
paul
Gespeichert
Jens-A. Koch
Maintainer
*
Offline Offline

Beiträge: 574

One-Man Team


« Antworten #6 am: Juli 19, 2011, 08:30:03 »

Hallo Paul,

Danke für deinen Beitrag. Ich möchte einige der Vorschläge und Ideen aufgreifen und ein wenig dazu schreiben...

Ich denke deine Idee der Quicklinks entspricht den festen 1:1 Routen (/index/about), (/meinquicklink). Das lässt sich jetzt schon durch Definition in der Routing-Config festlegen.

Gut ist dein Hinweis, dass bestimmte Routen nicht vergeben oder ausgewählt werden
können, weil sie tatsächlich existieren (sei es nun als Modulname oder Actionname etc.).
Wenn wir soweit sind, müssten wir das in der Routen-Verwaltung berücksichtigen.
Ticket dazu: http://trac.clansuite.com/ticket/219

Zitat
Ein Gedanke für die dynamischen Angaben:
 - Wenn es eine ID ist: z.b. <id>.html
 - Wenn es ein parameter array ist, diese Parameter Base64 verschlüsseln und als: <Base64 code>.phtml
benennen
Man ersieht dann aus der Kennung ob es sich um eine ID oder ein Param-Array handelt.
Für die Kennung kann man sich ja festlegen was was bedeuten soll.

Simple Beispiel:
bei Zeige news #1
/news/showone/1.html        würde dann automatisch: mod=news&action=showone&id=1

oder bei Zeige alle news von <datum> bis <datum> (z.B. aus einem Formular für die Eingrenzung der Anzeige von News)
param{vonDate => 01.07.2011, bisDate => 07.07.2011}

Base64 encode string
/news/showrange/cGFyYW17dm9uRGF0ZSA9PiAwMS4wNy4yMDExLCBiaXNEYXRlID0+IDA3LjA3LjIwMTF9.phtml

oder als MD5 hash encode string weil das kürzer ist.
/news/showrange/c855603fad1a5c8161a3c42d544ed6b4.phtml

Der Vorteil ist:
 - man brauch die parametern nicht auch noch wertepaar mässig mit / trennen.
 - der Link wird nicht zu lange und bleibt übersichtlich
 - in dem encode string können x-beliebige wertepaare als array abgelegt werden


Ja, ok, der Vorteil ist, dass man ein größeres Array in einem kompakten, weil encoded'ten, String unterbringen kann. Technisch ist das gar kein Thema, aber aber es bringt erhebliche Nachteile was Suchmaschinen anbelangt. Der Suchmaschine ist es prinzipiell egal, aber indexiert wird der Inhalt dann nur unter dem sehr benutzerunfreundlichen und kryptischen md5-String - und das äußert sich dann auch in einem niedrigeren Ranking.

Zitat
Im Prinzip strebe ich eine möglichst kurze User- und Suchmaschinenfreundliche URL an.
Meiner Meinung nach gibt es nichts schlimmeres als eine URL die ellenlang mit Parametern gespickt ist.

Das kann ich nachvollziehen. Wenn es zu viele Parameter werden, dann würde ich auf einen POST-Request ausweichen. Das Problem stellt sich ja besonders bei der Suchmasken und auch bei der Pagination. Deswegen hab ich auch damals gefragt, wieviele Parameter dir dazu einfallen.

Um die URLs kurz zu halten, hab ich ja auch im Datagrid die Abkürzungen eingeführt (sortC / sortO usw.).

Insgesamt bin ich eher für Speaking-Urls bzw. Stichwort-Urls zu haben.
Beim Django-Framework nennt sich das "Sluggified Urls".
Das was du zuletzt vorgeschlagen hast, würde ich daher bevorzugen aber ohne die zusätzliche Map:
Zitat
HashAlias[irgendwassinnvolles] = 'c855603fad1a5c8161a3c42d544ed6b4';
erstellen. Als Link dann: /news/showrange/irgendwassinnvolles.phtml.


Also eine Lösung beispielsweise die abgekürzte (oder den Anfang einer) Titelzeile mit in die Url aufnimmt.
Das würde dann so aussehen "/news/der-titel-der-news/comment-page-1#comment-1".
In dieser Url ist der Pagewechsel berücksichtigt und das direkte Springen auf einen Kommentar. Intern ist das dann "news/showone" mit getNewsByTitle("der-titel-der-news") + Pagination.

Ticket dazu: http://trac.clansuite.com/ticket/220

Zitat
Wenn die actions ebenfalls in der Map erfasst sind und man dynamische parameter hat,
kann man den link aus der Map holen und entsprechend um die dynamischen Parameter ergänzen.


Ja, das kann man machen. Dazu müsste man bei der Bildung der URL schlicht die Routingregel berücksichtigen und die weiteren dynamischen Parameter anhängen.

Ich hoffe, mit Map meinst du das Array mit den Routing-Definitionen?

Zitat
Man kann das ganze unendlich weiter spinnen und auf verschiedene Arten lösen.
Ich möchte mit dem Post nur mal Gedanken zu unterschiedlichen möglichen Lösungsansätze geben. Viele Unterschiedliche Ansätze/Gedanken führen meist schneller zu einem brauchbaren und
vielleicht einfacheren Resultat.


Tja, leider implementieren sich die gesammelten Ideen nicht von selbst.
Und ich arbeite leider zu oft außerhalb der Roadmap und der Tickets...

Gruß Jens
Gespeichert

Keine Supportanfragen per PN oder Mail. Fragen bitte nur im Forum stellen (Wie man Fragen richtig stellt).
paulbr
Developer
*****
Offline Offline

Beiträge: 126


« Antworten #7 am: Juli 20, 2011, 01:06:16 »

Hallo Jens,

Zitat
Ich hoffe, mit Map meinst du das Array mit den Routing-Definitionen?
Ja das meinte ich Smiley

Zitat
Also eine Lösung beispielsweise die abgekürzte (oder den Anfang einer) Titelzeile mit in die Url aufnimmt.
Das würde dann so aussehen "/news/der-titel-der-news/comment-page-1#comment-1".
In dieser Url ist der Pagewechsel berücksichtigt und das direkte Springen auf einen Kommentar. Intern ist das dann "news/showone" mit getNewsByTitle("der-titel-der-news") + Pagination.
Die Browser reagieren unterschiedlich auf die länge der URL.
Der IE z.B. hat eine max. zulässige Anzahl an Zeichen der gesamten URL von 2083 Zeichen.
Der domainname selbst darf 63 Zeichen haben + der querystring.
Dazu kommt, das zu lange URL's bei Google auch nicht grad zum Vorteil gereicht

Das einzige logische wäre hier, den Titel abzuschneiden oder 2 Titel zu vergeben:
 - Normaler langer Text (255 zeichen) für die Ausgabe auf der Webseite
 - URL freundlicher Kurztitel (z.B. 20-30 Zeichen) für den link
   /news/showonce/i14/der-kurztitel-der-news.html

Der Vorteil bei einem zusätzlichen Kurztitel -feld ist der, das man hier explizit als Titel auch
Keywords einbinden könnte bzw. diesen Titel prägnanter auf den inhalt benennen kann Smiley

Die Relevanz für den Router ist hier nur:
 - news (controller)
 - showonce (action)
 - i14 (ID)

"der-kurztitel-der-news.html" dagegen ist nur für Suchmaschinen Relevant

Die Seitenangabe, Sortierkriterien, etc. wird ja bei angabe der ID oder dem Titel nicht benötigt.
Das sind direkte Links die in einer Google-Sidemap gehören.

Dynamische mit Seitenangabe, Sortierkriterien etc. sind nur innerhalb der Seite
bei der Suche oder bei kataloglisten nötig und ändern sich von Suche zu Suche.
Das muss dann anders definiert werden.

Bei einer Kategoriensuche z.B. könnten die Angaben so ausschauen:
  /news/list/i23/p95/parameter-hash-string.phtml
Hier werden ja nur Listen angezeigt, keine konkrete News/Artikel oder Comments.
In dem Hash-String können dann alle Möglichen Kriterien für diese Suche angegeben werden.
  (i = ID, p = page)

Ein Titel kann hier nicht angegeben werden, da es ja eine Liste mit mehreren links zu
Statischen Artikeln/Comments/News etc.. ist.
Hier werden aber Suchkriterien benötigt je nachdem wie Umfangreich eine Suche gestaltet wird,
sind das wenige bis viele Parameter.
Was man hier machen könnte wäre ein Hash array in der der hash string abgelegt wird.
z.B.
  /news/list/i23/p95/allgemein.phtml

$hash[i23][p95][allgemein] = c855603fad1a5c8161a3c42d544ed6b4

wobei ich denke das man dies nicht braucht, wenn man eine Google Sidemap verwendet.

Suchmaschinen Relevant wäre hier höchstens nur die Kategorie liste selbst ohne Suchkriterien,
also: /news/list/i23/name-der-kategorie.html
       (/controller/action/id)

Der Sinn einer Google Sidemap (xml) ist ja der, das Google nicht mehr alles Spidern muss.
In der Sidemap sollten links zu allen Artikeln/News/Comments/etc.. als Statische links stehen,
mit Relevanz und Ablaufdatum.
Das ist ja eine Routing-Definitions Liste für Google.
Google Spidert im normalfall lediglich die links aus der Sidemap je nach Relevanz und Ablaufdatum.

Jede Url die Suchparameter enthält oder nur auf einer Liste zeigt ist für Google weniger Relevant
als eine direkte statische Url bei der man durch klick direkt zu einem Artikel kommt.
Das schlägt sich ebenfall im Ranking nieder.

Die Schwierigkeit an dem Routing ist ja, das man nach aussen hin Statische links, intern dynamisch
umsetzen muss Smiley

Anmerkung:
Es ist auch ein Sicherheitsvorteil wenn man die actions ebenfalls in die Routing-Definitionen mit aufnimmt.
Denn wenn
 [controller][action]  oder
 [controller][subcontroller][action]
darin nicht existieren ein Fehler vorliegt.

Quicklinks:
Eine weitere Möglichkeit um die URL kürzer zu machen ist, verschiedene feste definitionen zu machen.
Beispiel:
Normale quicklinks für action=show
  /news
  /article
  /forum
  ...
 
Controller
   ar = artikel
   co = comment
   ne = news
   ...

Action
   so   = showone
   lst   = liste
   ...

/ne-so/i15/der-kurztitel-der-news.html
/ne-ls/i2/name-der-kategorie.html

bei kategorien könnte man diese auch anhand des namens auflösen
$cats[allgemein] = 1
$cats[irgendwas] = 2
   /ne-ls/allgemein/index.html
entspricht dann:
  controller = news
  action = list
  id = 1

wobei hier berücksichtigt werden muss, das kategorien in den unterschiedlichen sections/leveln auch
gleiche namen haben können. Hier müsste dann noch section/level mit angegeben werden.
Besser und auch performanter ist da schon die /ne-ls/i2/name-der-kategorie.html Angabe.
Wobei /ne-ls/i2 je nach definition auch reichen würde und name-der-kategorie.html nur für
Suchmaschinen gedacht ist.
Lediglich Dynamische links, wenn Parameterangaben vorhanden sind, müssen speziell erkenntlich sein
damit im Routing richtig verfahren werden kann.

Routing-Definitionen
Eine Idee zum performanterem Mapping wäre es, wenn man mehrere definitions-dateien erzeugt,
abhängig vom controller.
So lädt man die Map mit dem benötigten controller namen, da sind weniger Einträge die durchsucht
werden müssen. Der controller ist bekannt, das ist ja die mindest angabe in der URI.

Zitat
Tja, leider implementieren sich die gesammelten Ideen nicht von selbst.
Und ich arbeite leider zu oft außerhalb der Roadmap und der Tickets...
Da hast du Recht, es ist schade das sich nicht mehr Leute mit einbringen.
Ich kann leider auch nicht ständig an der Clansuite arbeiten, da ich Selbstständig bin
und meine Kundenprojekte sich nicht von alleine realisieren.
Mein Tag hat mitunter 16 stunden, da hab ich dann auch keine Power mehr für Clansuite.
Also kann ich mich nur Sporatisch immer wenn es meine Zeit zulässt einbringen.

gruss
paul
Gespeichert
Jens-A. Koch
Maintainer
*
Offline Offline

Beiträge: 574

One-Man Team


« Antworten #8 am: Juli 20, 2011, 02:44:24 »

Der Sitemap Generator auf Basis des Routings ist natürlich ne sehr schöne Idee.

Ok..dann halte ich das mal in einigen Tickets fest:

http://trac.clansuite.com/ticket/149 - Google-Sitemap generieren
http://trac.clansuite.com/ticket/221 - Google-Sitemap Generator verwendet die Routing-Regeln

http://trac.clansuite.com/ticket/222 - Routing-Regeln pro Modul ablegen
Routing-Regeln pro Controller nachladen (folglich auch nur den Controller-Teil matchen) bzw.
Routing-Regeln aller Module zusammenführen in die allgemeine Routing Datei
Allgemeine Routing Datei cachen (APC etc)

Ich hoffe, ich hab alles wesentliche in Tickets festgehalten...

Zitat
Da hast du Recht, es ist schade das sich nicht mehr Leute mit einbringen.


Tja, ich hab leider keine Ahnung, was ich machen muss, um mehr Leute an Bord zu holen und die Community aufzubauen.

Werbung für unfertiges Produkt schalten?
Werbung für die Entwickler-Community machen?
Community-Events wieder einführen?
Entwickler-Videos auf youtube + vimeo stellen?
Kopfgeld auf Bugs und Features aussetzen?
Kleine Belohnungen aussetzen, etwa Bücher oder ein Handy-Gewinnspiel?
400 Euro Nebenjob ausschreiben?
Einen PHP'ler Vollzeit einstellen?

Zitat
Ich kann leider auch nicht ständig an der Clansuite arbeiten, da ich Selbstständig bin
und meine Kundenprojekte sich nicht von alleine realisieren.
Mein Tag hat mitunter 16 stunden, da hab ich dann auch keine Power mehr für Clansuite.
Also kann ich mich nur Sporatisch immer wenn es meine Zeit zulässt einbringen.


Ja - und trotzdem findest du ab und zu die Zeit, die eine oder andere Klasse zu schreiben oder dich an Diskussionen zu beteiligen und gute neue Ideen beizusteuern!

Gruß Jens
Gespeichert

Keine Supportanfragen per PN oder Mail. Fragen bitte nur im Forum stellen (Wie man Fragen richtig stellt).
paulbr
Developer
*****
Offline Offline

Beiträge: 126


« Antworten #9 am: Juli 21, 2011, 12:46:09 »

Zitat
Kopfgeld auf Bugs und Features aussetzen?
Kleine Belohnungen aussetzen, etwa Bücher oder ein Handy-Gewinnspiel?
400 Euro Nebenjob ausschreiben?
Einen PHP'ler Vollzeit einstellen?

Das wäre definitiv der falsche Weg!

Wie der Begriff Community sagt, handelt es sich um ein Gemeinschaftsprojekt
von einigen bis vielen Menschen die Spass an einer gemeinsamen Sache haben,
sich freiwillig einbringen und sich mit Ihren unterschiedlichen Wissen ergänzen.

Werbung braucht es denke ich mal nicht, da Clansuite ja relativ viel besucht ist und
auch jede Menge Mitglieder hat Smiley

Meiner Meinung nach Wissen viele nur gar nicht, was die Clansuite im aktuellen Stand
der Entwicklung bereits leisten kann.

Die Clansuite, wie sie auf der Homepage beschrieben ist zielt speziell auf eine bestimmte
Anwendergruppe hin. Alle anderen die eben keine Clanseite erstellen wollen oder keinen
Verein innehaben etc. denken die Clansuite (weil der Name das ja schon festlegt) wäre für
Sie nicht geeignet als CMS.

Die Clansuite ist im Prinzip kein CMS sondern ein WCMS zumindest im Core.
Man kann sehr wohl jetzt schon mit dem aktuellen Core auch ohne den unvollständigen
Modulen eine Webpräsenz erstellen.

Ich erkläre mal in kurzer Exkursion hier an der Stelle zu was Clansuite bereits seit Anfang des
Jahres schon imstande ist zu leisten, auch wenn man es vlt. nicht glauben mag.
Vieleicht gibt das ja dem einen oder anderen einen Schubs und schliesst sich aktiv der Community an.

Eigene Erfahrung und die flexibilität der Clansuite
Ich hatte im letzten Quartal 2010 ein Kundenprojekt, ein Branchenbuch zu realisieren.
Das Branchenbuch hatte Auszugsweise folgende Voraussetzung zu erfüllen:
- Mehrsprachigkeit (zum Start: deutsch,englisch,spanisch,polnisch; geplant insgesamt 20 sprachen)
- Interaktive Maps zum klicken der jeweiligen Zonen (Karte)
  mit anschliessender Liste aller Branchen aus dieser Zone
- Bei Suche nach einer Branchenkategorie, farbliche hervorhebung der Zonen auf der Map
  in denen Branchenbucheinträge zu dieser Kategorie zu finden sind (wenn welche vorhanden sind).
- Online Eintragsformular für einen Brancheneintrag
  Beim Absenden des Eintrages wird man auf PayPal geleitet wo man den Eintrag bezahlen muss.
  Im Anschluss wird nach Bezahlung der Eintrag in die DB integriert, bei Abbruch der Zahlung nicht.
- Brancheneinträge mit Vimeo Videos, wenn der kunde dies bestellt hat.
- VIP Branchenbucheinträge mit Slideshow der Bilder
- Das ganze Branchenbuch sollte Verkäufer und Zonen Orientiert aufgebaut sein.
  Grund: Die Manager sollen Ihre Zonen/Gebiete in einem Franchise eigenständig
  als Plattform nutzen können.
  Zugleich müssen alle Zonen/Gebiete welche keine Franchise-Manager haben von einem
  Default-Manager (Administrador) Verwaltet werden können.
   Schema:
  - Administrador
    |- Manager 1 (1-X Zonen)
       |- Zone1
         |- Vertreter 1
         |- Vertreter 2
         ...
    |- Manager 2 (1-X Zonen)
       |- Zone1
         |- Vertreter 1
         |- Vertreter 2
         ...
Jeder Vertreter kann nur innerhalb seiner freigegebenen Zone Brancheneinträge Verkaufen.
Manager haben nur Kontrolle innerhalb Ihrer freigegeben Zonen.
Ein Umschichten der Manager<->Zonen und Vertreter<->Manager musste möglich sein.
Jeder Vertreter darf nur seine Kunden Verwalten.
Jeder Manager nur seine eigenen Kunden und die seiner Vertreter.
Und vieles mehr, also nicht gerade ein einfaches Handling.

Ich hatte mal spasseshalber den Stand der Clansuite von Anfang des Jahres, also noch vor
der Umstellung auf Doctrine2 und noch vor den seither vielen Erneuerungen, Verbesserungen und
Änderungen genommen und dieses Kundenprojekt damit Nachprogrammiert.
Es funktionierte einwandfrei.
Im Core musste lediglich das Login aktiviert werden und ein paar kleinigkeiten angepasst werden bzgl. dem Sessionhandling.
Das Staging hatte ich um die 3 vorhandenen landes Domains ergänzt, damit je nach domain
die entsprechende default Grund-Sprache (deutsch,englisch,spanisch) gestartet wird.
Ansonsten habe ich nur ein neues Modul "branchen", payments und anstatt dem Controlcenter
ein neues Adminmodul "comerciales" erstellt.
Anstelle den Clansuite eigenen get-text Sprachdateien habe ich eigene Sprachdateien verwendet.
Ein neues Thema generiert und die Webseite funktionierte exakt so wie das bereits realisierte Kundenprojekt.
Ende der Exkursion.

Indem man den Core nimmt, sich ein Projekt ausdenkt und damit realisiert, erkennt man schwächen
und Mängel im Core. Diese postet man im Forum und/oder bespricht sich mit den anderen Entwicklern.

Ich will damit sagen, die Clansuite ist nicht so eingleisig fixiert auf Clans, man kann sie sehr wohl
für Internetprojekte jeder Art einsetzen.
Die Clansuite ist ein Framework mit dem sich sehr vieles Realisieren lässt, auch nicht Clan spezifisches.
Man lässt nicht benötigte Module weg und erstellt ebend eigene Module speziell für ihren
Verwendungszweck. Der Core sollte "im Normalfall" unbetroffen und somit update/upgrade -bar bleiben.

Ich denke das die meisten gar nicht Wissen welches Potenzial sich hinter der Clansuite eigentlich befindet.
Ich hatte es damals gesehen, was auch der Grund ist warum ich mich seitdem mehr oder weniger
aktiv an der Clansuite beteilige und das eine oder andere einbringe.

Der Core ist das wesentliche Element, der Motor der laufen muss.
Viele Denken, das es wichtiger ist Module fertig zu stellen um die Clansuite benutzen zu können.
Ich sage wenn der Core stimmig ist kann man alles mit der Clansuite realisieren.
Man könnte mit der Clansuite ohne grossen Aufwand alles realisieren was allle anderen am Markt
befindlichen Freie und auch Komerzielle Frameworks anbieten.
Es ist nur eine Frage der Zeit wann dies der Fall sein wird.
Wenn sich mehr Leute bereit erklären würden mit Hand an dem Projekt zu legen ist das füher
der Fall, ansonsten ebend etwas später.


gruss
paul
Gespeichert
Seiten: [1]   Nach oben
  Drucken  
 
Gehe zu:  


Powered by SMF 1.1.16 | SMF © 2006-2009, Simple Machines

Google visited last this page Mai 11, 2012, 07:20:12