Ankündigung

Einklappen
Keine Ankündigung bisher.

Router ohne mapping

Einklappen

Neue Werbung 2019

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

  • #16
    Denn Sinn von Callbacks habe ich irgendwie noch nicht richtig verstanden. Durch die Url kenne ich die Methode die ich aufrufen will und die Anzahl der Parameter kenne ich auch über die Url. Ich kann also mit method_exists überprüfen ob es die Funktion gibt und wenn ja, dann führe diese aus. Wenn es Parameter gibt werden diese übergeben.
    Ich weiß also welche Funktion ich aufrufe und die Anzahl der Parameter ist mir auch bekannt.

    Kommentar


    • #17
      Zitat von tr0y Beitrag anzeigen
      Dein Router sollte im übrigen keine "defaults" kennen, da diese Komponente nur sagen soll ob eine registrierte Route auf den aktuellen Request anwendbar ist. Die Route-Instanz mag dann bestenfalls informationen über ein aufzurufendes Callback haben, alles was darüber hinaus geht bindet dein Router an etwas das unnötig ist. Das ist auch der Grund warum die meisten Router Callbacks zu routes Assoziieren und keine Controller.

      Du kannst dich da gerne an diverse Router der großen Frameworks orientieren oder optimaler Weise an: https://github.com/nikic/FastRoute ( dessen Prinzip ich aktuell als kleverste Lösung halte )
      Du kannst eine Routing-Tabelle auch wie ein Key-Value-Array verstehen. So mache ich das. Der Key ist ein Routingpattern und im Valuepart darf stehen was will. Völlig egal. Der RouterLookup findet dir nur den Valuepart zu dem Arraykey. Damit sind "Routingtabelle" und "Lookup" konzeptionell getrennt. Rest ist Belang der Applikation. Die Applikation kann sich hier festlegen, ob sie Callbacks/Closures, Arrays oder Objekte als Valuepart nutzt.

      Meine nutzt Arrays. Da steht dann (wieder anwendungsspezifisch) drin, dass ein Controller und darin eine Methode aufgerufen werden soll. Ausserdem leiten sich möglicherweise aus dem gefundenen Routingpattern, sowie aus get und post noch Parameter für Methode ab. Ob von Post oder get wird ebenfalls im gefunden Routing spezifiziert, sonst drohen Gefahren wie CSRF.

      Hat man alles zusammen, übergibt man die gewonnenen Informationen (die man auch hätte ganz anders gewinnen können) an einen Dispatcher. Der bekommt via Constructorinjection bei mir Zugriff auf einen Servicelocator. Der Dispatcher hat eine Methode, um mit den Parametern "FQ-Classname", "Methode" und "Parameter" (=Key-Value-Array) eine Klasse zu instanziieren und hier eine Methode mit Parametern aufzurufen.

      Beim Instanziieren der Klasse wird via Reflection geschaut, welche Parameter der Constructor erwartet. Wurde bei Parametern via Typehinting Klassentypen angegeben, werden diese entsprechend über den Servicelocator gesucht, der seinerseits dann vielleicht via DependencyInjection die gesuchte Abhängigkeit zusammensetzt. Ansonsten geht der Servicelocator über den Namen der Variable die dann so heissen muss, sie der Instanzschlüssel im Servicelocator.

      Die Methode wird auf ähnliche Art aufgerufen. Hier erlaube ich bislang aber nur scalare Werte und arrays. Wenn kein Typehint für Array angegeben wurde, dann muss der Wert scalar sein, vice versa. Sonst: Exception.

      Hat der Controller den Input verarbeitet, gibt er sein Ergebnis in Form eines einfachen scalaren Wertes, oder eines arrays zurück. Objekt geht natürlich auch. Das gibt dann der Dispatcher auch 1:1 an die aufrufende Instanz weiter.

      In den Routing - Informationen steht nicht nur, wen ich mit was aufrufe, sondern auch, was ich mit dem Ergebnis mache. Beispielsweise als JSON ausgeben. Oder an eine Templateengine weiterreichen. Naja, Rest ist selbsterklärend.

      Jetzt erst mal Frühstück nach Sport

      Kommentar


      • #18
        @rkr: wo bleibt der Code? Würde mich mal interessieren wie der aussieht. "Nachhher" dürfte mittlerweile abgelaufen sein

        Kommentar


        • #19
          Bin gerade im Urlaub

          Kommentar


          • #20
            So, ich habe mal versucht meinen bisherigen Approach GitHub-faehig zu machen. Das ganze ist noch längst nicht perfekt, aber da kann man sicher schon was fuer sich ableiten:

            https://github.com/rkrx/php-simple-router

            https://github.com/rkrx/php-dispatcher

            Wenn Bedarf ist kann ich die Tage (wenn ich etwas mehr Zeit habe) ein kleines Beispiel dazu erstellen.

            Kommentar


            • #21
              Finde deinen Router und Dispatcher sehr übersichtlich, da du nicht soviel Code verwendet hast.

              Benutzt eigentlich niemand im Router $_SERVER['REQUEST_URI'] um den aktuellen Pfad zu bekommen? Oder woher bekommt ihr euren Pfad aus der URL?

              Bei meinem Router habe ich mit class_exists($class) und method_exists($class, $method) überprüft ob der Pfad aufrufbar ist. Ich habe über call_user_func() schon was gelesen, aber nicht so richtig verstanden. Kann man mit der Funktion überprüfen ob Klassen und Methode vorhanden sind?

              Hab jetzt übrigens meinen Router erstmal zurückgestellt und eigne mir Laravel an, da es einfach zuviel Zeit und Verständnis braucht um was gescheites hinzu bekommen

              update: schnell mal einen fehler behoben . ich meinte call_user_func()

              Kommentar


              • #22
                $_SERVER['PATH_INFO'] wäre schon von Vorteil, da spart man sich das gehampel mit der URI.
                [URL="https://gitter.im/php-de/chat?utm_source=share-link&utm_medium=link&utm_campaign=share-link"]PHP.de Gitter.im Chat[/URL] - [URL="https://raindrop.io/user/32178"]Meine öffentlichen Bookmarks[/URL] ← Ich habe dir geholfen ? [B][URL="https://www.amazon.de/gp/wishlist/348FHGUZWTNL0"]Beschenk mich[/URL][/B].

                Kommentar


                • #23
                  Zitat von Fuel Beitrag anzeigen

                  Gibt es mit dieser Configuration Sicherheitsprobleme die ich beachten sollte? Und wieso machen das nicht alle Frameworks so?

                  Ja, du hast dir so eine vermutlich eine LFI gebaut.

                  Kommentar


                  • #24
                    Zitat von tr0y Beitrag anzeigen
                    $_SERVER['PATH_INFO'] wäre schon von Vorteil, da spart man sich das gehampel mit der URI.
                    Ich zögere immer vor der Verwendung von PATH_INFO, weil mir das mal bei einer Kundenkonfiguration nicht zur Verfügung stand. Ich habe die Gelegenheit natürlich gleich genutzt und geschaut, in wiefern das heute noch relevant ist:
                    http://stackoverflow.com/questions/1...-get-path-info
                    Zitat von Fuel Beitrag anzeigen
                    Benutzt eigentlich niemand im Router $_SERVER['REQUEST_URI'] um den aktuellen Pfad zu bekommen? Oder woher bekommt ihr euren Pfad aus der URL?
                    Hast du die README.MD gelesen?

                    Kommentar


                    • #25
                      Es gibt heute keinen logischen Grund warum PATH_INFO nicht erzeugt werden sollte. Das PATH_INFO in einigen Konfigurationen fehlt mag an dem alter der dort verwendeten Software liegen.
                      [URL="https://gitter.im/php-de/chat?utm_source=share-link&utm_medium=link&utm_campaign=share-link"]PHP.de Gitter.im Chat[/URL] - [URL="https://raindrop.io/user/32178"]Meine öffentlichen Bookmarks[/URL] ← Ich habe dir geholfen ? [B][URL="https://www.amazon.de/gp/wishlist/348FHGUZWTNL0"]Beschenk mich[/URL][/B].

                      Kommentar


                      • #26
                        rkr
                        So, ich habe mal versucht meinen bisherigen Approach GitHub-faehig zu machen. Das ganze ist noch längst nicht perfekt, aber da kann man sicher schon was fuer sich ableiten:

                        https://github.com/rkrx/php-simple-router
                        Wenn ich mir zwei kleine Optimierungsvorschläge für Deinen Router erlauben darf

                        1) Ich würde $this->routePatterns = $this->compileRoutes($routes); aus dem Konstruktor raus nehmen und erst beim lookup die Routen in regex umwandeln. Aktuell hast Du immer einen unnötigen overhead, es sei denn der lookup greift erst bei der allerletzten Route.

                        2) Die Kompilierung läßt sich noch um einiges beschleunigen:

                        Anstatt:

                        PHP-Code:
                        private function compileRoute($route) {
                            
                        $route preg_quote($route'/');
                            
                        $route preg_replace_callback('/\\\\\\[(.*?)\\\\\\]/', function ($input) {
                                return 
                        "(?:{$input[1]})?";
                            }, 
                        $route);
                            
                        $route preg_replace_callback('/\\\\:\\w+/', function ($input) {
                                
                        $key $input[0];
                                
                        $key ltrim($key'\\:');
                                return 
                        "(?P<{$key}>\\w+)";
                            }, 
                        $route);
                            return 
                        "/^{$route}$/";

                        besser

                        PHP-Code:
                        private function compileRoute($route) {
                            
                        $route preg_quote($route'/');
                            
                        $route str_replace(array('\[''\]'), array('(?:'')?'), $route);
                            
                        $route preg_replace('/(?:\\\:(\w+))/''(?P<$1>\\w+)'$route);
                            return 
                        "/^{$route}$/";

                        Die zweite Implementierung ist mehr als doppelt so schnell und kann zusätzlich auch verschachtelte optionalen Parameter (bis zu einer beliebigen Tiefe) verarbeiten z.B.:

                        GET /test[/:id[/:start]]



                        vg
                        jack
                        -

                        Kommentar


                        • #27
                          @tr0y: Ich denke, ich werde es umbauen. Muss mich damit noch etwas beschäftigen.

                          @jack8: Cool, danke. Hast du Bock einen PR zu machen?

                          Kommentar


                          • #28
                            Gern geschehen.

                            Hat sich gerade so ergeben, da ich seit einigen Wochen selbst an einem MVC-Grundgerüst herumexperimentiere und in diesem Zusammenhang auch einen Router entwickeln musste.

                            Hast du Bock einen PR zu machen?
                            Sorry, verstehe nicht ganz - was ist ein PR?

                            vg
                            jack
                            -

                            Kommentar


                            • #29
                              Ein pull-request bei github.

                              Kommentar


                              • #30
                                Ein pull-request bei github.
                                aahhha...

                                Vielleicht in diesem Zusammenhang noch ein paar abschließende Gedanken zum Router.

                                Ich würde stärker zwischen Router und Route unterscheiden. Vielleicht brauchst Du die Route noch mal später um daraus z.B. wieder eine URI zu generieren.

                                "Simple" ist immer gut, aber nur solange die Flexibilität nicht allzu sehr darunter leidet. Insbesondere bei einem Router halte ich das für wichtig. Denn was nutzt mir ein Router mit dem ich viele URLs nicht unterscheiden, also nicht routen kann. REQUST_URI und REQUEST_METHOD als einzige Environment-Routingkriterien/Restrictions – das reicht für viele Anwendungsfälle einfach nicht aus.

                                Deshalb gehören für mich zu einem Router/Route zumindest die folgenden Kerneigenschaften:

                                - Verschachtelte optionale Parameter
                                - Default Parameter
                                - Parameter restrictions
                                - Request/Environment restrictions

                                und damit lookup() nicht über die Zeit ausartet lookup($requestUri, $method, $port, $remoteAddr, $subdomain……)

                                ist es besser von Anfang an ein Request-Objekt zu nehmen mit einem klaren Interface z.B.:

                                lookup(RequestInterface $request);

                                PHP-Code:
                                interface RequestInterface {
                                    public function 
                                get($key null$default null);
                                    public function 
                                getQuery($key null$default null);
                                    public function 
                                getPost($key null$default null);
                                    public function 
                                getPath();
                                    public function 
                                getScheme();
                                    public function 
                                getIp();
                                    public function 
                                getUserAgent();
                                    public function 
                                getMethod();
                                    public function 
                                getHost(); 
                                    public function 
                                getPort();

                                Falls irgendwann irgendetwas fehlen sollte, dann läßt sich das so jederzeit leicht ergänzen. So bleibt man auch für die Zukunft gut gerüstet

                                Gibt’s gerade kein Request Objekt zur Hand, dann kann man sich eins temporär z.B. von Symfony oder Zend ausleihen und nur einen Adapter mit dem eigenen Interface implementieren (so mache ich das zurzeit, da ich keinen bock hatte auch noch eine RequestKlasse zu implementieren – ist auch nicht ganz trivial wenn man es richtig machen will).

                                Natürlich wird der Router dadurch etwas „umfangreicher“, das bedeutet allerdings nicht daß er auch in der Anwendung deutlich umständlicher zu handhaben sein muss.

                                Route::create($route, array $defaults = array(), array $envRestrictions = array(), array $paramRestrictions = array())

                                PHP-Code:
                                // Routen
                                $request = new Request();
                                $router = new Router();

                                $router->add(Route::create('/books', array('controller' => function() { echo "Bin im Books-Controller!"; })));
                                $router->add(Route::create('/admin', array('controller' => 'Books\\Admin'), array(ROUTE::SCHEME => 'https')));
                                $router->add(Route::create('/admin', array('controller' => 'Books\\Admin''action' => 'insecureConnection'), array(ROUTE::SCHEME => 'http')));

                                try {
                                    
                                $route $router->match($request);
                                    
                                // controller vorbereiten
                                    
                                $resolver = new Resolver();
                                    
                                $callable $resolver($route);
                                    
                                // und action….
                                    
                                $callable();
                                    
                                // usw ....
                                } catch (RouteNotFoundException $e) {
                                    
                                // Route nicht gefunden
                                } catch (Exception $e) {
                                    
                                // irgendwas anders ist schief gelaufen

                                vg
                                jack
                                -

                                Kommentar

                                Lädt...
                                X