MVC-Architektur in Tntnet (Variante II.)

Standard

Wie schon im Artikel „MVC-Architektur in Tntnet (Variante I.)“ angekündigt, kommt hier eine alternative Variante, um eine MVC-Architektur in Tntnet zu realisieren. Diese Variante ist etwas einfacher in der Handhabung. Dafür stellt sie eine nicht ganz 100%-ig saubere Lösung dar. Denn hier wird erst der View aufgerufen; dieser ruft den Controller auf, der wiederum mit dem Model arbeitet. Klassischer Weise wird erst der Conroller und dann der View aufgerufen. Ein weitere Punkt ist sowohl ein Vor- wie ein Nachteil. Der Aufruf des Controllers wird nicht über das Routing gesteuert, da der View den Controller aufruft. Der Vorteil ist, dass sich eine einzige Route mit der Komponente verbindet. Das macht es einfacher und transparenter über URLs Zugriffsrechte zu kontrollieren oder generische Komponenten-Link-URLs zu verwenden. Dazu zu einem späterem Zeitpunk mehr. Jetzt erst mal zur konkreten Umsetzung der alternativen MVC-Variante.

Contoller

Die Controller-Klasse ist eine ganz normale C++-Klasse. Diese Klasse wird von dem View, der in der ecpp-Auszeichnungssprache erstellt wird, eingebunden. Bevor gezeigt wird, wie der View die logische Verarbeitung der Benutzereingaben an den Controller delegiert, wird hier erst mal ein exemplarischer Controller-Code gezeigt. Der gezeigte Controller soll die Kontrolle über den Login-Prozess übernehmen: Die Datei AlterLogInController.h:

#ifndef ALTERLOGINCONTROLLER_H
#define ALTERLOGINCONTROLLER_H

#include <Core/models/UserSession.h>
#include <tnt/httprequest.h>
#include <tnt/httpreply.h>
#include <iostream>

    class AlterLogInController
    {
        public:
            AlterLogInController (UserSession& userSession_): userSession(userSession_){};
            void operator() (
                tnt::HttpRequest& request,
                tnt::HttpReply& reply,
                tnt::QueryParams& qparam
            );
            std::string feedback;
            UserSession& userSession;
    };
#endif

Und die Datei AlterLogInController.cpp:

#include <Core/controller/AlterLogInController.h>
#include <Core/manager/WebACL.h>
#include <Core/models/UserSession.h>
#include <cxxtools/log.h>
#include <tnt/httprequest.h>
#include <tnt/httpreply.h>

log_define("Core.AlterLogInController")

void AlterLogInController::operator() (
    tnt::HttpRequest& request,
    tnt::HttpReply& reply,
    tnt::QueryParams& qparam)
{

    // define the query parameters
    std::string  arg_name     = qparam.arg<std::string>("arg_name");
    std::string  arg_password = qparam.arg<std::string>("arg_password");
    bool  arg_login_button    =  qparam.arg<bool>("arg_login_button");

    log_debug("authUser(" << arg_name << ", ***)");

    if ( arg_login_button ) {
        if ( WebACL::authUser ( arg_name, arg_password ) )
        {
            userSession.setUserName ( arg_name );
            userSession.addRoll (  WebACL::getRoll ( arg_name ) );
            reply.redirect ( "/home" );
        }
        else
        {
            log_debug("fail");
            feedback = "Login fehlgeschlagen!";
        };
    }
}

