php.de

Zurück   php.de > Webentwicklung > Software-Design

Software-Design Diskussionen auf Profi-Niveau: PHP Lösungen auf konzeptioneller Ebene

Antwort
 
LinkBack (1) Themen-Optionen Bewertung: Bewertung: 2 Stimmen, 4,50 durchschnittlich.
Alt 11.10.2008, 00:28  
Erfahrener Benutzer
 
Registriert seit: 06.09.2008
Beiträge: 189
#Avedo befindet sich auf einem aufstrebenden Ast
Standard Strukturierung größerrer Projekte

Guten Morgen!
Ich habe leider immer öfter das Problem, dass ich nicht weiß, wie ich größere Projekte Strukturieren soll. Daher wende ich mich nun hoffnungsvoll an euch.

Eine meiner Meinung nach sinnvolle Struktur habe ich mal in dieser PDF-Datei aufgezeigt.

Nun habe ich allerdings das Problem, dass ich nicht weiß, wie ich die einzelnen Module sinnvoll aufbauen soll. Eins ist sicher jedes Modul, ich nehme jetzt mal als Beispiel ein News-Modul, soll sein eigenes Template sowohl für das Backend, als auch für das Frontend besitzen. Die einzelnen Aktionen, die innerhalb eines Moduls verfügbar seien sollen, sollen ausgelagert und am besten auch getrennt werden. Doch, wie lagere ich die Aktionen am geschicktesten in eine oder mehrere Dateien aus und wie führe ich letzt endlich alles am geschicktesten zusammen? Und wie mache ich am geschicktesten Objekte, wie eine Datenbank-Verbindung oder geladenene Konfigurationen global verfügbar?

Viele Fragen und gleich das nächste Problem? Wie kann ich mir Ausgaben erleichtern? Gibt es da einfach Muster, wie zum Beispiel bei einer Pager-Klasse, die eine Blätterfunktion ersetzt? Die Ausgabe von Daten in sortierbaren Tabellen ist sehr schick und für den User absolut angenehm, aber, wenn man sie jedesmal in das Layout einpassen muss, doch sehr ermüdent und zeitaufwendig. Lohnen sich hier Klassen, die bei solchen Aufgaben helfen und welche lassen könnten das neben einer Pager-Klasse noch sein?

Und gleich die nächste Frage. Natürlich ist es nicht schön, wenn man einmal etwas gecodet hat und es beim nächsten mal wieder schreiben muss, da man nicht alles wiederverwenden kann. Daher möchte ich gerne ein Grundsystem schreiben, dass eigentlich nicht mehr erlaubt als Benutzer, Einstellungen und Packages (Module) zu verwalten. Wie könnte so eine Verwaltung aussehen? Ich weiß es leider nicht. Ist es sinnvoll auf einfache Tarballs zurück zu greifen und sollte ich diese lieber einfach auf dem komplizierten Weg über die file()-Funktionen entpacken oder sollte ich die Gefahr auf mich nehmen, dass auf dem einen oder anderen Webspace exec() und system() verboten bzw. gesperrt sind? Wie könnte die Package-erwaltung weiter aussehen? Sollte eine Klasse die Installation eines Packages übernehmen? Das könnte zum Beispiel dann ja einfach so aussehen, dass diese Klasse einen Tarball einfach in ein temporäres Verzeichnis entpackt und dort eine install.php aufruft, die alle wichtigen Dateien verschiebt, Datenbanken erstellt und erste Einträge vornimmt. Ein Problem wäre dann die Deinstallation dieses Paketes. Eine weitere die Verknüpfung zwischen Paketen. Wie kann man überprüfen, ob ein Paket überhaupt gelöscht werden darf ohne andere zu beeinflussen? Sollten installierte Pakete in einer Datenbank erfasst werden?

Wie schon gesagt - sehr sehr viele Fragen, aber ich hoffe ihr könnte mir etwas weiter helfen.
MfG, Andy
__________________
I'm so tired of slitting the throats of people calling me a violent psychopath.
#Avedo ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 11.10.2008, 00:46  
Moderator und Wett-König
 
Benutzerbild von dr.e.
 
Registriert seit: 21.05.2008
Beiträge: 3.633
PHP-Kenntnisse:
Fortgeschritten
dr.e. ist ein Lichtblickdr.e. ist ein Lichtblickdr.e. ist ein Lichtblickdr.e. ist ein Lichtblickdr.e. ist ein Lichtblickdr.e. ist ein Lichtblick
dr.e. eine Nachricht über Skype™ schicken
Standard

Hallo Andy,

