BRAINSTORMING PHP/SQL/HTML/JS/CSS Ihr habt eine Idee, aber keinen genauen Ansatz? Diskutiert mit anderen Usern des Forums über eure Gedankengänge um evtl. hilfreiche Ideen zu bekommen!
Normale Fragen bitte weiterhin in die entsprechenden Foren! |
 |

23-08-2010, 10:45
|
|
gourmet
Registrierter Benutzer
|
|
Registriert seit: Feb 2007
Beiträge: 154
|
|
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
|

23-08-2010, 11:48
|
AmicaNoctis
 Moderatorin
|
|
Registriert seit: Jul 2009
Beiträge: 5.550
|
|
Hallo,
Zitat:
Zitat von gourmet
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:
Zitat von gourmet
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
__________________
Hast du die Grundlagen zur Fehlersuche gelesen? Hast du Code-Tags benutzt? 
Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
Super, danke! 
Geändert von AmicaNoctis (23-08-2010 um 11:54 Uhr)
|

23-08-2010, 13:30
|
|
gourmet
Registrierter Benutzer
|
|
Registriert seit: Feb 2007
Beiträge: 154
|
|
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
|

23-08-2010, 13:57
|
|
combie
PHP Expert
|
|
Registriert seit: May 2006
Beiträge: 2.925
|
|
Eine Verbindung reicht!
Diese kannst du in einer Registry halten, oder per Dependency Injection verteilen.
|

23-08-2010, 14:29
|
|
gourmet
Registrierter Benutzer
|
|
Registriert seit: Feb 2007
Beiträge: 154
|
|
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
|

23-08-2010, 16:40
|
AmicaNoctis
 Moderatorin
|
|
Registriert seit: Jul 2009
Beiträge: 5.550
|
|
Zitat:
Zitat von gourmet
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.
__________________
Hast du die Grundlagen zur Fehlersuche gelesen? Hast du Code-Tags benutzt? 
Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
Super, danke! 
|

23-08-2010, 17:55
|
unset
 Moderator
|
|
Registriert seit: Jan 2007
Ort: Düsseldorf
Beiträge: 3.778
|
|
Ich würd's ja eher im Zweifel von "oben" holen, aber das ist am Ende wohl Geschmackssache.
|

23-08-2010, 21:49
|
|
gourmet
Registrierter Benutzer
|
|
Registriert seit: Feb 2007
Beiträge: 154
|
|
Zitat:
Zitat von AmicaNoctis
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
|

26-08-2010, 15:13
|
|
pascal007
Registrierter Benutzer
|
|
Registriert seit: Jul 2006
Beiträge: 255
|
|
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.
|

26-08-2010, 18:09
|
AmicaNoctis
 Moderatorin
|
|
Registriert seit: Jul 2009
Beiträge: 5.550
|
|
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.
__________________
Hast du die Grundlagen zur Fehlersuche gelesen? Hast du Code-Tags benutzt? 
Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
Super, danke! 
Geändert von AmicaNoctis (27-08-2010 um 12:01 Uhr)
|

31-10-2010, 13:42
|
Shurakai
Master  
|
|
Registriert seit: May 2004
Ort: Bergisch Gladbach
Beiträge: 3.090
|
|
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.
Zitat:
|
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:
Zitat von AmicaNoctis
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
|

31-10-2010, 15:57
|
AmicaNoctis
 Moderatorin
|
|
Registriert seit: Jul 2009
Beiträge: 5.550
|
|
Zitat:
Zitat von Shurakai
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:
Zitat von Shurakai
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.
__________________
Hast du die Grundlagen zur Fehlersuche gelesen? Hast du Code-Tags benutzt? 
Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
Super, danke! 
|

02-11-2010, 11:03
|
|
gourmet
Registrierter Benutzer
|
|
Registriert seit: Feb 2007
Beiträge: 154
|
|
huch hier wird ja fleißig weiter diskutiert  .
Ich habe es übrigens mit Typehinting gelöst...
|

03-11-2010, 19:14
|
Shurakai
Master  
|
|
Registriert seit: May 2004
Ort: Bergisch Gladbach
Beiträge: 3.090
|
|
Zitat:
Zitat von AmicaNoctis
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)
Zitat:
|
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.
Zitat:
|
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.
Zitat:
|
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
|

03-11-2010, 20:14
|
|
gourmet
Registrierter Benutzer
|
|
Registriert seit: Feb 2007
Beiträge: 154
|
|
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
|
|
Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)
|
|
|
| Themen-Optionen |
|
|
| Thema bewerten |
|
|
Forumregeln
|
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.
HTML-Code ist aus.
|
|
|
|
PHP News
|