hotti: OOP (in PHP) - 3 Fragen

Beitrag lesen

hi Take,

Das war glaub ich ein bisschen unglücklich ausgedrückt. Was ich meinte war: Die Klasse "page" versucht die angeforderte Seite zu laden (Überprüft ob die Datei existiert). Was tut sie, wenn die Datei nicht existiert? Automatisch die 404-Seite laden? Oder einfach nur false zurückgeben und irgendwo anders (wo?) wird dann ermittelt, dass die 404-Seite im Falle einer nicht gefundenen Seite geladen werden muss und der Klasse gesagt, sie solle jetzt die 404-Seite laden.

Ganze einfach in der Webserverkonfig:

ErrorDocument 404 => ResponseHandler (index.php)
Alle Requestse    => ResponseHandler (index.php)

Der Trick, damit Beides funktioniert: Der ResponseHandler (index.php) steht NICHT in der Verwaltung.

Äh, was? Ich habe eine index.php Bei einem Request wird erstmal die Seite per GET-Parameter übergeben: index.php?page=index oder index.php?page=test/index Und wie soll da der Webserver einen 404 schmeißen, wenns die Datei test/index nicht gibt?

In diesem Fall wirft natürlich NICHT der Webserver den 404. index.php wird jedoch einen Status: 404 Not Found an den Webserver senden, damit dieser den richtigen Header ausgibt und index.php wird dem Bescucher eine schöne Seite zeigen mit hilfreichen Links.

Der Webserver wirft nur dann selbst einen 404, wenn der Request an index.php vorbei auf eine nicht vorhandende Datei greift. Du musst dazu eine passende Rewrite-Condition UND eine passende R-Rule haben, ohne dem gehts natürlich nicht ;)

Es gibt zwei Fälle, die auch von Deiner Cond/Rule abhängen:

  1. der Webserver findet zum Request die lokale Ressource nicht ( außerhalb der RewriteRule)
  2. die Rule greift, aber das Response-Object kann nicht erstellt werden, weil es nicht in der Verwaltung steht

Hinweis, Vorsicht, die Zeile
ErrorDocument 404 /index.php

Baue erst zum Schluss ein, Fehler in der Cond/Rule sind sonst sehr schwer zu finden (den Fall hatte ich gestern abend).

Was meinst du mit "Verwaltung"?

Das ist die Konfiguration, siehe weiter oben: Eine Tabelle mit ALLEN URLs, welche Deine Website beinhaltet.

Wozu brauch ich denn die? Nehmen wir an, ich arbeite ganz stumpf mit Flatfiles, dann prüfe ich einfach per file_exists(), ob eine Datei (=Seite) existiert.

Deine Website hat URLs like /foo.html /bar.html /downloads/mp3/otto.mp3 usw. Alles nur virtuell, die liegen nicht als Dateien im FS. Diese URLs werden in einer Tabelle verwaltet, das sind Objecte mit Eigenschaften. Eine solche Verwaltung gibt das Dateisystem nicht her, das musst Du schon selber bauen. Wo die Tabelle liegt, ist egal, das kann MySQL sein oder ein Flatfile, oder eine ini oder sonstwas: Performant muss es sein!

Es muss dafür gesorgt sein, dass der Controler unterscheiden kann, ob ein Submit oder ein Ajaxrequest vorliegt. Das kann über einen speziellen Header erfolgen oder anhand eines Parameters.

Ist mir klar. Aber _wer_ unterscheidet das? Der Controler oder eine Extra-Klasse?

Der Controler kann in einer extra Klasse liegen, muss aber nicht. In meiner Praxis ist der Controler eine Methode des Response-Objects. Diese Methode wird dann gerufen, wenn es GET oder POST Parameter gibt UND wenn zu dem requesteten URL überhaupt Parameter erlaubt sind UND wenn die Berechtigung stimmt (Session, Anmeldung liegt vor). Auch hieran erkennst Du den Vorteil der OOP, nämlich: Alles was jetzt gebraucht wird, sind Attribute des Response-Objects. Und die stehen in der Verwaltung.

Beispiel, Verwaltung in einer ini-Datei

[/users/login] # das ist die Objekt-ID, der URL zu einem Login-Formular
    title=Login für den Kundenbereich
    descr=Lass dir was einfallen...
    type=text/html
    css=/cust.css
    js=/base.js
    iswas=template # Name der Methode, welche den Body erstellt
    control=login  # so heißt die Methode, die beim Eintippen der Benutzerdaten aufgerufen wird. sub login{} ist der Controler, eine Klassenmethode der Singleton-Class

Das heißt, ich speichere für jede Seite, jedes Template, etc. einfach eine Serialisierte Form des Objektes (wohin ist erstmal egal)? Ich hatte mir das eher so vorgstellt, das die "page" Klasse eine Methode "load" hat, die dann eine bestimmte Seite lädt, sodass dieses Objekt jetzt diese Seite wiederspiegelt.

Genau! Request geht auf /users/login, der Reponse-Handler prüft, ob der Request erlaubt ist, das ist der Fall, den URL gibts in der Verwaltung. Das Response-Object wird erstellt, es ruft die Methode template auf, welch den Body (Formular) erstellt und alles zsammen zum Browser schickt. Der gibt user/pass ein, was die Methode sub contol{} aufruft, da drinnen werden die Parameter geprüft, der Login prozessiert und das Ergebnis ausgegeben.

Genauer: Es gibt noch eine Funktion, die Du mit 'load' meinst (vermute ich). Nenne die nicht load, sondern erzeuge_body, getbody, bodygen, bodybuild oder so ähnlich. Weil: Der Contoler (sub login{}) ruft letztendlich wieder die Methode template{} auf, wenn keine Fehler oder nur kleine Fehler aufgetreten sind (Benutzername falsch oder so...). Ein fataler Fehler wäre ein unerlaubter Parameter, da sollte nicht das Formular gezeigt werden, sondern eine richtig gute Fehlerseite. Die Methode bodybuild wird als Letzte in der Verarbeitungskette aufgerufen, die guckt in den Fehlerspeicher (ein Attribut des Response-Objects) und tauscht bei fatalen Fehlern den Body aus. Ansonsten kommmt das Template, woher auch immer (Datei, DB...).

Wie gesagt: Alles nur ein Vorschlag. Hat sich aber gut bewährt ;)

Ich habs in Perl umgesetzt, in PHP würde das ähnlich aussehen, evntl. ist die Templategeschichte damit schöner zu machen (mit dem Gedanken spiele ich seit ein paar Tagen)

Schönes Wochenende,
Hotti