du formulierst viele Fragen, auf die ich gerne eingehen will. Allerdings ist jetzt schon recht spät und ich habe morgen eine lange Fahrt inkl. Hochzeitseinladung vor mir. Ich melde mich deshalb am Sonntag mit einer ausführlichen Antwort.

Zu deinem Post habe ich folgende schnelle Hinweise:
- Basis für Entwicklung: Adventure PHP Framework - Startseite
- Strukturierung von Modulen: Adventure PHP Framework - Gaestebuch Tutorial
- Pager: Adventure PHP Framework - Mitgelieferte Module
- Datenbank-Abstraktion: Adventure PHP Framework - Klassenreferenz connectionManager
- Wiederverwendbarkeit: Adventure PHP Framework - Kommentar Funktion Tutorial
- Grundsystem User-Verwaltung: Adventure PHP Framework - Generischer OR Mapper und forum.adventure-php-framework.org [de] • Thema anzeigen - GenericORMapper

Ich hoffe da ist etwas für dich dabei.
__________________
Viele Grüße,
Dr.E.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Think about software design before you start to write code!
2. Discuss and review it together with experts!
3. Choose good tools (-> Adventure PHP Framework (APF))!
4. Write clean and reusable software only!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dr.e. ist offline   Mit Zitat antworten
Alt 11.10.2008, 18:49  
Erfahrener Benutzer
 
Benutzerbild von phpdummi
 
Registriert seit: 06.06.2008
Beiträge: 1.631
PHP-Kenntnisse:
Anfänger
phpdummi ist zur Zeit noch ein unbeschriebenes Blatt
Standard

Hallo Andy,

um ein System möglichst modular zu entwickeln, benötigt man eine PAC-Ähnliche Architektur.
Um möglichst flexibel zu bleiben sollte aber jedes Modul die Möglichkeit besitzen, eigenständige
Models (Daten), Views (Präsentation) und Controller (Logik) zu haben.
Somit kann ein Modul zum Beispiel Frontend Views & Controller, und Backend Views & Controller
haben die auf das gleiche Model zurückgreifen. Die Module bleiben damit voneinander unabhängig.
Jetzt kommt natürlich die Frage auf, wie man die Module am besten zusammensteckt.
Einerseits sollen die Module unabhängig sein, andererseits benötigt man Flexibilität, damit sie
miteinander interagieren können. Zusätzlich muss der letzte Status jedes Moduls gespeichert werden.

Beispiel:
Das Menü und der Inhaltsbereich einer Internetseite sollen als getrennte Module entwickelt werden.
Das Menü benötigt immer den letzten Status um zu wissen, welcher Knoten gerade aufgeklappt ist,
schließlich soll es ja nicht einfach wieder zuklappen wenn jemand im Inhaltsbereich auf "weiter lesen" klickt.
Andererseits soll durch eine Navigation im Menü nicht direkt eine andere Seite im Inhaltsbereich erscheinen -
jedenfalls nicht wenn man nur eine Kategorie im Menü aufklappt.
Um die Usabilty weiter zu verbessern, soll im Menü immer der aktuelle Bereich aufklappen, der im
Inhaltsbereich ausgewählt wurde. Gelangt ein User also durch einen Klick auf einen Link in einen
anderen Bereich der Seite soll sich das Menü dazu entsprechend verhalten.

Damit haben wir also 2 Module die miteinander agieren. Beide müssen ihren letzten Zustand wissen
- ergo speichern - und über neue Events benachrichtigt werden. Das Menü hat die Events auf/zu klappen
und der Inhaltsbereich das Event anzeigen. Der Status eines Moduls kann entweder im Model oder
über eine Session-Objekt festgehalten werden. Die Benachrichtigung über neue Aktionen geschieht
üblicherweise über die URL. Bleibt noch die Frage bestehen, wie man die Module einer Applikation
am besten zusammensteckt. Dazu bietet sich das DOM (Document Object Model) an.
Es erlaubt eine beliebige Knotenstruktur und ermöglicht es über einfache Methoden, neue Knoten an
einer beliebigen Stelle einzufügen. Glücklicherweise ist es in PHP bereits implementiert, daher kann man Zeit bei der Entwicklung und Zeit bei der Code-Ausführung sparen.
(integrierte Klassen sind in der Ausführung immer schneller als eigene)

Fortsetzung folgt, ich muss zu einem Termin ...
__________________
"Nobody is as smart as everybody" - Kevin Kelly
— The best things in life aren't things
phpdummi ist offline   Mit Zitat antworten
Alt 12.10.2008, 12:35  
Erfahrener Benutzer
 
Registriert seit: 06.09.2008
Beiträge: 189
#Avedo befindet sich auf einem aufstrebenden Ast
Standard