Das einzig Besondere an der Klasse ist, dass sie eine Methode "operator()" aufweist, der bestimmte Referenzen übergeben werden. Das sind Objekte der Klassen tnt::HttpRequest, tnt::HttpReply und tnt::QueryParams die in der ecpp-View-Umgebung zur Verführung stehen. Dem Controller werden die Referenzen auf diese Instanzen übergeben, damit dieser mit den Werten und Informationen weiter arbeiten kann. So z.B. stecken in tnt::QueryParams& qparam die übergebenen http-request-Parameter mit ihren Werten. In unserem Fall ist das der Name, das Passwort und ob der Button,  für das Abschicken des Login-Formulars geklickt wurde. Die Art wie die Parameter aus den übergebenen Objekt-Reverenzen heraus gelesen werden, ist die selbe wie im Artikel „MVC-Architektur in Tntnet (Variante I.)“ beschrieben. Nur ein kleiner Hinweis auf die Besonderheit des Funktion-Aufrufes reply.redirect ( "/home" );. Diese Funktion der Klasse tnt::HttpReply wird vm Tntnet-Framework bereitgestellt und dient dazu, auf eine andere Seite weiter zu leiten. In unserem Fall auf die Startseite /home. Wird der Login abgelehnt,  so wird eine Nachricht in der Klasseneigenschaft feedback für den View (/home) bereitgehalten. Dies geschieht in der Zeile

feedback = "Login fehlgeschlagen!";

Model

Für das Model gilt in dieser Variante II das Gleiche, wie in der I. Variante.

View

Im View gibt es bei dieser Variante einen entschiedenen Unterschied zur I. Variante:

<%session
    scope="shared"
    include="Core/models/UserSession.h" >
        UserSession userSession;
</%session>
<%request
    scope="shared"
    include="Core/controller/AlterLogInController.h">
        AlterLogInController  alterLogInController(userSession);
</%request>
<%cpp>
    alterLogInController.operator(
        request,
        reply,
        qparam
    );
</%cpp>

<!DOCTYPE HTML>
<html>
<head>
    <meta charset = "UTF-8" />
</head>
<body>
        <form method="post" >
            <h2>Login</h2>
% if ( alterLogInController.feedback != "" ) {
            <div class="feedback-box">
                <b><$ alterLogInController.feedback $> </b>
            </div>
% }
            <p>Für den gewählten Bereich muss du angemeldet sein. Bitte
            authentifiziere dich...
            </p>
            <p>Benutzer:<br>
                <input
                    class="full-size"
                    name="arg_name"
                    type="text"
                    size="40"
                    maxlength="40">
            </p>
            <p>Passwort:<br>
                <input
                    class="full-size"
                    name="arg_password"
                    type="password"
                    size="40"
                    maxlength="40"></p>
            <p>
                <button name="arg_login_button"
                            value="pushed"
                            type="submit">Login
                </button>
            </p>
        </form>
        </p><a href="NewAccount">Hier</a> kannst du dir ein Account erstellen</p>
</body>
</html>

Dem Konstruktor der Klasse AlterLogInController wird die Instanz der Kasse UserSession als Parameter mitgegeben. Die Klasse AlterLogInController braucht die Klasse UserSession nämlich, um die Information über einen erfolgreichen Login zu hinterlegen, damit andere Komponenten auf diese Information zugreifen können. In dem Abschnitt,der mit dem Tag <%cpp> umschlossen ist, wird der Controller dazu aufgefordert den Request entgegen zu nehmen und zu verarbeiten. In den <%cpp>-Tags kann man ganz normalen C++-Code einbetten. Weiter unten im ecpp-Code werden die Controller-Eigenschaften genutzt, um den View mit generischen Werten zu befüllen.

% if ( alterLogInController.feedback != "" ) {

Routing

Damit der View unter der gewünschten Rute vom Browser gefunden wird, muss diese noch gesetzt werden: alterLogInController.feedback app.mapUrl( "^/LogIn", "LogInView" ); Jetzt wird das Loginfenter unter http://DieDomain.de/LogIn zu erreichen sein. Es ist möglich mehrere Routen zu ein und der selben Komponente zu definieren. Allerdings sollte man sein ACL-Konzept nicht auf Basis von URLs realisieren, weil man dann u.U. seine eigenen ACLs ungewollt austrickst. Die Regel „halte es einfach“ ist bei dem Thema Routing sicher zu empfehlen.


Creative Commons Lizenzvertrag

Advertisements

Ein Gedanke zu “MVC-Architektur in Tntnet (Variante II.)

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s