Ankündigung

Einklappen
Keine Ankündigung bisher.

Request-Parameter und deren Routing

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Request-Parameter und deren Routing

    Hallo zusammen,

    in den letzten Tagen beschäftigt mich immer wieder folgende Überlegung: Wie gestalte ich das Routing von Request-Parametern dynamischer und effizienter? Mein momentanes Vorgehen möchte ich in aller Kürze vorstellen.

    In der index.php wird ein Front-Controller instanziiert. Diesem wird per Konstruktur das $_GET-Array übergeben, welches anschließend in einer switch-Anweisung landet. Anhand der verschiedenen Fälle wird entweder ein weiterer Controller geladen, bspw.:

    PHP-Code:
    case 'gästebuch':
        require_once 
    'gaestebuch_controller.php';
        
    $controller = new Gaestebuch_Controller($request);
        break; 
    oder es wird ein Model geladen und dessen Daten an einen View übergeben, z.B.:

    PHP-Code:
    default:
        
    $model = new Content('default');    
        
    $main = new View;        
        
    $main->setTemplate('template/content.inc.php');
        
    $main->setVar('title'$model->getTitle());    
        
    $main->setVar('data'$model->getData());
        
    Site::set('main'$main); 
    Angenommen es wird ein weiterer Controller geladen, wie in diesem Falle der Gästebuch-Controller, ist dessen Konstruktur recht ähnlich gestaltet im Vergleich zum Front-Controller. Wieder findet sich eine switch-Anweisung, wobei anhand der verschiedenen Fälle entweder ein weiterer Controller geladen wird oder eine Action-Methode aufgerufen wird, wie z.B.:

    PHP-Code:
    case 'beitrag-schreiben':
        
    $this->createEntry();
        break; 
    Prinzipiell ist der Verschachtelung bzw. Tiefe keine Grenze gesetzt. Mich stört allerdings gewaltig, dass jeder Konstruktur eine mal längere oder auch kürzere switch-Anweisung enthält. Auch habe ich den Eindruck, das dies wohl keine gängige Vorgehensweise ist. Demnach würde mich interessieren, welche Vorgehensweise ihr für das Routing pflegt. Schließlich muss der Controller wissen, welche Methoden er aufzurufen hat bzw. ob das Laden eines weiteren Controllers notwendig ist.

    Bei mir erledigen das im Moment ausschließlich switch-Anweisungen, die je nach Umfang der Klasse ziemlich sperrig wirken. Wie sieht es bei euch aus?

  • #2
    Hallo Trainmaster,

    das Thema ist bereits mehrfach diskutiert worden. Schau mal unter


    Aus meiner Sicht fehlt dir eine generische Implementierung von MVC mit einem Routing, das frei konfigurierbar ist, oder noch besser eine HMVC-Impelemntierung, in der das Aufbauen einer GUI komplett frei passiert und kein Routing mehr nötig ist. Das gekoppelt mit einem Front Controller, der die Business-Logik entsprechend den einzelnen Modulen/Elementen einer Seite vor dem Aufbau der GUI ausführen kann löst die Aufgabenstellung IMHO nachhaltig.
    Viele Grüße,
    Dr.E.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1. Think about software design [B]before[/B] you start to write code!
    2. Discuss and review it together with [B]experts[/B]!
    3. Choose [B]good[/B] tools (-> [URL="http://adventure-php-framework.org/Seite/088-Why-APF"]Adventure PHP Framework (APF)[/URL][URL="http://adventure-php-framework.org"][/URL])!
    4. Write [I][B]clean and reusable[/B][/I] software only!
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Kommentar


    • #3
      Naja, du identifizierst den Namen des Moduls, des Controllers und der Action anhand des Requests und übergibst diesen deiner Routing-Routine. Die Standard-Routing-Routine mappt anhand der 3 Angaben (oder der variablen Parameter) nun auf eine bestimmte Methode einer Klasse (die Aktion), wobei natürlich fehlende Angaben auf ein Default zurückspringen, das vorher (z.B. über eine Config) definiert wurde. Da braucht es überhaupt keine switch-Anweisungen, das fixiert ja nur deine möglichen Routen.

      Deiner Routing-Routine könntest du jetzt noch weitere Routinen voranfügen (im Zend gibt es statische, RegExp- usw. Routinen), die prüfen, ob die Route auf sie zutrifft. Wenn ja liefern sie den Namen des Moduls/Controllers/Action. Wenn du weitergehst kannst du auch noch eine Routine einhängen, die die initialen Angaben (M/C/A) übersetzt (deutsch -> englisch) usw.
      "[URL="http://www.youtube.com/watch?v=yMAa_t9k2VA&feature=youtu.be&t=25s"]Mein Name ist Lohse, ich kaufe hier ein.[/URL]"

      Kommentar


      • #4
        @ dr.e.

        Danke für deine Antwort. Einige deiner genannten Themen habe ich mir bereits in den letzten Tagen mehrfach gelesen. Allerdings muss ich zugeben, dass mir teilweise die nötige Erfahrung und ein gewisses Grundwissen fehlt, damit ich daraus etwas lernen kann (Das betrifft auch teilweise deine Beiträge ). Ich denke, ich sollte mir ein wenig Literatur anschaffen.


        @ Chriz

        Soweit ich deine Ausführung verstanden habe, ist in diesem Falle die Routing-Routine das Schlüsselkonzept. Wenn du sagst, dass rein gar keine switch-Anweisungen nötig sind, frage ich mich, auf welche Weise die Routing-Routine weiß, wie sie zu verfahren hat. Sind sämtliche Routen bspw. in einer XML-Datei gespeichert? Irgendwo muss schließlich hinterlegt sein, welche Aktion bei den verschiedenen URL-Parametern ausgeführt werden soll.

        Kommentar


        • #5
          Ne, wenn ich jetzt

          http://www.example.org/news/list

          aufrufe, dann wandelt Mod-Rewrite das ja beispielsweise um in:

          index.php?request=news/list

          Nun zerlegt der FrontController diese Anfrage in
          Controller = news
          Action = list
          (lassen wir die Module mal weg).

          Jetzt sucht er in deinem Controllerverzeichnis nach einer Datei "NewsController.php" und der darin befindlichen Klasse "NewsController". Die wird instanziert, bekommt den Request übergeben. OK, erste Hürde geschafft. Jetzt wird geprüft, ob die Methode "listAction" der NewsController-Klasse existiert. Wenn nein, 404 (Nicht gefunden) Errorhandling antriggern (z.B. per Exception), gleiches für fehlenden Controller. Falls gefunden -> aufrufen! Fertig. Jetzt musst du eigentlich nur eins tun wenn du eine neue "Route" (ich schreibs mal in Anführungszeichen) erstellen willst: Du erstellst eine Controller-Klasse und die dazugehörige Methode. Das wars, kein switch() mehr.

          Zusätzlich sinnvoll:
          Eingabevalidierung (also Controller und Action-Bezeichner validieren/normalisieren, so dass gültige Klassen- bzw. Methodennamen herauskommen, was ja bei "my-news" nicht der Fall wäre)
          Jeder Controller muss Instanz eines Controller-Interfaces (oder einer abstrakten Controller-Basisklasse) sein
          Jede Action muss auch als Action-Methode im Controller definiert sein (damit dir keiner __construct aufruft o.ä. Spielchen).
          (damit dein MVC nicht zum RPC/RMI mutiert)
          "[URL="http://www.youtube.com/watch?v=yMAa_t9k2VA&feature=youtu.be&t=25s"]Mein Name ist Lohse, ich kaufe hier ein.[/URL]"

          Kommentar


          • #6
            Zitat von Chriz Beitrag anzeigen
            Ne, wenn ich jetzt

            http://www.example.org/news/list

            aufrufe, dann wandelt Mod-Rewrite das ja beispielsweise um in:

            index.php?request=news/list
            Ich würde jetzt eher an etwas wie index.php?controller=news&action=list denken?!

            Zitat von Chriz Beitrag anzeigen
            Nun zerlegt der FrontController diese Anfrage in
            Controller = news
            Action = list
            (lassen wir die Module mal weg).
            Das ist für meinen Geschmack sehr starr und willkürlich. Was ist, wenn "list" keine Action ist, sondern einen weiteren Controller verlangt? Wird dann trotzdem versucht, eine Action auszuführen?

            Zitat von Chriz Beitrag anzeigen
            Jetzt sucht er in deinem Controllerverzeichnis nach einer Datei "NewsController.php" und der darin befindlichen Klasse "NewsController". Die wird instanziert, bekommt den Request übergeben. OK, erste Hürde geschafft. Jetzt wird geprüft, ob die Methode "listAction" der NewsController-Klasse existiert.
            Demnach bleibt bei der Namensgebung nicht sehr viel Spielraum. Wie verhält es sich zudem bei Mehrsprachigkeit? Beispielsweise mag "listAction" existieren, "anzeigenAction" jedoch nicht.
            Zudem würde ich das Vorgehen etwas anders angehen. Nachdem "list" nicht unbedingt eine Action sein muss, würde ich zunächst in einem Art Verzeichnis des NewsController überprüfen, welches weitere Vorgehen bei "list" zu wählen ist. Es kann doch sowohl ein weiterer Controller verlangt werden als auch die Ausführung einer Methode?

            Kommentar


            • #7
              aber eigentlich brauchst du doch den Konstruktoren nicht jedesmal das Get-Array durchreichen - das ist doch "sowieso" Superglobal vorhanden .... oder hab ich da deine Beschreibung missverstanden?
              "Irren ist männlich", sprach der Igel und stieg von der Drahtbürste [IMG]http://www.php.de/core/images/smilies/icon_lol.gif[/IMG]

              Kommentar


              • #8
                Zitat von eagle275 Beitrag anzeigen
                aber eigentlich brauchst du doch den Konstruktoren nicht jedesmal das Get-Array durchreichen - das ist doch "sowieso" Superglobal vorhanden .... oder hab ich da deine Beschreibung missverstanden?
                In einer Klasse sollte man möglichst so wenig wie möglich mit irgendwelchen globalen variablen, wie z.b. get, post, etc arbeiten, das schafft abhängigkeiten, macht code schlechter testbar, etc
                [URL="http://www.robo47.net"]robo47.net[/URL] - Blog, Codeschnipsel und mehr
                | :arrow: [URL="http://www.robo47.net/blog/192-Caching-Libraries-and-Opcode-Caches-in-php-An-Overview"]Caching-Klassen und Opcode Caches in php[/URL] | :arrow: [URL="http://www.robo47.net/components"]Robo47 Components - PHP Library extending Zend Framework[/URL]

                Kommentar


                • #9
                  Zitat von eagle275 Beitrag anzeigen
                  das ist doch "sowieso" Superglobal vorhanden .... oder hab ich da deine Beschreibung missverstanden?
                  Nein, hast du nicht. Aber das trägt ja nichts zu der Thematik bei bzw. ändert nichts an meinen Sorgen

                  Kommentar


                  • #10
                    Zitat von Trainmaster Beitrag anzeigen
                    Ich würde jetzt eher an etwas wie index.php?controller=news&action=list denken?!
                    Ist ja egal wie das aussieht, aber dann verlagerst du wieder (zumindest etwas) Logik ins .htaccess, was ich persönlich nicht so prickelnd finde. Ich glaube auch der FC des Zend Frameworks greift einzig auf $_SERVER["REQUEST_URI"] zurück.


                    Zitat von Trainmaster Beitrag anzeigen
                    Das ist für meinen Geschmack sehr starr und willkürlich.
                    Also starr und willkürlich widerspricht sich meiner Meinung nach. Bei starr könnte ich dir recht geben (Convention over Configuration), aber ich sehe das als Vorteil. Denn ich will ja das jeder weiß, welche URL auf welche Controller-Action umgemappt wird. Gleichzeitig bleibe ich aber flexibel, wenn ich neue Routen einführe. Starr ist allerdings, da hast du Recht die Struktur: Modul, Controller, Action. Mehr Tiefe gibt es nicht. Zumindest nicht beim MVC.

                    Zitat von Trainmaster Beitrag anzeigen
                    Was ist, wenn "list" keine Action ist, sondern einen weiteren Controller verlangt? Wird dann trotzdem versucht, eine Action auszuführen?
                    Redest du jetzt von Modulen oder allgemein einem Action-Stack? Also dem mehrfachen Ausführen von Actions, z.B. um Contentboxen in einem Layout mit eigener Logik zu versehen?

                    Zitat von Trainmaster Beitrag anzeigen
                    Demnach bleibt bei der Namensgebung nicht sehr viel Spielraum.
                    Wie gesagt, das sehe ich als Vorteil an.

                    Zitat von Trainmaster Beitrag anzeigen
                    Wie verhält es sich zudem bei Mehrsprachigkeit? Beispielsweise mag "listAction" existieren, "anzeigenAction" jedoch nicht.
                    Na dann klemmst du im Router eben eine Übersetzungsroutine ein, die aus "anzeigen" eben ein "list" macht und schon trifft die Route wieder.

                    Zitat von Trainmaster Beitrag anzeigen
                    Zudem würde ich das Vorgehen etwas anders angehen. Nachdem "list" nicht unbedingt eine Action sein muss, würde ich zunächst in einem Art Verzeichnis des NewsController überprüfen, welches weitere Vorgehen bei "list" zu wählen ist. Es kann doch sowohl ein weiterer Controller verlangt werden als auch die Ausführung einer Methode?
                    Warum, die listAction() kann doch durchaus weitere Controller-Actions aufrufen oder in den Stack legen (siehe z.B. ZF), wenn du soetwas in deinem Dispatcher implementiert hast.
                    "[URL="http://www.youtube.com/watch?v=yMAa_t9k2VA&feature=youtu.be&t=25s"]Mein Name ist Lohse, ich kaufe hier ein.[/URL]"

                    Kommentar


                    • #11
                      Zitat von Chriz Beitrag anzeigen
                      Ist ja egal wie das aussieht, aber dann verlagerst du wieder (zumindest etwas) Logik ins .htaccess, was ich persönlich nicht so prickelnd finde.
                      Das stimmt allerdings, daran habe ich nicht gedacht.

                      Zitat von Chriz Beitrag anzeigen
                      Starr ist allerdings, da hast du Recht die Struktur: Modul, Controller, Action. Mehr Tiefe gibt es nicht. Zumindest nicht beim MVC.
                      Das ist ja, gelinde gesagt, ziemlich hässlich. Was ist, wenn doch mehr Tiefe benötigt wird? Mit solch einem Problem wird der ein oder andere bereits konfrontiert gewesen sein.

                      Zitat von Chriz Beitrag anzeigen
                      Redest du jetzt von Modulen oder allgemein einem Action-Stack?
                      Ich rede davon, dass gemäß der Struktur angenommen wird, dass "list" als eine Action zu werten ist. Dennoch könnte "list" gleichermaßen ein Controller sein. Mit dieser starren Struktur "modul -> controller -> action" werde ich nicht warm. Ich denke stets an Fälle wie "modul -> controller -> weiterer controller -> action". Aber vielleicht habe ich auch einen gewaltigen Denkfehler. Ich könnte theoretisch folgendes Gebilde entwickelen "Modul -> Controller -> Action -> Controller -> Action". Sozusagen die Action eines Controllers dazu verwenden, einen weiteren Controller zu laden. Damit kann ich mir recht einfach mehr Tiefe verschaffen? Jetzt bin ich endgültig verwirrt

                      Zitat von Chriz Beitrag anzeigen
                      Na dann klemmst du im Router eben eine Übersetzungsroutine ein, die aus "anzeigen" eben ein "list" macht und schon trifft die Route wieder.
                      Das ist wohl das erste, was ich erledigen muss. Gibt es dazu empfehlenswerte Vorgehensweisen?

                      Zitat von Chriz Beitrag anzeigen
                      Warum, die listAction() kann doch durchaus weitere Controller-Actions aufrufen oder in den Stack legen.
                      Mir geht es nicht darum, weitere Controller-Actions aufzurufen, sondern einen weiteren Controller.

                      Kommentar


                      • #12
                        Also die fehlende Tiefe bei MVC finde ich auch nachteilig, da geb ich dir Recht. HMVC heißt das andere Pattern, dass wohl etwas flexibler ist. Habe damit allerdings keine Erfahrung gemacht, über die Forensuche findest du bestimmt einige Diskussionen dazu, falls du es noch nicht kennst.

                        Mir geht es nicht darum, weitere Controller-Actions aufzurufen, sondern einen weiteren Controller.
                        Dann haben wir beide aber ein unterschiedliches Verständnis eines Controllers, denn einen Controller ohne Action aufzurufen macht keinen Sinn, es sei denn er führt intitial bereits Aktionen durch. Dann ist es aber kein Controller mehr. Ist zumindest mein Verständnis von der Materie. Oder habe ich dich falsch verstanden?
                        "[URL="http://www.youtube.com/watch?v=yMAa_t9k2VA&feature=youtu.be&t=25s"]Mein Name ist Lohse, ich kaufe hier ein.[/URL]"

                        Kommentar


                        • #13
                          Das rührt daher, dass meine Controller bereits im Konstruktur anhand der Request-Parameter die entsprechenden Aktionen ausführen. Dass ich mich davon verabschieden möchte, habe ich hoffentlich zu verstehen gegeben.

                          Eine abschließende Frage: Gibt es bewährte Verfahren, einem Router Mehrsprachigkeit beizubringen. Die Übersetzungen in einer Datenbank zu speichern, halte ich für ungeschickt. Schließlich sollte das Ganze gleichermaßen ohne Datenbank funktionieren. Ich dachte bspw. an XML-Sprachdateien. Wäre das ein geeigneter Weg?

                          Das HMVC-Pattern scheint wohl das von mir gesuchte Entwurfsmuster zu sein. Auch wenn mir noch einige Dinge unklar sind, selbst nach stundenlanger Lektüre zahlreicher Forenbeiträge, werde ich einen Versuch starten. Wahrscheinlich endet dass in einem kunterbunten-Mischmasch an verschiedenen Entwurfsmustern. Achja, dr.e., ich weiß deinen Hinweis zu schätzen, dass das APF für mich hilfreich wäre

                          Kommentar


                          • #14
                            Wie wäre es mal wenn du dir einfach mal MVC und Router in der Praxis in einigen Frameworks anschaust ? Von Quellcode kann man oftmals was lernen, seien es was für Features es gibt, wie man es implementieren kann, etc.

                            Apf, Zend, Symfony, .... dort siehst du wie sowas in der praxis umgesetzt werden kann, was für Features geboten werden.

                            Da routen ja auch meistens nichts sind was sich täglich ändern, lassen sich solche daten auch für den Produktiv-betrieb cachen (php-datei, apc, memcache, .... ) sprich ob die ursprungsdaten in einer datenbank oder datei (xml, json, ini, yml, php, .... ) liegen ist dann egal für die performance.
                            [URL="http://www.robo47.net"]robo47.net[/URL] - Blog, Codeschnipsel und mehr
                            | :arrow: [URL="http://www.robo47.net/blog/192-Caching-Libraries-and-Opcode-Caches-in-php-An-Overview"]Caching-Klassen und Opcode Caches in php[/URL] | :arrow: [URL="http://www.robo47.net/components"]Robo47 Components - PHP Library extending Zend Framework[/URL]

                            Kommentar


                            • #15
                              Ich finde die Switch-Variante jetzt nicht soo schlecht. Damit bist Du weitmöglichst flexibel. Du könntest jetzt einen abstrakten Controller schreiben, der Dir für 0815-Module die Funktionalität kapselt. Vielleicht auch ein Array, statt eines Switches verwenden (GET-value => ActionObjekt) und den GET-key noch als Parameter an das Objekt binden.
                              [COLOR="#F5F5FF"]--[/COLOR]
                              [COLOR="Gray"][SIZE="6"][FONT="Georgia"][B]^^ O.O[/B][/FONT] [/SIZE]
                              „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
                              [URL="http://www.php.de/javascript-ajax-und-mehr/107400-draggable-sorttable-setattribute.html#post788799"][B]Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“[/B][/URL][/COLOR]
                              [COLOR="#F5F5FF"]
                              --[/COLOR]

                              Kommentar

                              Lädt...
                              X