Vielen dank für die Links und den bisher sehr sehr informativen Post! Muss noch etwas weiterlesen und verarbeiten.
MfG, Andy
__________________
I'm so tired of slitting the throats of people calling me a violent psychopath.
#Avedo ist offline   Mit Zitat antworten
Alt 12.10.2008, 15:32  
Erfahrener Benutzer
 
Benutzerbild von phpdummi
 
Registriert seit: 06.06.2008
Beiträge: 1.631
PHP-Kenntnisse:
Anfänger
phpdummi ist zur Zeit noch ein unbeschriebenes Blatt
Standard

Hola señor, da bin ich wieder.

DOM.
Mit dem DOM kannst du nun also deine Module - beliebig tief verschachtelt - in deinen Applikationsbaum
einbinden. Jetzt stellt sich die Frage wie du möglichst einfach den voneinander unabhängigen Modulen
mitteilst auf welche Events sie anspringen sollen. Am einfachsten wäre es den Modulen direkt beim
Einbinden in den Applikationsbaum einen URL Parameter und ggf. einen Startwert mitzugeben.
Da kommen wir zum Thema Templates. Es wäre ja eigentlich super, wenn das Hinzufügen der
Module zum Applikationsbaum über die Templates passieren könnte.
HTML Dokumente werden ja auch über das DOM repräsentiert. Also könnte man ein Root-Template
basteln von dem ausgehend alle Module eingebunden werden. Die Module können in ihren
jeweiligen Templates natürlich auch wieder andere (Teil-)Module einbinden.
Wie nun die Module im HTML einbinden? Um nicht HTML- und PHP-Code zu vermischen benötigt
man einen Tag. Zum Beispiel <import namespace="modules::menu::pres" module="Menu" urlparam="$MenuAction" connectto="Content" init="StartValue" />
Damit wäre das Modul "Menü" aus dem Namespace modules:menu::pres eingebunden und
mit dem Modul Content verbunden. Es weiß auf welchen Parameter es für Events hören muss
und mit welchem Startwert es initialisiert wird.
So far so good.
Die Template Komponente des Systems übersetzt die Tags entsprechend und fügt anstelle des
Tags das jeweilige Module in den Applikationsbaum ein. Jetzt benötigt man nur noch einen
URL-Manager, der sich darum kümmert die Links des Menüs an den URL-Parameter des
Content-Moduls zu binden. Um nicht so theoretisch zu bleiben etwas Code:
Code:
<html>
  <head>
    [..]
  <body>
    <import namespace="modules::menu::pres" module="Menu" urlparam="$MenuAction" connectto="Content" init="StartValue" />
    [..]
    <import namespace="modules::content::pres" module="Content" urlparam="$ContentAction" init="Home" />
  </body>
</html>
Der URL-Manager müsste also erkennen, dass das Menü- mit dem Content-Modul verbunden ist.
Der Inhalt des Menü-Moduls:
Code:
<ul>
  <li><a href="/Start" title="Startseite">Home</a></li>
  <li><a href="/News" title="Aktuelles">News</a></li>
</ul>
Der URL-Manager macht daraus:
Code:
<ul>
  <li><a href="?ContentAction=/Start" title="Startseite">Home</a></li>
  <li><a href="?ContentAction=/News" title="Aktuelles">News</a></li>
</ul>
Das wars auch schon. Die Sache mit den Tags in den Templates kann man nun noch beliebig
fortführen indem man eine Tag-Library implementiert usw.
Wenn du den Links zum Adventure PHP Framework gefolgt bist wirst du eigentlich alles hier aufgeführte zumindest in ähnlicher Form wieder finden.
Das APF ist allerdings wesentlich weitsichtiger angelegt, so kann man dort verschiedene Designs erstellen
und per loadDesign für Unterseiten ein komplett anderes Design anzeigen und viele andere tolle Sachen über die TagLib machen.

Frage: Warum schreibt hier nicht noch jemand über seine Erfahrung? Gibt doch so viele Cracks hier :-)
Wie sieht eure Architektur aus?
*bray to the ÜMOD*

PS: Hab dir mal einiges vorweggenommen, dr.e. ;-)
__________________
"Nobody is as smart as everybody" - Kevin Kelly
— The best things in life aren't things
phpdummi ist offline   Mit Zitat antworten
Alt 12.10.2008, 17:20  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 34.244
PHP-Kenntnisse:
Fortgeschritten
nikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz sein
Standard

Wenns sein muß, Dummy...

Ich bin nicht so bewandert in Softwaredesign wie Doc. E. und andere, deshalb werden einige meinen Stil vielleicht als inkonsequent oder unkonventionell bezeichnen. Nur ganz kurz mein derzeitiger Ansatz.

