Hi Sven!
Mit anderen Worten: Du hast ein (geplantes) Gesamtpaket, aus dem du einzelne Elemente herausschneiden willst.
Und ggfs. später weitere Teile hinzufügen können will.
Und wenn man etwas schneidet, dann ... blutet es? Nein, dann hat man Schnittstellen!
Hm. Ich dachte man hat ein Programm, welches halt modular aufgebaut ist(was auch immer das jetzt heißt), und das komplette Programm hat Schnittstellen um mit der Außenwelt kommunizien zu können, das dachte ich immer.
Du brauchst also vor allem Schnittstellen. Und am sinnvollsten sind welche, die nicht nur das erledigen, was du JETZT für die Module brauchst, die du planst, sondern was auch für andere Module, die du noch nicht planst, sinnvoll sein kann.
Gut, aber darunter kann ich mir jetzt nichts vorstellen. Was wäre das denn praktisch? Für mich ist eien Schnittstelle eher ein Programmteil, oder eigenes Modul, welches z.B. einen Daten-Export oder Import erledigt, oder die Anbindung an ein anderes Backend-System. Das ist dann halt ein Scrip welches entweder Dateien aus der DB generiert, oder Dateien parst und einfügt, oder ein komplette Kommunikation regelt. Das ist für mich eine Schnittstelle. Interne Schnittstellen kann ich mir nur schwer vorstellen. Schnittstellen wozwischen? Zwischen den Modulen? Aber dazuwischen findet doch im Prinzip kein Datenaustausch statt, alle Module greifen auf dieselbe Datenquelle zurück. Bei diesem Punkt füllt mir auch ein - das sollte man vielleicht auch abkapseln, also die Schnittstelle zur eigenen Datenbank, denn zur Zeit verwende ich munter in allen Scripten mysql_funktionen, ich habe zwar mysql_qery() schon in eine zentrale Funktion gebannt, aber mysql_fetch_assoc(), mysql_num_rows()... das verwende ich noch alles einzelnd. Das solte ich vielleicht auch in Funktionen schreiben, vielleicht schreibe ich mir eine eigene DB-Kasse, die vorhandenen finde ich viel zu aufgebläht! Vielleicht gucke ich mir auch mal PEAR:DB an, mal schaun, oder hast Du einen Tipp? Eigentlich sollten einige Funktionen reichen: mysql_query, mysql_fetch_assoc, mysql_fetch_row, mysql_num_row, mehr verwende ich eigentlich gar nicht. Ich wüßte jetzt auch nicht als KLasse, ich verwende eh nur eine DB, also hat es keinen großen Sinn für eine DB-Connection extra eine Instanz zu erstellen, vielleicht für eine Abfrage, mal schaun. Wäre vielleicht sogar ganz gut, um ein wenig das Frontend von der Datenstruktur abzukoppeln, wenn ich dann einen Spaltennamen ändere mache ich das zentral in der Klasse und nicht mehr in jeder Abfrage! Ein gutes Argument ;-) Nochmal zu den internen Schnittstellen, ein Problem ist z.B. das Menü. für jedes neue Modul brauche ich meist mind. einen Menüeintrag. Bisher habe ich eine Menüleiste, in der die Menüs als link fest reingeschreiben sind. Einen guten Ansatz habe ich in einem featured Artikel zu einem Javascript-Menü mit Baustruktur gesehen, da wurden die einzelnen Menüpunkte in Funktionsaufrufe mit einer ID und einer Parent_ID geschreiben, um am Ende daraus eine schöne Baustruktur zu machen. Das könnte ich ja so übernehmen, vielleicht mache ich ja direkt ein Menü mit Untermenüs also Aufklappmenü. Dann schreibe ich am besten die Menü-Punkte mit einer ID und einer Parent_ID in eine MySQL Tabelle, um die Struktur einfach verändern zu können, und kann dann daruas beim "Installieren" eines neuen Moduls daraus jedesmal die "menue.inc"-Datei neu zu generieren. Das wäre für den Live-Betrieb vermutlich erheblich besser als jedesmal eine DB oder Flat-File abzufragen und daraus zur Laufzeit das Menü zu generieren.
Plane voraus: Alle Dinge müssen sich dynamisch erledigen lassen.
Was sind "alle Dinge"? Wo fängt "alle Dinge" an und wo hört das auf? Menü ist klar. Was noch? z.B. mein Modul "Fragebogengenerator". Hierfür brauche ich eine extra Datei, und ein oder zwei extra-Tabellen. Das hätte ich ja so schon abgedeckt. Vielleicht noch meine Message-Seite, in der dann immer die Bestätigung der Änderung ausgegeben wird, aber das mache ich eh schon "modular", denn dafür habe ich eien eigene Funktion, der ich die "Message"... übergebe, und die dann einen einen Location-Header schickt, mit der Message, Titel, Sekunden bis meta-Refresh und Refresh-Ziel als Parameter.
Menüs sind zum Beispiel nicht fest codiert, sondern werden durch deine Module definiert. Das bedeutet, dass beispielsweise jedes Modul eine Funktion besitzen könnte, die einen Menüeintrag zurückliefert,
Aber wie mache ich das? Das ist wie im obigen Beispiel eine eigene Datei. Wie mache ich jetzt der Menüleiste klar das diese Datei ab heute ebenfalls abgefragt werden soll? Und woher weiß ich vorher wie die Funktion heißen wird?
oder die Einträge werden einer entsprechenden Variablen hinzugefügt.
auch das muß ich dann zur Laufzeit machen. Nur wie soll ich denn Code in die Menü-Erstell-Funktion einfügen, die eben diesen String dem Menü-Array hinzufügt? Da hatte Thomas ja einen guten Ansatz genannt, mit include, aber auch da weiß ich praktisch nicht wie das aussehen könnte. Ich würde das jetzt so machen: ich binde in meine globale Datei die überall eingebunden wird und ale Funktionen... enthält eine Datei module.inc ein, in der alles Modulrelevante steht. Nur was steht darin? Das müßte sich bei einem neuen Modul ja ändern, was aber den Haken hat, das ich bei jedem Modul diese Datei ändern muß, was ja noch nicht schlimm ist aber woher weiß ich vor der Ändernung welche Module bereits vorhanden sind, so dass ich genau das fehlende Modul hinzufüge, und alle bereits vorhandenen wieder reinschreibe? Wie wäre folgender Ansatz: Ich habe ein Verzeichnis "module/" in dem Verzeichnis liegt für jedes Modul eine Datei, so modul_a.inc, modul_b.inc... Dann lese ich mit einer Verzeichnis-Funktion alle Dateinamen in diesem Verzeichnis aus. Dann kann ich aber nicht einfach die Dateien includen, denn wie soll das gehen? Dann dürfte ich keine Funktionen und Variablennamen drin verwenden, da die sich sonst überschneiden und ich die sonst vorher nicht wissen kann. Also mache ich txt-Dateien, mit
Modulname:Fragebogengenrator Hauptmenuename:FB-Generator
naja, mehr Modul-spezifisches fällt mir an dieser Stelle nicht ein. Dann müßte ich jede dieser Dateien parsen und könnte dann alle Werte z.B. Hauptmenuename an den Array fürs Hauptmenü hängen. Aber wann sollte man das machen? Zur Laufzeit? Oder wie ich schon angeregt hatte einmal bei der Installation? Eigentlich könnte man das ganze auch einfacher mit der Datenbank machen ;-)
Mehrsprachige Seiten habe ich bislang so realisiert, dass es je Sprache ein Verzeichnis gibt (also /de/, /en/ und /fr/), in denen sich immer identische Dateien befinden.
Was bei statischen Seiten prima ist, für dynamische eher ungeeignet, oder?
Als Startseite im Hauptverzeichnis ist ein Skript aktiv, welches den Accept-Language-Header vom Browser auswertet und entsprechend auf eine der verfügbaren Sprachen weiterleitet. Auf diese Weise wird eine sinnvolle Vorauswahl getroffen, die der Benutzer jederzeit ändern kann - vorzugsweise wird er dies wohl gleich zu Beginn tun.
Das würde ich auch so machen. Aber da man sich sowieso anmelden muß, werde ich die Sprach-Präferenz bei jedem User speichern.
Was die Textausgabe angeht: Variablen, Variablen, Variablen. In allen Skripten ist die Angabe von festen Strings tabu - weil die logischerweise sonst dort übersetzt werden müßten. Alles, was irgendwie ausgegeben wird, muß flexibel bleiben: Menüpunkte, Tabellenbezeichnungen, Fehlermeldungen, Systemmeldungen... Alle diese Meldungen werden zentral definiert. Wenn du Mehrsprachigkeit hast, hast du noch die zusätzliche Schwierigkeit, dass du einerseits das Modul "Mehrsprachigkeit" unterbringen mußt, und zusätzlich müssen deine anderen Module natürlich ihre Textausgaben auch nur optional, dann aber eventuell mehrsprachig mitbringen. Das könnte knifflig werden.
Ich würde die String vermutlich in einer Tabelle speichern, mit einer extra-Spalte Modulnummer. 0 wäre das Basismodul, 1 der Generator... Dann könnte man sehr leicht entsprechend der vorhandenen Module die notwendigen Datensätze speichern. Nur auch hier die Frage, die kompletten Strings jedesmal aus der DB zu holen wäre vermutlich nicht so schön - wobei - das dürfte nur einige 1/100 Sekunden dauern, oder? Also lohnt es sich wohl das ganze in einen PHP-Array zu übertragen, der dann fest im Quelltext steht? Oder sollte man an Stelle eines Array für das ganze Projekt lieber einzelen Dateien einführen, also pro Datei eine Sprachdatei mit dem festen Sprach-Array nur mit den Strings für diese eine Datei?
Sowas funktioniert prima, wenn nur der Code ausgetauscht werden muß, aber nicht die Daten. Dann hält man den Server einfach für einen Moment an, kopiert die neuen Programmdateien aufs System, und fährt den Server wieder hoch.
Das ganze soll ja automatisch geschehen, also muß ich auch noch ein Sperre für alle Benutzer einbauen. Am besten über eine htaccess. Ob man den Server wegen neuen PHP-Dateien neu hochfahren muß? Wieso?
Wenn sich auch Datenformate geändert haben, muss man eben eine Konvertierungsroutine mit einbauen, die vor dem Wiederhochfahren die notwendigen Dinge ändert.
Das könnte ich vielleicht auch mit einer DB-Klasse sehr schön lösen, wenn der Zugriff immer über diese Klasse erfolgt brauche ich neben der Datenstruktur nur diese eine Klasse ändern. Muß nur die ganzen Module berücksichtigen... kompliziert, kompliziert...
Allerdings: Daten werden üblicherweise in Datenbanken gespeichert, und es ist durchaus möglich, das Programm so zu gestalten, dass es sich dynamisch an das derzeit verwendete Datenformat anpaßt und gewisse Dinge dann eben nicht zur Verfügung stellt - bzw. erst nach und nach einpaßt.
Hm? Wie soll das gehen? Nenn bitte mal ein Beispiel.
Ein Beispiel:
ah ;-)
Wenn du eine Telefonliste programmierst, und in Version 1 Datenfelder für Name und Telefonnummer anlegst, in Version 2 dann aber noch Geburtsdatum hinzufügst, ist das für die Daten nicht so schlimm. Du fügst beim Update das neue Datenbankfeld hinzu, die bestehenden Einträge bleiben bestehen, haben aber logischerweise kein Geburtsdatum. Du könntest das Erkennen der Datenversion erleichtern, wenn du in der Datenbank grundsätzlich ein Feld "Datenformatversion" mitführst. Allerdings glaube ich, dass es mehr Sinn macht, beim Update die vorhandenen Daten komplett zu konvertieren - oder diese Notwendigkeit einfach nicht hineinzuprogrammieren. :)
Nur das man sich durch sowas vermutlich leicht Fehlerquellen einbaut, oder?
Das Problem dürfte wohl die gedankliche Fassbarkeit der Dynamik sein.
Das habe ich gemerkt. Ein paar Punkte habe ich ja angesprochen, aber mehr fallen mir im Moment nicht ein! Kennst Du noch den ein oder anderen Punkt wo man drauf achten sollte?
Die eierlegende Wollmilchsau wirst du nicht programmieren, aber gewisse Dinge sind fürs Funktionieren unbedingt erforderlich - alles weglassen geht also auch nicht. Aber irgendwie ist ja nichts greifbar fest, wenn alles dynamisch ist. Das kriegt man wahrscheinlich am besten hin, indem man erstmal irgendwas Festes programmiert, was dann dynamisiert wird. Mit Sicherheit dauert das ein Weilchen, bis es fertig ist.
Das glaueb ich auch. Ich programmiere schon an einer statischen Version denn erstmal muß es laufen. Wenn ich das direkt dynamsich mache wird das mir zu komplex, ich habe jetzt schon Probleme mit der Datenstruktur, da ich die nicht im Kopf behalten kann, sollte ich evtl. mal ausdrucken oder noch besser, mal schön hinmalen, mit allen Vernüpfungen... Vielleicht sollte ich jetzt mal mit Transaktionen anfangen, oder Foreign Keys... aber das kann mysql nicht, und damit sollte das ganze schon funktionieren, obwohl ich gerne mal auf postgres umschwenken würde, ich hab einfach noch keinen echten Websever mit postgres, bekomme jetzt zwar einen, aber das wird nur temporär sein. Naja, bald wird es Zeit für einen eigenen Root-Server ;-)
Viele Grüße und vielen Dank mal wieder Andras