Class Routing



  • Moin 😉

    In meinem Web-Application Framework wird nach Klassen geroutet. In der Routingtable ist dafür zu jedem URL ein Klassenname angegeben. Mit diesem Namen wird das ResponseObjekt erstellt wie folgt:

    $bin = readbinf(BINFILE); // Routingtable
    $class = isset($bin[$url]['class']) ? $bin[$url]['class'] : 'NotFound';
    require_once "$class.php"; 
    $BODY = ob_get_clean(); ob_start(); # Klassendatei kann HTML enthalten
    $ro = new $class (array('BODY' => $BODY, 'BIN' => $bin, 'URL' => $url, 'SESSION' => $SESSION));
    
    

    Mit C++ nun, geht das nicht so einfach. Bisher mache ich das so

            if( classname.compare("Form") == 0 )response->control(new Form);
            else response->control(new NotFound);
    
    

    usw. Gibt es eine Möglichkeit, den Namen der Klasse variable anzugeben? Danke im Vorab

    und MFG (Mit freundlichen Grüßen)



  • Ergänzung: Diese Klassen sind nur Dummies. Also es gibt die schon aber sie sind hohl:

    // Routing Klassen, Pseudoklassen
    class Form{};
    class NotFound{};
    class HTMLfile{};
    class PDFfile{};   // noch nicht fertig
    

    Diese Pseudoklassen (sic) habe ich nur, um die control()-Methode überlagern zu können. Das ermöglicht, mit bestimmten URLs bestimmte Conten-Types auszuliefern und natürlich auch an verschiedene URLs gebundene verschiedene Parameter-Kontroll-Strukturen (Verarbeitung von Formulareingaben). Des Weiteren ermöglicht diese Framework-Architektur das Setzen von Platzhaltern für bestimmte Webseiten die für die Ausgabe an den Browser über ein Template gerendert werden (dynamische Inhalte).

    In Fakt muss die main nur angepasst werden wenn eine neue Aufgabe betreff Eingabeverarbeitung oder Platzhalter ansteht.

    Vielleicht kann mans aber auch andes machn 😉

    MFG



  • Mahlzeit;

    so manche Idee führt in eine Sackgasse, das ist normal. Mittlerweile nimmt mein Class-Routing auch in C++ Gestalt an. Wobei es in meinem Fall egal ist, ob ich den Konstruktor einer Klasse aufrufe oder einfach nur eine Funktion. So habe ich mich für den einfachen Aufruf einer Funktion entschieden, siehe Code untenstehend bez. DateCalc. Auf das Framework bezogen ist DateCalc eine Erweiterung die in einer externen Datei definiert ist.

    #include "DateCalc.cpp"
    //////////////////////////////////////////////////////////////////////////////////////////
    int main(){
        binmode();
        Response response;
        try{
            string classname = response.classname();
            
            if( classname.compare("Form") == 0 )          Form( response );
            else if( classname.compare("Folder") == 0 )   Folder( response );
            else if( classname.compare("HTMLfile") == 0 ) {}
            else if( classname.compare("Env") == 0 )      Env( response );
            else if( classname.compare("DateCalc") == 0 ) DateCalc( response );
            else                                          NotFound( response );
            
            response.start_html();
            response.menu();
            response.body();
            response.footer();
            response.end_html();
        }
        catch(string errstr){
            cout << "Content-Type: text/plain; Charset=utf-8\n\n" << errstr;
            return 1;
        }
    
        // Alles gutgegangen
        cout << response.header();
        cout << response.start_html_buffer  
                + response.menu_buffer 
                + response.body_buffer
                + response.footer_buffer
                + response.end_html_buffer;
    
        return 0;  
    }
    

    Und der Code zeigt auch die Art und Weise der Einbindung anderer Erweiterungen. Das Deployment erfordert eine minimale Änderung der main mit anschließender Kompilierung. Ich habe für dieses Beispiel eine etwas ältere Library, die ich im Jahr 2008 zur Kalenderberechnung in C geschrieben habe wiederbelebt. Wer Interesse daran hat, melde sich einfach.

    Die Webanwendung ist diese da http://rolfrost.de/datecalc.chtml

    Schönen Sonntag 😉



  • Für mich klingt das eher so, als wenn du eine Art Factory bräuchtest.

    Also sowas (ungetestet hier rein getippt)

    class Response {
       virtual std::string header() const = 0;
       ...
    };
    // save name->create instance functions here
    std::map registry<std::string, std::function<std::unique_ptr<Response>()>>; 
    
    
    class DateCalc : public Response {
       ...
    };
    
    class Folder : public Response {
       ...
    };
    
    ...
    
    int main() {
        registry["DateCalc"] = [](){return std::make_unique<DateCalc>();};
        registry["Folder"] = [](){return std::make_unique<Folder>();};
    
        std::string classname = "get it from somewhere";
        auto obj = registry[classname]();
        std::cout << obj->header();
    }
    
    

    Also vom Prinzip eine Map machen, in der man die Name->Klasse Zuordnung speichert. Dann Objekt erzeugen und ausführen.

    Sicher könnte man die Resistry jetzt auch klüger machen. Und außerdem überlegen welche Funktionen man eigentlich will und braucht. Sollen die z.B. alle Strings liefern oder nicht lieber direkt in einen ostream schreiben?



  • @wob ,

    ja so könnte es auch gehen, danke Dir. Das würde aber bedeuten, daß alle Klassen verfügbar sein müssen und vom Request bis zur Response die Subklasse übernimmt.

    Mit der jetztigen Lösung jedoch gibt es nur einer Responseklasse und damit verfolge ich noch einen anderen Ansatz: Das dynamische Nachladen von Code. Damit meine ich, daß anstelle der festen Einbindung #include <DateCalc.cpp> eine DLL geladen wird, welche den Code für die Anwendung definiert. So wird der Code für die Anwendung nur dann geladen wenn ein Request-URL an diese Klasse gebunden ist. Andererseits, wenn einfach nur HTML-Seiten ausgeliefert werden, wird bspw. DateCalc nicht geladen, ebenso wird eine Instanz der CGI-Klasse auch nur dann erstellt wenn Eingaben (Parameter, POST, PUT usw.) zu verarbeiten sind.

    Ob man dieses dynamische Nachladen von Code auf Klassen oder einfach nur Methoden anwendet ist eine ander Frage.

    Viele Grüße und einen schönen Rest-Sonntag 😉



  • @_ro_ro Dann kannst du doch einfach in der zu ladenden Library 2 Funktionen anbieten: 1. den Namen, 2. eine Funktion, die das Objekt erzeugt. Dann noch irgendwo eine Konfigurationsdatei und du musst das Hauptprogramm nicht mehr neu erzeugen.



  • @wob sagte in Class Routing:

    @_ro_ro Dann kannst du doch einfach in der zu ladenden Library 2 Funktionen anbieten: 1. den Namen, 2. eine Funktion, die das Objekt erzeugt. Dann noch irgendwo eine Konfigurationsdatei und du musst das Hauptprogramm nicht mehr neu erzeugen.

    Genau das ist das Ziel 😉

    Danke Dir und viele Grüße.


Anmelden zum Antworten