Ich benutze zu allererst einen Frontcontroller, um meinen Anfrage und Rückgaben zu zentralisieren. Der Frontcontroller verwaltet anfallende Request- und sonstige Parameterdaten (e.g. Sessions). Die Ausgabe - genauer der Response - ist an eine globale GUI Klasse gekoppelt, an die Teilausgaben bestimmter Templatebestandteile gehen. Dazu gleich mehr.

1. Grundlegende Anwendungsteile stehen in Libraries zur Verfügung, im allgemeinen benutze ich oft das Abstract Factory (AF) Pattern, stelle dann einige Defaultkomponenten zur Verfügung und überlasse es später dem "Entwickler" in seiner Umsetzung, die Codebasis durch weitere Ableitungen und zugehörige konkrete Fabriken zu ergänzen. In passenden Fällen benutze ich ein Verfahren, bei dem sich eine Fabrik bei dem AF-Client als Fabrik anmeldet. Jede so verwaltete Fabrik stellt eine canHandle () Methode bereit. Im Objekt-Erzeugungs-Kontext durchläuft der Client alle eingetragenen Factories mit bestimmten Parametern. Die erste passende Factory erhält den Zuschlag und erzeugt das Objekt. - Wie auch immer man dieses Pattern beziechnen mag, es ist praktisch.

2. Um eine Modularität zu gewährleisten, teile ich meine Anwendung in - ich nenne es - Komponenten auf. Jede Komponente besitzt einen Controller, der ihr Verhalten steuert und einen, der ihre Ausgabe kontrolliert. Beide Controller werden über Requestparameter gesteuert und melden sich dazu bei der Frontcontrollerkomponente an. Zum Zeitpunkt des Aufrufs der Komponente beziehen sie dann die für sie relevanten Controlling-Daten und reagieren nach vorgegebenem Verhalten. (Letzteres ist momentan noch recht fest verdrahtet)
Komponenten werden in meiner Anwendung zunächst bekannt gemacht (dabei werden die Klassen eingebunden). Die Businesslogik kann je nach Bedarf anschließend explizit aufgerufen werden oder erst aus dem "Template" kurz vor der Ausgabe (also dem Aufruf der View-Logik).
Kurz zu den "Templates": Ich benutze nur einfache <?php echo $Inhalt ?> Syntax, weil ich kein Fan von String- oder gar regulären Ersetzungen in diesem Zusammenhang bin. *)
Aus einem Main-Template werden dann alle Module die eine Ausgabe erzeugen über die GUI Klasse aufgerufen (u.U. auch rekursiv), abgearbeitet und gerendert. Zunächst in einen Puffer, der später in den Response des Frontcontrollers eingeht und dort schließlich nach nötigen Headerausgaben zur Ausgabe kommt.

3. Um jetzt nicht alle Komponenten, die in der Anwendung vorkommen können, einbinden zu müssen
- ach ja, Exkurs: ich bin kein Freund von dynamischer Einbindung von Programmteilen über irgendwelche zusammengefrickelten Pfade aus Namespaces und Klassennamen, bei mir ist alles explizit eingebunden. Ich gebe zu, meine Anwendungen waren bisher keinen Schwerlasttests ausgesetzt -
... habe ich eine weitere Hierarchiestruktur implementiert: Eine Art Pagecontrolling, das in etwa die thematische Struktur einer Website repräsentiert. Also bspw. eine Page pro Formular und Verarbeitung, wahlweise je eine oder eine gruppierende Seite für Inhaltsseiten etc.
Auch hier kommt ein Controller zum Einsatz, die Settings sind in einer Datenbank konfigurierbar, dabei können Platzhalter mehrere Thementeile auf eine gemeinsame Page bündeln.

4. Für diverse Einstellungen und Strukturen, statische Templates und Queryergebnisse kommt Caching zum Einsatz.

*) Möglicherweise werde ich diese Einstellung zumindest für die Aufrufe der Komponenten überdenken müssen, da bisher keine Trennung der anfallenden Ausgaben möglich ist.
__________________
--
One pixel is still too big. Please make it smaller. ASAP.

Initiative Mittelstand.
Die wichtigste Gestaltungsregel im Screendesign ist Pi mal Daumen des Arbeitgebers.
--

Geändert von nikosch (12.10.2008 um 17:29 Uhr).
nikosch ist gerade online   Mit Zitat antworten
Alt 13.10.2008, 13:38  
Erfahrener Benutzer
 
Registriert seit: 06.09.2008
Beiträge: 189
#Avedo befindet sich auf einem aufstrebenden Ast
Standard

