Mein eigenes MVC-Framework: PreFilter und PostFilter und die Einbindung im FrontController

<< Zurück zur Übersicht

In diesem Kapitel geht es um etwas, was nicht unbedingt notwendig ist. Falls ihr es eilig habt, könnt ihr das auch überspringen. Es kann aber sein, dass bestimmte Teile des restlichen Frameworks später darauf aufbauen, was momentan jedoch nicht der Fall ist.

Und zwar geht es um Filter, mit denen man die Anfrage (Request) und die Antwort (Response) vor (PreFilter) bzw. nach (PostFilter) der Abarbeitung des Controllers manipulieren kann.

Dazu muss jeder Filter eine Methode implementieren, die ein FW_Http_Request- und ein FW_Http_Response-Objekt als Parameter hat. Wenn das nicht nach einem Interface schreit…

interface FW_Filter_Interface
{
  public function execute(FW_Http_Request $request, FW_Http_Response $response);
}

FW_Filter_Chain
Es soll möglich sein, mehrere Filter zusammenzufügen und nacheinander abarbeiten zu lassen. Dazu gibt es eine FW_Filter_Chain-Klasse, die so aussieht:

class FW_Filter_Chain implements FW_Filter_Interface
{
  private $filters = array();
  private $response = null;
  private $request = null;

  public function addFilter(FW_Filter_Interface $filter)
  {
    $this->filters[] = $filter;
  }

  public function execute(FW_Http_Request $req, FW_Http_Response $res)
  {
    foreach($this->filters as $filter)
    {
      $filter->execute($req, $res);
    }
  }
}

Wie man sieht, implementiert die Klasse das FW_Filter_Interface, weil sie nach außen wie ein Filter aussieht und auch so arbeitet. Der FrontController nimmt an, dass Objekte der Klasse FW_Filter_Chain die Filter selbst sind. Also ein Problem weniger!

Mit der addFilter-Methode kann man den eigentlichen Filter (oder wieder eine FW_Filter_Chain) hinzufügen. So läßt sich eine Baumstruktur realisieren.

Die execute-Methode ruft von jedem Filter die execute-Methode auf und sorgt so dafür, dass alle abgearbeitet werden.

Filter in den FrontController einbetten
Dazu ergänzt man einfach FW_FrontController um folgende Attribute:

  private $preFilters = array();
  private $postFilters = array();

und folgende Methoden:

  public function addPreFilter(FW_Filter_Interface $filter)
  {
    $this->preFilters->addFilter($filter);
  }

  public function addPostFilter(FW_Filter_Interface $filter)
  {
    $this->postFilters->addFilter($filter);
  }

Der Konstruktor sorgt dafür, dass $preFilters und $postFilters FW_Filter_Chain-Objekte sind, so dass mit addFilter gearbeitet werden kann:

  private function __construct()
  {
    $this->preFilters = new FW_Filter_Chain;
    $this->postFilters = new FW_Filter_Chain;
  }

In der run()-Methode des FrontControllers wird dann am Anfang die Filterkette $preFilters und am Ende $postFilters abgearbeitet. Der Aufbau der Methode ist dann in etwa so:

public function run(FW_Http_Request $request, FW_Http_Response $response)
  {
    $this->preFilters->execute($request, $response);
    $debugger = FW_Debugger::getInstance();

    $module = $request->getControllerName();
    $action = $request->getActionName();
    $action .= "_Action";

    $controllers = $this->controllerpath;
    $path = $controllers."/".FW_Controller_Abstract::getValidControllerFileName($module);
    if(file_exists($path))
    {
        require_once($path);
        $controller = "Controller_".$module;
        if(class_exists($controller, false))
        {
            $this->runSubControllers($request, $response, true); //runBeforeMainController
            $controller = new $controller($request, $response);
            if(FW_Controller_Abstract::isValid($controller))
            {
                try
                {

                  if(is_callable(array($controller, $action)))
                  {
                    $controller->$action();
                  }
                  else
                  {
                    $response->redirect("Error", "error404");
                  }
                  $this->runSubControllers($request, $response, false); //runAfterMainController
                  //Display Data with View
                  $view = FW_View::getView();
                  $view->display($response);
                }
                catch(Exception $e)
                {
                  echo $e->getMessage();
                }
            }
            else
            {
              $debugger->log("Der Controller ist nicht valid", __FILE__, __LINE__, "error");
            }
       }
       else
       {
        $debugger->log("Controllerklasse nicht gefunden: ".$controller, __FILE__, __LINE__, "error");
       }
    }
    else
    {
       $debugger->log("Controllerdatei nicht gefunden: ".$path."\n Eventuell ist der erste Buchstabe des Datein
                           amens nicht groß geschrieben. ", __FILE__, __LINE__, "error");
    }
    $this->postFilters->execute($request, $response);
    $response->send();
  }

Lasst euch vom Debugger nicht iritieren! Der wird später noch genau beschrieben.

Ein Beispiel für einen Filter
Ein mögliches Beispiel für einen FW_Filter wäre z.B. ein Filter, der die GET-Parameter prüft. Dieser wäre dann selbstverständlich ein PreFilter.

Hier zeige ich euch einen PostFilter, der vor dem Absenden der Response alles in Großbuchstaben umwandelt:

class Filter_Big implements FW_Filter_Interface
{
  public function execute(FW_Http_Request $request, FW_Http_Response $response)
  {
    $txt = $response->getContent();
    $txt = strtoupper($txt);
    $response->replaceContent($txt);
  }
}

(Die Datei sollte im Ordner projektname/classes/filter liegen und big.class.php heißen)

In der index.php müssen wir den Filter dann noch registrieren:

$myChain = new FW_Filter_Chain();
$myChain->addFilter(new Filter_Big());
$frontController->addPostFilter($myChain);

oder direkt so:

$frontController->addPostFilter(new Filter_Big());

Man sieht, die Sache ist sehr einfach!

Jetzt beschäftigen wir uns mit einer neuen Art der Controller: SubController

1 Star2 Stars3 Stars4 Stars5 Stars (Wurde noch nicht bewertet)
Loading...


7 Kommentare zu “Mein eigenes MVC-Framework: PreFilter und PostFilter und die Einbindung im FrontController”

  1. […] Mein eigenes MVC-Framework: PreFilter und PostFilter und die Einbindung im FrontController […]

  2. […] PreFilter und PostFilter und die Einbindung im FrontController […]

  3. totaler schrott… völlig durcheinander und nur zu ein viertel fertig, wenn überhaupt….

  4. Du solltest evtl. schreiben, was genau „zu ein viertel fertig“ ist.

  5. Was mich mir noch nicht so ganz erschlossen hat, ist folgendes:

    Ich habe jetzt einen neuen Command aufgebaut, bzw. bei mir sind das keine Commands, sondern Module, die jeweils in nem anderen Verzeichnis liegen (ich habe die Struktur nicht 1:1 so umgesetzt, wie hier besprochen).

    Nun möchte ich für die verschiedenen Module (oder halt auch Commands) die einzelnen Aktionen einbauen. Wie du auch oben besprochen hattest.

    Aber: für die einzelnen Aktionen habe ich auch manchmal einzelne Filter, so müssen z.b. bei einem Formular nachträglich die Benutzerdaten validiert werden. Jedoch möchte ich die nur bei dieser Aktion diese Filter registrieren.

    In der RUN Methode, die zum Frontcontroller gehört, müssen aber die PreFilters bereits vor Aufruf der Aktion ausgeführt werden.

    Wo bind ich denn nun die PreFilters ein, die nur zu dieser Aktion, sagen wir mal „writeComment“ gehören… nicht aber zu dem kompletten Modul.

    Außerdem noch etwas: du hast geschrieben, „In der index.php müssen wir den Filter dann noch registrieren:“. Widerspricht das nicht wieder dem MVC Charakter? Ich möchte doch diese Filter nicht hart in den Quellcode reinschreiben, sondern „zur Laufzeit“ hinzufügen können….

    VIelleicht hast du eine Idee für mich!

  6. Hi,

    Die Validierung von Daten würde ich nicht als Filter „missbrauchen“. Unter Filter verstehe ich Komponenten, die die Daten tatsächlich filtern, also z.B. schädliche Zeichen entfernen oder sowas in der Art.

    > Wo bind ich denn nun die PreFilters ein, die nur zu dieser Aktion, > sagen wir mal “writeComment” gehören… nicht aber zu dem kompletten > Modul.

    Da muss ich dir leider sagen, dass das so nicht geht. Zumindest noch nicht. Falls ich das irgendwann mal brauche, passe ich das FW dementsprechend an. Bisher habe ich aber noch keinen Einsatz für sowas gefunden.

    Vllt. kannst du den entsprechenden Teil des FCs ja selbst anpassen und hier von deinem Ergebnis berichten 😉 Wäre echt nett

    > Außerdem noch etwas: du hast geschrieben, “In der index.php
    > müssen wir den Filter dann noch registrieren:”. Widerspricht das > nicht wieder dem MVC Charakter? Ich möchte doch diese Filter
    > nicht hart in den Quellcode reinschreiben, sondern “zur Laufzeit” > hinzufügen können….

    Ja, auf der einen Seite hast du Recht, auf der anderen finde ich es aber oft nützlich, einen Filter überall anwenden zu lassen, also auf allen Controllern.

    Danke für deine Anregungen!
    Ich bemühe mich, deine Ideen demnächst umzusetzen

    MfG
    Simon

  7. Die aktuellste Version meines HMVC-Frameworks erhaltet ihr ab sofort immer hier: http://www.net-developers.de/blog/2011/02/13/download-info-shfw-hmvc-framework-in-php/

Hinterlasse einen Kommentar!

Time limit is exhausted. Please reload the CAPTCHA.

»Informationen zum Artikel

Autor: Simon
Datum: 19.02.2009
Zeit: 01:20 Uhr
Kategorien: Mein MVC-Framework
Gelesen: 6718x heute: 2x

Kommentare: RSS 2.0.
Diesen Artikel kommentieren oder einen Trackback senden.

»Meta