Klaus: OOP Konflikt

Moinsen.

Folgendes.

Zurzeit arbeite ich an einemBoard/Forum.

Nun. Dieses Board/Forum hat verschiedene Kategorien, in den Kategorien sind Threads und in den Threads wird natürlich mit Posts geantwortet.
Die Kategorien können Unterkategorien haben und diese können auch wieder Unterkategorien haben.

So.

OOP ausgedrückt habe ich das ganze mal in 3 Klassen formuliert:

class.Category
--------------

# zeigt Kategorien und Unterkategorien Kategorie 1 -> Kategorie 2 -> Kategorie 1 -> 3  
showCategoryStructur()  
  
# Holt mir alle Kategorien in ein Array  
allCategories2Array()  
  
# löscht eine Kategorie  
delCategory()  
  
# benennt eine Kategorie um  
renameCategory()  
  
# fügt eine Kategorie hinzu  
addCategory()  
  
# Listet die Kategorien und gibt sie aus  
listCategories()  

class.Article
-------------

# holt alle Threads der Kategorie  
allArticleOfCategory  
  
# holt einen Thread + Antworten  
oneArticle()  
  
# zeigt die X neusten Threads  
newestArticles(x)  
  
# erstellt neuen Thread  
mkNewArticle()  
  
# löscht einen Thread  
delArticle()  
  
# editiert einen Thread  
editArticle()  
  
# Macht Thread (un-)sichtbar  
setArticlesVisibility()  
  
# gibt Thread + Antworten aus  
showArticle()  
  
# erstellt eine Antwort zu einem Thread  
answerArticle()  
  
# zeigt ein Formular zum erstellen/editieren eines Artikels  
showArticleForm()  
  
# generiert eine Vorschau  
previewArticle()  
  
# bewertet einen Thread  
rateArticle()

Beide Klassen sollen nun in der class.Board kombiniert werden.
Im Konstruktor der Board-Klasse werden nun Requests abgefangen und entsprechend behandelt. Wenn ich z.B. auf den "löschen"-Button klicke, steht im Konstruktor
if(isset($_POST['del'])) Article::delArticle();

So in etwa. Würdet ihr das mit dem Abfangen von Requests genauso machen?
Anders wüsste ich nicht wie ich das machen soll.

Aber das ist auch schon ein Problem. Eine Klasse bekommt _zwei_ Klassen.

Ich möchte allerdings das NUR die Boardklasse auf die Category und Article Klassen zugreifen darf. Damit fällt das statisch machen schonmal weg, denn dann, kann ja jeder darauf zugreifen.
Oder gibt es da eine Möglichkeit?

Wie würdet ihr das ganze machen? Oder würdet ihr daraus eine große Boardklasse machen?

Liebe Grüße,

Klaus

  1. echo $begrüßung;

    Wie würdet ihr das ganze machen? Oder würdet ihr daraus eine große Boardklasse machen?

    Ich würde das Ganze nach dem MVC-Pattern aufbauen. Schau dir mal an, wie man mit dem Zend Framework eine Anwendung erstellt.

    echo "$verabschiedung $name";

    1. Hallo.

      Ich würde das Ganze nach dem MVC-Pattern aufbauen. Schau dir mal an, wie man mit dem Zend Framework eine Anwendung erstellt.

      Wenns geht möchte ich ohne irgend ein Framework auskommen ;).
      Das MVC-Pattern werde ich mir mal anschauen.

      LG,

      Klaus

      1. echo $begrüßung;

        Wenns geht möchte ich ohne irgend ein Framework auskommen ;).

        Es ist aber immer eine gute Idee, sich von anderen inspirieren zu lassen. Versuch nicht, die eierlegende Wollmilchsau zu programmieren. Das wird am Ende ein unwartbares Gebilde. Die Natur hat schon gewusst, warum sie für jede Aufgabe eine eigene Klasse entwickelt hat ... oder so ähnlich :-)

        echo "$verabschiedung $name";

    2. Hi.

      Ich würde das Ganze nach dem MVC-Pattern aufbauen. Schau dir mal an, wie man mit dem Zend Framework eine Anwendung erstellt.

      Hm und wie würdest du das machen?
      Also soll ich nur das Board-System so aufbauen oder die komplette Seite?
      Also nach die Klassen die hinzukommen werden wie Navigation, Registrierung, Login/Out, Kontaktformular usw.. alles zusammen als EIN MVC Pattern? Alles einzelnd als MVC Pattern?

      Weil bisher ist meine Kontaktklasse zum Beispiel eine eigene einzelne Klasse.
      D.h. M, V und C in einer Klasse.

      Und dann Artikel, Kategorien einzelnd oder alles zusammen ein MVC?

      Lg

      1. echo $begrüßung;

        » Ich würde das Ganze nach dem MVC-Pattern aufbauen. Schau dir mal an, wie man mit dem Zend Framework eine Anwendung erstellt.
        Hm und wie würdest du das machen?
        Also soll ich nur das Board-System so aufbauen oder die komplette Seite?

        Alles oder nichts. Gemischt wird unübersichtlich.

        Also nach die Klassen die hinzukommen werden wie Navigation, Registrierung, Login/Out, Kontaktformular usw.. alles zusammen als EIN MVC Pattern? Alles einzelnd als MVC Pattern?

        Diverse vorbereitende Abläufe sind im MVC-Teil schlecht aufgehoben, weil sie für jeden Controller implementiert werden müssten. Es wird sicher eine Superklasse für alle Controller geben, doch auch da sind diese gemeinsamen Teile fehlplatziert. Als "Türwächter" gibt es dazu einen Front Controller. Der ermittelt nicht nur, welcher Controller aufgerufen werden muss, er kümmert sich auch um Authentifizierung und Autorisierung des jeweiligen Requests, denn das muss ja vor dem Controller-Aufruf passieren.

        Registrierung, Login/-out und Kontaktformuler sind Aufgaben für Controller. Wenn du unter Navigation das Erstellen von HTML-Code für Menüs und dergleichen meinst, dann ist das Aufgabe der Views. Die bedienen sich für das HTML-Grundgerüst und gemeinsame Teile der Ausgabe am besten eines Master-Templates.

        Und dann Artikel, Kategorien einzelnd oder alles zusammen ein MVC?

        Überleg dir, welche Abläufe zur gleichen Aufgabengruppe gehören und bau für jede dieser Aufgabengruppen einen Controller. Der dirigiert aber nur, sorgt dafür, dass die Daten aus der richtigen Quelle (Model) abgefragt werden und ans richtige Ziel (View) gelangen. Das Daten-Handling übernimmt das Model und sämtliche Aufbereitung für die Ausgabe macht die View.

        Sehr schön ist das MVC-Pattern auch für die jüngst freigegebene MVC-Implementierung für ASP.NET beschrieben. Der Code dort ist zwar Visual Basic .NET und C# und einige Dinge auch .NET-spezifisch, aber das Prinzip der Aufgabenteilung zwischen den Bestandteilen des MVC sollte auch so zu erkennen sein.

        echo "$verabschiedung $name";

        1. echo $begrüßung;

          »» » Ich würde das Ganze nach dem MVC-Pattern aufbauen. Schau dir mal an, wie man mit dem Zend Framework eine Anwendung erstellt.
          »» Hm und wie würdest du das machen?
          »» Also soll ich nur das Board-System so aufbauen oder die komplette Seite?

          Alles oder nichts. Gemischt wird unübersichtlich.

          D.h. also das jede Klasse, die auch nur eine visuelle Ausgabe hat, 3 Dateien hat. Einmal Model wo berechnungen und Queries ausgeführt werden und einmal Views wo alles ausgegeben wird und einmal Controller wo Model aufgerufen und an Views übergeben wird usw...

          Bei 10 Klassen sind das 30 Dateien.
          Wie handelt ihr das denn dann?
          newsletter.m.php
          newsletter.v.php
          newsletter.c.php

          ?

          Und dann pro Klasse ein eigener Ordner?

          »» Also nach die Klassen die hinzukommen werden wie Navigation, Registrierung, Login/Out, Kontaktformular usw.. alles zusammen als EIN MVC Pattern? Alles einzelnd als MVC Pattern?

          Diverse vorbereitende Abläufe sind im MVC-Teil schlecht aufgehoben, weil sie für jeden Controller implementiert werden müssten.

          Verstehe ich nicht was du meinst.

          Es wird sicher eine Superklasse für alle Controller geben, doch auch da sind diese gemeinsamen Teile fehlplatziert.

          Ja es gibt eine Klasse die nennt sich bei mir "loadController" dort werden Requests abgefangen und bearbeitet und die dementsprechende Klasse includet und die gewünschte Methode ausgeführt falls du das meinst.

          »» Als "Türwächter" gibt es dazu einen Front Controller. Der ermittelt nicht nur, welcher Controller aufgerufen werden muss,

          Ja das macht mein "loadController".

          er kümmert sich auch um Authentifizierung und Autorisierung des jeweiligen Requests, denn das muss ja vor dem Controller-Aufruf passieren.

          Hm Authentifizierung und Autorisierung sieht bei mir bisher nur so aus das gecheckt wird, ist folgendes vorhanden?: Klassendatei, Klasse, Methode

          Registrierung, Login/-out und Kontaktformuler sind Aufgaben für Controller.

          Ja aber diese Klassen zeigen ja auch das Login Formular und das Registrierungsformular und den Logoutbutton.
          Also muss ich auch bei diessen 3 Dateien machen M, V, C.

          Wenn du unter Navigation das Erstellen von HTML-Code für Menüs und dergleichen meinst, dann ist das Aufgabe der Views. Die bedienen sich für das HTML-Grundgerüst und gemeinsame Teile der Ausgabe am besten eines Master-Templates.

          Puh also wirds komplizierter als ich dachte.

          REQUEST -> Master-Controller-Klasse -> Master-Model-Klasse-> loadController -> KontaktKlasse-Controller -> KontaktKlasse-Model

          RESULT von KontaktKlassen-Model->  KontaktKlassen-Controller -> KontaktKlasse-View

          RESULT  von KontaktKlassen-View -> KontaktKlassen-Controller -> Master-Model-Klasse -> Master-Controller-Klasse

          Master-Controller-Klasse -> Master-View-Klasse -> AUSGABE

          Das ist doch viel zu kompliziert!
          Oder versteh ich da was falsch?

          »» Und dann Artikel, Kategorien einzelnd oder alles zusammen ein MVC?

          Überleg dir, welche Abläufe zur gleichen Aufgabengruppe gehören und bau für jede dieser Aufgabengruppen einen Controller. Der dirigiert aber nur, sorgt dafür, dass die Daten aus der richtigen Quelle (Model) abgefragt werden und ans richtige Ziel (View) gelangen. Das Daten-Handling übernimmt das Model und sämtliche Aufbereitung für die Ausgabe macht die View.

          S.o. ich blicke nicht mehr durch... bitte hilf mir.

          lg, Klaus

          1. echo $begrüßung;

            D.h. also das jede Klasse, die auch nur eine visuelle Ausgabe hat, 3 Dateien hat. Einmal Model wo berechnungen und Queries ausgeführt werden und einmal Views wo alles ausgegeben wird und einmal Controller wo Model aufgerufen und an Views übergeben wird usw...

            Das muss nicht so sein. Gegebenenfalls kann man Models oder Views mehrfach verwenden. Natürlich nur dann, wenn die selbe Aufgabe mehrfach benötigt wird. Es sollte nicht so sein dass beispielsweise eine View mal das Kontaktformular und mal Forumsbeiträge liefert. Sie kann aber je nach Anmeldezustand die gewünschte Ausgabe bringen oder auch nur, dass man sich erst anmelden müsse.

            Auch ist es nicht so, dass M, V und C immer ein 1:1:1-Verhältnis bilden. Ein Controller kann durchaus mehrere Views bemühen, um die komplette Ausgabe zu erstellen oder je nach konkreter Aufgabenstellung eine unterschiedliche View mit der Ausgabe beauftragen. Es kommt immer darauf an, wie sich die Aufgaben am besten ein übersichtliche Einzelteile separieren lassen.

            Es kann sich auch ergeben, dass für die Erledigung der gesamten Aufgabe mehrere Controller-Actions benötigt werden. Wenn die Seite modular aufgebaut ist, kann jedes Modul (Menü, Login-Bereich, Hauptinhalt, News des Tages, Werbung, ...) von einem eigenen Controller (und dessen Actions) behandelt werden und die Ausgaben zusammen eine Seite bilden.

            Bei 10 Klassen sind das 30 Dateien.
            Und dann pro Klasse ein eigener Ordner?

            Meist werden die Klassen in die Ordner Models, Views und Controllers sortiert. Unterordner, beispielsweise um Views zu gruppieren, sind auch möglich. Der Fantasie und Ordnungsliebe sind hier keine Grenzen gesetzt.

            Ich empfahl doch schon mal das Zend Framework. Schau mal in den Quickstart, da siehst du unter anderem, wie eine Verzeichnisstruktur aussehen kann.

            » »» Also nach die Klassen die hinzukommen werden wie Navigation, Registrierung, Login/Out, Kontaktformular usw.. alles zusammen als EIN MVC Pattern? Alles einzelnd als MVC Pattern?
            » Diverse vorbereitende Abläufe sind im MVC-Teil schlecht aufgehoben, weil sie für jeden Controller implementiert werden müssten.
            Verstehe ich nicht was du meinst.

            Das sollte eigentlich mit dem Nachfolgenden deutlicher werden. Der Prozess der Benutzeridentifikation, so du eine implementieren möchtest, wird für alle Requests benötigt. Bestimmte Aufgaben (Controller und deren Actions) dürfen nicht ohne Autorisierung aufgerufen werden. Diese Prüfungen in die Controller oder Actions zu verlagern bläht diese nur auf und dupliziert vielleicht nicht den gesamten Autorisierungscode aber zumindest die immer gleichen Aufrufe. Stattdessen prüft der Front Controller und leitet die Aufrufe im Nicht-Berechtigt-Fall an einen anderen Controller oder zumindest an eine andere Action weiter.

            » Es wird sicher eine Superklasse für alle Controller geben, doch auch da sind diese gemeinsamen Teile fehlplatziert.

            Ja es gibt eine Klasse die nennt sich bei mir "loadController" dort werden Requests abgefangen und bearbeitet und die dementsprechende Klasse includet und die gewünschte Methode ausgeführt falls du das meinst.

            Das meinte ich nicht damit. Dein loadController wird sicher nicht die Basisklasse für die anderen Klassen sein, die dann von ihm erben (... extends loadController).

            »» Als "Türwächter" gibt es dazu einen Front Controller. Der ermittelt nicht nur, welcher Controller aufgerufen werden muss,
            Ja das macht mein "loadController".

            Dann hast du damit bereits das Front-Controller-Pattern implementiert, ohne dass du es wusstest. (So funktioniert das mit den Pattern. Man kann sie nicht einfach erfinden, man erkennt aus eigener Erfahrung oder der Erfahrungen mehrerer (auch unabhängiger) Entwickler, dass es ein Muster gibt, wie man bestimmte Aufgaben erledigen kann, beschreibt dieses Muster und gibt dem Kind einen Namen.)

            » er kümmert sich auch um Authentifizierung und Autorisierung des jeweiligen Requests, denn das muss ja vor dem Controller-Aufruf passieren.
            Hm Authentifizierung und Autorisierung sieht bei mir bisher nur so aus das gecheckt wird, ist folgendes vorhanden?: Klassendatei, Klasse, Methode

            Das ist keine Authentifizierung und Autorisierung sondern ein Prüfen des Requests, ob dieser eine Aktion verlangt, die es auch tatsächlich gibt. Im Webserver wäre das die Ausgabe einer 404-Meldung, wenn die auszuliefernde Ressource nicht gefunden werden konnte.

            » Registrierung, Login/-out und Kontaktformuler sind Aufgaben für Controller.
            Ja aber diese Klassen zeigen ja auch das Login Formular und das Registrierungsformular und den Logoutbutton.
            Also muss ich auch bei diessen 3 Dateien machen M, V, C.

            Nicht immer wird ein Model benötigt und es kann auch Aufgaben geben, die in sich selbständig sind, aber keine Ausgabe erzeugen (Formulardaten waren fehlerfrei, Datenbank wurde aktualisiert und der Client wird mit einem Redirect woanders hingeschickt).

            » Wenn du unter Navigation das Erstellen von HTML-Code für Menüs und dergleichen meinst, dann ist das Aufgabe der Views. Die bedienen sich für das HTML-Grundgerüst und gemeinsame Teile der Ausgabe am besten eines Master-Templates.

            Oder ergänzend zu dieser Aussage: Wie oben erwähnt kann man einzelnen Modulen auch eigene Controller spendieren, wenn die notwendigen Schritte (Code) zum Erzeugen der Ausgabe umfangreicher werden.

            Puh also wirds komplizierter als ich dachte.

            Das MVC-Pattern ist ein recht mächtiges Muster. Man kann mit ihm sehr flexibel und einfach erweiterbar eine Aufgabenstellung lösen. Aber Flexibilität kommt immer mit Komplexität daher. Der anfängliche Mehraufwand rentiert sich erst später. (Hinzu kommt noch das Lehrgeld, wenn man wenig Erfahrung mit einer neuen Technik hat.)

            Das ist doch viel zu kompliziert!
            Oder versteh ich da was falsch?

            Einige Schritte implementierst du ja nur einmal. Sie müssen zwar immer wieder abgearbeitet werden, aber das passiert ja ohne dein Zutun, wenn sie einmal fehlerfrei implementiert wurden. Wenn eine neue URL-Verarbeitungsregel hinzukommt, schreibst du die einfach zu den anderen hinzu

            /{controller}/{action}  - Default-Regel
            /{controller}/{action}/{parameter1}/{parameter2} - neue Regel

            Der Router im Front Controller perst die Regel, erkennt die Schlüsselwörter controller und action, weiß damit, welche Controller-Action aufzurufen ist und übergibt die ihm unbekannten parameter1 und 2 als Parameter an die Action.

            Wenn benötigt: Authentifizierung kann man als Plugin für den Front Controller lösen, wenn man das Zend Framework verwendet, Autorisierung ebenso. Ansonsten kann man das auch anderweitig als abzuarbeitende Schritte des Front Controllers implementieren.

            S.o. ich blicke nicht mehr durch... bitte hilf mir.

            Vermutlich ist es durch meine Ausführungen nicht besser geworden. Vielleicht gewinnst du die Übersicht wieder, wenn du dir mal eines der vorhandenen PHP-Frameworks nimmst, dein Projekt erst einmal auf Eis legst und dich in die Konzepte dieses Frameworks einarbeitest. Die erscheinen (hoffentlich) in sich einheitlicher als meine mal in die eine, mal in die andere Richtung gehenden Anmerkungen.

            Wenn ich mir anscheinend teilweise widerspreche, so liegt das daran, dass es keinen starren Weg zu einer Lösung gibt. Je nachdem, welchen Weg man aus welchen Gründen auch immer einschlägt, ergibt sich die eine oder die andere Möglichkeit als hilfreich zur Zielerreichung.

            echo "$verabschiedung $name";

            1. Also die einzelnen Klassen zu unterteilen in M, V und C ist mit denk ich verständlich geworden.

              Wie ich aber das ganze jetzt Modul-/Klassenübergreifend machen kann ist mir nicht klar.

              Eine einzelne Klasse würde ich jetzt so aufbauen.

              Als Beispiel nehme ich jetzt mal die Boardklasse.

              Ordnerstruktur:

              Board
              Board -> boardController.php
              Board -> Model -> boardModel.php
              Board -> View -> boardView.php

              Demnach würden die Dateien etwa so aufgebaut sein:

              model.php:

                
              class boardModel{  
                
                public function __construct(){}  
                
                // Holt alle Einträge eines bestimmten Datums  
                public function getArticlesFromDate($date){  
                  $resultArray=// Query  
                  return $resultArray;  
                }  
              }  
              
              

              boardController.php

                
              class boardController{  
                
                const A_FROM_DATE = 1;  
                
                public function __construct(array $params){  
                
                  $model = new boardModel();  
                
                  if($params['whatToDo']==A_FROM_DATE){  
                    $this->viewBoard($model->getArticlesFromDate($params['condition']), "articles");  
                  }  
                }  
                
                // Verwaltet die Anzeige  
                public function viewBoard($articles='',$what=''){  
                  $view = new boardView($articles);  
                
                  $view->showBoardHeader();  
                
                  $numberOfArticles=count($articles);  
                  foreach($articles as $s){  
                    $view -> toDo($what);  
                  }  
                
                  $view->showBoardFooter();  
                }  
              }  
              
              

              boardView.php

                
              class boardView{  
                
                private $toShow;  
                
                public function __construct(array $toShow=array()){  
                 $this->toShow = $toShow;  
                }  
                
                public function showBoardHeader(){}  
                public function showBoardFooter(){}  
                
                public function toDo($what){  
                  switch($what){  
                    case 'articles':  
                      $showMe="<h2>".$this->toShow['title']."</h2>;  
                      break;  
                    case 'categories':  
                      $showMe="<ul>";  
                      foreach($this->toShow as $show){  
                        $showMe.="<li>".$show['category']."</li>;  
                      $showMe="</ul>"  
                      break;  
                  }  
                  echo $showMe;  
                }  
              }  
              
              

              So in etwa? Und das mit jeder Klasse?
              oder sollte das alles eher so aussehen:

              Ordnerstruktur:

              index.php
              FrontController.php
              View.php

              Models->NewsletterModel.php
              Models->ContactModel.php
              Models->BoardModel.php

              Views->NewsletterView.php
              Views->ContactView.php
              Views->BoardView.php

              Controllers->NewsletterController.php
              Controllers->ContactController.php
              Controllers->BoardController.php

              Bei einem Request für den Newsletter würde folgendes passieren:

              Der in der index.php inkludierte FrontController würde den NewsletterController aufrufen welcher die Anfrage an das NewsletterModel weiterleitet, und die Daten danach an NewsletterView übergibt. Die Ausgabe würde der Front Controller an View.php weitergeben welche ebenfalls in der index.php inkludiert ist.

              ?!

              Ich hab mir das ZendFramework angeguck tund auch runtergeladen aber leider ist mir aus der Ordnerstruktur kein M, V, C nachvollziehbar. Sagen wir so - zu kompliziert und es heißt halt nicht Model, View, Controller.

              lg,

              Klaus

              1. echo $begrüßung;

                Also die einzelnen Klassen zu unterteilen in M, V und C ist mit denk ich verständlich geworden.
                Wie ich aber das ganze jetzt Modul-/Klassenübergreifend machen kann ist mir nicht klar.

                Fehler zu machen, wenn man das erste Mal mit einer Technik in Berührung kommt, ist ganz natürlich. Aus deinen Ausführungen entnehme ich aber, dass dir noch grundlegende Implementierungsdetails unbekannt sind. Ein Controller entscheidet nicht, was auszuführen ist, sondern kümmert sich nur um das Wie. Die Was-Entscheidung obliegt dem Router. Der ermittelt, welche Action eines Controllers aufzurufen ist. Ein Controller kann mehrere Aufgaben eines Themengebiets bündeln. Die Abarbeitung dieser Teilaufgaben obliegt den Actions, was nichts anderes als öffentliche Methoden des Controllers sind. Nichtöffentliche Methoden können Hilfsfunktionen für eine oder mehrere Actions ausführen. Der Routing-Prozess ist Teil des Front Controllers. Der Front Controller ist aber kein direkter Bestandteil des MVC-Patterns, auch wenn er das Wort Controller im Namen führt. Das MVC-Pattern wird jedoch gern mit einen Front Controller verbunden, denn irgendwer muss ja die Actions der MVC-Controller aufrufen.

                Eine einzelne Klasse würde ich jetzt so aufbauen.
                Ordnerstruktur:

                Board
                Board -> boardController.php
                Board -> Model -> boardModel.php
                Board -> View -> boardView.php

                Ich sehe hier wieder die 1:1:1-Zuordnung. Vermutlich wird das Board aber mehrere Arten der Darstellung haben. Anzeige der Themenbereiche, Anzeige der Überschriften der Beiträge eines Themas, Anzeige eines Beitrags inklusive Antworten, Formular für einen neuen Beitrags, Formular für eine Antwort. Die beiden Formular-Ansichten unterscheiden sich vermutlich nur geringfügig, weswegen man sie sicher in einer View unterbringen kann. Alle anderen sind aber besser in jeweils einer eigenen View aufgehoben, sonst hat man eine schlecht wartbare Riesenview.

                Die Verzeichnisstruktur wüede ich andersrum aufbauen (was auch üblicher ist). Alle (MVC-)Controller (den Front Controller also nicht) in ein Controllers-Verzeichnis, alle Models in ein Models-Verzeichnis und die Views ebenso. Innerhalb des Views-Verzeichnisses kann man ja dann die Board-spezifischen Views in ein Unter-Verzeichnis einsortieren.

                Auch das Model kann man verschieden gestalten. Zum einen könnte es ein Model pro Tabelle im DBMS geben. Für das Board braucht es dann mehrere Models, beispielsweise eins für die Themen und eins für die Beiträge. Zum anderen kann man auch nur ein Model für das Board erstellen und über eine Methode die Themen anfordern, über eine andere die Beiträge. Wo das Model die Daten herholt ist dem Controller egal, oder besser: das muss dem Controller egal sein. Je weniger er über die Interna des Models Bescheid weiß, desto besser lassen sich diese bei Bedarf ändern, ohne dass das einen Änderungsaufwand an anderen Stellen des Gesamtkunstwerkes nach sich zieht.

                model.php:

                Soweit so gut.

                boardController.php

                Der aber nicht mehr.

                class boardController{

                const A_FROM_DATE = 1;

                public function __construct(array $params){

                $model = new boardModel();

                if($params['whatToDo']==A_FROM_DATE){
                      $this->viewBoard($model->getArticlesFromDate($params['condition']), "articles");
                    }
                  }

                Der Controller erfüllt mehrere Aufgaben rund um das Board. Diese kommen jede in eine eigene Action. Wenn alle das Model brauchen, so kann man es durchaus im Constructor initialisieren und in einer Objektvariable ablegen. Die konkrete Datenabfrage muss aber die jeweilige Action selbst machen, denn jede braucht ja unterschiedliche Daten.

                // Verwaltet die Anzeige
                  public function viewBoard($articles='',$what=''){
                    $view = new boardView($articles);

                $view->showBoardHeader();

                $numberOfArticles=count($articles);
                    foreach($articles as $s){
                      $view -> toDo($what);
                    }

                $view->showBoardFooter();
                  }
                }

                Des Controllers Aufgabe ist eigentlich auch nicht, die Ausgabe zusammenzustellen. Er soll lediglich die passenden (Roh-)Daten an die View liefern, die sich um den Rest kümmert. Dazu gehört auch das Iterieren über die Datenmenge. Das wird zweifellos und sinnvollerweise für die Ausgabe benötigt, aber letztlich liegt das in der Hand der View, ob sie das macht und wenn ja, wie sie das tut, denn nur sie weiß, wie die Daten für die Ausgabe am besten zu durchlaufen sind.

                boardView.php

                Die kommentiere ich nicht extra, denn in meinen obigen Ausführungen stehen (so hoffe ich) genug Hinweise dazu. Nur so viel: Vergiss nicht die kontextgerechte Behandlung der Ausgabewerte (Stichwort: htmlspecialchars()). Auch das ist Aufgabe der View.

                oder sollte das alles eher so aussehen:

                Ah ja, hier hast du es ja in der üblichen Strukturierweise angeordnet. Besser so, zuzüglich der obigen Anmerkungen.

                Bei einem Request für den Newsletter würde folgendes passieren:
                Der in der index.php inkludierte FrontController würde den NewsletterController aufrufen welcher die Anfrage an das NewsletterModel weiterleitet, und die Daten danach an NewsletterView übergibt. Die Ausgabe würde der Front Controller an View.php weitergeben welche ebenfalls in der index.php inkludiert ist.

                Wenn View.php die grundsätzliche Struktur der Webseiten enthält und der NewsletterController (oder besser: eine seiner Views) nur noch den einzufügenden HTML-Teil liefert, dann ist das eine mögliche Herangehensweise.

                Ich hab mir das ZendFramework angeguck tund auch runtergeladen aber leider ist mir aus der Ordnerstruktur kein M, V, C nachvollziehbar. Sagen wir so - zu kompliziert und es heißt halt nicht Model, View, Controller.

                Der zweite Code-Sample-Kasten von Create Your Project aus dem Quickstart zeigt eine der möglichen Verzeichnisstrukturen. Das Verzeichnis tests ist erstmal uninteressant, in library stehen die Dateien des Zend Framworks und weiterer allgemeiner Bibliotheken, die keinen spezifischen Bezug zu deiner Anwendung haben. Das Verzeichnis public ist das DocumentRoot des Webservers. Wenn man http://domain.example.com/ aufruft, muss man dorthin kommen. Die anderen Verzeichnisse liegen alle neben dem DocumentRoot und sind somit nicht direkt per HTTP-Request erreichbar. Als weiterer Inhalt des public-Verzeichnisses kommen statische Ressourcen wie CSS-Dateien und Bilder in Frage. In der public/index.php residiert nur wenig Code, der den Aufruf des Bootstraps vorbereitet und erledigt.

                Das wichtigste Verzeichnis ist application, da findest du neben Bootstrap und einem Verzeichnis für Konfigurationsdaten die Verzeichnisse für Controller, Models und Views. Da Index- und ErrorController recht einfach sind, gibt es für die beiden auch nur jeweils eine View, ansonsten lägen in index und error (passend jeweils zum Namen des Controllers) mehr Dateien. Es gibt auch noch ein Verzeichnis helpers, in dem für die Ausgabe benötigte Hilfsfunktionen abgelegt werden können. Eine Datenmenge zum Beispiel als Liste darzustellen, muss man nicht in jeder View <ul><li>... inklusive Schleife notieren, man übergibt besser die Daten einer Helper-Funktion, die die Listendarstellung erzeugt.

                Das Models-Verzeichnis ist leer. Das muss so sein. Es gibt auch keine Basisklasse für Models im Zend Framework. Die Aufgaben eines Models sind stark von der Geschäftslogik der Anwendung abhängig und zu individuell, um eine für viele Zwecke verwendbare gemeinsame Grundlage zu erstellen. Ein einfaches Model besteht aus einer Klasse mit einer Methode, die (etwas untertrieben) vielleicht zwei Zahlen zusammenrechnet. Es gibt aber sehr wohl Hilfsmittel für die Models, beispielsweise Klassen, die sich mit Datenbankzugriff oder Webservices beschäftigen. Auf diese Hilfsmittel kann ein Model zugreifen, um seine Aufgabe zu erledigen.

                echo "$verabschiedung $name";

                1. Hi.

                  Fehler zu machen, wenn man das erste Mal mit einer Technik in Berührung kommt, ist ganz natürlich. Aus deinen Ausführungen entnehme ich aber, dass dir noch grundlegende Implementierungsdetails unbekannt sind. Ein Controller entscheidet nicht, was auszuführen ist, sondern kümmert sich nur um das Wie. Die Was-Entscheidung obliegt dem Router. Der ermittelt, welche Action eines Controllers aufzurufen ist. Ein Controller kann mehrere Aufgaben eines Themengebiets bündeln. Die Abarbeitung dieser Teilaufgaben obliegt den Actions, was nichts anderes als öffentliche Methoden des Controllers sind. Nichtöffentliche Methoden können Hilfsfunktionen für eine oder mehrere Actions ausführen. Der Routing-Prozess ist Teil des Front Controllers. Der Front Controller ist aber kein direkter Bestandteil des MVC-Patterns, auch wenn er das Wort Controller im Namen führt. Das MVC-Pattern wird jedoch gern mit einen Front Controller verbunden, denn irgendwer muss ja die Actions der MVC-Controller aufrufen.

                  Moment - das mit den Actions ist jetzt was verwirrend.
                  Also ein FrontController reagiert z.B. auf Formulareingaben, und instanziert dann die passende Klasse die durch __autoload() nachgeladen werden und ruft den passenden Controller auf, dieser entscheidet dann ein zweites mal, an welche Methode die Daten in "Models" müssen und lässt das Ergebnis dann in "Views" ausgeben.

                  Richtig?

                  Der Controller erfüllt mehrere Aufgaben rund um das Board. Diese kommen jede in eine eigene Action. Wenn alle das Model brauchen, so kann man es durchaus im Constructor initialisieren und in einer Objektvariable ablegen. Die konkrete Datenabfrage muss aber die jeweilige Action selbst machen, denn jede braucht ja unterschiedliche Daten.

                  Definiere Action und gebe mir ein kleines CodeBeispiel für einen Controller bitte. Reicht in Pseudo.

                  »» boardView.php

                  Die kommentiere ich nicht extra, denn in meinen obigen Ausführungen stehen (so hoffe ich) genug Hinweise dazu. Nur so viel: Vergiss nicht die kontextgerechte Behandlung der Ausgabewerte (Stichwort: htmlspecialchars()). Auch das ist Aufgabe der View.

                  Jap ist mir klar geworden =).

                  Ah ja, hier hast du es ja in der üblichen Strukturierweise angeordnet. Besser so, zuzüglich der obigen Anmerkungen.

                  Okay. Und wie machst du das mit der Bennenung der Dateien? So wie ich im Beispiel? KlassennameView.php / -Controller.php / -Model.php ?

                  Der zweite Code-Sample-Kasten von [...]

                  Danke für diese Ausführungen.

                  man übergibt besser die Daten einer Helper-Funktion, die die Listendarstellung erzeugt.

                  Die man dann aber selber schreibt oder?

                  Lg, Klaus

                  1. echo $begrüßung;

                    Also ein FrontController reagiert z.B. auf Formulareingaben,

                    Die Formulareingaben sind eigentlich weniger interessant für ihn. Die Routing-Information entnimmt er im Allgemeinen der URL.

                    und instanziert dann die passende Klasse

                    Der vom FrontController verwendete Router ermittelt zwei Dinge: den Controller und eine Action davon.

                    die durch __autoload() nachgeladen werden und ruft den passenden Controller auf,

                    Ob Autoload oder nicht ist nebensächlich. Auf jeden Fall wird der (Action-)Controller instantiiert. Der kann in seinem Konstruktor allgemeine Initialisierungsaufgaben für sein Fachgebiet erledigen, wenn das erforderlich ist.

                    dieser entscheidet dann ein zweites mal, an welche Methode die Daten in "Models" müssen und lässt das Ergebnis dann in "Views" ausgeben.

                    Nach der Instantiierung des ActionControllers ruft der FrontController eine Action dieses ActionControllers auf. Diese Action führt das aus, was zu tun ist. Sie jongliert mit Daten (inklusive der Formulardaten) zwischen Model und View und gibt am Ende etwas an den FrontController zurück, das dieser dem Webserver als Ergebnis überreicht.

                    Definiere Action und gebe mir ein kleines CodeBeispiel für einen Controller bitte. Reicht in Pseudo.

                    Ich zeig dir mal ein "echtes Beispiel", allerdings in C#: http://www.asp.net/learn/mvc/tutorial-21-cs.aspx. Roll da mal runter bis zum Listing 1. Da ist ein Grundgerüst für einen Controller namens HomeController zu sehen (Eigentlich müsste der MoviesController heißen, doch der Einfachheit halber hat man für das Beispiel den HomeController missbraucht.)

                    Du findest dort solche Zeilen:

                    // GET: /Home/Details/5
                      public ActionResult Details(int id)

                    ActionResult ist der Typ des Rückgabewertes, Details der Name der Action. Und im Kommentar sieht man, welche URL (im Default-Fall, also wenn man den Router nicht mit eigenen Regeln erweitert hat) zum Aufruf dieser Action führt. Der Router hat also aus der URL ermittelt, dass der HomeController zu instantiieren ist, ruft von ihm die Action Details auf und übergibt eine 5 als Parameter namens id (und vom Typ int(eger)).

                    Weitere Actions sind Index, Create und Edit. Create und Edit gibt es jeweils in zwei Ausführungen. Einmal kann man sie per GET aufrufen, um das Anlegen eines neuen Datensatzes oder das Editieren eines bestehenden zu beginnen. Dazu wird ein leeres Formular angezeigt (Create) oder eins mit den Daten aus der Datenbank (Edit). Wenn das Formular per POST zurückgesendet wird, wird die andere Action aufgerufen, die sich um das Eintragen kümmert und anschließend auf die Index-Action weiterleitet.

                    Da es sich bei dem Listing nur um ein automatisch erstelltes Grundgerüst handelt, sieht man als Inhalt der Actions meist nur ein return View(). Welche View ausgeführt wird, ergibt sich im Default-Fall automatisch aus den Namen von Controller und Action. Auch sieht man noch keinen Zugriff auf ein Model. Es ist lediglich bei den POST-Actions angedeutet, dass da noch eine Verarbeitung zu implementieren ist.

                    Und wie machst du das mit der Bennenung der Dateien? So wie ich im Beispiel? KlassennameView.php / -Controller.php / -Model.php ?

                    Du benennst sie nach ihrer jeweiligen Aufgabe. Beispielsweise (Dateien inklusive Verzeichnisse und Klassen gemäß Zend-Framework-Benamsungsschema):

                    • Controller/Board.php -> Controller_Board

                    • View/Board/Index.php -> View_Board_Index (falls eine Einstiegsseite benötigt wird, sonst kann man auch gleich die Kategorien listen)

                    • View/Board/Categories.php -> View_Board_Categories (Liste aller Kategorien)

                    • View/Board/CategoryEdit.php -> View_Board_Category (Formular für das Erstellen oder Ändern einer Kategorie)

                    • View/Admin/Board/CategoryEdit.php -> View_Admin_Board_Category (Alternative, wenn Admin-Tätigkeiten in einem eigenen Controller implementiert werden)

                    • View/Board/Postings.php -> View_Board_Postings (Liste aller Postings einer Kategorie)

                    • View/Board/Posting.php -> View_Board_Posting (ein Posting (inklusive Antworten))

                    • View/Board/PostingNew.php -> View_Board_PostingNew (Formular für das Erstellen eines Postings)

                    • Model/Board/Category.php -> Model_Board_Category

                    • Model/Board/Posting.php -> Model_Board_Posting

                    Öffentliche Methoden von Model_Board_Category können zum Beispiel sein: List(), Get(id), Create(name), Edit(id, name)

                    » man übergibt besser die Daten einer Helper-Funktion, die die Listendarstellung erzeugt.
                    Die man dann aber selber schreibt oder?

                    Ja, falls sie noch nicht vorhanden ist. Schau mal im Zend Framwork in das Verzeichnis Zend/View/Helper. Da stehen schon einige.

                    echo "$verabschiedung $name";

                    1. Hallo.

                      Die Formulareingaben sind eigentlich weniger interessant für ihn. Die

                      Also werde ich dem Formular per action="" die Informationen für die weitere Verarbeitung geben und der FrontCrontroller kann sie per URL weiterverarbeiten.

                      Warum heißt es denn jetzt Action? Der Unterschied zwischen Funktion und Methode ist mir bewusst aber jetzt kommt noch Action dazu. Wo ist denn jetzt der Unterschied zwischen Action und Methode? Nennt man eine Methode Action wenn sie innerhalb eine MVC-Patterns agiert?

                      »» dieser entscheidet dann ein zweites mal, an welche Methode die Daten in "Models" müssen und lässt das Ergebnis dann in "Views" ausgeben.

                      Nach der Instantiierung des ActionControllers ruft der FrontController eine Action dieses ActionControllers auf. Diese Action führt das aus, was zu tun ist. Sie jongliert mit Daten (inklusive der Formulardaten) zwischen Model und View und gibt am Ende etwas an den FrontController zurück, das dieser dem Webserver als Ergebnis überreicht.

                      »» Und wie machst du das mit der Bennenung der Dateien? So wie ich im Beispiel? KlassennameView.php / -Controller.php / -Model.php ?

                      Du benennst sie nach ihrer jeweiligen Aufgabe. Beispielsweise (Dateien inklusive Verzeichnisse und Klassen gemäß Zend-Framework-Benamsungsschema):

                      Also packe ich immer den Pfad vom projektroot bis zum Ordner wo die Klasse liegt + Klassennamen zusammen und trenne sie mit _ .

                      Aber:

                      Du hast geschrieben das der FrontController die Information das ein  Request(POST oder GET) entgegennimmt und dementsprechend die passende Klasse instanziert.
                      Das sehe ich auch so.
                      Dann aber hast du gerade geschrieben das der FrontController auch die passende Action/Methode aufruft.

                      So.

                      Ich nehme mal an du meinst eine Methode die die restlichen Daten des Requests entgegennimmt und dann zwischen Model und View hin und herschiebt oder?

                      Könnte man sich diese Methode dann nicht sparen und in den Konstruktor packen? Sie wird doch eh jedes mal benötigt. Weil ohne Daten - macht das Ding nichts. Selbst ohne Daten wir dann reagiert weil er keine Daten hat.

                      Ich wüsste sonst auch nichts was in den Konstruktor reinpassen könnte, ausser sich Variablen zurechtzuweisen.

                      Liebe Grüße.

                      1. Ich hab da noc hne Frage.

                        Wie soll ein View jetzt aufgebaut sein.

                        Soll es eine Klasse sein?
                        Zum Beispiel bei einem Newsletter-System gäbe es was die Empfänger des Newsletter angeht zwei visuelle Ausgaben.

                        1. Das Formular zum eintragen des Newsletters
                        2. Eine Liste aller Newsletter Empfänger

                        Des bisherigen Verlaufs entnommen würde ich daraus logischerweise zwei Views machen. Aber soll ich dann jeweils eine Klasse erstellen?
                        Denn laut Listing 3 – Views\Home\Index.aspx, würde die direkte Ausgabe dort stehen. Wenn ich aber die Daten aus dem Array noch aufarbeiten muss, würde ich eher eine Klasse machen.
                        Ich blick niht ganz durch. Also das Model würde mir ja höchstens die Daten holen.

                        Naja mir fällt jetzt auch spontan kein Beispiel ein wo die Daten noch weiterverarbeitet werde müssten.

                        Achja. Eine Frage zum FrontController.

                        Sorgt der auch für den kompletten Seitenaufbau?
                        Denn der Frontcontroller muss ja irgendwo geladen werden.
                        Lade ich ihn OBEN in der index.php kann er Weiterleitungen per header() vollziehen, Session besser setzen usw... Aber - er kann den View nicht direkt ausgeben, sondern muss den View einer Variable zuweisen die dann irgendwo im Skript ausgegeben werden muss.

                        Das hieße aber auch wenn ich eine Liste mit Postings wie bei meinem Boardskript erstelle, muss ich die View so einstellen das
                        es die Postings etwa so handhabt:

                        $endausgabe=''  
                        foreach($ResultFromModel as $posting){  
                          $endausgabe.="<div>DAS FORMATIERTE POSTING MIT ALLEM DRUM UND DRAN</div>";  
                        }  
                          
                        return $endausgabe;
                        

                        Hier eine Frage am Rande. OffTopic:
                        So ein Posting welches Name, Bild, Posting selbst, Datum, Uhrzeit, Signatur usw anzeigt, packe ich das in ein <li></li> oder einen Div-Container? Rein semantisch gesehen.

                        Danke!

                        1. echo $begrüßung;

                          Wie soll ein View jetzt aufgebaut sein.
                          Soll es eine Klasse sein?

                          Es gibt keine Vorschriften diesbezüglich.

                          Zum Beispiel bei einem Newsletter-System gäbe es was die Empfänger des Newsletter angeht zwei visuelle Ausgaben.

                          1. Das Formular zum eintragen des Newsletters
                          2. Eine Liste aller Newsletter Empfänger
                            Des bisherigen Verlaufs entnommen würde ich daraus logischerweise zwei Views machen.

                          Genau.

                          Aber soll ich dann jeweils eine Klasse erstellen? Denn laut Listing 3 – Views\Home\Index.aspx, würde die direkte Ausgabe dort stehen.

                          Sowohl beim ASP.NET-MVC als auch bei dem des Zend Frameworks ist eine View nicht viel mehr als ein Template mit eingebauten Codestücken. Also ähnlich wie klassisches Wald- und Wiesen-PHP: HTML-Code mit <?php ?>-Blöcken dazwischen. Der qualitative Unterschied ist, dass sich in diesen Code-Blöcken nur Darstellungslogik befindet, und das möglichst sparsam.

                          Nun hat man aber bei einem Projekt, dessen Seiten bis auf den Haupt-Inhalt immer gleich aussehen sollen, wiederkehrende HTML-Teile. Diese einzeln in jede View zu kopieren ist nicht sehr wartungsfreundlich. Bei ASP.NET gibt es als Lösungsmöglichkeit das Konzept der Masterpages. Das ZF bietet dazu Zend_Layout an (in dem drei weitere Design Pattern stecken). Aber - siehe ganz oben - selbstverständlich kannst du die Views auch als Klassen implementieren, wenn dir das besser gefällt.

                          Wenn ich aber die Daten aus dem Array noch aufarbeiten muss, würde ich eher eine Klasse machen.
                          Ich blick niht ganz durch. Also das Model würde mir ja höchstens die Daten holen.

                          Ja. Es kommt darauf an, was du unter Aufarbeitung verstehst. Wenn es eine Datenverarbeitung im Sinne der Geschäftslogik ist, dann ist es Aufgabe des Models dies zu tun. Wenn es dazu zwei Schritte braucht (erst Daten holen und dann bearbeiten) oder noch mehr, dann muss es die eben erledigen. Gegebenenfalls kann auch der Controller zwischen mehreren Model-Schritten vermitteln. Wenn eine Model-übergreifende Verarbeitung notwendig ist (das eine holt die Daten, das andere bearbeitet sie) dann ist es sehr empfehlenswert, das den Controller vermitteln zu lassen, so dass die Models untereinander keine Abhängigkeiten aufbauen müssen, was ihren Wiederverwendungswert schmälerte.

                          Die Darstellung hingegen obliegt allein der View. Dazu gehören auch Modifikationen die nur zu Darstellungszwecken erforderlich sind. Die Darstellungslogik kann mitunter recht umfangreich werden, zum Beispiel wenn eine Datenstruktur mit mehreren HTML-Elementen zur Anzeige gebracht werden soll. Wenn diese Aufgabe auch noch mehrfach durchzuführen ist, hat man ein Standard-Problem des Programmierens. Und dafür gibt es Standard-Lösungen. Allgemein gesagt: wenn Code zu groß und unübersichtlich wird, strukturiert man ihn. Man erstellt beispielsweise Funktionen (die man auch in eigene Codedateien auslagern kann). Speziell gesagt: wenn die Darstellungslogik zu umfangreich wird (nicht nur dann), kann man sie ebenfalls auslagern. Das ZF bringt bereits einige solcher "ausgelagerten Logiken" in Form der View-Helper mit. Eigene View-Helper lassen sich implementieren und in das ZF einbinden. An der Stelle hast du ein weiteres Beispiel, wie dir ein Framework bei der Arbeit helfen kann. Es hat wieder eins deiner Probleme bereits gelöst oder zeigt zumindest eine Vorgehensweise auf, die man zur Lösung verwenden kann.

                          Achja. Eine Frage zum FrontController.
                          Sorgt der auch für den kompletten Seitenaufbau?
                          Denn der Frontcontroller muss ja irgendwo geladen werden.
                          Lade ich ihn OBEN in der index.php kann er Weiterleitungen per header() vollziehen, Session besser setzen usw... Aber - er kann den View nicht direkt ausgeben, sondern muss den View einer Variable zuweisen die dann irgendwo im Skript ausgegeben werden muss.

                          Der FrontController muss eigentlich nicht weiterleiten. Höchstens im Fehlerfall, wenn er keinen passenden ActionController findet. Aber auch da kann er sich im Prinzip auf die Ausgabe eines 404ers beschränken. Weiterleiten wollen aber gegebenenfalls die Controller. Alles kein Problem, denn eine Ausgabe wird ja erst auf Anweisung des Controllers erstellt. Ein Controller kann also beliebig HTTP-Header setzen. Selbst wenn mehrere Controller (oder Actions) nacheinander aufgerufen werden müssen, ist das nicht weiter tragisch, die jeweiligen Ausgaben müssen dann eben gepuffert werden. Man kann sogar soweit gehen, dass die Views nicht sofort mit ihrer Arbeit beginnen, sondern dass sie nur mit den jeweiligen Daten initialisiert und in eine Warteschlange eingereiht werden. Der FrontController arbeitet die dann zu gegebener Zeit ab und stößt den Renderprozess der Views an. In dem Fall müssten die Views dann sinnvollerweise Klassen sein und nicht nur Templates.

                          An welcher Stelle die Session getartet wird, kommt drauf an. Wird sie stets benötigt, kann das der FrontController als zentrale Instanz tun. Wird sie nur von einem oder verhältnismäßig wenigen Controllern kann man den Start auch in den/die Controller legen. Auch die Antwort auf die Frage "Will oder muss ich den Anwender immer mit (Session-)Cookies belästigen oder nur wenn es nötig ist?" kann zur Entscheidungsfindung beitragen.

                          Das hieße aber auch wenn ich eine Liste mit Postings wie bei meinem Boardskript erstelle, muss ich die View so einstellen das es die Postings etwa so handhabt:

                          Müssen muss man nicht. Können kann man aber. Dürfen darf man auch. Andere Wege gehen zum Beispiel. Ein Ansatz ist, sämtliche Ausgaben in einer Variable zu sammeln (oder an ein Array anzuhängen, das spart einige PHP-interne Umkopieraktionen beim Erweitern des Strings). Ein anderer Ansatz ist:

                          class PostingView extends BasisView {  
                            private $posting;  
                            
                            public function __construct($posting) {  
                              $this->posting = $posting;  
                            }  
                            
                            private function fooHelper($value) {  
                              return doSomethingWithValue($value); // was auch immer, ist nur ein Beispiel, dass man die View mit Ausgabelogik-Helpern anreichern kann.  
                            }  
                            
                            public function render() {  
                          ?>  
                          <div class="posting">Es folgt ein Beitrag von <?php echo $this->escape($posting->author) ?>.  
                            <h3><?php echo $this->escape($posting->subject) ?></h3>  
                            <p><?php echo $this->escape($posting->content) ?></p>  
                          </div>  
                          <?php  
                            }  
                          }
                          

                          Da eine Controller-Action immer nur eine Teilaufgabe erledigen soll, ist es auch gar nicht ihre Aufgabe für das Gesamtlayout zu sorgen. Auch kann der FrontController mehrere Actions zur Ermittlung des Gesamtergebnisses aufrufen. Die jeweiligen Ausgaben zu sammeln und sie in das Gesamt-Layout einzubinden ist dann seine Aufgabe. Oder siehe oben - er sammelt nicht die Ausgaben sondern die Views ein und lasst sie zu gegebener Zeit rendern.

                          Hier eine Frage am Rande. OffTopic:
                          So ein Posting welches Name, Bild, Posting selbst, Datum, Uhrzeit, Signatur usw anzeigt, packe ich das in ein <li></li> oder einen Div-Container? Rein semantisch gesehen.

                          Diese Daten bilden für mich keine Liste, also bekommen sie eine Individualbehandlung. Zumal du sicher nicht alles unter- oder nebeneinander anordnen willst sondern vielleicht Name, Bild, Datum und Uhrzeit links und Posting und Signatur rechts daneben. Schon dieses optische Bild widerspricht meiner Meinung von einer Liste. Das Posting wird aus einem oder mehreren Absätzen bestehen. Eine Signatur ist eigentlich kein Absatz im engeren Sinne. Ein Name, ein Bild und Zeitangaben sind es garantiert nicht. Beim Durchsehen der HTML-Elemente ist mir jetzt keins aufgefallen, das wirklich passend wäre, also bleibt wohl nur das Universal-Element div.

                          echo "$verabschiedung $name";

                          1. Also.

                            Ich habe mal einen kleinen Versuch gestartet.
                            Es geht um das "Handling" des Paramters, bzw wie das ganze später navigiert wird.

                            Es kommt folgender Aufruf: index.php?show=Views_Newsletter_NewReceiver

                            Das Skript funktioniert. Nur ist es sinnvoll? Verbesserungsschläge bevor ich weitermache..

                            index.php

                              
                            include('Config/settings.php'); $set_settings=new settings();  
                            include('Helpers/tools.php');  
                            include('Helpers/__autoload.php');  
                            include('FrontController.php'); $FrontController=new FrontController();  
                            
                            

                            Helpers/__autoload.php

                            <?php  
                              
                            function __autoload($klasse){  
                            	  
                            	$file = null;  
                            	  
                            	// die bösesten zeichen in klassennamen mal sicherheitshalber verbieten  
                            	if (strpos ($klasse, '.') !== false || strpos ($klasse, '/') !== false  
                            		|| strpos ($klasse, '\\') !== false || strpos ($klasse, ':') !== false) {  
                            	  return;  
                            	}  
                            	  
                            	// Aufruf auseinandernehmen  
                            	$path=explode('_',$klasse);  
                            	  
                            	// Path-Size  
                            	$pathCount=count($path);  
                            	  
                            	// Pfad erstellen  
                            	for($i= 0; $i<$pathCount; ++$i){  
                            		$file.=$path[$i];  
                            		$file.=($i==$pathCount-1) ? ".php" : "/";  
                            	}  
                            	  
                            	// Klasse inkludieren  
                            	if(file_exists($file)) {  
                            		include_once ($file);  
                            	}	  
                            }  
                            ?>
                            

                            FrontController.php

                            <?php  
                              
                            class FrontController{  
                              
                            	private $_dispatcherObject = null;  
                            	private $_dispatcherArray = null;  
                              
                            	public function __construct(){  
                              
                            		if(isset($_REQUEST))  
                            		{  
                            			$this->_sendRequest($_REQUEST);  
                            		}  
                            		  
                            		$this->_setIndexSite();  
                            	}  
                            	  
                            	// gibt Requests an den Dispatcher weiter  
                            	private function _sendRequest($request)  
                            	{  
                            		$this->_dispatcherObject=new Dispatcher_Dispatcher($request);  
                            		$this->_dispatcherArray=$this->_dispatcherObject->DispatcherHelper();  
                            	}  
                            	  
                            	  
                            	// stellt Seite zusammen  
                            	private function _setIndexSite(){  
                                            #  Header  
                            		$Main = new $this->_dispatcherArray['View_Main'];  
                            		echo $Main->toShow;  
                            		  
                            	}  
                            }  
                              
                            ?>
                            

                            Dispatcher/Dispatcher.php

                            class Dispatcher_Dispatcher{  
                              
                            	public $informations=array();  
                            	  
                            	private $_request;  
                              
                            	public function __construct($request)  
                            	{  
                            		$this->_request=$request;  
                            	}  
                              
                            	public function DispatcherHelper()  
                            	{  
                            		if($_POST) $this->workWithPosts();  
                            		if($_GET)  $this->workWithGets();  
                            		  
                            		return $this->informations;  
                            	}  
                            	  
                            	private function workWithPosts()  
                            	{  
                            		if(isset($_POST['FormReceiver']))  
                            		{  
                            			$Object = new $_POST['FormReceiver']();  
                            		}  
                            	}  
                              
                            	private function workWithGets()  
                            	{  
                            		// Hauptanzeige  
                            		if($_GET['show']){  
                            				array_push($this->informations, 'View_Main');  
                            				$this->informations['View_Main'] = $_GET['show'];  
                            				unset($_GET['show']);  
                            		}  
                            	}  
                            }
                            

                            Views/Newsletter/newReceiver.php

                              
                            <?php  
                            #########################################################################################  
                            // Zeigt das Formular zum Eintragen eines Newsletterempfängers  
                            #########################################################################################  
                            class Views_Newsletter_newReceiver{  
                            	  
                            	public $toShow = null;  
                            	  
                            	public function __construct(){  
                            		$this->toShow="  
                            		<form method='post'>  
                            			<input type='checkbox' name='newsletterbox'>Ja, ich m&ouml;chte den ".settings::$vars_project['Projektname']."-Newsletter empfangen!  
                            			<p>Bitte folgende Daten eintragen:</p>  
                            			<table>  
                            				<tr><td>Name:</td><td><input type='text' name='2i17tbs1o' /></td></tr>  
                            				<tr><td>E-Mail:</td><td><input type='text' name='bkqx2u6rd2b3' /></td></tr>  
                            				".tools::antiSpam(1,'','')."  
                            				<tr><td></td><td><input type='submit' name='newsletter_entry' value='Eintragen' /></td></tr>  
                            			</table>  
                            		</form>  
                            		";  
                            	}  
                            	  
                            }  
                            ?>  
                            
                            

                            Ich denke Code ist noch verständlich genug, ich weiß es ist ein bisschen wenig kommentierung.

                            Liebe Grüße,

                            Klaus

                            1. echo $begrüßung;

                              Das Skript funktioniert. Nur ist es sinnvoll? Verbesserungsschläge bevor ich weitermache..

                              Ich sehe, du versuchst immer noch nicht nur inhaltlich sondern auch strukturell deinen eigenen Weg zu gehen. Du nimmst zwar ein paar Idden auf, setzt die aber nicht wie angedacht ein. Versuch doch mal, deine jetzige Struktur um eine andere Aufgabe zu erweitern. Geht das gut? Dann kann dein Weg nicht so schlecht gewesen sein. Geht es nicht oder nur mit Anpassungen, ...

                              Es kommt folgender Aufruf: index.php?show=Views_Newsletter_NewReceiver

                              Eine URL hat Außenwirkung. Gestalte ihr Aussehen nicht nur nach technischen Erwägungen sondern eher so, wie du als Benutzer sie sehen wollen würdest.

                              include('Config/settings.php'); $set_settings=new settings();

                              (Ein include ist keine Funktion und braucht keine Klammern.) Ich sehe nicht, wofür du die Variable $set_settings anlegst. Auch erschließt sich mir nicht, warum du ein Objekt von settings anlegst. Im weiteren Verlauf greifst du nur statisch auf die Klasse zu.

                              include('FrontController.php'); $FrontController=new FrontController();

                              Auch der FrontController wird nach seiner Instantiierung nicht mehr gebraucht. Er hat ja noch nicht mal öffentliche Eigenschaften, die man verwenden kann. Du brauchst also auch dafür eine Instanz in einer Variable ablegen. Was allerdings schwerer wiegt ist, dass du den Konstruktoraufruf missbrauchst. Du initialisierst nicht nur sondern lässt ihn die gesamte Arbeit machen. Nach außen hin sieht das ganze wie ein Funktionsaufruf aus. Es bietet sich dann eher an, eine statische Methode zu verwenden. Wenn du für interne Zwecke eine Instanz benötigst, kannst du sie in einer privaten (statischen) Klassenvariable ablegen.

                              public $informations=array();

                              (Das englische Wort information hat keine Pluralform.)

                              public function DispatcherHelper()

                              Bezeichner sollten sprechend sein, so dass man ihre konkrete Aufgabe zumindest erahnen kann.

                                if($\_POST) $this->workWithPosts();  
                                if($\_GET)  $this->workWithGets();  
                                return $this->informations;  
                              

                              Es ist nicht ersichtlich, warum hier $this->informations zurückgegeben wird, zumal es gar nicht verwendet wurde. Jedenfalls sieht man nichts. Dass das als Nebenwirkung in den anderen Methoden passiert muss man sich erst erarbeiten. Wenn du Ursache und Wirkung so auseinandernimmst hast du es schwer, wenn du das System warten musst, musst du dann doch all diese versteckten Beziehungen beachten.

                              Ich hab zwar nicht alles bewertet und kommentiert, aber ich wollte auch nicht gleich alles neu schreiben :-)

                              echo "$verabschiedung $name";

                              1. Hi.

                                Ich sehe, du versuchst immer noch nicht nur inhaltlich sondern auch strukturell deinen eigenen Weg zu gehen. Du nimmst zwar ein paar Idden auf, setzt die aber nicht wie angedacht ein. Versuch doch mal, deine jetzige Struktur um eine andere Aufgabe zu erweitern. Geht das gut? Dann kann dein Weg nicht so schlecht gewesen sein. Geht es nicht oder nur mit Anpassungen, ...

                                Ach verdammt.Eigendlich verstehe ich sollche Dinge wahnsinnig schnell aber irgendwo war wohl der Zeitpunkt wo ich ins Labyrinth gerannt bin... Jetzt finde ich das Ende nicht.

                                Bei mir sieht MVC gerade so aus:

                                Meine Umsetzung von MVC
                                http://img3.imagebanana.com/view/1hwclav7/xx.jpg

                                Desweiteren sieht die Ordnerstruktur anhand des Beispiels Newsletterklasse so aus:

                                /index.php
                                /FrontController.php
                                /Config/Settings.php
                                /Config/inis/settings.ini
                                /Config/inis/newsletter.ini // jede klasse bekommen - falls nötig, ihre eigene INI
                                /Dispatcher/dispatcher.php
                                /Helper/ // Hilfsklassen, wie statische Datenbank-Klase
                                /Helper/ErrorHandling/
                                /Scripts/ // Javascripte
                                /Styles/ // CSS-Dateien
                                /Views/Newsletter/ // die views
                                /Models/ // die Models
                                /Controller/ // die Controllers

                                Eine URL hat Außenwirkung. Gestalte ihr Aussehen nicht nur nach technischen Erwägungen sondern eher so, wie du als Benutzer sie sehen wollen würdest.

                                Das wäre natürlich statt
                                index.php?show=Views_Newsletter_NewReceiver

                                View/Newsletter/Registrierung

                                Aber das wäre jetzt rumfuchtelei mit mode_rewrite. Ausserdem muss ich die Klassen dann eindeutschen, weil die Seite ja eine deutsche Zielgruppe hätte.
                                Wenn ich das jetzt so umsetzen wollen würde sollte ich dann 3 GET Parameter daraus machen (show1,show2,show3) und diese aneinanderreihen oder sollte ich daraus einen Parameter machen? Also wie würdest du das angehen?

                                »» include('Config/settings.php'); $set_settings=new settings();

                                (Ein include ist keine Funktion und braucht keine Klammern.) Ich sehe nicht, wofür du die Variable $set_settings anlegst. Auch erschließt sich mir nicht, warum du ein Objekt von settings anlegst. Im weiteren Verlauf greifst du nur statisch auf die Klasse zu.

                                Um die Klasse zu instanzieren da sie im Konstruktor alles wichtige an Settings lädt. Z.b. - bin ich im Internet oder im Develop-Mode(zeigt alles Fehler an E_ALL | E_STRICT), die Zeitzone die ich verwende, Name des Projektes, der URL, Name des smtp-Server für mail() usw..
                                Okay - die Variablenzuweisung ist Schwachsinn.

                                »» include('FrontController.php'); $FrontController=new FrontController();

                                Auch der FrontController wird nach seiner Instantiierung nicht mehr gebraucht. Er hat ja noch nicht mal öffentliche Eigenschaften, die man verwenden kann. Du brauchst also auch dafür eine Instanz in einer Variable ablegen. Was allerdings schwerer wiegt ist, dass du den Konstruktoraufruf missbrauchst. Du initialisierst nicht nur sondern lässt ihn die gesamte Arbeit machen. Nach außen hin sieht das ganze wie ein Funktionsaufruf aus. Es bietet sich dann eher an, eine statische Methode zu verwenden. Wenn du für interne Zwecke eine Instanz benötigst, kannst du sie in einer privaten (statischen) Klassenvariable ablegen.

                                Hm, wie sonst soll ich dafür sorgen das er mit den Requests arbeitet, sie abfängt usw? Soll ich dafür extra eine Methode schreiben und sie dann in der index.php aufrufen?

                                »» public $informations=array();

                                (Das englische Wort information hat keine Pluralform.)

                                Ich weiß - allerdings klang das für mich einleuchtener, das es um "mehrere" geht.

                                Bezeichner sollten sprechend sein, so dass man ihre konkrete Aufgabe zumindest erahnen kann.

                                Okay ich sollte also mehr darauf achten das man erkennt was woher kommt..

                                Desweiteren habe ich mir - auch wenns im Geschichte LK war, etwas für die Views einfallen lassen:

                                Eine Views.php von der jeder erbt. Sie hat folgende Methoden:

                                public function tellNeedles(){
                                  // Hole Ausdrücke von parseText()
                                  // Hole ggf. sonstige Informationen
                                  return array
                                }

                                parseText($text){
                                 // Parse den Text
                                 // Schreibe alles Ausdrücke raus und packe sie in ein Array
                                 return array
                                }

                                public function getNeedles($text,$result){
                                 // Ersetze Ausdrücke durch Ergebnisse von Model.
                                 // Gebe den View zurück
                                 return $View;
                                }

                                Die Views die von ihr erben haben eine Art Template-System.
                                Überall, wo etwas hinsoll aus einer Datenbank z.B. steht {|Tabellenname.Ausdruck|}
                                Z.B.
                                $output="<html><head><title>{|Projectdatas.title|}</title></head><body></body></html>";

                                Der Controller kann also per tellNeedles sich zeigen lassen was er braucht und per getNeedles bekommt die/der View was er/sie braucht.

                                Die View.php wird per extends eingebunden und vllt kann man ja dazu ein Interface oder eine Abstrakte Klasse schreiben, die dies zur Vorraussetzung macht.

                                Wie ist die Idee?

                                Ich müsste meinen Kopf mal aufräumen da ich nicht durchblicke wie die Requests(GET / POSTS) am besten verarbeitet werden, hast ja beim letzten Post gesehen was dabei rauskommt. Naja ich habe dir ja oben ein Bild gemacht wie ich das zur Zeit sehe. Wenn das nicht stimmt. Wissen wir ja schonmal das ich bisher schonmal ganz falsch an die Sache rangegangen bin.

                                Ich möchte das alles auf jeden Fall verstehen - auch bevor ich ein Framework einsetze. Vllt werde ich das ZF später nutzen, sobald ich das ganze verstanden habe, mir reichts zu wissen "das könnte ich auch umsetzen" - von der Theorie.

                                Liebe Grüße, danke für deine Mühe.

                                1. echo $begrüßung;

                                  Bei mir sieht MVC gerade so aus:

                                  Meine Umsetzung von MVC
                                         http://img3.imagebanana.com/view/1hwclav7/xx.jpg

                                  So sieht das ja gar nicht schlecht aus. Nur das was du da an Code erstellt hast, erscheint mir nicht besonders klar nach Aufgaben getrennt und mit allgemeiner Wiederverwendbarkeit im Hinterkopf implementiert. Und manche Code-Teile tun effektiv nichts. Vielleicht hättest du doch schon jetzt deinen Code kommentieren sollen. Vielleicht haben sie ja für später eine Bedeutung.

                                  Auch fängst du an, ein allgemeines Framework zu entwickeln, hast aber dabei immer im Hinterkopf deine konkrete Anwendung. Wenn das Framework gut werden soll, muss es jeder Anwendung eine Basis bieten. Du musst es also sehr abstrakt entwickeln. Die Anforderungen, die du an das Framework stellst, müssen dabei konkret aber anlassunabhängig formuliert werden. Das erfordert eine Menge Erfahrung. Die kannst du sammeln, indem du mit existierenden Frameworks arbeitest, ein Gefühl für ihre Arbeitsweise bekommst und dabei erkennst, welche Vorteile und welche Schwächen sie haben.

                                  Desweiteren sieht die Ordnerstruktur anhand des Beispiels Newsletterklasse so aus:

                                  Die Ordnerstruktur ist in Ordnung. Dein Problem ist das Innenleben deiner Klassen.

                                  Das wäre natürlich statt
                                  index.php?show=Views_Newsletter_NewReceiver
                                  View/Newsletter/Registrierung

                                  Wozu dient das Wort View? Webseiten zeigen immer was an. Du brauchst das "View" nur, um daraus einen Klassennamen zu bilden. Wenn die Default-Routing-Regel nicht ausreicht, einen passenden ActionController-Namen zu ermiteln, kannst du eine spezielle definieren, die den Namen passend zusammenstellt. Beim ZF zerlegt der Router die URL in Parameter. Aus bestimmten Parametern bildet der Dispatcher den ActionController-Klassenamen. Der Router kann für fehlende Teile auch selbst Parameter hinzufügen.

                                  Aber das wäre jetzt rumfuchtelei mit mode_rewrite.

                                  Nö, da kommt eine ganz allgemeine Regel rein, die den Request nur auf index.php lenkt ohne irgendwelche URL-Teile zu GET-Parametern umzuschreiben. Zur Auswertung des Requests gibt es den Router. Der nimmt REQUEST_URI und wendet darauf seine Regeln an.

                                  Ausserdem muss ich die Klassen dann eindeutschen, weil die Seite ja eine deutsche Zielgruppe hätte.

                                  Auch hier kann der Router für eine Übersetzung sorgen.

                                  Wenn ich das jetzt so umsetzen wollen würde sollte ich dann 3 GET Parameter daraus machen (show1,show2,show3) und diese aneinanderreihen oder sollte ich daraus einen Parameter machen? Also wie würdest du das angehen?

                                  Siehe oben, REQUEST_URI direkt auswerten.

                                  » Ich sehe nicht, wofür du die Variable $set_settings anlegst. Auch erschließt sich mir nicht, warum du ein Objekt von settings anlegst. Im weiteren Verlauf greifst du nur statisch auf die Klasse zu.
                                  Um die Klasse zu instanzieren da sie im Konstruktor alles wichtige an Settings lädt. Z.b. - bin ich im Internet oder im Develop-Mode(zeigt alles Fehler an E_ALL | E_STRICT), die Zeitzone die ich verwende, Name des Projektes, der URL, Name des smtp-Server für mail() usw..
                                  Okay - die Variablenzuweisung ist Schwachsinn.

                                  Also wieder ein Fall von Konstruktormissbrauch. Wenn du sowieso die Konfigurationswerte statisch abfragbar ablegst, kannst du auch gleich eine statische Methode zu deren Ermittelung erstellen.

                                  Hm, wie sonst soll ich dafür sorgen das er [der FrontController] mit den Requests arbeitet, sie abfängt usw? Soll ich dafür extra eine Methode schreiben und sie dann in der index.php aufrufen?

                                  Wie gesagt, der Konstruktor ist für eine grundlegende Initialisierung der Instanz da. Weiterführende Initialisierungen kann man in eigenen Methoden unterbringen. Die über Initialisierung hinausgehende Arbeit kommt auf alle Fälle in (eine) eigene Methode(n). Beim FrontController vom ZF heißt sie dispatch(). Und wenn man auf großartige Initialisierungen verzichten kann, gibt es die statische Methode run(), die sich selbst eine Instanz erstellt und davon dispatch() aufruft.

                                  » »» public $informations=array();
                                  » (Das englische Wort information hat keine Pluralform.)
                                  Ich weiß - allerdings klang das für mich einleuchtener, das es um "mehrere" geht.

                                  Naja, für den Engländer ist es einleuchtender, dass "information" sowas wie "Sand" ist: besteht impliziert aus mehreren Einzelteilen.

                                  Desweiteren habe ich mir - auch wenns im Geschichte LK war, etwas für die Views einfallen lassen:
                                  Wie ist die Idee?

                                  Vielleicht zu aufwendig. Der Controller sollte eigentlich seine Schäfchen kennen, ohne sie vorher befragen zu müssen. Was kann er denn tun, wenn das Template mehr Platzhalter meldet als Werte aus der Datenbank abzufragen gehen? Genausowenig wie das Template was machen kann, wenn der Controller einen Wert zu wenig liefert. Wenn du allerdings die View mit spezifischen Informationen spickst, die das Model eigentlich zu verbergen hat, bringst du dir direkte Abhängigkeiten zwischen beide. Genau die versucht man ja zu vermeiden.

                                  Und was ist, wenn der Wert aus dem Model vom Controller erst noch bearbeitet werden muss, bevor er an die View gehen kann? Wie willst du sowas implementieren?

                                  Ich möchte das alles auf jeden Fall verstehen - auch bevor ich ein Framework einsetze. Vllt werde ich das ZF später nutzen, sobald ich das ganze verstanden habe, mir reichts zu wissen "das könnte ich auch umsetzen" - von der Theorie.

                                  Ich ging bisher andersrum an die Sache ran. Zunächst versuche ich was Vorgefertigtes zu nehmen, stelle dann aber fest, dass es meinen Anforderungen nicht entspricht oder vielleicht zu umständlich und aufgebläht ist. Dann setz ich mich hin und erstelle was eigenes, nehme die guten Ideen mit und versuche das in meinen Augen weniger gelungene auf passendere Weise zu implementieren.

                                  echo "$verabschiedung $name";

                                  1. Hallo.

                                    Was hälst du von der Umsetzung von ihm?
                                    Das versteh ich gut wie er es gemacht hat.

                                    Alternativ wäre ich dafür die Verarbeitungsverzweigung in hidden-inputs zu stecken also:

                                    <input type="hidden" name="class" value="klassenname"/>
                                    <input type="hidden" name="action/method" value="action/methodenname"/>

                                    Aber das klingt unsicher. Oder man machts etwas "versteckter" - in Sessions.
                                    Beim laden des Formulars werden entsprechende Sessions gesetzt..

                                    Mit der URL - ist immer son Ding, das es einmal gut aussieht und zweitens von der Technik passt.

                                    Auch fängst du an, ein allgemeines Framework zu entwickeln, hast aber dabei immer im Hinterkopf deine konkrete Anwendung. Wenn das Framework gut werden soll, muss es jeder Anwendung eine Basis bieten. Du musst es also sehr abstrakt entwickeln. Die Anforderungen, die du an das Framework stellst, müssen dabei konkret aber anlassunabhängig formuliert werden. Das erfordert eine Menge Erfahrung.

                                    Ja stimmt es soll schon etwas abstrakter / allgemeiner werden so das ich soviel Code wiederverwenden kann, wie nur möglich.

                                    »» Das wäre natürlich statt
                                    »» index.php?show=Views_Newsletter_NewReceiver
                                    »» View/Newsletter/Registrierung

                                    Wozu dient das Wort View? Webseiten zeigen immer was an. Du brauchst das "View" nur, um daraus einen Klassennamen zu bilden. Wenn die Default-Routing-Regel nicht ausreicht, einen passenden ActionController-Namen zu ermiteln, kannst du eine spezielle definieren, die den Namen passend zusammenstellt. Beim ZF zerlegt der Router die URL in Parameter. Aus bestimmten Parametern bildet der Dispatcher den ActionController-Klassenamen. Der Router kann für fehlende Teile auch selbst Parameter hinzufügen.

                                    Ich weiß aber nicht genau wie ich das umsetzen soll. Wie er?

                                    Also wieder ein Fall von Konstruktormissbrauch. Wenn du sowieso die Konfigurationswerte statisch abfragbar ablegst, kannst du auch gleich eine statische Methode zu deren Ermittelung erstellen.

                                    Okay dann lege ich dafür eine Methode an und rufe diese zu Beginn des Skripts auf. Soll das initialisieren der Settings im FronController passieren? Und ist es okay für jede Klasse eine eigene ini zu erstellen und in den KlassenControllern im Konstruktor parsen/einlesen zu lassen?

                                    »» Hm, wie sonst soll ich dafür sorgen das er [der FrontController] mit den Requests arbeitet, sie abfängt usw? Soll ich dafür extra eine Methode schreiben und sie dann in der index.php aufrufen?

                                    Vielleicht zu aufwendig. Der Controller sollte eigentlich seine Schäfchen kennen, ohne sie vorher befragen zu müssen. Was kann er denn tun, wenn das Template mehr Platzhalter meldet als Werte aus der Datenbank abzufragen gehen? Genausowenig wie das Template was machen kann, wenn der Controller einen Wert zu wenig liefert. Wenn du allerdings die View mit spezifischen Informationen spickst, die das Model eigentlich zu verbergen hat, bringst du dir direkte Abhängigkeiten zwischen beide. Genau die versucht man ja zu vermeiden.

                                    Und was ist, wenn der Wert aus dem Model vom Controller erst noch bearbeitet werden muss, bevor er an die View gehen kann? Wie willst du sowas implementieren?

                                    Stimmt, hättest du Verbesserungsvorschläge?
                                    Also sollte ich jedem Controller direkt sagen was er für welche Action braucht? Bzw. nee. Ich lege in jedem Model direkt fest was gebraucht wird und der Controller weiß nur - dieses Model oder diese Modelaction gehört zu dem und dem View..

                                    Und wer baut am Ende die Seite zusammen?
                                    Also die Views werden doch am Ende dem Controlelr übergeben und dann mache ich da eine Methode welche Header usw ausgibt nacheinander?
                                    Also die Views sortiert ausgitb z.B.:
                                    echo $this->Header;
                                    echo $this->Navigation1;
                                    echo $this->Body;
                                    echo $this->Footer;

                                    so in etwa?

                                    Liebe Grüße,

                                    Klaus

                                    1. echo $begrüßung;

                                      Was hälst du von der Umsetzung von ihm?
                                      Das versteh ich gut wie er es gemacht hat.

                                      Das sieht für den Einstieg gut aus. Alles ist simpel gehalten, auf das Nötigste begrenzt. Das ZF ist hingegen schon recht ausgewachsen. Wenn du erst einmal mit dem kleinen anfängst und das bei Bedarf erweiterst solltest du gut fahren.

                                      Alternativ wäre ich dafür die Verarbeitungsverzweigung in hidden-inputs zu stecken also:
                                      Mit der URL - ist immer son Ding, das es einmal gut aussieht und zweitens von der Technik passt.

                                      Wie auch immer. Du solltest es nur einheitlich machen und nicht verschiedene Verfahren mischen. Für lesende Requests wirst du sicher nicht ständig Formulare absetzen wollen, also brauchst du eine Möglichkeit über die URL die passende Action zu ermitteln. Und die kannst du dann auch für Formulare verwenden.

                                      Ich weiß aber nicht genau wie ich das umsetzen soll. Wie er?

                                      Er macht sich die Sache an der Stelle sehr einfach, indem er zwei URL-Parameter nimmt: controller=foo;action=baz. Damit landet aber technischer Kram in der URL.

                                      Das ZF machte sich die Sache früher einfach, indem es starr aus /controllername/actionname/optionalparametername1/wert1/optionalparametername2/wert2/ die Angaben zu Controller und Action und gegebenenfalls Parameter holte. Realisiert wurde das durch Auswertung von REQUEST_URI. Und mod_rewrite hatte nur eine Regel.

                                      RewriteCond %{REQUEST_FILENAME} !-f
                                        RewriteCond %{REQUEST_FILENAME} !-d
                                        RewriteRule ^.*$ index.php [QSA,L]

                                      Das war zu einfach und zu starr, so dass sich recht schnell der RewriteRouter als StandardRouter durchsetzte, der die REQUEST_URI regelbasiert auswertete.

                                      Okay dann lege ich dafür eine Methode an und rufe diese zu Beginn des Skripts auf. Soll das initialisieren der Settings im FronController passieren?

                                      Ja, für den Anfang ist das ok.

                                      Und ist es okay für jede Klasse eine eigene ini zu erstellen und in den KlassenControllern im Konstruktor parsen/einlesen zu lassen?

                                      Das kommt drauf an, wieviel zu konfigurieren ist. Allzu viel wird sicher nicht anfallen. Das passt auch in eine ini-Datei. Man kann die ja gut in Abschnitte gliedern und mit parse_ini_file() einfach einlesen.

                                      Ich lege in jedem Model direkt fest was gebraucht wird und der Controller weiß nur - dieses Model oder diese Modelaction gehört zu dem und dem View..

                                      Klingt gut.

                                      Und wer baut am Ende die Seite zusammen?
                                      Also die Views werden doch am Ende dem Controlelr übergeben und dann mache ich da eine Methode welche Header usw ausgibt nacheinander?

                                      Auch das ist für den Anfang in Ordnung. Die View gibt nur den Hauptinhalt zurück und der FrontController lässt den in ein Layout-Grundgerüst einbauen.

                                      echo "$verabschiedung $name";

                                      1. Super.

                                        Dann fehlt mir jetzt eigendlich nur noch das Verständnis von REQUEST_URI.
                                        Was meinst du damit genau. Könntest du mir ein kleines Beispiel von einem Formular geben und dessen Verarbeitung?

                                        Den Rest werde ich dann erstmal wie er umsetzen..

                                        lg, Klaus

                                        1. echo $begrüßung;

                                          Dann fehlt mir jetzt eigendlich nur noch das Verständnis von REQUEST_URI.

                                          Schau dir die Ausgabe von phpinfo() besonders im unteren Bereich an.

                                          echo "$verabschiedung $name";

                                          1. Schau dir die Ausgabe von phpinfo() besonders im unteren Bereich an.

                                            Ich habe mich falsch ausgedrückt - ich weiß schon was mir die Variable anzeigt - nur ich weiß nicht wie ich damit arbeiten soll sprich - wie soll ich jetzt das Formular gestalten und wie die URL auswerten genau. Controller mode/view angeben oder dies oder jenes?

                                            Lg, Klaus

                                            1. echo $begrüßung;

                                              Ich habe mich falsch ausgedrückt - ich weiß schon was mir die Variable anzeigt - nur ich weiß nicht wie ich damit arbeiten soll sprich - wie soll ich jetzt das Formular gestalten und wie die URL auswerten genau. Controller mode/view angeben oder dies oder jenes?

                                              Du hast URLs wie

                                              /newsletter/subscribe
                                              /board/categories
                                              /board/articles/5 (5: Kategorie-ID)
                                              /board/article/4711

                                              Falls noch ein Querystring dranhängt, dann wirf ihn weg (ab einschließlich dem ersten ? alles wegschneiden).
                                              Den vorderen / brauchen wir nicht und falls hinten einer steht, den auch nicht. Weg damit: trim(url, '/')
                                              Nun kannst du das Gebilde am / explodieren lassen und hast zwei oder drei Teile. Die ersten beiden können Controller und Action angeben, der dritte ist ein Parameter für die Action. Manchmal bekommst du nur einen oder gar keinen Teil, dann musst du Default-Werte einsetzen.

                                              Wenn du die Action mit call_user_func() aufrufst, dann nimm stattdessen call_user_func_array() und übergib als Parameter-Array die explodierte URL abzüglich der beiden ersten Elemente. So kannst du die Parameter übergeben.

                                              echo "$verabschiedung $name";

                                              1. Okay.

                                                Hier mal ein Vorschlag:

                                                <?php  
                                                                        $fulluri=$_SERVER['REQUEST_URI'];  
                                                			  
                                                			$uri_params=explode("?",$fulluri);  
                                                			$uri=trim($uri_params[0], '/');  
                                                			$uri=explode("/",$uri);  
                                                			  
                                                			$controller="Controllers_".$uri[0];  
                                                			$object=new $controller();  
                                                			  
                                                			  
                                                			$paramstring = $uri_params[1] ;  
                                                			  
                                                			$params=explode("&",$paramstring);  
                                                  
                                                			$object->$uri[1]( $params);  
                                                			  
                                                ?>
                                                

                                                Hast du dir das so vorgestellt ca?

                                                Ich hoffe das ist okay so. Sag mal was man da noch besser machen könnte, irgendeine Sicherheitslücke?

                                                Also ich habs mal ausgeben lassen indem ich folgendes gemacht habe:

                                                echo "Controller: ".$uri[0]."<br> ";  
                                                echo "Action: ".$uri[1]."<br> ";  
                                                var_dump($params);
                                                

                                                Bei dieser URL:
                                                http://localhost/controller/action/?parameter=2&klappt=true

                                                kommt folgende Ausgabe:

                                                Controller: controller
                                                Action: action
                                                array(2) { [0]=> string(11) "parameter=2" [1]=> string(11) "klappt=true" }

                                                Also klappt =).

                                                Danke für deine bisherige Hilfe,

                                                Klaus

                                                1. echo $begrüßung;

                                                  $fulluri=$_SERVER['REQUEST_URI'];
                                                  $uri_params=explode("?",$fulluri);

                                                  $fulluri und das Umkopieren dahinein ist überflüssig. Schreib das $_SERVER... gleich anstelle von $fulluri in die zweite Zeile.

                                                    	$controller="Controllers\_".$uri[0];  
                                                  

                                                  Du muss noch testen, ob $uri[0] und $uri[1] überhaupt existieren. Bei URLs der Sorte / oder /foo tun sie es (teilweise) nicht.

                                                    	$paramstring = $uri\_params[1] ;  
                                                    	$params=explode("&",$paramstring);  
                                                  

                                                  Das brauchst du nicht, dafür gibt es fix und fertig aufbereitet $_GET. Was ich meinte waren die Teile ab $uri[2] und aufwärts. Vergleiche meine Beispiel-URLs. Ich hab da nicht nur Controller und Action sondern auch für den Inhalt relevante Teile drin (Nummer der Kategorie oder des Postings). Diese zusätzlichen Teile braucht man nicht unbedingt, man kann da auch GET-Parameter verwenden, allerdings finde ich es schöner, wenn solche inhaltsrelevanten Parameter Teil des Pfades sind und nur "nebensächliche", wie Sortierfeld und -richtung als GET-Parameter dranhängen.

                                                  echo "$verabschiedung $name";

                                                  1. Okay.

                                                    Was hälst du von folgendem:

                                                      
                                                                            $uri_params=explode("?",$_SERVER['REQUEST_URI']);  
                                                    			$uri=explode("/",trim($uri_params[0], '/'));  
                                                    			  
                                                    			// Sind Controller UND Action vorhanden?  
                                                    			if(isset($uri[0])&&isset($uri[1]))  
                                                    			{  
                                                    				# Objekt erstellen  
                                                    				$controller="Controllers_".$uri[0];  
                                                    				$object=new $controller();  
                                                    				  
                                                    				# Parameterarray  
                                                    				$params = array();  
                                                    				  
                                                    				# Sonstige Parameter  
                                                    				$misc=explode("&",$uri_params[1]);  
                                                    				($misc==false) ? NULL : array_push($params,$misc);  
                                                    				  
                                                    				# Wichtige Parameter  
                                                    				for($i=2; $i<=count($uri)-1; ++$i){  
                                                    					array_push($params,$uri[$i]);  
                                                    				}  
                                                    				  
                                                    				# Action aufrufen  
                                                    				$object->$uri[1]( $params);  
                                                    			}  
                                                    
                                                    

                                                    Am Ende wird als Parameter ein Array übergeben, wessen erster Wert [0] - IMMER ein Array ist mit sonstigen Werten oder NULL ist.
                                                    Ab [1] kommen wichtige Werte, abzüglich Controller und Action.

                                                    Man kann den Wert [0] ja dann checken mit einer statischen Funktion oder so
                                                    if(is_array($params[0])) ....

                                                    Ich hoffe es entspricht mehr deiner Vorstellung.

                                                    Lieben Gruß,

                                                    Klaus

                                                    1. echo $begrüßung;

                                                        	// Sind Controller UND Action vorhanden?  
                                                        	if(isset($uri[0])&&isset($uri[1]))  
                                                      

                                                      Und wenn nicht?

                                                      Was hältst du von der Idee, im Falle der Absenz der Action einen Default-Wert wie "Index" zu nehmen und beim Controller das gleiche? Das setzt dann voraus, dass jeder ActionController eine Index-Action erhalten muss und es einen Index-Controller geben muss (der mindestens eine Index-Action benötigt).

                                                        		# Sonstige Parameter  
                                                        		$misc=explode("&",$uri\_params[1]);  
                                                        		($misc==false) ? NULL : array\_push($params,$misc);  
                                                      

                                                      Wie gesagt, der Querystring ist bereits in $_GET zu finden. Abgesehen davon gibt es parse_str(). Und was du da mit dem Trinitätsoperator machst ist auch eine Form des Missbrauchs. Nimm ihn nur, wenn du einen Ent-Oder-Weder-Rückgabewert brauchst. Alle anderen Fälle sind in einem if besser aufgehoben.

                                                      Was ist der Unterschied zwischen

                                                      $i<=count($uri)-1;

                                                      und

                                                      $i < count($uri);

                                                      ? Keiner, aber die zweite Zeile ist einfacher :-)

                                                        		# Wichtige Parameter  
                                                        		for($i=2; $i<=count($uri)-1; ++$i){  
                                                        			array\_push($params,$uri[$i]);  
                                                        		}  
                                                      

                                                      array_slice() gibt es auch noch.

                                                        		$object->$uri[1]( $params);  
                                                      

                                                      call_user_func_array() wäre mein Favorit.

                                                      call_user_func_array(array($object, $uri[1]), array_slice($uri, 2));

                                                      Eine Action, die zwei Parameter erwartet, ist dann eine Funktion/Methode mit zwei Argumenten

                                                      public function foo($bar, $qux) {...}

                                                      echo "$verabschiedung $name";

                                                      1.   
                                                                                $uri_params=explode("?",$_SERVER['REQUEST_URI']);  
                                                        			$uri=explode("/",trim($uri_params[0], '/'));  
                                                        			  
                                                        			# Parameterarray  
                                                        			$params = array();  
                                                        			  
                                                        			// Sind Controller UND Action vorhanden?  
                                                        			if(isset($uri[0])&&isset($uri[1]))  
                                                        			{  
                                                        				# Controllernamen setzen  
                                                        				$controllername = $uri[0];  
                                                        				  
                                                        				# Wichtige Parameter  
                                                        				$main=array_slice($uri, 2);  
                                                        				$params[]=$main;  
                                                        				  
                                                        				# Sonstige Parameter  
                                                        				parse_str($uri_params[1], $misc);  
                                                        				$params[]=$misc;  
                                                        				  
                                                        				# Action setzen  
                                                        				$action = $uri[1];  
                                                        			}  
                                                        			else  
                                                        			{  
                                                        				# Controllernamen setzen  
                                                        				$controllername='Index';  
                                                        				# Action setzen  
                                                        				$action='IndexAction';  
                                                        			}  
                                                        			  
                                                        			// Objekt erstellen & Action aufrufen  
                                                        			$controller="Controllers_".$controllername;  
                                                        			$object=new $controller();  
                                                        			call_user_func_array(array($object, $action), $params);
                                                        

                                                        So hab ich das jetzt gelöst, ich hoffe all deine Ratschläge wurden umgesetzt.
                                                        Allerdings habe ich ein Problem.
                                                        In meinem Testskript, wird der Controller "Newsletter" mit der Action run(array $params) aufgerufen.

                                                        Die URL dazu sieht so aus:
                                                        http://localhost/Newsletter/run/cat/5/?test=okay

                                                        Wenn ich var_dump($params) vor ich call_user_func_array() aufrufe,
                                                        habe ich folgende Ausgabe:
                                                        array(2) {
                                                           [0]=>  array(2) { [0]=>  string(3) "cat" [1]=>  string(1) "5" }
                                                           [1]=>  array(1) { ["test"]=>  string(4) "okay" }
                                                        }

                                                        Das ist ja auch richtig so.

                                                          
                                                        public function run(array $params){  
                                                        		var_dump($params);  
                                                        	}  
                                                        
                                                        

                                                        So sieht die Action im Controller aus - und was gibt der Drecksack mir aus?

                                                        array(2) { [0]=>  string(3) "cat" [1]=>  string(1) "5" }

                                                        Egal was ich versuche - ob ich sie mit $params[0/1] anspreche oder aus $params[]=$main; -> $params['main']=$main;  mache und dann über $params['main'] das Subarray anspreche. Es klappt nicht. Er überträgt irgendwie nur ein Array.

                                                        Ich wette das ist nur gerade ein Flüchtigketisfehler mit nem Brett überm Kopf. Ich bin grad echt zu blöd ein mehrdimensionales Array als Parameter zu übergeben.

                                                        Gruß,
                                                        Klaus

                                                        1. echo $begrüßung;

                                                          So hab ich das jetzt gelöst, ich hoffe all deine Ratschläge wurden umgesetzt.

                                                          Hmm, manche Sachen überliest du einfach konsequent obwohl ich sie mitunter mehrfach erwähne und dann:

                                                          Allerdings habe ich ein Problem.

                                                          Und das tut ja nun nicht not.

                                                          Lass das Querystring-Handling aus dem Router komplett raus. POST und GET sollen Nutzdaten transportieren. Für Routing-Zwecke wollen wir sie nicht verwenden. Der FrontController/Router soll auch nicht entscheiden oder wissen müssen, aus welcher Quelle (POST oder GET) die Nutzdaten kommen. Das muss allein die Action wissen, die die Daten benötigt.

                                                            		# Sonstige Parameter  
                                                            		parse\_str($uri\_params[1], $misc);  
                                                            		$params[]=$misc;  
                                                          

                                                          Der Teil fliegt raus. Und wenn eine Action $_GET oder $_POST oder sonst eine Quelle auswerten will, soll sie das selbst machen.

                                                          Damit löst sich dein Problem auf, weil nur noch die Pfad-Parameter übertragen werden müssen und das ist ein einfaches Array, welches von call_user_func_array() in einzelne Funktionsargumente umgesetzt wird.

                                                          Noch eine kleine Korrektur:

                                                            		# Wichtige Parameter  
                                                            		$main=array\_slice($uri, 2);  
                                                            		$params[]=$main;  
                                                          

                                                          wird zu

                                                          $params = array_slice($uri, 2);

                                                          und dann ist es schon fast perfekt.

                                                          So sieht die Action im Controller aus - und was gibt der Drecksack mir aus?
                                                          array(2) { [0]=>  string(3) "cat" [1]=>  string(1) "5" }

                                                          call_user_func_array() übersetzt das Array in einzelne Parameter. Wenn du ein Array hast

                                                          $params = array('foo', 'bar');

                                                          dann erhältst du mit call_user_func_array('qux', $params) für

                                                          function qux($arg1, $arg2) {...}

                                                          'foo' in $arg1 und 'bar' in $arg2.

                                                          Umgesetzt auf mein Beispiel hattest du statt 'foo' und 'bar' jeweils ein Array und hast nur $arg1 ausgewertet.

                                                          Die URL dazu sieht so aus:
                                                          http://localhost/Newsletter/run/cat/5/?test=okay

                                                          Welche Bedeutung überträgt cat? Wenn die 5 bereits die Kategorien-ID ist, dann ließe ich den cat-Teil weg (=> /Newsletter/run/5?test=okay) und schriebe

                                                          public function run($catID) {
                                                              machWasMitKategorie($catID);
                                                              machWasAnderesMit($_GET['test']);
                                                            }

                                                          echo "$verabschiedung $name";

                                      2. Achja und eine weitere Frage.

                                        Das Model holt dem View ja die Daten.
                                        Wohin würden die Aufgaben kommen:

                                        • Trage Newsletter in die Datenbank ein
                                        • Verschicke Newsletter an die E-Mail: xxx@xxx.xxx

                                        Also sorgt das Model nur für die Datenbeschaffung oder auf für weitere Art von Verarbeitung?

                                        1. echo $begrüßung;

                                          Wohin würden die Aufgaben kommen:

                                          • Trage Newsletter in die Datenbank ein

                                          Klarer Fall für das Model.

                                          • Verschicke Newsletter an die E-Mail: xxx@xxx.xxx

                                          Martin Fowler beschreibt in seinem Buch Patterns of Enterprise Application Architecture das Model als etwas, das alle Daten und Methoden enthält, die nicht für die Benutzerschnittstelle verwendet werden. E-Mail-Senden wäre also auch eine Aufgabe für das Model. Diese spezielle Aufgabe darf es durchaus an einen Spezialisten weiterleiten (selbständige E-Mail-Klasse, -Funktion, wasauchimmer).

                                          Also sorgt das Model nur für die Datenbeschaffung oder auf für weitere Art von Verarbeitung?

                                          Im Prinzip kümmert es sich um die gesamte Geschäftslogik, alles was hinter den Kulissen abläuft. Model, View und Controller sind Aufgaben. Sie müssen keineswegs immer als monolithisches Gebilde realisiert werden. Wenn beispielsweise die View sich ihr Template aus einer Datenbank holt, dann sehe ich die Datenbank für diesen Vorgang als Teil der View-Rolle. Auch wenn das gleiche physikalische DBMS vorher Daten für das Model geliefert hat. Für diese Aufgabe war sie Teil der Model-Rolle.

                                          echo "$verabschiedung $name";

                      2. Ich bin nochmal da. ^^

                        Ich habe im Moment dieses Konstrukt:

                        FontController.php
                        index.php
                        Helper/class.db.php
                        Helper/class.tools.php
                        Helper/ErrorControl/class.error.php
                        Helper/ErrorControl/Errorlogs
                        Settings/class.settings.php
                        Settings/settings.ini
                        Views/Board/ // hier sind die Views vom Board drin.
                        Controller/Controller_Board.php
                        Models/Board/ // hier sind die Models vom Board drin.

                        Ein Model ist immer eine Klasse und bekommt nur eine Aufgabe zugewiesen wie "hole mir alle Postings aus der Datenbank" oder?

                        Ich habe ja den diktatorischen FrontController. Sollte ich noch eine FrontView-Klasse anlegen?
                        Eine Front-Model klasse halte ich wohl für unsinnig.

                        Übrigens die Helperklassen werde ich direkt in die index.php includen und Settings werde ich direkt instanzieren.
                        Alle Klassen im Ordner Helper sind statisch aber die DB_klasse setzt auf lazy Connect.

                        1. echo $begrüßung;

                          Models/Board/ // hier sind die Models vom Board drin.
                          Ein Model ist immer eine Klasse und bekommt nur eine Aufgabe zugewiesen wie "hole mir alle Postings aus der Datenbank" oder?

                          Letztlich ist es deine Entscheidung. Zerhack das Model nicht zu sehr. Welche Zusammenhänge und welche Unterschiede bestehen zwischen den Aufgaben der Board-Models? Es wird sicher eine Tabelle Kategorien und eine für Postings geben. Alle Kategorien-Aufgaben kommen in eine Klasse, alle Posting-Aufgaben in eine andere. Wenn die beiden am Ende zu wenig Code ergeben, als dass eigenen Klassen gerechtfertigt sind, wäre auch eine Zusammenlegung in eine Board-Klasse möglich. Wenn sich allerdings durch die anderen Teile des Projekts ergibt, dass dort einzelne Klassen sinnvoll sind, sollte man das Prinzip aus Konsistenzgründen überall anwenden.

                          Ich habe ja den diktatorischen FrontController. Sollte ich noch eine FrontView-Klasse anlegen?
                          Eine Front-Model klasse halte ich wohl für unsinnig.

                          Arbeitet ein Diktator selbst? Zumindest hat er für den Kleinkram sein Personal. Der vom ZF verteilt noch nicht mal die Requests selber sondern übergibt diese Aufgabe an Router und Dispatcher. Wenn im Gesamtlayout eine Navigation enthalten ist, deren Daten aus einer Datenhaltung ausgelesen werden, dann wäre das eine Aufgabe für einen Layout-ActionController. Wenn der FrontController die Ergebnisse aller Einzelaufgaben eingesammelt und sie mit einer leichten Handbewegung in das Gesamtkunstwerk eingebettet hat, steht er immer noch als großer Held da.

                          Alle Klassen im Ordner Helper sind statisch aber die DB_klasse setzt auf lazy Connect.

                          Arbeit die liegen bleibt ist nie vergebens. Man kann sogar einen Lazy Fetch implementieren.

                          Normalerweise fetcht die MySQL-API nach einem SELECT im Hintergrund still und leise sämtliche Daten der Ergebnismenge in einen Zwischenpuffer. Nur so sind ihr Aussagen wie die Anzahl der Ergebniszeilen möglich. Auf diesen Zwischenpuffer kann man nicht direkt zugreifen. Man muss immer brav selbst fetchen und bekommt Stück für Stück die Daten aus dem Zwischenpuffer. Als Model will man ja die Implementierungsdetails der Datenabfrage verbergen, also legt man ein Array an, in das man die Datensätze ablegt und schafft sich so einen zweiten Zwischenpuffer. Die View <del>rödelt</del><ins>iteriert</ins> meist nur einmal drüber und das wars. Klingt nach Verschwendung? Und besonders bei größeren Datenmengen nicht nach Performance-Optimum? Da widerspreche ich (mir) nicht. Den ersten Zwischenpuffer bekommt man weg, indem man eine ungepufferte Abfrage startet. mysql_unbuffered_query() lassen wir links liegen, wer mit Design Pattern hantiert kann auch mit der mysqli-Extension arbeiten. Leider ist die Prepared-Statements-Implementierung in mysqli für Wald- und Wiesen-Scripte optimiert und für eine generische API nicht besonders geeignet [1], also bleibt es beim mysqli::query(). Das bekommt als resultmode-Parameter MYSQLI_USE_RESULT verpasst. Die Fetch-Funktionen fetchen dann die Datensätze direkt vom Server. Der eigene Zwischenpuffer lässt sich umgehen, indem man sich der SPL bedient. Die bietet unter anderem das Iterator-Interface an. Das Model gibt also kein Array zurück sondern ein Objekt einer Klasse, die das Iterator-Interface implementiert hat. Beim Instantiieren bekommt das Objekt ein MySQLi_Result-Objekt übergeben. Und bei jedem next() wird davon ein Datensatz gefetcht. Ein foreach über ein Objekt einer Iterator implementierenden Klasse führt zu next()-Aufrufen. Ergebnis ist, dass die View "denkt", sie bekäme wie üblich ein Array mit Datensätzen und "foreacht" sie in die Ausgabe. Stattdessen macht es next() und fetch() direkt vom MySQL-Server.

                          Die Sache hat allerdings mindestens drei Haken. Wie implizit erwähnt, geht mit einer ungepufferten Abfrage kein mysqli_result->num_rows. Das heißt, es geht schon, liefert aber erst dann ein richtiges Ergebnis, wenn man alle Datensätze abgeholt hat. Und man muss ein Resultset erst komplett gefetcht haben, bevor man eine weitere Query absetzen kann. Wenn mehrere Querys von einem oder mehreren ActionControllern veranlasst werden sollen, muss man immer die passende View rendern lassen, bevor man die nächste Query starten kann. Doch damit hätten wir wieder einen Zwischenpuffer gefüllt. Der dritte Nachteil ist, man kann über das Ergebnis genau einmal iterieren, dann ist es weg, wenn man es sich nicht irgendwohin ablegt (zwischenpuffert).

                          Wenn also mehr als eine Query abgearbeitet werden soll, kommt man um einen Zwischenpuffer nicht umhin, aber es müssen nicht zwei werden. Nehmen wir also doch eine gepufferte Abfrage und verlagern nur den eigenen Fetch-Vorgang in das Iterator-Interface. Dann kann man auch mehrfach drüber iterieren, indem man beim rewind() ein mysqli_result::data_seek(0) ausführt.

                          [1] Prepared Statements wollen "echte" Variablen für das Bind der Platzhalterparameter und für das Bind des Resultsets. Ein Array anzubinden, um eine beliebige Anzahl an Parametern übergeben und eine beliebige Anzahl an Spalten im Resultset auffangen zu können, ist recht umständlich zu lösen. Zudem ist der Prepared-Statements-Mehraufwand gegenüber einem herkömmlichen Query-Fetch zu beachten, der sich erst bei Massendaten lohnt/rentiert.

                          echo "$verabschiedung $name";

                      3. echo $begrüßung;

                        » Die Formulareingaben sind eigentlich weniger interessant für ihn. Die
                        Also werde ich dem Formular per action="" die Informationen für die weitere Verarbeitung geben und der FrontCrontroller kann sie per URL weiterverarbeiten.

                        Ja. So ein FrontController ist nur dann sinnvoll, wenn alle Requests auf ihn geleitet werden und er sie dann verteilt. Welche Aktion ausgeführt werden soll übergibt man am besten im Pfad-Teil der URL. Man hat dann nämlich noch den Querystring und die POST-Daten zur Übertragung von anwendungsspezifischen Daten. Im Pfadteil stehen auch solche Daten, die für das Ergebnis bedeutend sind. Die wertet der FrontController nicht selbst aus, extrahiert sie aber und übergibt sie der Action als Parameter. In Zeile drei des nachfolgenden Beispiels ist die 5 so ein Kandidat.

                        /board/categories
                          /board/categogies?sort=name;dir=desc
                          /board/category/5  gegebenenfalls zuzüglich POST-Daten mit dem Formularinhalt um die Kategorie Nummer 5 zu ändern

                        Die erste Zeile liefert eine Auflistung aller Kategorien. Die zweite ebenfalls, aber absteigend sortiert nach Namen. Die Sortierinformation übergebe ich deshalb als Querystring, weil der Inhalt der gleiche ist wie bei /board/categories, nur die Anordnung ist eine andere. Man könnte die URL auch als /board/categories/name/desc schreiben, aber für mein Verständnis sieht das eher nach einer signifikant anderen Ressource aus als bei der Variante mit den angehängten Query-Parametern. (Ich las auch, dass die Suchmaschinen (oder die eine zumindest) die Query-String-Variante weniger wichten und damit nicht als Duplicate Content ansehen. Ob's stimmt? Weiß ich nicht. Ich bin keine Suchmaschine und SEO interessiert mich nicht. Es klang jedenfalls plausibel.)

                        Die dritte Zeile mit GET aufgerufen gibt die Detaildaten von Kategorie Nummer 5 als Formular aus. Als POST aufgerufen zeigt die unveränderte URL an, dass man immer noch mit Nummer 5 hantiert, kann aber nun noch POST-Daten mitliefern. Alternativ kann man auch das Formular an /board/category/edit senden und die ID aus den POST-Daten entnehmen. Oder ... oder ... oder ... Der Kreativität sind da keine Grenzen gesetzt. Auch wenn man ein "fremdes" Framework verwendet, kann und muss man noch genügend eigene Ideen einbringen, so dass trotzdem am Ende auf etwas selbst Geschaffenes zurückblicken kann.

                        Warum heißt es denn jetzt Action? Der Unterschied zwischen Funktion und Methode ist mir bewusst aber jetzt kommt noch Action dazu. Wo ist denn jetzt der Unterschied zwischen Action und Methode? Nennt man eine Methode Action wenn sie innerhalb eine MVC-Patterns agiert?

                        Ein Pattern ist erst einmal nur, wie der Name schon sagt, ein Muster, eine Lösungsidee. Man muss so ein Muster nicht unbedingt mit OOP in eine konkrete Form bringen. Ein Pattern beschreibt nur den allgemeinen Aufbau ohne auf konkrete Implementierungsdetails einzugehen. Das sieht man auch an den Begrifflichkeiten. Ein Controller aus dem MVC-Pattern hat eine oder mehrere Actions, je eine für eine bestimmte (Teil-)Aufgabe. Er gruppiert, wenn man so will, Actions zu einem bestimmten Thema. Gießt man so einen ActionController in konkreten Code, noch dazu OOP-Code, so bietet es sich an, den Controller als Klasse und die Actions als Methoden zu implementieren. (Wie immer, kann man auch das MVC-Pattern auf andere Weise implementieren. Unter Python beispielsweise muss man nicht unbedingt eine Klasse anlegen. Jede Code-Datei wird als ein Modul behandelt. Legt man die Actions in einer Code-Datei als Funktionen an, so sind diese schon durch das Modul gruppiert, das Modul ist hier also der Controller. - Ob das eine gute Idee ist, sei mal dahingestellt, es ist jedenfalls eine mögliche.)

                        Wenn man es genau nimmt, ist bei allgemeinen Beschreibungen des MVC-Patterns immer/meist nur vom Controller, nicht aber von Actions die Rede. Es hat sich jedoch eingebürgert, die Aufgaben eines Controllers in Actions aufzuteilen, was der Übersichtlichkeit und Wartbarkeit dienlich ist.

                        Du hast geschrieben das der FrontController die Information das ein  Request(POST oder GET) entgegennimmt und dementsprechend die passende Klasse instanziert.
                        Das sehe ich auch so.
                        Dann aber hast du gerade geschrieben das der FrontController auch die passende Action/Methode aufruft.
                        Ich nehme mal an du meinst eine Methode die die restlichen Daten des Requests entgegennimmt und dann zwischen Model und View hin und herschiebt oder?

                        Mit der Instantiierung einer Klasse ist es ja noch nicht getan, denn außer dem Konstruktor ist ja noch nichts ausgeführt worden. Der Konstruktor hat aber nur initialisierende Aufgaben und soll nicht gleicht die ganze Arbeit erledigen. Zumal wir uns ja entschieden haben, zwecks Übersichtlichkeit die Aufgaben eines Controllers in Actions zu gliedern. Wenn der Konstruktor alles erledigte, bräuchte man für jede Action eine eigene Klasse ... und könnte gleich "herkömmliche" Funktionen nehmen.

                        Könnte man sich diese Methode dann nicht sparen und in den Konstruktor packen? Sie wird doch eh jedes mal benötigt. Weil ohne Daten - macht das Ding nichts. Selbst ohne Daten wir dann reagiert weil er keine Daten hat.

                        Schau dir nochmal den BoardController an, so wie ich ihn bereits skizziert habe. Er hat ja viele Aufgaben. Er muss nicht nur auf verschiedene Weisen mit den Beiträgen umgehen sondern auch Kategorien anzeigen und eventuell bearbeiten können. All diese Teilaufgaben separiert man besser als sie in einem großen Codehaufen unterzubringen.

                        Ich wüsste sonst auch nichts was in den Konstruktor reinpassen könnte, ausser sich Variablen zurechtzuweisen.

                        Lass ihn einfach leer oder weg, wenn dir im Moment dafür keine Verwendung einfällt.

                        echo "$verabschiedung $name";