Danke für eure sehr informativen Posts. Ich muss leider zugeben, dass ich den zweiten etwas besser verstanden habe. Ich setzte zudem in Templates auch lieber auf die Templateeigenschaften von PHP und nutze manchmal auch die Alternativsyntaxfür Kontrollstrukturen, wobei ich eigentlich versuche dies zu vermeiden. Leider habe ich nicht richtig verstanden, wie ich mir einen Frontcontroller vorstellen muss. Ist das soetwas wie eine HTTP-Klasse, die eben die verschiedenen Request (HEAD/GET/POST) an ein Script sendet und dabei Cookies, File-Handles und Parameter übergibt, sodass nur die Antwort aufgefangen, zwischengespeichert und dann in ein Template oder Ähnliches eingebunden werden muss? Würde das gnaze ja sehr vereinfachen. Wäre nett, wenn mir das noch jemand etwas genauer erläutern könnte. Zudem würde mich, wie schon gesagt, interessieren, welche sinnvollen Möglichkeiten es gibt, mit OOP Ausgaben zu erleichtern (Beispiel Pager-Klasse). Macht es zum Beispiel Sinn eine Klasse zu schreiben, die eine einfach tabellarische ausgabe anhand eines Arrays macht. Oder ist es irgendwie möglich die Validierung von Formular-Daten zu zentralisieren, sodass nicht mehr so ewig lange Kontroll-Strukturen nötig sind. Habe natürlich noch viele Fragen und diese Werden sich bestimmt noch weiter häufen, wenn ich die Artikel von Dr. e endlich alle durch habe, aber nun muss ich leider auch erstmal wieder weg. Ich möchte mich aber nochmal für eure Hilfe und Mühen bedanken. Danke.
MfG, Andy
__________________
I'm so tired of slitting the throats of people calling me a violent psychopath.
#Avedo ist offline   Mit Zitat antworten
Alt 13.10.2008, 19:09  
Erfahrener Benutzer
 
Benutzerbild von phpdummi
 
Registriert seit: 06.06.2008
Beiträge: 1.631
PHP-Kenntnisse:
Anfänger
phpdummi ist zur Zeit noch ein unbeschriebenes Blatt
Standard

Front-Controller:
Ein Front-Controller ist ein Objekt, das alles Anfragen an eine Webapplikation entgegennimmt und die
Arbeiten durchführt, die bei allen Anfragen identisch sind. Zur Erzeugung der Antwort auf die Anfrage
leitet es die Anfragen an die Objekte weiter, die die unterschiedlichen Anfragen verarbeiten können.

