MVC Verständnissfrage

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

  • MVC Verständnissfrage

    Hallo Leute,

    ich beschäftige mich zur Zeit mit der Umsetzung von MVC in PHP.

    Wenn ich alles richtig verstanden habe, dann ist das Datenbank-Objekt ein Model.
    Wenn ich jetzt z.B.die Einträge eines Gästebuches anzeigen lassen möchte, läuft das ganze vom View zum Controller, der dann die Daten vom Model bekommt und nun meine Frage.

    Jetzt müßte ich ja im Controller ein Datenbank-Objekt erstellen?
    Ist es nicht auch möglich, das Datenbank-Objekt schon im View zu erstellen und an den Controller zu übergeben?


    Vielen Dank für einen Denkanstoß

    gourmet

  • #2
    Hallo,

    Zitat von gourmet Beitrag anzeigen
    Jetzt müßte ich ja im Controller ein Datenbank-Objekt erstellen?
    Genau, der Controller verarbeitet die Anfrage, instanziiert benötigte Model- und View-Klassen und vermittelt zwischen ihnen.

    Zitat von gourmet Beitrag anzeigen
    Ist es nicht auch möglich, das Datenbank-Objekt schon im View zu erstellen und an den Controller zu übergeben?
    Auf keinen Fall. Model und View kommen miteinander niemals in Berührung und sind passiv. Jede Aktion wird vom Controller angestoßen. Der Controller wird typischerweise dem Model sagen "hole dies", "speichere das" und dem View "gib das hier mal aus" bzw. "erzeug davon mal eine ausgabefähige Repräsentation".

    Gruß,

    Amica
    Zuletzt geändert von AmicaNoctis; 23.08.2010, 10:54.
    [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
    Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
    Super, danke!
    [/COLOR]

    Kommentar


    • #3
      Hallo Amica,

      das hab ich mir doch gleich gedacht., dass das mit dem Datenbank-Objekt im View Unsinn ist .

      Hmm, jetzt würde bei jedem Controller (Subcontroller) ein neues Datenbank-Objekt erstellt und damit auch eine neue Verbindung. Summiert sich das ganze sich dann nicht oder wird die Verbindung getrennt und erst wieder neu aufgebaut, wenn ich ein neues DB-Objekt initialisiere?


      gourmet

      Kommentar


      • #4
        Eine Verbindung reicht!

        Diese kannst du in einer Registry halten, oder per Dependency Injection verteilen.
        Wir werden alle sterben

        Kommentar


        • #5
          Das eine Verbindung reicht weiß ich ja und meinte ich auch damit.

          Daran das Datenbank-Objekt zu globalisieren dachte ich auch schon.
          Werde es dann wohl mit einer Registry machen.

          Vielen Dank erstmal bis hierher

          Kommentar


          • #6
            Zitat von gourmet Beitrag anzeigen
            Daran das Datenbank-Objekt zu globalisieren dachte ich auch schon.
            Werde es dann wohl mit einer Registry machen.
            Nicht einmal das würde ich machen. Mein Vorschlag: Der Frontcontroller instanziiert es einmal und reicht es bei der Initialisierung der "Subcontroller" im Konstruktor durch. Mit von PDO abgeleiteten Klassen kann man das durch Typehinting wunderbar sicherstellen.
            [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
            Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
            Super, danke!
            [/COLOR]

            Kommentar


            • #7
              Ich würd's ja eher im Zweifel von "oben" holen, aber das ist am Ende wohl Geschmackssache.
              [FONT="Helvetica"]twitter.com/unset[/FONT]

              Shitstorm Podcast – Wöchentliches Auskotzen

              Kommentar


              • #8
                Zitat von AmicaNoctis Beitrag anzeigen
                Nicht einmal das würde ich machen. Mein Vorschlag: Der Frontcontroller instanziiert es einmal und reicht es bei der Initialisierung der "Subcontroller" im Konstruktor durch. Mit von PDO abgeleiteten Klassen kann man das durch Typehinting wunderbar sicherstellen.
                Hmm, ich glaube so meinte ich es auch die ganze Zeit.
                Mal ein kleines vereinfachtes Beispiel.

                index.php
                PHP-Code:
                require_once 'autoload.php';
                $db = new DB;
                require_once 
                'FrontController.php';
                $frontcontroller = new FrontController($db);
                $frontcontroller->run(); 
                FrontController.php
                PHP-Code:
                class FrontController {
                private 
                $action;
                private 
                $controller;
                private 
                $db_obj;

                     public function 
                __construct($db_obj) {
                     
                $this -> db_obj $db_obj;
                     
                //...
                     
                }

                     public function 
                run() {
                     
                //...
                     
                $controller = new $this->controller($this->db_obj);
                     
                //...
                     
                }

                TestController.php
                PHP-Code:
                class TestController {
                private 
                $db_obj;
                private 
                $view;

                     public function 
                __construct($db_obj) {
                     
                $this -> db_obj $db_obj;
                     
                $this -> view = new View();
                     }

                     public function 
                Test_Aktion() {
                     
                $data =  $this -> db_obj -> prepare('SELECT name FROM table');
                     
                $this -> view -> data $data;
                     }

                View.php
                Ausgabe der Daten

                Ich habe fertig und hoffe ich habe nichts vergessen

                Kommentar


                • #9
                  Also ich habe immer noch Popo's (Plain Old Php Objects)... mit dem Controller hole ich die Daten aus der Datenbank und speichere sie dann in einem Popo ;-).

                  Kann die DB also auch als "Popo" fungieren im MVC? Ich dachte immer für das MVC müsse man solche Popo-Objekte erzeugen die der Controller dann abfüllt.

                  Kommentar


                  • #10
                    Ich kenne zwar POPOs nicht, aber wenn das einfache Daten-Objekte ohne Methoden (oder zumindest nur mit Gettern und Settern) sind, dann machen die schon Sinn. Ich nehme die einfach dazu, den Payload mit dem Model auszutauschen und eine Ausgabeunabhängige Repräsentation an das View zu übergeben.

                    Die DB ist jedoch nur eine Möglichkeit für das Model und muss austauschbar bleiben, also von den reinen Datenklassen/structs unabhängig.
                    Zuletzt geändert von AmicaNoctis; 27.08.2010, 11:01.
                    [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
                    Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
                    Super, danke!
                    [/COLOR]

                    Kommentar


                    • #11
                      Ich bin gerade über diesen Thread gestolpert und habe einfach mal nach "Dependency" gesucht, wodurch ich auf magere 20 Ergebnisse und diesen Thread als 1. gestoßen bin. Ich erlaube mir, auch nach ca. 2 Monaten hier mal zu antworten und ein paar Kommentare abzugeben.

                      Auf keinen Fall. Model und View kommen miteinander niemals in Berührung und sind passiv. Jede Aktion wird vom Controller angestoßen. Der Controller wird typischerweise dem Model sagen "hole dies", "speichere das" und dem View "gib das hier mal aus" bzw. "erzeug davon mal eine ausgabefähige Repräsentation".
                      Es gibt verschiedene MVC-Paradigmen, aber so zu programmieren, halte ich für falsch. Wenn nämlich der Controller dem View vorschreibt, was er benutzen darf und was nicht, ist der View an den Controller gebunden, obwohl das nicht sein muss. Aus diesem Grund darf der View nämlich sehr wohl auf das Model zugreifen, aber nur lesend. (Das ist der springende Punkt!)

                      Zitat von AmicaNoctis Beitrag anzeigen
                      Nicht einmal das würde ich machen. Mein Vorschlag: Der Frontcontroller instanziiert es einmal und reicht es bei der Initialisierung der "Subcontroller" im Konstruktor durch. Mit von PDO abgeleiteten Klassen kann man das durch Typehinting wunderbar sicherstellen.
                      Das ist ein Anti-Pattern: Wieso sollte der FrontController eine Abhängigkeit (!), und damit eine Kopplung, zu einem DB-Objekt haben, wenn es das überhaupt nicht braucht? Eine Regel in der OOP-Welt lautet: "Nimm nur das, was DU brauchst, nicht was andere brauchen."

                      Aus diesem Grund werden im Konstruktor klar die Abhängigkeiten deklariert, das übergeben von Parametern "nach gut Dünken" ist unnötig. Für diesen Zweck gibt es übrigens Dependency Injection Container, z.B. den PICO Container oder den Symfony Injection Container. (Direktlink für die PHP 5.3 Version: Auf Github.com. Eine Einleitung zum Symfony 1.x Container für PHP 5.2 gibt es hier: What is Dependency Injection? - Fabien Potencier. (6 Artikel))


                      Ganz wichtig ist, dass man sich klar macht, dass eine Abhängigkeit nicht von oben nach unten durchgereicht werden soll oder irgendwo im Code (z.B. im Konstruktor) erzeugt werden sollte, sondern ggf. mit Inversion of Control gearbeitet wird. Das heißt, Steckkastenprinzip wird angewandt:

                      PHP-Code:
                      new Auto(new Lenkrad(Color::RED), new Reifen([...])); 
                      Und so weiter. Mit Hilfe des Dependency-Injection-Containers wird das einfach zu
                      PHP-Code:
                      $container->get('auto'); 
                      Grüße
                      Christian
                      Für alle die Fehler suchen, gibts gratis tolle Debuggingmöglichkeiten:
                      var_dump(), print_r(), debug_backtrace und echo.
                      Außerdem gibt es für unsere Neueinsteiger ein hervorragendes PHP Tutorial zu PHP 4 und PHP 5 (OOP)
                      Es heißt $array['index'] und nicht $array[index]! Und nein, das ist nicht egal!
                      Dieses Thema lesen, um Ärger im Forum und verzögerte Hilfen zu vermeiden.

                      Kommentar


                      • #12
                        Zitat von Shurakai Beitrag anzeigen
                        Es gibt verschiedene MVC-Paradigmen, aber so zu programmieren, halte ich für falsch. Wenn nämlich der Controller dem View vorschreibt, was er benutzen darf und was nicht, ist der View an den Controller gebunden, obwohl das nicht sein muss. Aus diesem Grund darf der View nämlich sehr wohl auf das Model zugreifen, aber nur lesend. (Das ist der springende Punkt!)
                        Wieso sollte das View auf das Model zugreifen können? Es sollte normalerweise nur mit Nutzdaten gefüttert werden und diese ausgeben. Wenn es sich die selbst besorgt, ist das Model nicht mehr einfach austauschbar und dann kannst du den Controller gleich weglassen.

                        Wenn du dagegen diese einfachen Datenobjekte meinst, um die es hier im Thread ging, auf die kann das View sehr wohl zugreifen. Die gehören ja nicht direkt zum Model, haben normalerweise keine inhärente Logik, sondern sind im Prinzip komplexe Datentypen, die jeder verwenden kann, genau wie z. B. Floats und Arrays. Außerdem besorgt sich das View diese Dinger auch nciht selbst, sondern bekommt sie übergeben, um sie auszugeben. Das ermöglicht dieselbe Funktionalität wie dein direkter Zugriff, ohne die negativen Implikationen und Kopplungsprobleme.

                        Zitat von Shurakai Beitrag anzeigen
                        Wieso sollte der FrontController eine Abhängigkeit (!), und damit eine Kopplung, zu einem DB-Objekt haben, wenn es das überhaupt nicht braucht?
                        Irgendwer muss ja einmal alles instanziieren. Wenn nicht der Frontcontroller, wer denn sonst? Dependency Injection ist es ja und dafür braucht man nunmal jemanden, der injiziert. Wenn du mit diesen Containern arbeitest, dann ist mein Frontcontroller eben solch ein Container. Daher gebe ich die Frage mal zurück: Wieso sollte eine DI-Container eine Abhängigkeit und Kopplung zu einem DB-Objekt haben, wenn es dieses DB-Objekt selbst nicht braucht? Weil es sie eben für andere bereitstellen muss.

                        Deine weiteren Beispiele und Ausführungen klingen zwar, als würdest du mich korrigieren wollen, sind aber genau das, was ich auch mache. Dein letztes Beispiel ist übrigens imho mit einer Factory besser zu lösen.
                        [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
                        Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
                        Super, danke!
                        [/COLOR]

                        Kommentar


                        • #13
                          huch hier wird ja fleißig weiter diskutiert .

                          Ich habe es übrigens mit Typehinting gelöst...

                          Kommentar


                          • #14
                            Zitat von AmicaNoctis Beitrag anzeigen
                            Wieso sollte das View auf das Model zugreifen können? Es sollte normalerweise nur mit Nutzdaten gefüttert werden und diese ausgeben. Wenn es sich die selbst besorgt, ist das Model nicht mehr einfach austauschbar und dann kannst du den Controller gleich weglassen.
                            Deshalb programmiert man ja auch immer auf Interfaces, nicht auf Implementierungen. Der Einwand ist somit hinfällig.

                            Schau dir doch mal diesen Link hier an: P of EAA: Model View Controller

                            Das Buch "PoEAA" von Martin Fowler ist ein Standardwerk für (Enterprise) Patterns und ist übrigens sehr zu empfehlen.

                            Der Controller ist eben nur genau dafür da, den Request (!) entgegenzunehmen, zu schauen, welche Models aufgerufen werden sollen und welcher View benötigt wird. Der View kann sich durchaus Daten auch selber holen.

                            Insbesondere ist es wichtig, dass der View nur lesen darf, nicht aber schreiben. Das Model an sich darf übrigens NICHT auf den ViewLayer zugreifen. (Weil es darüber nix wissen muss)

                            Wenn du dagegen diese einfachen Datenobjekte meinst, um die es hier im Thread ging, auf die kann das View sehr wohl zugreifen. Die gehören ja nicht direkt zum Model, haben normalerweise keine inhärente Logik, sondern sind im Prinzip komplexe Datentypen, die jeder verwenden kann, genau wie z. B. Floats und Arrays. Außerdem besorgt sich das View diese Dinger auch nciht selbst, sondern bekommt sie übergeben, um sie auszugeben. Das ermöglicht dieselbe Funktionalität wie dein direkter Zugriff, ohne die negativen Implikationen und Kopplungsprobleme.
                            Dass jeder Layer natürlich Datenstrukturen braucht ist klar und wird nicht in Abrede gestellt.

                            Irgendwer muss ja einmal alles instanziieren. Wenn nicht der Frontcontroller, wer denn sonst? Dependency Injection ist es ja und dafür braucht man nunmal jemanden, der injiziert. Wenn du mit diesen Containern arbeitest, dann ist mein Frontcontroller eben solch ein Container. Daher gebe ich die Frage mal zurück: Wieso sollte eine DI-Container eine Abhängigkeit und Kopplung zu einem DB-Objekt haben, wenn es dieses DB-Objekt selbst nicht braucht? Weil es sie eben für andere bereitstellen muss.
                            Genau, irgendwer muss das ja mal tun. Aber der FrontController sicherlich nicht! Wenn man bestimmte Objekte bei JEDEM Aufruf benötigt, dann gehört sowas in einen Bootstrap-Mechanismus, nicht in einen FrontController.

                            Der FrontController nimmt nur den Request an und entscheidet, z.B. mit Hilfe eines Routers, welcher (Action)Controller aufgerufen wird, führt Plugins aus usw.

                            Zu deiner Frage: Ein Dependency Injection Container hat eben gerade KEINE Abhängigkeit zu einem DB Objekt, eine Kopplung erfolgt gerade nicht - genauso haben die Datenobjekte keine Abhängigkeit zum Container. Solange du dem DIC nicht beibringst - zum Beispiel per XML, PHP oder YAML Datei - weiß der Container nichts. Erst wenn du ihn explizit aufforderst, ein solches Objekt zu erzeugen, wird er das tun. Das ist übrigens auch ein Vorteil: Lazy-Loading.

                            Deine weiteren Beispiele und Ausführungen klingen zwar, als würdest du mich korrigieren wollen, sind aber genau das, was ich auch mache. Dein letztes Beispiel ist übrigens imho mit einer Factory besser zu lösen.
                            Nun, das letzte Beispiel ist sicherlich konstruiert gewesen. Dennoch gibt es viele Vorteile gegenüber einer Fabrik:

                            1.) Fabriken sind i.A. hardcoded, wenig erweiterbar und (häufig!) noch weniger wiederverwendbar. Um Abhängigkeiten zu ändern, musst du den SourceCode ändern - bei Hochsprachen ist das meistens mit einem recompile verbunden. DICs werden häufig mit XML oder YAML Dateien gefüttert, die auch "live" geändert werden können. Natürlich kann man auch im Quellcode bestimmte Parameter setzen.

                            2.) Eine Fabrik weiß i.A., wie man einen (!) Typen erzeugt. Ein DIC weiß i.A., wie man viele Typen (mit vielen unterschiedlichen Konfigurationen) erzeugt. (Userobjekte, Datenbankverbindungsobjekte, Service-Objekte, Plugins, ...). Gut, man könnte einer Fabrik Parameter mitgeben - aber das muss man dann jedesmal, wenn man dieses Objekt erstellt, was sicherlich lästig ist. Ein DIC erledigt das alles für einen.

                            3.) IoC / DIC ist in sich geschlossen. Das heißt, dass z.B. die ServiceObjekte keine unnötigen Abhängigkeiten zu irgendwelchen Fabriken haben.

                            Es ist ja so: Verwendest du eine Fabrik, ist die Frage: WER erzeugt diese Fabrik und übergibt diese - zwecks Austauschbarkeit - an die Objekte, die sie benötigen? Welches Objekt weiß von all diesen Abhängigkeiten? Man erzeugt lediglich eine neue Abhängigkeit, nämlich zur Factory. Der DIC wird i.A. einmal instantiiert und wird dann z.B. in einem Controller benutzt. Der DIC erzeugt den kompletten Abhängigkeitsgraphen. Damit ist das Problem gelöst - und die erzeugten Objekte wissen nichtmal, dass der DIC existiert. (Siehe oben)




                            Tipp: Bei youtube gibt es Videos von Misko Hevery, Mi?ko Hevery die bei Google aufgezeichnet wurden. ("Google Tech Talks", i.A. zu empfehlen.) Diese sind unter "The clean code talks" zu finden und sehr sehenswert. Die entsprechenden Folien kann man oben auch selber ansehen.


                            Nochmal kurz ein paar Prinzipien:

                            - Ein "new" in einem Konstruktor-Rumpf deutet auf eine unterschlage Abhängigkeit hin. Übergeben als Parameter, nicht "selber beschaffen"!
                            (Ein "new" im SourceCode ist fast immer ein Zeichen für fehlende Abhängigkeiten.)

                            - Hat ein Objekt A eine Abhängigkeit auf Objekt B, nur um es an andere Objekte zu übergeben (z.B. C), so liegt ein Designfehler vor. An A sollte C übergeben werden, nachdem C bereits B erhalten hat. (Form: new A(new C(new B()))), wie oben im Beispiel)

                            - Wer durch Objektgraphen wandert a la "$this->getUser()->getItem()->getBla()->getFoo()" hat einen Designfehler gemacht. $this benötigt das Foo-Objekt? Dann sollte diese Abhängigkeit im Konstruktor klar deklariert werden.


                            Diese Probleme werden übrigens mit dem DIC sehr elegant gelöst.

                            Grüße
                            Christian
                            Für alle die Fehler suchen, gibts gratis tolle Debuggingmöglichkeiten:
                            var_dump(), print_r(), debug_backtrace und echo.
                            Außerdem gibt es für unsere Neueinsteiger ein hervorragendes PHP Tutorial zu PHP 4 und PHP 5 (OOP)
                            Es heißt $array['index'] und nicht $array[index]! Und nein, das ist nicht egal!
                            Dieses Thema lesen, um Ärger im Forum und verzögerte Hilfen zu vermeiden.

                            Kommentar


                            • #15
                              Hallo Shurakai,

                              ihr habt wahrscheinlich beide Recht oder die Wahrheit liegt irgendwo in der Mitte .

                              Anbei noch ein Link zu einem Buch das ich mir mal zugelegt habe und wo auch einiges zum Thema MVC steht.

                              PHP Design Patterns - 2.Auflage


                              VG
                              gourmet

                              Kommentar

                              Lädt...
                              X