(Stephan Schmidt in PHP Design Patterns, O'Reilly)

Der Front-Controller ist die Zentrale Schnittstelle einer Applikation.
Um nicht nur auf normale HTTP-Anfragen sondern um zum Beispiel auch auf SOAP oder AJAX, ohne
die eigentliche Anwendung umschreiben zu müssen, reagieren zu können, abstrahiert man sowohl
Anfrage als auch Antwort und packt sie in eigene Objekte. Für HTTP wären das HttpRequest
und HttpResponse, für SOAP dann SoapRequest und SoapResponse und so weiter.

Da man immer gegen Schnittstellen programmieren sollte, zunächst mal die Interfaces für Request und Response:
PHP-Code:
interface Request {
    public function 
issetParameter($name);
    public function 
getParameter($name);
    public function 
getParameterNames();
    public function 
getHeader($name);
}

interface 
Response {
    public function 
write($data);
    public function 
addHeader($name$value);
    public function 
setStatus($status);
    public function 
flush();

Konkrete Implementierung (HTTP).
Request
PHP-Code:
<?php
require_once 'Request.php'// interface

class HttpRequest implements Request {

    private 
$parameters;

    public function 
__construct() {
        
$this->parameters $_REQUEST;
    }

    public function 
issetParameter($name) {
        return isset(
$this->parameters[$name]);
    }

    public function 
getParameter($name) {
        if (isset(
$this->parameters[$name])) {
            return 
$this->parameters[$name];
        }
        return 
null;
    }

    public function 
getParameterNames() {
        return 
array_keys($this->parameters);
    }

    public function 
getHeader($name) {
        
$name 'HTTP_' strtoupper(str_replace('-''_'$name));
        if (isset(
$_SERVER[$name])) {
            return 
$_SERVER[$name];
        }
        return 
null;
    }
}
?>
und Response
PHP-Code:
<?php
require_once 'Response.php'// interface

class HttpResponse implements Response {
    private 
$status '200 OK';
    private 
$headers = array();
    private 
$body null;

    public function 
setStatus($status) {
        
$this->status $status;
    }

    public function 
addHeader($name$value) {
        
$this->headers[$name] = $value;
    }

    public function 
write($data) {
        
$this->body .= $data;
    }

    public function 
flush() {
        
header("HTTP/1.0 {$this->status}");
        foreach (
$this->headers as $name => $value) {
            
header("{$name}: {$value}");
        }
        print 
$this->body;
        
$this->headers = array();
        
$this->body null;
    }
}
?>
In den Response schreibt man über die write($data) Methode. Sobald die Antwort gesendet werden soll, wird die flush() Methode verwendet.

Beispiel zur Anwendung:
PHP-Code:
<?php
$request 
= new HttpRequest();
$response = new HttpResponse();

if (
$request->issetParameter('Name')) {
    
$response->write("Hallo ");
    
$response->write($request->getParameter('Name'));
    
$response->flush();
}
?>
Anstatt nun direkt den Front-Controller zu programmieren sollten wir uns erst über dessen Ziel Gedanken machen.
Wir möchten möglichst flexibel sein, deshalb haben wir Request und Response abstrahiert (anstatt einfach $_REQUEST zu verwenden).

Der Request enthält immer einen konkreten Auftrag. Alle möglichen Aufträge die unsere Applikation hat
möchten wir in Objekte kapseln. Dazu kommt das Command-Pattern wie gerufen.

Das Command-Pattern kapselt einen Auftrag als Objekt. Dadurch wird ermöglicht,
andere Objekte mit Aufträgen zu parametrisieren, Aufträge in eine Queue zu stellen
oder diese Rückgängig zumachen.

(Stephan Schmidt in PHP Design Patterns, O'Reilly)

Damit ein Befehl arbeiten kann benötigt er das Request und Response Objekt,
daraus resultiert folgendes Interface
PHP-Code:
<?php
interface Command {
    public function 
execute(Request $requestResponse $response);
}
?>
Für die Erzeugung der einzelnen Seiteninhalte sind also Objekte zuständig, die das Command-Interface implementieren.
Vorteile:
  1. Die einzelnen Objekte sind austauschbar.
  2. Es können leicht neue Klassen hinzugefügt werden, die neue Inhalte erzeugen.
  3. Ein Seitenaufbau kann von mehr als einem Command-Objekt erzeugt werden,
    dazu müssen lediglich mehrere Objekte zu einem Zusammengefügt werden.
Ein Beispiel Command-Objekt:
PHP-Code:
<?php
require_once 'Command.php'// interface

class HelloWorldCommand implements Command {
    public function 
execute(Request $requestResponse $response) {
        if (
$request->issetParameter('Name')) {
            
$response->write("Hallo ");
            
$response->write($request->getParameter('Name'));
        } else {
            
$response->write("Hallo Unbekannter");
        }
    }
}
?>
Dieser kann nun wie im vorhergehenden Beispiel ausgeführt werden:
PHP-Code:
<?php
$request 
= new HttpRequest();
$response = new HttpResponse();
$command = new HelloWorldCommand();
$command->execute($request$response);
$response->flush();
?>
Der Teil des Front-Controllers, der Anhand der Anfrage entscheiden kann was getan werden
soll, ist der CommandResovler. Er soll wie gewünscht Command-Objekte laden, aber wir wollen flexibel bleiben.
Vielleicht nutzt unsere Applikation später einen anderen Weg Befehle auszuführen.
Daher benötigen wir zunächst mal ein Interface:
PHP-Code:
<?php
interface CommandResolver {
    public function 
getCommand(Request $request);
}
?>
Alle Klassen, die dieses Interface implementieren, sind in der Lage zu entscheiden, welcher Befehl
für die Erzeugung der Antwort verwendet werden soll. Dazu verlangt das Interface eine getCommand()
Methode, die den Request übergeben bekommt und das entsprechende Objekt zurück liefert.
Die Logik der einzelnen CommandResolver-Klassen kann dabei so komplex sein wie es die
Applikation verlangt. Für dieses Beispiel genügt eine einfache Implementierung, die nach folgendem Schema arbeitet:
  • Der Name des Commands kann in dem Parameter cmd (für command) übergeben werden
  • Der Wert des cmd-Parameters muss identisch mit dem Namen der Command-Klasse sein
  • Wird kein cmd-Parameter übergeben soll per Default das HelloWorldCommand verwendet werden.
Die einzelnen Commands werden im Ordner commands/ gespeichert. Los gehts:
PHP-Code:
<?php
require_once 'CommandResolver.php'// interface

class FileSystemCommandResolver implements CommandResolver {
    private 
$path;
    private 
$defaultCommand;

    public function 
__construct($path$defaultCommand) {
        
$this->path $path;
        
$this->defaultCommand $defaultCommand;
    }

    public function 
getCommand(Request $request) {
        if (
$request->issetParameter('cmd')) {
            
$cmdName $request->getParameter('cmd');
            
$command $this->loadCommand($cmdName);
            if (
$command instanceof Command) {
                return 
$command;
            }
        }
        
$command $this->loadCommand($this->defaultCommand);
        return 
$command;
    }

    protected function 
loadCommand($cmdName) {
        
$class "{$cmdName}Command";
        
$file  "commands/{$cmdName}Command.php";
        if (!
file_exists($file)) {
            return 
false;
        }
        include_once 
$file;
        if (!
class_exists($class)) {
            return 
false;
        }
        
$command = new $class();
        return 
$command;
    }
}
?>
Das letzte Beispiel nun mit dem Resolver:
PHP-Code:
<?php
$request 
= new HttpRequest();
$response = new HttpResponse();
$resolver = new FileSystemCommandResolver('commands''HelloWorld');
$command $resolver->getCommand($request);
$command->execute($request$response);
$response->flush();
?
Nun kann man die Datei mit dem Parameter ?cmd=Command aufrufen um den gewünschten Befehl auszuführen.
Alle nötigen Schritte sind getan, jetzt können wir endlich den Front-Controller programmieren, unsere Zentrale Schnitstelle:
PHP-Code:
<?php
require_once 'Command.php';
require_once 
'Request.php';
require_once 
'Response.php';

class 
FrontController {

    private 
$resolver;

    public function 
__construct(CommandResolver $resolver) {
        
$this->resolver $resolver;
    }

    public function 
handleRequest(Request $requestResponse $response) {
        
$command $this->resolver->getCommand($request);
        
$command->execute($request$response);
        
$response->flush();
    }
}
?>
Anwendung (index.php)
PHP-Code:
<?php
require_once 'FrontController.php';
require_once 
'HttpRequest.php';
require_once 
'HttpResponse.php';
require_once 
'FileSystemCommandResolver.php';

$resolver = new FileSystemCommandResolver('commands''HelloWorld');
$controller = new FrontController($resolver);

$request = new HttpRequest();
$response = new HttpResponse();

$controller->handleRequest($request$response);
?>
Den Front-Controller kann man nun noch durch Intercepting-Filter erweitern um Daten
vor und nach der Verarbeitung durch die Command-Objekte zu verändern.

Die Codebeispiele und die meisten Erläuterungen stammen aus dem Buch "PHP Design Patterns" von Stephan Schmidt.
Die Codebeispiele können von der Seite PHP Design Patterns heruntergeladen werden.
__________________
"Nobody is as smart as everybody" - Kevin Kelly
— The best things in life aren't things
phpdummi ist offline   Mit Zitat antworten
Alt 15.10.2008, 00:01  
Erfahrener Benutzer
 
Registriert seit: 06.09.2008
Beiträge: 189
#Avedo befindet sich auf einem aufstrebenden Ast
Standard

Danke für deine ausführlichen Erläuterungen. Habe mir das Buch nochmal genauer angeschaut (hattest mir ja einen Link gegeben) und habe mir dann heute nochmal die Zeit genommen, etwas in das Buch reinzulesen. Ich war sehr begeistert, da es wirklich mal etwas ganz anderes ist. Habe es mir auch sogleich zugelegt und bin nun dabei das ganze durch zu arbeiten. Bin jetzt bis zu den Erzeugungsmustern (S.100) vorgedrungen und bis dahin ist noch alles relativ klar, aber ich habe mir aus besonderem Interesse schon das Kapitel über das Registry Patern durchgelesen und habe da noch ein kleines Verständnis Problem.

Das Registry Pattern ist, wenn ich das richtig verstanden habe, ein Design Pattern, das dem Programmierer helfen soll, Objekte bzw. Variabeln in einer Applikation (Anwendung) global verfügbar zu machen. Das beste Beispiel sind wohl Konfigurationsdaten oder ein LogHandler-Objekt, die, wie schon im Buch richtig angemerkt, überall in einer Anwendung verfügbar sein müssen. So werden Konfigurationsdaten zur Auswahl des Templates und zur Verbindung zu einer Datenbank benötigt. Dies widerspricht nun aber dem strikten Schichtmodell. Mein Problem ist nun, dass ich nicht verstehe wieso man nicht einfach immer, wie später im betreffenden Kapitel vorgestellt eine SessionRegistry Klasse verwendet. Wan braucht man welche Klasse? Des weiteren verstehe ich nicht, wieso die SessionRegistry Klasse auf der Registry Klasse aufbaut. Zuletzt würde mich interessieren, wie Ihr die ganzen Klassen, die die Registry bzw. die SessionRegistry Klasse lädt, einbinden würdet, denn davon ist dort keine rede. Ist hier eine geschickte Implementierung von __autoload() in der Kombination mit einer clevern Prefix-Vergabe, wie bei PEAR, die passende Lösung?

Besonders interessiert hat mich auch das Kapitel über das Template-View-Pattern (habe ich auch schon vorgezogen), da ich bisher eher schief angesehen wurde, wenn ich auf die Template-Eigenschaften von PHP zurückgegriffen habe, wodurch meine Templates großteils wie folgt aussahen.
PHP-Code:
<html>
    <head>
        <title><?= $this->title?></title>
    </head>
    <body>
        <h1 id="masthead"><?= $this->title?></h1>

        <p class="right">
            <? if( $this->name !== null ): ?>
                Hallo <?= $this->name?>!</p>
            <? else: ?>
                Hallo Gast!
            <? endif;: ?>
        </p>

        <menu>
            <? foreach( $this->navi as $entry ): ?>
               <li><a href="<?= $entry['link']; ?>"><?= $entry['name']; ?></a></li>
            <? endforeach: ?>
        </menu>

        <p id="footer">Copyright © 2004-<?= $this->date?><?= $this->domain?> - All Rights Reserved.</p>
    </body>
</html>
Das scheint aber unter Verwendung der Richtigen Template-Klasse ein legitimer und auch gern genommener Weg zu sein. Beruhigt mich doch etwas.

Wieder viele Fragen und ich hoffe ich strapaziere eure Nerven nicht zu stark. Ich bin ech sehr dankbar für eure Hilfe.
MfG, Andy
__________________
I'm so tired of slitting the throats of people calling me a violent psychopath.
#Avedo ist offline   Mit Zitat antworten
Alt 17.10.2008, 17:03  
Erfahrener Benutzer
 
Registriert seit: 06.09.2008
Beiträge: 189
#Avedo befindet sich auf einem aufstrebenden Ast
Standard

Kann keiner etwas zu meinem Problem mit dem Registry-Design-Pattern etwas sagen?
MfG, Andy
__________________
I'm so tired of slitting the throats of people calling me a violent psychopath.
#Avedo ist offline   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

LinkBacks (?)
LinkBack to this Thread: http://www.php.de/software-design/48056-strukturierung-groessyerrer-projekte.html
Erstellt von For Type Datum
Adventure PHP Framework - Literatur This thread Refback 02.12.2008 15:17

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Suche kleinere Projekte Gawain Beitragsarchiv 1 24.07.2008 20:09
Zend Studio und Projekte breaker PHP-Fortgeschrittene 0 26.05.2008 13:51
Partner für neuartige online Projekte gesucht iSi Trash 0 25.03.2006 21:22
Strukturierung einer kleinen DB c-f-g Datenbanken 6 24.03.2006 09:54
Strukturierung modularer Website mit CleanUrls ssm PHP Tipps 2006 20 22.03.2006 16:49
Mach Websiten und oder ganze Projekte ClaBo3 Trash 26 06.02.2006 15:12
[Erledigt] Projekte effektiv Planen? PHP Tipps 2005 17 18.10.2005 16:06
Programierer für projekte gesucht! Beitragsarchiv 3 19.09.2005 16:20
mehrere projekte auf 1 Datenbank möglich? PHP Tipps 2005-2 5 17.07.2005 17:20
Erfahrener Typo3-Entwickler sucht neue Projekte Beitragsarchiv 1 16.07.2005 14:53
S: Programm, Projekte verwalten Flor1an Beitragsarchiv 5 17.04.2005 12:12
Partner für Projekte Beitragsarchiv 5 03.03.2005 12:23
Freelancer: PHP Entwickler sucht Projekte phpprofi Beitragsarchiv 4 18.02.2005 17:16
Projekte nachträglich auf Klassen und Objekte umstellen??? PHP-Fortgeschrittene 7 10.12.2004 15:33
Freelancer sucht neue Projekte Beitragsarchiv 0 12.08.2004 09:31

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
frontcontroller interfaces request php, php strukturieren, projekte strukturieren, php projekte strukturieren, php strukturierung, php strukturiert, php anwendung strukturieren, strukturierung php, php richtig strukturieren, große php projekte strukturieren, strukturierte ausgabe php, php strukturierte ausgabe, homepage strukturieren php, php html strukturieren, php richtig struktorieren, php command resolver, php code strukturieren, php korrekte strukturierung, php verzeichnis strukturieren, strukturieren php

Alle Zeitangaben in WEZ +1. Es ist jetzt 14:23 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum