Andreas Korthaus: Web-Programme modular aufbauen

Hallo!

Ich hatte eigentlich genau das vor längerer Zeit schonmal gepostet, aber das ist dann eigentlich "nur" auf eine Diskussion ob OOP oder nicht hinausgelaufen, damals sehr interessant für mich, aber heute habe ich dies bezüglich eine etwas anders gelagerte Frage:
Ich bin dabei eine Softwre zu schreiben, die verschiedene Module enthalten soll. Das heißt ein Basis-Modul mit der eigentlichen Basissoftware, und dazu kann man evtl noch zusätzliche Erweiterungen(Module) installieren, so z.B. ein Modul Mehrsprachigkeit, oder ein Modul Fragebogengenerator. Programmiert wird das ganze in PHP/PERL und MySQL.
Wie man an den beiden Beispielen sieht, greifen die Module unterschiedlich weit in die gesamte Anwendung ein, gerade die Mehrsprachigkeit z.B. recht weit. Module sollen nicht von vornherein vorhanden sein, sondern sich auch nachträglich installieren lassen.
Das heißt es muß bei der "nachinstallation" z.B. in die Navigationsleise ein zusätzlicher Einrag erfolgen, oder es muss noch ein Extra Menü für die Konfigurierung des Moduls eingefügrt werden. Merhsprachigkeit dagegenb müßte ja von vornherein vorgesehen werden, dazu habe ich auch schon einige Threads hier verfolgtm, weiß aber noch nicht so Recht welches jetzt der "goldene Weg" ist, dies zu implementieren. Mit dem Accept-Language Header des Browsers finde ich eher ungünstig, eher als Indiz für die Starteinstellung. Also muß ich alle Texte in Variabvlen speichenr und die wiederum in der Datenbank, und dann bei jedem Seitenaufruf erstmal alle Texte aus der Datenbank auslesen - auch nicht wirklich optimal. Oder wie könnte man das besser einarbeiten?
Noch so eine Sache ist wie man bei einee WEB-Anwendung eine Update-Funktion implementiert. D.h. wenn die Anwendung stetig weiterentwickelt wird, das dann sehr problemlos auf eine neue Version upgedatet werden kann, so dass alle Einstellungen und Daten bestehen bleiben... problematisch ist auch das Updaten über mehrere Versionen hinweg.
Naja, leider habe ich mit solchen Dingen so gut wie gar keine Erfahrung. Hat da vielleicht jemand Tipps für mich, oder kennt jemand Projekte wo das ganze gut gelöst wurde?

Viele Grüße
Andreas

  1. Hallo Andreas,

    ein Modul Mehrsprachigkeit, oder ein Modul Fragebogengenerator. Programmiert wird das ganze in PHP/PERL und MySQL.

    IMHO ist die effizienteste Methode Mehrsprachigkeit zu implementieren, sämtliche Texte als Variablen in php-Dateien abzulegen und diese einzubinden, je nach Bedarf. (d.h. ich würde die Datein etwas unterteilen, dass nicht jedesmal alles mit eingefügt werden muss)
    Natürlich sollte man sein System von Anfang an darauf ausrichten (dieser Mehraufwand mit im Nachhinein einfügen ist echt anstrengend ;) sitze gerade davor und kann vor lauter Englischen Begriffen kaum noch gucken )

    Generell würde ich sagen ist es Sinnvoll sich immer Türen offen zu lassen für spätere Implementationen.
    Letztendlich müssen ja für solche Sachen wie der Fragebogengenerator, nur Menueinträge offen gehalten werden. Der Rest geschieht sicherlich auf einer völlig neuen Seite.

    Beim updaten fehlt mir jetzt etwas das Verständnis, da Du nur die Seite updatest, bleiben Datenbankeinträge ja bestehen oder täusche ich mich?
    Also kommen die probleme doch erst, wenn Du die Datenbank optimierst IHMO, dazu sollte man einfach sich ein Script bauen (vielleicht gibts ja einen Adminbereich), welches die alten Einträge in die Neue übernimmt und welches je nach Änderung angepasst wird.

    ciao
    romy

    --
    DIE ROMY AUS L. AN DER P. SAGT DANKE UND AUF WIEDERSEHEN
    ->Alles ist gut wenn es aus Schokolade ist
    1. Hallo Andreas,

      ich sowas seinerzeit (vor ca. 15 Jahren) mal in dBase programmiert.

      Das ist absolut vergleichbar, da dBase auch eine Interpretersprache war/ist, in der Makronamen ($$variable) möglich sind. Man muss für die Erweiterungen nur einen "Include-Anker" setzen. Der zeigt auf die Erweituerung und lädt die nach. Auch die Mehrsprachigkeit kann man so sehr leicht erschlagen. Die Begriffe in Variablen zu verpacken, darum kommst Du nicht drum herum. Aber eine Datenbank, wie z.B. Informix oder MySQL brauchst du nicht dafür. Das dauert viel zu lange. Ein rudimentärer Zugriff auf eine Datei mit der Language-Expansion reicht völlig. Das entsprechende Include muss eben nur nach, oder anstelle der Origianlzuweisung erfolgen.

      Es empfiehlt sich, alle Funktionen ausschließlich mit assoziativen  Arrays als Übergabeparametern zu schreiben. Dann kann man neue Parameter leicht einführen, ohne dass die alte Funktionsausführung damit ungültig wird. Nur der neue Parameter wird eben ignoriert. Das ist das, was man im DLL-Konzept mit Call by Index oder Call by name erreicht. Die neue DLL kann alles, was die alte auch konnte, und kann auch mit der kleineren Parameteranzahl der alten umgehen.

      Menus kann man auf diese Weise auch leicht erweitern. Die Position des neuen Paramters ist bei Call-by-Name (nicht verwechslen mit CallByReference/CallByName) für die Funktiohn auch unerheblich, für den User aber ggf. entscheidend.

      Jede neue Funktion muss dann nur wieder ein include auf eine leere Referenz mitbringen.

      Da es sich bei Webanwendungen allerdings sowieso um atomistische Programmmodule handelt, sollte man diese dann besser austauschen...

      Die Naviagation könnte aber alle Module laden und jedes bringt seinen Array-Eintrag zur Navigation mit. Du musst dann nur eine Schleife auf "Include all Files like *.module" legen.

      Viel Spaß und nochmehr Erfolg

      Tom

      1. Hallo!

        ich sowas seinerzeit (vor ca. 15 Jahren) mal in dBase programmiert.

        Da habe ich vermutlich gerade mit Lego gespielt ;-)

        Das ist absolut vergleichbar, da dBase auch eine Interpretersprache war/ist, in der Makronamen ($$variable) möglich sind. Man muss für die Erweiterungen nur einen "Include-Anker" setzen. Der zeigt auf die Erweituerung und lädt die nach.

        Ja, das hört sich ja prima an, aber wie ist das in der Praxis? erstmal, wie bekomme ich das Script dazu, die Module variabel nachzuladen? Dazu muß ich das Script bei jeder Änderung modifizieren, oder? Und was genau soll dann eingebunden werden? Wenn ich da an PHPs include() Funktion denke, was genau soll dann in so einer Datei stehen? Funktionen fallen aus da nicht doppelt vorkommen dürfen und ich den Namen nicht vorher wissen kann. Bei strings dasselbe. Höchtens ein $hauptmenue[]="abc";

        Auch die Mehrsprachigkeit kann man so sehr leicht erschlagen. Die Begriffe in Variablen zu verpacken, darum kommst Du nicht drum herum. Aber eine Datenbank, wie z.B. Informix oder MySQL brauchst du nicht dafür. Das dauert viel zu lange.

        Sicher? Eine so einfache und kleine Tabelle auszulesen, wenn eh schon eine persistenet Verbidnung besteht kann _sehr_ schnell gehen!

        Ein rudimentärer Zugriff auf eine Datei mit der Language-Expansion reicht völlig.

        Wie sieht das denn praktisch  in PHP aus? Was sollte dann genau da drin stehen? Sollte man das nicht lieber Dateiweise verteilen?

        Das entsprechende Include muss eben nur nach, oder anstelle der Origianlzuweisung erfolgen.

        verstehe ich nicht. Include kannst Du eimal am Anfang machen. Was willst Du dadurch ersetzen? Meinst Du mit Deinem "include" die php-include() Funktion?

        Es empfiehlt sich, alle Funktionen ausschließlich mit assoziativen  Arrays als Übergabeparametern zu schreiben. Dann kann man neue Parameter leicht einführen, ohne dass die alte Funktionsausführung damit ungültig wird. Nur der neue Parameter wird eben ignoriert.

        Das ist eine gute Idee.

        Jede neue Funktion muss dann nur wieder ein include auf eine leere Referenz mitbringen.

        das verstehe ich nicht. Was denn für ein include in der Funktion, udn was für eine Referenz und warum eine leere?

        Da es sich bei Webanwendungen allerdings sowieso um atomistische Programmmodule handelt, sollte man diese dann besser austauschen...

        was sind "atomistische Programmmodule"? Sowas wie "autonom"? Wie wäre das bei Mehrsprachigkeit?

        Die Naviagation könnte aber alle Module laden und jedes bringt seinen Array-Eintrag zur Navigation mit. Du musst dann nur eine Schleife auf "Include all Files like *.module" legen.

        Ja, das würde wohl gehen. as genau würdest Du dann in einer Datei *.modul stehen haben? Entweder kein PHP, so wie in meiner Antwort auf Svens Posting gechrieben, oder PHP, aber dann array_menue[]="abc", dann würde das automatisch eingefügt, nur bräuchte ich hierfür keine Funktion!

        Danke auch Dir!

        Viele Grüße
        andreas

    2. Hallo!

      IMHO ist die effizienteste Methode Mehrsprachigkeit zu implementieren, sämtliche Texte als Variablen in php-Dateien abzulegen und diese einzubinden, je nach Bedarf. (d.h. ich würde die Datein etwas unterteilen, dass nicht jedesmal alles mit eingefügt werden muss)

      Das überlege ich auch. Muß ich mir noch Gedanken zu machen.

      Natürlich sollte man sein System von Anfang an darauf ausrichten (dieser Mehraufwand mit im Nachhinein einfügen ist echt anstrengend ;) sitze gerade davor und kann vor lauter Englischen Begriffen kaum noch gucken )

      Trotzdem ist das der bessere Weg, da das projekt so nict zu komplex wird und einige Fehlerquellen erstmal wegfallen ;-)

      Generell würde ich sagen ist es Sinnvoll sich immer Türen offen zu lassen für spätere Implementationen.

      Das ist leichter gesagt als getan, vermutlich hilft hier nur Erfahrung...

      Letztendlich müssen ja für solche Sachen wie der Fragebogengenerator, nur Menueinträge offen gehalten werden. Der Rest geschieht sicherlich auf einer völlig neuen Seite.

      Das denke ich _jetzt_ auch, aber z.B. die Mehrsprachigkeit muß ja bei einer NAchinstallation auch reagieren, es muß ja festgelegt werden für welche Module die Sprach-Daten vorhanden sein müssen...

      Beim updaten fehlt mir jetzt etwas das Verständnis, da Du nur die Seite updatest, bleiben Datenbankeinträge ja bestehen oder täusche ich mich?

      normalerweise schon.

      Also kommen die probleme doch erst, wenn Du die Datenbank optimierst IHMO, dazu sollte man einfach sich ein Script bauen (vielleicht gibts ja einen Adminbereich), welches die alten Einträge in die Neue übernimmt und welches je nach Änderung angepasst wird.

      Ich glaueb ich probeire einfach mal, so ins blaue ist das ganze schon sehr abstrakt, viele Probleme fallen vermutlich bei der Implementation erst auf ;-)

      Danke Dir!

      Grüße
      Andreas

  2. Moin!

    Ich bin dabei eine Softwre zu schreiben, die verschiedene Module enthalten soll. Das heißt ein Basis-Modul mit der eigentlichen Basissoftware, und dazu kann man evtl noch zusätzliche Erweiterungen(Module) installieren, so z.B. ein Modul Mehrsprachigkeit, oder ein Modul Fragebogengenerator. Programmiert wird das ganze in PHP/PERL und MySQL.
    Wie man an den beiden Beispielen sieht, greifen die Module unterschiedlich weit in die gesamte Anwendung ein, gerade die Mehrsprachigkeit z.B. recht weit. Module sollen nicht von vornherein vorhanden sein, sondern sich auch nachträglich installieren lassen.

    Mit anderen Worten: Du hast ein (geplantes) Gesamtpaket, aus dem du einzelne Elemente herausschneiden willst. Und wenn man etwas schneidet, dann ... blutet es? Nein, dann hat man Schnittstellen!

    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.

    Das heißt es muß bei der "nachinstallation" z.B. in die Navigationsleise ein zusätzlicher Einrag erfolgen, oder es muss noch ein Extra Menü für die Konfigurierung des Moduls eingefügrt werden.

    Plane voraus: Alle Dinge müssen sich dynamisch erledigen lassen. 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, oder die Einträge werden einer entsprechenden Variablen hinzugefügt.

    Merhsprachigkeit dagegenb müßte ja von vornherein vorgesehen werden, dazu habe ich auch schon einige Threads hier verfolgtm, weiß aber noch nicht so Recht welches jetzt der "goldene Weg" ist, dies zu implementieren. Mit dem Accept-Language Header des Browsers finde ich eher ungünstig, eher als Indiz für die Starteinstellung. Also muß ich alle Texte in Variabvlen speichenr und die wiederum in der Datenbank, und dann bei jedem Seitenaufruf erstmal alle Texte aus der Datenbank auslesen - auch nicht wirklich optimal. Oder wie könnte man das besser einarbeiten?

    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. Will man von einer deutschen Seite auf die zugehörige englische Seite, dann könnte man im Pfad einfach das "de" durch "en" ersetzen und hätte so "umgeschaltet". Die einfache Variante ist natürlich, dass jede Sprache unabhängig von den anderen Sprachen ist, und die Links einfach zur Startseite führen.

    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.

    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.

    Noch so eine Sache ist wie man bei einee WEB-Anwendung eine Update-Funktion implementiert. D.h. wenn die Anwendung stetig weiterentwickelt wird, das dann sehr problemlos auf eine neue Version upgedatet werden kann, so dass alle Einstellungen und Daten bestehen bleiben... problematisch ist auch das Updaten über mehrere Versionen hinweg.

    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.

    Wenn sich auch Datenformate geändert haben, muss man eben eine Konvertierungsroutine mit einbauen, die vor dem Wiederhochfahren die notwendigen Dinge ändert. 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.

    Ein Beispiel: 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. :)

    Naja, leider habe ich mit solchen Dingen so gut wie gar keine Erfahrung. Hat da vielleicht jemand Tipps für mich, oder kennt jemand Projekte wo das ganze gut gelöst wurde?

    Das Problem dürfte wohl die gedankliche Fassbarkeit der Dynamik sein. 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.

    - Sven Rautenberg

    --
    Diese Signatur gilt nur am Freitag.
    1. 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

      1. Hallo Andreas,

        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.

        Plugins (oder Module, wie du es nennst) sind Teile der
        Aussenwelt.

        Gut, aber darunter kann ich mir jetzt _nichts_ vorstellen.
        Was wäre das denn praktisch?

        Das kommt auf dein Programm an :) Software-Design ist zwar
        viel allgemeines, aber wenn es an Schnittstellen geht, wird
        es anwendungsspezifisch.

        Interne Schnittstellen kann ich mir nur schwer vorstellen.
        Schnittstellen wozwischen? Zwischen den Modulen?

        Ja.

        Aber dazuwischen findet doch im Prinzip kein
        Datenaustausch statt, alle Module greifen auf dieselbe
        Datenquelle zurück.

        Tja, aber die Datenquelle ist nicht alles. Z. B. sind
        Variablen-Inhalte meist durch den Programmablauf bestimmt.

        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.

        Dann mach doch hier einen Punkt, an dem sich die Module
        einhaken koennen. Jedes Modul, dass geladen wird, hat z. B.
        eine Funktion/Methode 'menu' und gibt eine Struktur zurueck,
        die die Menue-Struktur des Plugins beschreibt. Der Menue-Teil
        macht dann daraus das HTML.

        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?

        Alles, was Funktionalitaet in sich birgt, muss dynamisch
        geschehen. Alles, was mit dem Design zusammenhaengt, kann
        statisch sein.

        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?

        Da gibts verschiedene Strategien. Einige lesen ein Verzeichnis
        aus, in dem alle Module liegen muessen, anderen arbeiten mit
        Konfigurations-Dateien. Ich halte zweiteres fuer sinnvoller.

        Und woher weiß ich vorher wie die Funktion heißen wird?

        Entweder, du gibst das vor (das ist gar nicht so selten, das
        wird sehr oft gemacht. Bei OO waere das ein typisches
        Konstrukt fuer Vererbung: die Elternklasse wuerde die
        Schnittstelle in Form einer abstrakten Klassen darstellen und
        die Kind-Klasse wuerde sie implementieren) oder du hast eine
        Konfigurations-Variable, in der Referenzen gespeichert sind.

        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?

        Halte ich fuer gut und sinnvoll, ja.

        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.

        Du kennst if()s? :)

        Nur das man sich durch sowas vermutlich leicht
        Fehlerquellen einbaut, oder?

        Ja. Das Datenformat ist IMHO etwas, was bestehen bleiben
        *muss*.

        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.

        Nein! Bitte nicht :) Aus so einem "Konzept" enstehen die
        ekeligsten Codes.

        Ich kann dir, wenn du moechtest, mal ein Konzept fuer eine
        PHP-basierte Groupware, die ich gerade schreiben muss,
        darlegen. Mach ich jetzt aber so nicht ungefragt, das gibt
        ein laengeres Posting...

        Gruesse,
         CK

        1. Hallo Christian,

          Da gibts verschiedene Strategien. Einige lesen ein Verzeichnis
          aus, in dem alle Module liegen muessen, anderen arbeiten mit
          Konfigurations-Dateien. Ich halte zweiteres fuer sinnvoller.

          Warum eigentlich? Ich denke, beides hat Vorteile. Wenn man schnell Module entfernen oder nachinstallieren will, dann sind die Verzeichnisse IMHO besser, wenn man wenig daran verändert, dann eher die Config-Dateien. Eventuell könnte man das kombinieren, dass es eine Funktion gibt, die die Verzeichnisse ausliest und daraus autmatisch eine Konfigurationsdatei erstellt, "caching" sozusagen. Diese Funktion kann dann vom Administrator aufgerufen werden.

          Entweder, du gibst das vor (das ist gar nicht so selten, das
          wird sehr oft gemacht. Bei OO waere das ein typisches
          Konstrukt fuer Vererbung: die Elternklasse wuerde die
          Schnittstelle in Form einer abstrakten Klassen darstellen und
          die Kind-Klasse wuerde sie implementieren)

          Das Problem bei PHP ist, dass der OO-Support sehr 'dürftig' ist, um es mal so zu sagen. Ich hab' mal einen Thread zum Thema Validierung gestartet [1] und habe mir sehhhr lange ein Konzept überlegt und jetzt endlich angefangen, zu implementieren. Ich habe mich dann doch für den Form-Generator entschieden. Was mich am meisten stört: wenn ich ein Objekt von irgendeiner meiner Klassen instantiere, muss ich die Zuweisung explizit per Referenz erfolgen lassen, also $obj =& new Klasse (...); (man beachte das &-Zeichen) Das "Problem" wird sogar im Manual beschrieben: http://www.php.net/manual/en/language.oop.newref.php In einer richtigen[tm] OOP-Sprache würde ich das auch mit Klassen lösen, aber bei PHP ist das u.U. nicht so ideal.

          Nur das man sich durch sowas vermutlich leicht
          Fehlerquellen einbaut, oder?

          Ja. Das Datenformat ist IMHO etwas, was bestehen bleiben
          *muss*.

          ACK. IMHO sollte sich die Major-Version des Projekts ändern, wenn so gravierende Änderungen am Datenformat vorgenommen werden, die nicht mit einem einfachen Hinzufügen von Spalten oder Tabellen gelöst werden können.

          Grüße,

          Christian

          [1] </archiv/2002/10/27058/>

          --
          Sollen sich alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen und nicht mehr davon erfasst haben als eine Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst.
                                -- Albert Einstein
          1. Hallo Christian,

            Da gibts verschiedene Strategien. Einige lesen ein
            Verzeichnis aus, in dem alle Module liegen muessen,
            anderen arbeiten mit Konfigurations-Dateien. Ich halte
            zweiteres fuer sinnvoller.

            Warum eigentlich?

            Die Konfigurations-Datei muss eh geparsed werden, also ist
            ein Verzeichnis-Scan immer ein Mehraufwand. Ausserdem bringt
            es einen weiteren Unsicherheitsfaktor mit rein: was, wenn da
            eine Datei liegt, die *kein* Plugin ist?

            Das Problem bei PHP ist, dass der OO-Support sehr
            'dürftig' ist, um es mal so zu sagen.

            ACK. Verlangt halt mehr Disziplin vom Programmierer.

            Gruesse,
             CK

            1. Hallo Christian,

              Ausserdem bringt
              es einen weiteren Unsicherheitsfaktor mit rein: was, wenn da
              eine Datei liegt, die *kein* Plugin ist?

              Naja, dafür hat dann schon der Admin zu sorgen.

              Das Problem bei PHP ist, dass der OO-Support sehr
              'dürftig' ist, um es mal so zu sagen.

              ACK. Verlangt halt mehr Disziplin vom Programmierer.

              Das, was da ist, hält mich *gerade noch* davon ab, laut aufzuschreien und PHP zu verfluchen. ;-) Im Ernst: Ich hoffe, mit PHP 5 wird das wirklich besser... Naja, das kommt davon, dass ich C++ gewöhnt bin, wenn's ums OOP, das kann ich nicht so einfach auf eine Scriptsprache übertragen.

              Grüße,

              Christian

              --
              Sollen sich alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen und nicht mehr davon erfasst haben als eine Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst.
                                    -- Albert Einstein
              1. Hallo!

                Das, was da ist, hält mich *gerade noch* davon ab, laut aufzuschreien und PHP zu verfluchen. ;-) Im Ernst: Ich hoffe, mit PHP 5 wird das wirklich besser... Naja, das kommt davon, dass ich C++ gewöhnt bin, wenn's ums OOP, das kann ich nicht so einfach auf eine Scriptsprache übertragen.
                Kennst Du: http://www-user.tu-chemnitz.de/~meal/php/php5/? Ich kenne mich leider nicht genug aus um was dazu sagen zu können.

                Grüße
                Andreas

                1. Hallo Andreas,

                  Kennst Du: http://www-user.tu-chemnitz.de/~meal/php/php5/?

                  Jetzt schon. ;)

                  Ich kenne mich leider nicht genug aus um was dazu sagen zu können.

                  Ahhh - wenn *das* endlich mal realisiert wird, ein PHP-Traum wird wahr! Namensräume, Packages, Exceptions, Übergabe per Referenz, Destruktoren, Private Variablen! Da könnte zwar noch einiges mehr kommen (ich denke da speziell an private/protected für Methoden und protected für Variablen), aber das ist schon mal viiiielll besser als die aktuelle Situation.

                  Grüße,

                  Christian

                  --
                  Sollen sich alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen und nicht mehr davon erfasst haben als eine Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst.
                                        -- Albert Einstein
          2. Hallo Christians!

            Das Problem bei PHP ist, dass der OO-Support sehr 'dürftig' ist, um es mal so zu sagen. Ich hab' mal einen Thread zum Thema Validierung gestartet [1] und habe mir sehhhr lange ein Konzept überlegt und jetzt endlich angefangen, zu implementieren. Ich habe mich dann doch für den Form-Generator entschieden. Was mich am meisten stört: wenn ich ein Objekt von irgendeiner meiner Klassen instantiere, muss ich die Zuweisung explizit per Referenz erfolgen lassen, also $obj =& new Klasse (...); (man beachte das &-Zeichen) Das "Problem" wird sogar im Manual beschrieben: http://www.php.net/manual/en/language.oop.newref.php In einer richtigen[tm] OOP-Sprache würde ich das auch mit Klassen lösen, aber bei PHP ist das u.U. nicht so ideal.

            Ich würde das ganze eigentlich sehr gerne mit OOP angehen, nur leider kenne ich mich damit noch sehr wenig aus. Das einzige was ich schonmal mit OOP umgesetzt habe ist ein Warenkorb. In diesem Fall hier weiß ich nicht so recht wo ich genau OOP verwenden könnte. Ich könnte eine Klasse "menu" erstellen mit den einzelnen Menü-Einträgen als Instanzen. Dann würde ich die Instanzen direkt beim Laden der Klasse erstellen. Dann könnte ich schön drauf zugreifen, aber was hätte ich groß davon? Ich könnte als Eigenschaft der Klasse einen Array mit den Instanzen, also den Menü-Einträgen zurückliefern, wo ich dann in der eigentlichen Datei dann mit einer foreach-Schleife draus den HTMl-Code generieren könnte. Aber wofür? Einen großen Nutzen sehe ich hier nicht, vor allem nicht in Bezug auf das Speichern bzw. Zugreifen auf die Menü-Elemente, also Module. Wie würde das denn eien OOP-Profi machen? Und wo könnte ich noch OOP einsetzen? Vielleicht noch bei der mhersprachigen ausgabe, also eine neue Klasse hierfür. Und sonst? Wenn ich nochwas wie das Menü hätte, könte ich hierfür noch eien KLasse machen... aber so richtig habe ich noch nict en Durchblick was  mir das am Ende bringt. OK, eine Sache wäre noch eine Klasse für den Datenbank-Zugriff, dann wäre ich nicht mehr so abhängig von mySQL, und könnte z.B. auch postgres verwenden. Nur wie mache ich das denn jetzt? Sagen wir mal ich wollte ein Postgres-Modul, ein MySQL Modul und ein Flat-File Modul verwenden können. Dann würde ich die von mir beschriebende DB-Klasse in eine Datei auslagern, die dann mit Include eingebunden wird, in einer conf-File wird dann halt die DB-include-Datei ausgewählt.

            Viele Grüße
            Andreas

        2. Hallo Christian!

          Plugins (oder Module, wie du es nennst) sind Teile der
          Aussenwelt.

          Ja? Ich kenne Plugins eigentlich nur vom IE. Das sind dann ganz andere Programme die von ganz anderen Firmen programmiert werden und in die Oberfläche des IE eingebunden sind. Meine Module stellen eher Erweiterungen das Basisprogramms dar, die Teil des Programms sind, wobei, das ist schon recht ähnlich.

          Tja, aber die Datenquelle ist nicht alles. Z. B. sind
          Variablen-Inhalte meist durch den Programmablauf bestimmt.

          ich mache das zur Zeit so, dass ich global eine Datei in alle Scripte einbeziehe, in der die DB-Verbindung hergestellt wird, die Funktionen einmalig stehen, die ich dann in den Scripten nutze. Noch ein paar .ini Änderungen, sonst nichts. Ist das schon eine Schnittstelle?

          Dann mach doch hier einen Punkt, an dem sich die Module
          einhaken koennen. Jedes Modul, dass geladen wird, hat z. B.
          eine Funktion/Methode 'menu' und gibt eine Struktur zurueck,
          die die Menue-Struktur des Plugins beschreibt. Der Menue-Teil
          macht dann daraus das HTML.

          Aber wie sol ich mir das praktisch vorstellen? Wenn ich auf die Funktion "menu" zugreifen will muß ich die Datei mit include einbinden - dann darf es aber auch nur nur ein Modul geben da ein Funktionsname nur einmal existieren darf! Und warum soll ich das als Funktion speichern? Wäre es nicht besser als mehrdimensionaler Array? Also nur eine Funktion "menu" ins Hauptprogramm, und in den Modul-Dateien dann:

          menu[]=array(menü-struktur...);

          Dann kann die Funktion alle Modul-Dateien nacheinander öffenen und so den Array menu mit Inhalt füllen? Wäre es denn nicht besser die komplette Menüstruktur in eine DB-Tabelle oder eigene conf_datei zu schreiben, und dann bei der Installation des Moduls eine neue PHP Datei zu erstellen, die den kompletten, aktuellen Menü-Array hardcoded enthält?

          Alles, was Funktionalitaet in sich birgt, muss dynamisch
          geschehen. Alles, was mit dem Design zusammenhaengt, kann
          statisch sein.

          Das hängt aber alles sehr zusammen, was ist bei einem Kontakt-Formular, das enthält eine Funktionalität, das menü wird dynamsich eingebunden, was solte hier noch dynamisch sein? Mein Problem st, das ich mir jetzt außer dem Menü keine weiteren Möglichkeiten vorstellen kann wo noch etwas dynamisch geschehen müßte.

          Wie mache ich jetzt der Menüleiste klar
          das diese Datei ab heute ebenfalls abgefragt werden soll?

          Da gibts verschiedene Strategien. Einige lesen ein Verzeichnis
          aus, in dem alle Module liegen muessen, anderen arbeiten mit
          Konfigurations-Dateien. Ich halte zweiteres fuer sinnvoller.

          Also eine eigene Konfigurations-Datei für alle Einstellungen, die durch ein Modul beeinflußt werden können, nur was steht dann darin? Nur:

          Modul-menuepunkt1
          Modul-menuepunkt3
          Modul-menuepunkt2

          eine einfache Liste der menü-Punkte? Udn wenn noch was dazu kommt? Leider weiß ich kein Beispiel, aber in welcher Form sollte das dann da stehen? Und das größte Problem: Wie erstelle ich diese Datei? Das doofe ist ja, ich muß wissen welche Module bereist installiertund welche dazu kommen, das muß ja dann alles in der Datei stehen!

          Und woher weiß ich vorher wie die Funktion heißen wird?

          Entweder, du gibst das vor (das ist gar nicht so selten, das
          wird sehr oft gemacht

          wie denn praktisch? bei 2 Modulen: menu1() und menu2()? Und woher weiß ich dann wieviele Module das sind...?

          Bei OO waere das ein typisches
          Konstrukt fuer Vererbung: die Elternklasse wuerde die
          Schnittstelle in Form einer abstrakten Klassen darstellen und
          die Kind-Klasse wuerde sie implementieren

          Was soll ich hier vererben? Das Problem ist ja an anderer Stelle, ich muß erstmal wissen welche Module ich habe und mit der Information z.B. die Menü-Struktur ermitteln. Nur ich weiß weder wie ich an diese beiden Informationen kommen soll, noch was das ganze mit Klassen zu tun haben soll.

          oder du hast eine
          Konfigurations-Variable, in der Referenzen gespeichert sind.

          Referenzen worauf? Und wo bekommt die Variable diese Informationen her?

          Hm? Wie soll das gehen? Nenn bitte mal ein Beispiel.

          Du kennst if()s? :)

          ja, ich meinte eher Praxisbeispiele.

          Nein! Bitte nicht :) Aus so einem "Konzept" enstehen die
          ekeligsten Codes.

          Ich werde das vermutlich dann kompleztt neu programmieren und nur Teile übernehmen, und dann unter anderen Gesichtspunkten(Erweiterbarkeit, Pflege...) den neuen Code schreiben.

          Ich kann dir, wenn du moechtest, mal ein Konzept fuer eine
          PHP-basierte Groupware, die ich gerade schreiben muss,
          darlegen. Mach ich jetzt aber so nicht ungefragt, das gibt
          ein laengeres Posting...

          Sehr, sehr gerne! Bin _immer_ an gutem Code sehr interessiert!
          Von wegen PHP-Groupware, http://moregroupware.sourceforge.net/ ist diebeste PHP-basierte Groupware die ich kenne. Leider noch nicht so richtig fertig, aber ich denke das wird eine gute Sache. Falls Du es nicht kennst, ist bestimmt interessant! Ich habe auch nochmal geguckt, die haben ja auch Module, vielleicht kann ich da ja auch was von gebrauchen.

          Viele Grüße und vielen Dank!

          Grüße
          Andreas

          1. Hallo nochmal!

            Sehr, sehr gerne! Bin _immer_ an gutem Code sehr interessiert!
            Von wegen PHP-Groupware, http://moregroupware.sourceforge.net/ ist diebeste PHP-basierte Groupware die ich kenne. Leider noch nicht so richtig fertig, aber ich denke das wird eine gute Sache. Falls Du es nicht kennst, ist bestimmt interessant! Ich habe auch nochmal geguckt, die haben ja auch Module, vielleicht kann ich da ja auch was von gebrauchen.

            in diesem Zusammenhang vielleicht nochmal, was hälst Du(haltet Ihr) von diesem Konzept: http://moregroupware.sourceforge.net/docs/mgw-addmodule.html?

            Grüße
            Andreas

          2. Hallo Andreas,

            Plugins (oder Module, wie du es nennst) sind Teile der Aussenwelt. Ja? Ich kenne Plugins eigentlich nur vom IE. Das sind dann ganz andere Programme die von ganz anderen Firmen programmiert werden und in die Oberfläche des IE eingebunden sind.

            Ehm, das ist eine Art Plugins fuer den IE.

            Meine Module stellen eher Erweiterungen das Basisprogramms dar,

            Na und? Sie sind externe Programm-Teile. Es ist nicht zwingend gegeben, dass du sie schreibst.

            Tja, aber die Datenquelle ist nicht alles. Z. B. sind Variablen-Inhalte meist durch den Programmablauf bestimmt. ich mache das zur Zeit so, dass ich global eine Datei in alle Scripte einbeziehe, in der die DB-Verbindung hergestellt wird, die Funktionen einmalig stehen, die ich dann in den Scripten nutze. Noch ein paar .ini Änderungen, sonst nichts. Ist das schon eine Schnittstelle?

            Ja, allerdings eine relativ primitive. Damit forderst du Inkonsistenzen geradezu heraus.

            Dann mach doch hier einen Punkt, an dem sich die Module einhaken koennen. Jedes Modul, dass geladen wird, hat z. B. eine Funktion/Methode 'menu' und gibt eine Struktur zurueck, die die Menue-Struktur des Plugins beschreibt. Der Menue-Teil macht dann daraus das HTML. Aber wie sol ich mir das praktisch vorstellen? Wenn ich auf die Funktion "menu" zugreifen will muß ich die Datei mit include einbinden - dann darf es aber auch nur nur ein Modul geben da ein Funktionsname nur einmal existieren darf!

            Dann benutze Klassen und Objekte. Oder setze den Funktions-Namen aus Modul-Name.'_menu' zusammen. Oder mach es sonstwie :) Du weisst doch, wie Referenzen in PHP funktionieren.

            Und warum soll ich das als Funktion speichern?

            Damit du dort ausfuehrbaren Code hast.

            Wäre es nicht besser als mehrdimensionaler Array? Also nur eine Funktion "menu" ins Hauptprogramm, und in den Modul-Dateien dann:

            menu[]=array(menü-struktur...);

            Klar, koenntest du machen. Damit machst du dich aber von dem Array abhaengig. Was ist, wenn du den mal umbenennst? Ausserdem widerspricht es dem Prinzip der Datentrennung. Ein externes Code-Stueck hat an internen Variablen einfach nix zu suchen, basta.

            Wäre es denn nicht besser die komplette Menüstruktur in eine DB-Tabelle oder eigene conf_datei zu schreiben, und dann bei der Installation des Moduls eine neue PHP Datei zu erstellen, die den kompletten, aktuellen Menü-Array hardcoded enthält?

            Ansichtssache. Ich halte das fuer zu inflexibel. Ich moechte meine Menues dynamisch aendern, abhaengig vom Programm-Ablauf.

            Alles, was Funktionalitaet in sich birgt, muss dynamisch geschehen. Alles, was mit dem Design zusammenhaengt, kann statisch sein. Das hängt aber alles sehr zusammen,

            Dann hast du etwas falsch gemacht.

            was ist bei einem Kontakt-Formular, das enthält eine Funktionalität, das menü wird dynamsich eingebunden, was solte hier noch dynamisch sein?

            Das Kontakt-Formular selber ist ein Modul. Das Modul hat ein Template, das bei Bedarf angepasst werden kann. Das Template bindet das Menue per include() oder etwas aehnlichem ein. Wo ist das Problem?

            Mein Problem st, das ich mir jetzt außer dem Menü keine weiteren Möglichkeiten vorstellen kann wo noch etwas dynamisch geschehen müßte.

            Dann mach erstmal nur das Menue dynamisch.

            Da gibts verschiedene Strategien. Einige lesen ein Verzeichnis aus, in dem alle Module liegen muessen, anderen arbeiten mit Konfigurations-Dateien. Ich halte zweiteres fuer sinnvoller. Also eine eigene Konfigurations-Datei für alle Einstellungen, die durch ein Modul beeinflußt werden können, nur was steht dann darin?

            Nee. Eine Konfigurations-Datei, in der die Plugins eingebunden werden. Bei meiner Groupware sieht das z. B. so aus:

            LOAD usermanagement.inc.php:UserManagement

            Und woher weiß ich vorher wie die Funktion heißen wird?

            Entweder, du gibst das vor (das ist gar nicht so selten, das wird sehr oft gemacht wie denn praktisch? bei 2 Modulen: menu1() und menu2()?

            Siehe oben.

            Und woher weiß ich dann wieviele Module das sind...?

            Zaehlen? :)

            Bei OO waere das ein typisches Konstrukt fuer Vererbung: die Elternklasse wuerde die Schnittstelle in Form einer abstrakten Klassen darstellen und die Kind-Klasse wuerde sie implementieren Was soll ich hier vererben? Das Problem ist ja an anderer Stelle, ich muß erstmal wissen welche Module ich habe und mit der Information z.B. die Menü-Struktur ermitteln.

            Nu haeng dich doch nicht so an der Menue-Struktur auf.

            Nur ich weiß weder wie ich an diese beiden Informationen kommen soll, noch was das ganze mit Klassen zu tun haben soll.

            Du hast eine Basis-Klasse, nennen wir sie mal 'KorthausPlugin'. Die definiert verschiedene Methoden, unter anderem z. B. die Methode 'menu_hook'. Rueckgabewert und Parameter sind definiert. Nun gehst du, wenn du das Menue generierst, alle in der Konfigurations-Datei angegebenen Plugins durch, instanzierst sie und rufst dann die Methode menu_hook auf. Aus den so gewonnen Funktionen kannst du dann Problemlos das Menue generieren.

            oder du hast eine Konfigurations-Variable, in der Referenzen gespeichert sind. Referenzen worauf?

            Auf Funktionen.

            Und wo bekommt die Variable diese Informationen her?

            Diese Variable steht im Modul. Du traegst die Informationen dort ein.

            Nein! Bitte nicht :) Aus so einem "Konzept" enstehen die ekeligsten Codes. Ich werde das vermutlich dann kompleztt neu programmieren und nur Teile übernehmen, und dann unter anderen Gesichtspunkten(Erweiterbarkeit, Pflege...) den neuen Code schreiben.

            Das ist deine Sache, aber ich wuerde das nicht tun. Ueberfluessiger Arbeitsaufwand...

            Ich kann dir, wenn du moechtest, mal ein Konzept fuer eine PHP-basierte Groupware, die ich gerade schreiben muss, darlegen. Mach ich jetzt aber so nicht ungefragt, das gibt ein laengeres Posting... Sehr, sehr gerne! Bin immer an gutem Code sehr interessiert!

            Code? :) Ich wollte das Konzept darstellen.

            Gut, zunaechst: was ist eine Groupware? Tja, schwer zu sagen. Wieder so ein schwammiger Begriff. Eine Groupware ist letztenendes alles und nichts. Und genau da liegt die Loesung: eine Groupware ist nicht ein festes Software-Paket, sondern viel mehr ein Rahmenwerk, das grundsaetzliche Techniken und Schnittstellen zur Verfuegung stellt. Klar sind in jeder Groupware gewissen "Standard-Plugins" mitgeliefert, aber das Wichtigste ist die leichte Erweiterbarkeit und das leichte Abspecken. Was also muss dieses Rahmenwerk leisten koennen? Nun, es muss grundsaetzlich erstmal einen Zugriff auf Daten erlauben. Der kann auf unterschiedliche Art und Weise passieren: generisch oder abstrahiert. Eine Abstraktions-Ebene einzufuehren waere zwar sauberer, aber dann muesste man 'Meta-Datenstrukturen' einfuehren. Und die haben einen ganz entscheidenden Nachteil: sie sind langsam. Also muss der Zugriff auf die Daten generisch sein, damit jedes Modul seine eigenen Datenstrukturen mitbringen kann. Definiert und bekannt sollten nur die wichtigsten sein: User-, Gruppen- und Rechte-Strukturen. Aber genau so darf ein Plugin auf diese Kern-Daten auch nicht direkt zugreifen. Die Module muessen sich darauf verlassen koennen, dass die Schnittstelle gleich bleibt, also muss noch eine Aufgabe in das Rahmenwerk: der Zugriff auf die Kern-Daten muss abstrahiert werden. Gut, weiter. Der Zugriff auf Plugins muss gegeben sein. Es kann durchaus vorkommen, dass Plugins miteinander kommunizieren muessen. Das ist zwar optional zu halten, aber es muss moeglich sein. Also muss der Zugriff auf Plugin-Routinen abstrahiert werden. Beispiel: ein Webmail-Tool koennte mit dem Adressbuch-Tool arbeiten, um E-Mail-Adressen herauszusuchen. Es muss aber sichergestellt werden, dass diese Zusammenarbeit optional ist. Denn ob ein Modul vorhanden ist oder nicht, haengt von der Konfiguration ab.

            So, jetzt geh ich erstmal baden :) Da bin ich wieder.

            So. Der naechste Punkt geht schon etwas tiefer. Wir haben gesagt, Plugins muessen miteinander kommunizieren koennen. Was ist aber, wenn ein Plugin Eingabedaten vom User braucht? Prinzipiell muesste also ein Plugin, dass mit einem anderen kommuniziert, die GUIs des anderen nachbauen. Das ist aber nicht sinnvoll, also muss es eine Moeglichkeit geben, die Kontrolle ueber mehrere Requests hinweg an ein Plugin zu geben. Nach den Ablaeufen muss die Kontrolle wieder zurueck gegeben werden an das 'alte' Plugin.

            Der letzte Fall ist ein Sonderfall. Ich habe die Mehrsprachigkeit mit in die API aufgenommen, damit das Handling einfacher wird. Ich habe eine Methode aufgenommen, die den Zugriff auf sprachspezifische Daten zulaesst und die aktuelle Sprache zurueck gibt.

            Damit stuende zumindest schonmal die Funktionalitaet der API (des Core-Teils) fest. Jetzt schauen wir uns die Schnittstellen mal naeher an:

            Der Zugriff auf die Daten geschieht ueber die Methode 'db_query'. Der wird als Parameter die Query als String uebergeben und dazu, optional, der Datenbank-Name. Wird kein Datenbanks-Name uebergeben, so wird die Default-Datenbank genommen. Jede Datenbank muss vorher in der Konfigurations-Datei dem System bekannt gemacht werden. Besteht eine Verbindung zu dem Datenbank-Server, so wird (bei Bedarf) nur die Datenbank gewechselt und dann die Query ausgefuehrt. Besteht keine Verbindung, so wird eine neue Verbindung aufgebaut und dann die Query abgesetzt. Die Rueckgabe ist eine DBResult-Klasse. Doch zu der spaeter.    Zusaetzlich zu db_query() gibt es noch db_escape(). Da wir halbwegs datenbanksunabhaengig bleiben wollen, ist das notwendig (verschiedene Datenbanksysteme habe verschiedene Quoting-Regeln). Als Parameter erwartet die Methode den String und, optional, den Datenbanks-Namen. Wird kein Datenbankname uebergeben, so wird die Default-Datenbank benutzt. Die Rueckgabe ist der escaped String.

            Najut. Der Zugriff auf die Kern-Daten. Was genau muessen wir ueber den User wissen? Eigentlich nur den Usernamen und vielleicht noch die Sprache. Ach ja, die User-ID waere noch ganz angenehm. Dazu noch, welche Rechte der User hat... gut, also gibt es eine Methode 'user_infos', die einen Array zurueck gibt, dessen erstes Argument die User-ID ist und dessen zweites Argument der Username ist. Die Sprache kann ueber die Methode 'lang' abgefragt werden. Die Rueckgabe ist die aktuelle User-Sprache. Ueber die Rechte bliebe etwas mehr zu sagen. Jedes Plugin muss seine eigenen Rechte mitbringen, aber das Minimum-Recht muss das Recht der generellen Benutzung sein. Warum, wird spaeter klar. Das Abfragen der Rechte muss allerdings durch das Rahmenwerk geschehen. Also gibt es eine Methode 'may_user', die ueberprueft, ob das Recht fuer den aktuellen User gesetzt ist. Um der Problematik der doppelten Benennung zu umgehen, hat jedes Modul seinen eigenen Namespace. Deshalb erwartet diese Methode als ersten Parameter den Rechte-Namen und als zweiten Parameter den Plugin-Namen. Die Rueckgabe ist True, wenn das Recht gesetzt ist, und False, wenn das Recht nicht gesetzt ist.

            Der Zugriff auf Plugins ist ueber die Methode 'plugin' gegeben. Diese Methode stellt zwei Sachen sicher: erstens, dass alle Plugins Singletons sind (sprich, sie koennen nur einmal instanziert werden) und b) dass der Zugriff auf Plugins nicht direkt geschieht. Als Parameter erwartet sie den Namen des Plugins. Der Rueckgabewert ist ein Plugin-Objekt, wenn das Plugin existiert und NULL, wenn das Plugin nicht existiert.

            Die Kontroll-Verwaltung geschieht ueber die Methoden 'give_control' und 'return_from_control'. Die erste Methode uebergibt die Kontrolle Zeitweise an ein Plugin und erwartet den Plugin-Namen als Parameter. Sie gibt 'true' zurueck, wenn die Kontroll-Uebergabe erfolgreich war und 'false', wenn sie nicht erfolgreich war. Die zweite Methode gibt die Kontrolle an das vorherige Plugin zurueck. Ist kein Plugin mehr im Stapel, wird auf die Hauptseite zurueck geleitet.

            Gut, zur Mehrsprachigkeit. Alle Ausgaben, die nicht in die Templates ausgelagert wurden (werden konnten), stehen in einem Array von Strings. In der ersten Ebene ist der Key die Sprache, in der zweiten Ebene ist der Key der Plugin-Name. Innerhalb der dritten Ebene kann dann das Plugin machen, was es will. Zum Zugriff auf diesen Array gibt es die Methode 'strings', dass den Plugin-Spezifischen Teil-Array zurueck gibt. Die Mehrsprachigkeit der Templates wird ueber die Struktur der Template-Verzeichnisse festgelegt. Unterhalb von de/ z. B. befinden sich alle deutschen Templates, unterhalb von en/ befinden sich alle englischen Templates. Die aktuelle Sprache kann ueber die Methode 'lang' ermittelt werden.

            Gut, damit haetten wir die generelle API. Dann mal was zu den Plugins selber. Es gibt zwei Arten von Plugins: Applikations-Plugins und 'Snipplets'. Snipplets sind Plugins, die bei jedem Request instanziert werden und ausgefuehrt werden. Das ist z. B. fuer dynamische Inhalte wie News oder so gedacht. Der Haken (der Ausfuehrungspunkt) ist vor jeglicher Ausgabe, direkt nach der Autentifizierung. Die zweite Art von Plugins bezeichnet erweiternde Funktionalitaeten. Ein Beispiel waere hier Webmail oder auch das Adressbuch. Fuer diese Art von Plugin gibt es vier Haken.   Ein Haken ist fuer die Hauptseite. Wenn die dargestellt wird, kann es uU userspezifische Meldungen geben (etwa 'Sie haben 5 neue Mails' oder 'Sie haben heute 5 Termine'). Wenn also die Hauptseite dargestellt werden soll, wird das Plugin instanziert und die Methode 'mainpage_hook' wird aufgerufen. Es werden keine Parameter uebergeben. Die Methode ist 'void'.   Der naechste Haken ist zur Generierung des Menues. Wenn das Menue generiert werden soll, werden alle Applikations-Plugins instanziert und die Methode 'menu_hook' wird aufgerufen. Es werden keine Parameter uebergeben und die Methode gibt einen Array zurueck, der die Menue-Eintraege beschreibt.   Der naechste Haken ist zum erfahren der Rechte, die es fuer dieses Plugin gibt. Wie gesagt, ein Plugin kann beliebige Rechte definieren. Wie die ausgewertet werden, bleibt dem Plugin ueberlassen. Einziges MUST-Recht ist das 'USE'-Recht. Um diese Rechte zu erfahren, wird die Methode 'right_infos' aufgerufen. Es werden keine Parameter uebergeben und als Rueckgabe wird ein Array erwartet, der die Rechte beschreibt.   Der letzte Haken ist der, wenn das Plugin gerade die Kontrolle hat. Kontrolle heisst, es werden mehrere Requests nach der Authentifizierung direkt an das Plugin weitergeleitet. Diese Methode nimmt keine Parameter entgegen und ist gibt nichts zurueck.

            Jetzt fehlt allerdings noch etwas: der Zugriff auf die API. Der ist dadurch gegeben, dass den Konstruktor des Plugins eine Referenz des API-Objekts und eine Referenz auf das Template-Objekt uebergeben werden. Damit hat ein Plugin beliebigen Zugriff auf Templates (Variablen setzen, Template-Dateien anzeigen lassen) und die API.

            Puh. Jetzt hab ich sicher die Haelfte vergessen... mal nachschauen. Ach ja, die DBResult-Klasse. Diese Klasse hat 'nur' die Methoden 'numRows', 'fetchRow', 'isError', 'getMessage', 'free' und 'insertId'. Duerfte selbsterklaerend sein.

            Mit dem oben abgebildeten Konzept sollte man eigentlich so ziemlich alles abbilden und einbauen koennen. Mir ist kein Fall eingefallen, der nicht moeglich ist. Jedes Plugin hat seinen eigenen Namespace und jedes Plugin hat seinen eigenen Tablespace. Kollisionen sind also nicht unmoeglich, aber sehr unwahrscheinlich.

            Jetzt faellt mir aber auch nicht mehr viel ein.

            Gruesse,  CK

            1. Hi Christian,

              alter Angeber, mit welchem Hintertürchen kannst Du bitte 15 KB posten??? Unverschämtheit, und unsereins darf seinen Beitrag ggfs. bis zur Unkenntlichkeit verstümmeln ;-)

              ich mache das zur Zeit so, dass ich global eine Datei in
              alle Scripte einbeziehe, in der die DB-Verbindung
              hergestellt wird, die Funktionen einmalig stehen, die ich
              dann in den Scripten nutze. Noch ein paar .ini Änderungen,
              sonst nichts. Ist das schon eine Schnittstelle?

              Ja, allerdings eine relativ primitive. Damit forderst du
              Inkonsistenzen geradezu heraus.

              wo denn? Meinst Du dass jedes Modul seine eigenen Funktionen... haben soll? Aber das mache ich gerade _weil_ in absehbarer Zeit niemals jemand anderer als ich ein Modul hierfür schreiben wird. Zumindest ist es nicht vorgesehen, falls das doch mal notwendig werden sollte muß ich das halt dokumentieren. Oder meinst Du noch was anderes?

              Dann benutze Klassen und Objekte. Oder setze den Funktions-Namen aus Modul-Name.'_menu' zusammen. Oder mach es
              sonstwie :) Du weisst doch, wie Referenzen in PHP
              funktionieren.

              weiß ich nicht, hab das gerade mal nachgelesen, interessante Variante! Nur brauche ich im Prinzip das genaue Gegenteil, hier kann ich mehrere Variablen definieren, mit dem glichen Inhalt, und dafür bräuchte ich nichtmal Referenzen, aber ich brauche irgendwie eine Variable mit verschiedenem Inhalt je nach Modul. Das kann nicht funktionieren. Und einen Rückgabewert, ob Klasse oder nicht, ich kann definitiv keien Funktion in das Modul schreiben, außer ich überlege mit einen zusammengesetzen Namen. Daher sollte man das IMHO besser in eine conf-File schreiebn und die parsen, das geht doch auch recht schnell. _Dann_ kann ich das in eine Klasse schreiben... warum auch immer das Sinn machen sollte.

              Und warum soll ich das als Funktion speichern?

              Damit du dort ausfuehrbaren Code hast.

              vermutlich sind includes auch nicht so viel schneller als ein fopen, und das parsen von ein paar Zeilen, nur damit hätte ich direkt _alle_ Werte in einer saubereren Struktur als Funktionen mit zusammengesetzten Namen. Ich würde ja evtl. das ganze bei jeder Änderung als ausführbaren Array hardcoden, aber da bist Du ja dagegen. Wobei man IMHO fast genauso leicht einen Array auch manuell verändern kann, wie eine csv-Datei!?

              menu[]=array(menü-struktur...);

              Klar, koenntest du machen. Damit machst du dich aber von dem
              Array abhaengig. Was ist, wenn du den mal umbenennst?
              Ausserdem widerspricht es dem Prinzip der Datentrennung. Ein
              externes Code-Stueck hat an internen Variablen einfach nix
              zu suchen, basta.

              Aber ist das denn mit Funktionen so viel anders? Da bin ich auch davon abhängig das ich die Funktion oder die Zusammensetzen dessen Namen nicht ändere. Einfache Datendatei wäre mir bisher eigentlich am liebsten.

              Was hälst Du von der Funktion parse_ini_file() für sowas?

              Wäre es denn nicht besser die komplette Menüstruktur in
              eine DB-Tabelle oder eigene conf_datei zu schreiben, und
              dann bei der Installation des Moduls eine neue PHP Datei
              zu erstellen, die den kompletten, aktuellen Menü-Array
              hardcoded enthält?

              Ansichtssache. Ich halte das fuer zu inflexibel. Ich moechte
              meine Menues dynamisch aendern, abhaengig vom
              Programm-Ablauf.

              reicht es da nicht einen kompletten Array zu haben und ggfs. nur einen Teil dessen auszugeben? Die komplette Navigation ändert sich doch nur wenn ich das sage, also wenn ein Modul oder Update dazu kommt. Das wird installiert und der Array wird wieder aktualisiert.

              was ist bei einem Kontakt-Formular, das enthält eine
              Funktionalität, das menü wird dynamsich eingebunden, was
              solte hier noch dynamisch sein?

              Das Kontakt-Formular selber ist ein Modul. Das Modul hat ein
              Template, das bei Bedarf angepasst werden kann. Das Template
              bindet das Menue per include() oder etwas aehnlichem ein. Wo
              ist das Problem?

              Jaja! Ein Problem habe ich nicht, nur dass ich nicht weiß was noch dynamisch sein soll, da Du sagst _alles_ soll dynamsich sein. Nochwas dazu:
              Sollte man denn das Modul Kontaktformular so frei machen könnten, das man die Navigation... selbst einbinden kann? Ich binde eigentlich immer 4 Dateien ein:
              1. global.inc (PHP-Funktionen...)
              2. header.inc
              3. footer.inc
              4. menu.inc

              Könnte man dei Struktur nicht auch noch aulagern, so dass man wirklich  als Template nur noch mit dem wirklichen body des Dokuments zu tun hat, und keine includes?

              LOAD usermanagement.inc.php:UserManagement

              Was ist das für eine Syntax? Oder parst Du das noch selbst?

              Und woher weiß ich dann wieviele Module das sind...?
              Zaehlen? :)

              genau da lag das Problem - was zählen... aber mit einer conf-File sieht das ganze ja schon etwas besser aus, jetzt komme ich an die Werte, deren Anzahl...

              Nur ich weiß weder wie ich an diese beiden Informationen
              kommen soll, noch was das ganze mit Klassen zu tun haben
              soll.

              Du hast eine Basis-Klasse, nennen wir sie mal
              'KorthausPlugin'. Die definiert verschiedene Methoden, unter
              anderem z. B. die Methode 'menu_hook'. Rueckgabewert und
              Parameter sind definiert. Nun gehst du, wenn du das Menue
              generierst, alle in der Konfigurations-Datei angegebenen
              Plugins durch, instanzierst sie und rufst dann die Methode
              menu_hook auf. Aus den so gewonnen Funktionen kannst du dann
              Problemlos das Menue generieren.

              Da kann ich Dir leider nicht folgen. OK, in der conf-File stehen die Module. Nur wie komme ich dann an die Werte? So wie ich das verstanden  habe hat jedes Modul eine Funktion menu, das bekomme ich nur durch include, also müßte ich hier wieder zusammengesetze Funktionsnamen haben - setzt Du das hier voraus?

              Referenzen worauf?
              Auf Funktionen.

              das geht doch? Aber was bringts? Sobald ich mehr als 1 Funktion mit demselben Namen einfüge, per include, ist Ende!

              Definiert und bekannt
              sollten nur die wichtigsten sein: User-, Gruppen- und
              Rechte-Strukturen.

              Ah, das hatte ich noch gar nicht bedacht. Bisher habe 2 Ebenen, von denen die eine mehr sieht als die andere. Diese Information müßte ich auch in das Menü mit einarbeiten. Sonst verwene ich als Login-Mechanismus Basic Authentification mit .htaccess und habe user und gruppen dort definiert. Aber das ist nicht so wield, denn die eine Gruppe darf nur in das Verzeichnis X, die andere nur in Y, und die dritte in Z. Die Module gelten aber immer nur in einem Verzeichnis. Das heißt ich muß nur die Hirarchie-Ebenen mit einbauen.

              also muss noch eine Aufgabe in
              das Rahmenwerk: der Zugriff auf die Kern-Daten muss
              abstrahiert werden.

              was heißt das praktisch? Zugriff auf die Kerndaten über eine Klasse oder was?

              Beispiel: ein
              Webmail-Tool koennte mit dem Adressbuch-Tool arbeiten, um
              E-Mail-Adressen herauszusuchen.

              Aber wieso muß ich hier auf Routinen(Funktionen) des anderen Moduls zurückgreifen? Ich prüfe ob das Modul vrohanden ist und greife dann direkt auf die DB zu! Obwohl, was wenn sich die Tabele da ändert... also brauche ich speziell hierfür eine eigene Klasse die den Zugriff auf die Adressdaten regelt, oder wie würdest Du das jetzt machen?

              So, jetzt geh ich erstmal baden :)

              wenigstens schön mit gelbem Quitscheentchen?

              Was ist aber, wenn ein Plugin Eingabedaten vom User braucht?
              Prinzipiell muesste also ein Plugin, dass mit einem anderen
              kommuniziert, die GUIs des anderen nachbauen. Das ist aber
              nicht sinnvoll, also muss es eine Moeglichkeit geben, die
              Kontrolle ueber mehrere Requests hinweg an ein Plugin zu
              geben. Nach den Ablaeufen muss die Kontrolle wieder zurueck
              gegeben werden an das 'alte' Plugin.

              Das kommt ja nicht oft vor. Wenn das vorkommt, könnte man da nicht eine extra Schnittstelle in das Telefonbuch-Plugin einbauen, die das Telefonbuch als html-Tabelle zurückgibt, die sich ggfs. in ein anderes Plugin einbetten ließe?

              Der Zugriff auf die Daten geschieht ueber die Methode
              'db_query'. Der wird als Parameter die Query als String
              uebergeben und dazu, optional, der Datenbank-Name. Wird kein
              Datenbanks-Name uebergeben, so wird die Default-Datenbank
              genommen. Jede Datenbank muss vorher in der
              Konfigurations-Datei dem System bekannt gemacht werden.
              Besteht eine Verbindung zu dem Datenbank-Server, so wird (bei
              Bedarf) nur die Datenbank gewechselt und dann die Query
              ausgefuehrt. Besteht keine Verbindung, so wird eine neue
              Verbindung aufgebaut und dann die Query abgesetzt. Die
              Rueckgabe ist eine DBResult-Klasse. Doch zu der spaeter.

              Ich plane hierfür die PEAR::DB Klasse zu verwenden. Das solte mir doch genügend Möglichkeiten geben, oder?

              Najut. Der Zugriff auf die Kern-Daten. Was genau muessen wir
              ueber den User wissen? Eigentlich nur den Usernamen und
              vielleicht noch die Sprache. Ach ja, die User-ID waere noch
              ganz angenehm. Dazu noch, welche Rechte der User hat... gut,
              also gibt es eine Methode 'user_infos', die einen Array
              zurueck gibt, dessen erstes Argument die User-ID ist und
              dessen zweites Argument der Username ist. Die Sprache kann
              ueber die Methode 'lang' abgefragt werden. Die Rueckgabe ist
              die aktuelle User-Sprache.

              Ich habe zur Zeit keine UserIDs. Wollte ich erst, aber das wäre dann wieder ein Join mehr geworden und ich hatte meist schon genug. Also Basis für meine userdaten habe ich die htpasswrd Datei, in der nur unique-User stehen dürfen. Die User stehen auch alle in einer Tabelle Users, da stehn dann  mehr Daten, da ich für Mails... auch deren Tel, email, Position, vollst. Namen... brauche. Und da steht auch die Hierarchie-Ebene und Sprache. Ich mache das so da ich keine Sessions verwende. Mit Session wäre das ganze vielleicht anders besser zu lösen, aber so will ich pro Seite möglichst wenig neu Abfragen, wobei, langsam werden es immer mehr Daten, vielleicht böte sich hier doch langsam ein Session-Mechanismus zum Speichern der Daten an.

              Mit dem oben abgebildeten Konzept sollte man eigentlich so
              ziemlich alles abbilden und einbauen koennen. Mir ist kein
              Fall eingefallen, der nicht moeglich ist. Jedes Plugin hat
              seinen eigenen Namespace und jedes Plugin hat seinen eigenen
              Tablespace. Kollisionen sind also nicht unmoeglich, aber sehr
              unwahrscheinlich.

              Das ist für die Anforderungen und vor allem für meien aktuellen Kenntnisstand noch etwas zu hoch ;-) Verstehe das zwar grob, könnte es aber so ohne weiteres nicht umsetzen. Ein paar Ideen konnte ich aber gewinnen, und spätestens bei meinem nächten Projekt werde ich das Posting noch(ein paar) mal lesen und dann vielleicht noch mehr davon einbringen können. Ich brauche einfach keine so ausgereifte Möglichkeit, es sollen wie gesagt nur 3 oder 4 von mir programmierte Plugins nachträglich eingebaut werden können, wenn ich Schnittstellen dazwischen brauche schreibe ich mir hierfür eine eigene Klasse und es sollte erstmal reichen.

              Jetzt faellt mir aber auch nicht mehr viel ein.

              Vielen, vielen Dank, hast mir sehr geholfen!

              Viele Grüße
              Andreas

              1. Hallo Andreas,

                alter Angeber, mit welchem Hintertürchen kannst Du bitte
                15 KB posten???

                vi fo_post.conf... ;)

                Unverschämtheit, und unsereins darf seinen Beitrag ggfs.
                bis zur Unkenntlichkeit verstümmeln ;-)

                Das sind die Vorrechte des Administrators *fg*

                Ja, allerdings eine relativ primitive. Damit forderst du
                Inkonsistenzen geradezu heraus.
                wo denn? Meinst Du dass jedes Modul seine eigenen
                Funktionen... haben soll?

                Nein, ich meine, was ist, wenn irgendwann mal die Struktur
                aenderst? Oder wenn du den Array-namen aenderst? Oder
                sonstwas? Wuerdest du das abstrahieren, sprich, Methoden
                definieren, die aufgerufen werden, koenntest du deren
                Rueckgabe evntl. transformieren. So muesstest du jedes Plugin
                umschreiben.

                Aber das mache ich gerade _weil_ in absehbarer Zeit
                niemals jemand anderer als ich ein Modul hierfür schreiben
                wird.

                Das kannst du nie wissen. *Jedes* Code-Stueck, und sei es
                noch so sehr dahingerotzt, kann an beliebiger Stelle wieder
                auftauchen.

                Nur brauche ich im Prinzip das genaue Gegenteil, hier kann
                ich mehrere Variablen definieren, mit dem glichen Inhalt,
                und dafür bräuchte ich nichtmal Referenzen, aber ich
                brauche irgendwie eine Variable mit verschiedenem Inhalt
                je nach Modul.

                *seufz*
                $funcname       = $modul."_menu_hook";
                $menu_entries[] = $funcname($arg1,$arg2);

                Und einen Rückgabewert, ob Klasse oder nicht, ich kann
                definitiv keien Funktion in das Modul schreiben,

                Natuerlich kannst du.
                $classname = $modul."Class";
                $obj &= new $classname($arg1,$arg2);
                $menu_entries[] = $obj->menu_hook();

                Und warum soll ich das als Funktion speichern?

                Damit du dort ausfuehrbaren Code hast.
                vermutlich sind includes auch nicht so viel schneller als
                ein fopen, und das parsen von ein paar Zeilen, nur damit
                hätte ich direkt _alle_ Werte in einer saubereren Struktur
                als Funktionen mit zusammengesetzten Namen.

                Hae? Du muesstest schon eine Script-Sprache nachbauen, wenn
                du das erreichen willst, was mir vorschwebt (bedingtes ein-
                und ausblenden von Teil-Menues, highlighten von
                Menue-Eintraegen, etc, pp).

                Ich würde ja evtl. das ganze bei jeder Änderung als
                ausführbaren Array hardcoden, aber da bist Du ja dagegen.
                Wobei man IMHO fast genauso leicht einen Array auch
                manuell verändern kann, wie eine csv-Datei!?

                Hae?

                menu[]=array(menü-struktur...);

                Klar, koenntest du machen. Damit machst du dich aber
                von dem Array abhaengig. Was ist, wenn du den mal
                umbenennst? Ausserdem widerspricht es dem Prinzip der
                Datentrennung. Ein externes Code-Stueck hat an internen
                Variablen einfach nix zu suchen, basta.
                Aber ist das denn mit Funktionen so viel anders?

                Da *verarbeitest* du Rueckgabewerte. Das ist eine
                Schnittstellen-Definition, du hast einen definierten
                Rueckgabewert, das wird sich nicht aendern. Aber wie du das
                intern weiterverwertest, ist voellig schnuppe.

                Da bin ich auch davon abhängig das ich die Funktion oder
                die Zusammensetzen dessen Namen nicht ändere.

                Warum?

                Was hälst Du von der Funktion parse_ini_file() für sowas?

                Nichts. Zu inflexibel.

                Ansichtssache. Ich halte das fuer zu inflexibel. Ich
                moechte meine Menues dynamisch aendern, abhaengig vom
                Programm-Ablauf.
                reicht es da nicht einen kompletten Array zu haben und
                ggfs. nur einen Teil dessen auszugeben?

                Dazu muss die Ausgabe-Routine aber von den Stati des Plugin
                wissen. Und das tut sie nicht (oder sollte sie zumindest
                nicht, dann ist sie nicht mehr modular). Nein, welcher Teil
                des Menues von der Ausgabe-Routine benutzt wird, sollte
                schon das Plugin entscheiden.

                Sollte man denn das Modul Kontaktformular so frei machen
                könnten, das man die Navigation... selbst einbinden kann?
                Ich binde eigentlich immer 4 Dateien ein:

                1. global.inc (PHP-Funktionen...)
                2. header.inc
                3. footer.inc
                4. menu.inc

                Könnte man dei Struktur nicht auch noch aulagern, so dass
                man wirklich  als Template nur noch mit dem wirklichen
                body des Dokuments zu tun hat, und keine includes?

                Hae?

                LOAD usermanagement.inc.php:UserManagement
                Was ist das für eine Syntax? Oder parst Du das noch selbst?

                Sicher.

                Du hast eine Basis-Klasse, nennen wir sie mal
                'KorthausPlugin'. Die definiert verschiedene Methoden,
                unter anderem z. B. die Methode 'menu_hook'.
                Rueckgabewert und Parameter sind definiert. Nun gehst
                du, wenn du das Menue generierst, alle in der
                Konfigurations-Datei angegebenen Plugins durch,
                instanzierst sie und rufst dann die Methode menu_hook
                auf. Aus den so gewonnen Funktionen kannst du dann

                Hier muss 'Informationen' statt 'Funktionen' hin.

                Problemlos das Menue generieren.
                Da kann ich Dir leider nicht folgen. OK, in der conf-File
                stehen die Module. Nur wie komme ich dann an die Werte?

                Indem du die Callback-Routinen aufrufst. Die Rueckgabe sind
                dann die benoetigten Werte.

                So wie ich das verstanden  habe hat jedes Modul eine
                Funktion menu, das bekomme ich nur durch include, also
                müßte ich hier wieder zusammengesetze Funktionsnamen haben

                • setzt Du das hier voraus?

                Es muss keine Funktion sein. Es kann eine Methode sein.

                Referenzen worauf?
                Auf Funktionen.
                das geht doch? Aber was bringts? Sobald ich mehr als 1
                Funktion mit demselben Namen einfüge, per include, ist
                Ende!

                Was hat das eine mit dem anderen zu tun?
                Deshalb bin ich btw. bei sowas dafuer, Plugins als Klassen
                zu implementieren. Dann hat man die Probleme der Namensgebung
                nur bedingt.

                also muss noch eine Aufgabe in
                das Rahmenwerk: der Zugriff auf die Kern-Daten muss
                abstrahiert werden.
                was heißt das praktisch? Zugriff auf die Kerndaten über
                eine Klasse oder was?

                Ja. Ueber definierte Methoden.

                Beispiel: ein
                Webmail-Tool koennte mit dem Adressbuch-Tool arbeiten,
                um E-Mail-Adressen herauszusuchen.
                Aber wieso muß ich hier auf Routinen(Funktionen) des
                anderen Moduls zurückgreifen?

                Warum sollte ich etwas doppelt implementieren? Meide
                Redundanzen!

                Ich prüfe ob das Modul vrohanden ist und greife dann
                direkt auf die DB zu! Obwohl, was wenn sich die Tabele da
                ändert... also brauche ich speziell hierfür eine eigene
                Klasse die den Zugriff auf die Adressdaten regelt, oder
                wie würdest Du das jetzt machen?

                Du benutzt das Plugin 'Adressbuch', um an die Daten zu
                kommen.

                Was ist aber, wenn ein Plugin Eingabedaten vom User
                braucht? Prinzipiell muesste also ein Plugin, dass mit
                einem anderen kommuniziert, die GUIs des anderen
                nachbauen. Das ist aber nicht sinnvoll, also muss es
                eine Moeglichkeit geben, die Kontrolle ueber mehrere
                Requests hinweg an ein Plugin zu geben. Nach den
                Ablaeufen muss die Kontrolle wieder zurueck gegeben
                werden an das 'alte' Plugin.
                Das kommt ja nicht oft vor. Wenn das vorkommt, könnte man
                da nicht eine extra Schnittstelle in das
                Telefonbuch-Plugin einbauen, die das Telefonbuch als
                html-Tabelle zurückgibt, die sich ggfs. in ein anderes
                Plugin einbetten ließe?

                Warum zum Teufel willst du Sachen zweimal implementieren?

                Der Zugriff auf die Daten geschieht ueber die Methode
                'db_query'. Der wird als Parameter die Query als String
                uebergeben und dazu, optional, der Datenbank-Name. Wird
                kein Datenbanks-Name uebergeben, so wird die
                Default-Datenbank genommen. Jede Datenbank muss vorher
                in der Konfigurations-Datei dem System bekannt gemacht
                werden. Besteht eine Verbindung zu dem
                Datenbank-Server, so wird (bei Bedarf) nur die
                Datenbank gewechselt und dann die Query ausgefuehrt.
                Besteht keine Verbindung, so wird eine neue Verbindung
                aufgebaut und dann die Query abgesetzt. Die
                Rueckgabe ist eine DBResult-Klasse. Doch zu der spaeter.
                Ich plane hierfür die PEAR::DB Klasse zu verwenden. Das
                solte mir doch genügend Möglichkeiten geben, oder?

                PEAR::DB ist maechtig, aber teilweise ziemlich idiotisch
                umgesetzt. Deshalb habe ich mich dagegen entschieden.

                Gruesse,
                 CK

                1. Hallo Christian!

                  vi fo_post.conf... ;)

                  Bekomme ich wenn ich den PRO-Account buche auch einen Shell-Zugang? ;-)

                  Das sind die Vorrechte des Administrators *fg*

                  sei Dir zugestanden ;-) Ich dacht Du hättest einen extra Parameter ?sonderrechte=ck einmgebaut ;-)

                  Nein, ich meine, was ist, wenn irgendwann mal die Struktur
                  aenderst? Oder wenn du den Array-namen aenderst? Oder
                  sonstwas? Wuerdest du das abstrahieren, sprich, Methoden
                  definieren, die aufgerufen werden, koenntest du deren
                  Rueckgabe evntl. transformieren. So muesstest du jedes Plugin
                  umschreiben.

                  stimmt. Das ist der Vorteil der OOP. Aber ich habe leider (*schäm*) immer noch Schrierigkeiten mir das hier vorzustellen. Das ist auch das Problem, zumindest ich rede teilweise an Dir vorbei, da mir vermutlich eine gedankliche Abstarktionsebene oder sowas fehlt. Kommt vermutlich auch daher das ich noch sehr unerfahren in OOP bin.
                  Also mal bei 0 angefangen:
                  ich habe eine Klasse, meinetwegen "basis" die, hier erstelle ich eine Instanz am Anfang. In der Klasse sind die ganzen Grundlagen enthalten.  D.h. die KLasse basis hat eigenschaften wie "root_path", "root_url", Mothoden wie "get_menu", "get_header"... die ich dann feriges HTML zurückgeben, um das überall einbauen zu können. Für das Menü gibt es eine eigene Klasse "menu". Diese hat für jeden Menüpunkt eine Instanz. Die einzelnen Instanzen werden beim Starten der Klasse erstellt, die hierfür notwendigen Angaben werded aus der zentralen menu_conf.inc geparst.
                  Die einzelnen Plugins wüßte ich beim besten Willen nicht wie ich die als Klassen einbinden soll. Ich würde jetzt für ein Modul ein einfaches Script schreiben, welches "get_header", "get_menu"... einbindet, udn für sich sonst ein eigenes PHP-Script ist. Aus der basisklasse können darüberhinaus angaben wir root_path... entnommen werden, der Datenbank-Zugriff erfolgt über PEAR. Wobei, ich glaube hierfür schreibe ich auch eine eigenes Modul, welches von mir aus PEAR benutzt, aber wenn ich direkt auf PEAR zugreife werde ich zwar unabhängig von der DMS, aber ich bin immer noch an genaue Spaltenangaben... gebunden. Wenn ich das jetzt noch abstrahiere, also nur auf eine Methode in der DB-Klase zugreife, kann ich ja an Stadt "SELECT telefon..." einfach "client_data->telefon" oder sowas schreiben. Wenn sich jetzt die Tabelle verändert kann kann ich das in der Klasse direkt für alle Plugins gleichzeitig ändern. Mehr fällt mir jetzt zum Thema OOP hier nicht ein.

                  *seufz*

                  tut mit Leid!

                  $funcname       = $modul."_menu_hook";
                  $menu_entries[] = $funcname($arg1,$arg2);

                  OK. Also kann man das ruhig so machen.

                  Und einen Rückgabewert, ob Klasse oder nicht, ich kann
                  definitiv keien Funktion in das Modul schreiben,

                  Natuerlich kannst du.
                  $classname = $modul."Class";
                  $obj &= new $classname($arg1,$arg2);
                  $menu_entries[] = $obj->menu_hook();

                  OK. Also das Modul als Klasse, so würde es gehen. Und was sind da dann für Methoden udn Eigenschaften drin, außer dem Menü-Array? Auch die HTML-Ausgabe betreffend? Steht das _ganze_ Modul in der Klasse? Also auch die Funktionen, die ich mit dieser Klasse implementieren will?
                  Dann würde ich aber, so wie ich das jetzt verstehe, immer _alle_ Module laden, ob ich es jetzt brauche oder nicht, oder? Aber wenn das Modul in der Klasse steht, und ich diese Klasse mit include einbinde, gibt es dann überhaupt eine extra PHP-Datei auf der Menüeintrag verlinkt, oder mache ich die komplette Ausgabe in einem Sript? Also mit Parametern?
                  Ich bräuchte also auf alle Fälle

                  $modul_list = file("modul_list.conf");
                  foreach($modul_list AS $modul) {
                      $classname = trim($modul)."Class";
                      $obj &= new $classname($arg1,$arg2);
                      $menu_entries[] = $obj->menu_hook();
                  }
                  und das immer wenn ein neues Script gestartet wird, korrekt?

                  Sollte man denn das Modul Kontaktformular so frei machen
                  könnten, das man die Navigation... selbst einbinden kann?
                  Ich binde eigentlich immer 4 Dateien ein:

                  1. global.inc (PHP-Funktionen...)
                  2. header.inc
                  3. footer.inc
                  4. menu.inc

                  Könnte man dei Struktur nicht auch noch aulagern, so dass
                  man wirklich  als Template nur noch mit dem wirklichen
                  body des Dokuments zu tun hat, und keine includes?

                  Hae?

                  Ich frage mich halt gerade, wie die Ausgabe geschiehen soll. Bisher hatte ich z.B. das Modul "Fragebogengenerator". dies besteht im Prinzip aus einem PHP-Script welches die oberen 4 Dateien einbindet, um eine den anderen Scripten entsprechnde Ausgabe/Design zu erzeugen.  Nach dem Header un vor dem Footer steht eine HTML-Tabelle in die ich schreiben kann was ich will. Da schreibe ich dann z.B. die Eingabefelder für den Generator hinein. Muß natürlich extra bestimmte Elemente mit bestimmten CSS-Klassen versehen. Das ganez hat jetz nichts mit Klassen zu tun, und ich wüßte auch nicht was eine Klasse hier hhelfen könte, außer vielleicht die Meta-Daten wie Menü-Eintrag für die Menüleisten-Klasse zugreifbar zu machen. Was sollte sonst noch in eine Klasse? Wenn ich das Formular mit den Änderungen abschicke, dann wird es an sich selbst geschickt, udn per IF wird geprüft, ob per POST die entsprechenden Parameter übermittelt werden und dem entsprechend Einträge in die DB gemacht. OK, diese Aktionen könnte ich auch in eine Klasse auslagern, müßte dann aber immer noch "manuelle" mit IF am Anfang prüfen was jetzt gemacht weden soll, ob einfach das leere Formular ausgegeben werden soll, oder ob die Methode der Klasse ausgeführt werden soll.

                  Es muss keine Funktion sein. Es kann eine Methode sein.

                  Das verlagert das Problem nur auf den Klassennamen. Aber ich hab es jetzt glaube ich verstanden.

                  das geht doch? Aber was bringts? Sobald ich mehr als 1
                  Funktion mit demselben Namen einfüge, per include, ist
                  Ende!

                  Was hat das eine mit dem anderen zu tun?

                  ich brauche je eine Funktion in dem Modul, udn damit die ausgefüßhrt wird muß ich die Datei mit include einbinden - was willst Du mehr?

                  Deshalb bin ich btw. bei sowas dafuer, Plugins als Klassen
                  zu implementieren. Dann hat man die Probleme der Namensgebung
                  nur bedingt.

                  Wie gesagt hat man dasselbe Problem, halt nur mit den Klassennamen. Das übergehe ich aber dann mit den variablen Namen wie oben.

                  Warum sollte ich etwas doppelt implementieren? Meide
                  Redundanzen!

                  Aber manchmal sind ist es erheblich einfach 2-3 Redundanzen in Kauf zu nehmen. Gerade auf meinem Kenntnisstand!

                  Ich prüfe ob das Modul vrohanden ist und greife dann
                  direkt auf die DB zu! Obwohl, was wenn sich die Tabele da
                  ändert... also brauche ich speziell hierfür eine eigene
                  Klasse die den Zugriff auf die Adressdaten regelt, oder
                  wie würdest Du das jetzt machen?

                  Du benutzt das Plugin 'Adressbuch', um an die Daten zu
                  kommen.

                  Das könnte ich mir durchaus vorstellen. Also mit einer Methode die direkt html zurückgibt, oder an welcher Stelle sollte man html erzeugen?

                  PEAR::DB ist maechtig, aber teilweise ziemlich idiotisch
                  umgesetzt. Deshalb habe ich mich dagegen entschieden.

                  Aber besser als sich auf mysql festzulegen, bei so gut wie 0 Mehraufwand!

                  Grüße
                  Andreas

      2. Moin!

        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.

        Schnittstellen sind so häufig, dass du gar nicht merkst, dass du sie benutzt. Die Parameter einer Funktion bilden eine Schnittstelle. Denn es ist durch die Funktion fest definiert, a) in welcher Reihenfolge b) welche Daten kommen müssen, und ob c) einige optional sind bzw. d) Default-Werte haben. Ebenso ist e) definiert, welches Format das Funktionsergebnis hat.

        Diese für Funktionen gültige Aufzählung a) bis e) kannst du natürlich auch auf Datenbanken übertragen:
        a) Die Reihenfolge spielt keine Rolle, aber du mußt wissen, welche Spalten du beschreiben oder lesen willst.
        b) Das Datenformat (String, INT, ENUM) muß natürlich bekannt sein.
        c) Du könntest einige Werte freilassen wollen, weil der Benutzer sie nicht angegeben hat.
        d) Diese Werte können einen Default-Wert haben.
        e) Ähm - die Datenbank hat natürlich auch ein Funktionsergebnis: Die Erfolgsmeldung - oder die Fehlermeldung. :)

        Du siehst also: Die gesamte Computerwelt besteht fast nur aus Schnittstellen, weil sich fast alles mit Funktionen erledigen läßt. Wenn du deine eigenen Funktionen definierst, definierst du deine eigenen Schnittstellen. Diese Schnittstellen _sinnvoll_ zu definieren ist nicht so leicht. Wenn man "mal eben" eine Funktion erstellt, dann tut die wahrscheinlich, was man von ihr will. Aber bestünde nicht die Möglichkeit, dass man noch andere Dinge von der Funktion will? Die Wiederverwendbarkeit der Funktion ist besser, wenn sie eine geeignete Schnittstelle besitzt.

        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.

        Ich weiß nicht, was du programmieren willst. Insofern ist es schwierig, da irgendwas konkret zu sagen. Aber eines stimmt: Die einzelnen Module selbst haben mit anderen Modulen nicht zu kommunizieren, sondern nur mit dem Basismodul. Bzw. genauer gesagt: Mit ihrem Elternmodul. Denn es ist ja durchaus denkbar, dass du ein Ausgabemodul geschrieben hast, welches allgemein gehalten ist. Dieses Ausgabemodul kriegt jetzt Untermodule, die die Ausgabe als HTML, XHTML, LaTeX, PDF, GIF, ASCII etc. auf Bildschirm, Festplatte, Papier usw. erledigen können. Das Basismodul sorgt dafür, dass das Ausgabemodul die auszugebenden Daten kriegt. Das Ausgabemodul verwaltet die vorhandenen Submodule und reicht die Daten an das passende Modul weiter.

        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 ;-)

        Definitiv. PEAR soll ja ganz nett sein - ich hab mich damit aber noch nie beschäftigt. Es ist jedenfalls eine _sehr gute_ Idee, wenn man schon modular arbeitet, dann die Datenbank-I/O auch über ein Modul regeln zu lassen. Dadurch bist du wesentlich freier in deiner Gestaltung. Auch wenn es derzeit nur ein MySQL-Modul geben wird, kannst du dennoch _im Prinzip_ jede andere Datenbank auch anbinden. Und die muß nicht mal eine echte Datenbank sein, denn solange du irgendwo speichern und lesen kannst und die Daten wiederfindest, würden auch Text- oder XML-Dateien funktionieren, um nur ein Beispiel zu nennen.

        Und das würde sich dann sogar ganz gut machen, denn wenn du sowohl ein MySQL-Modul als auch ein XML-Modul geschrieben hast, kannst du deine MySQL-Datenbank mit einem Export-Modul einfach aus MySQL auslesen und in XML reinschreiben und hast so eine nette Export-Funktion. Auf einem anderen Server hast du vielleicht kein MySQL, sondern PostgreSQL, aber natürlich auch XML, und kannst so den Datenimport regeln. :)

        Das schreibt und liest sich jetzt natürlich recht leicht - die zentrale Frage dabei ist immer: Wo docken die Module an? Im obigen Beispiel wäre es z.B. sinnvoll, wenn das MySQL- und das XML-Modul an einem DB-I/O-Modul andocken. Dort könnten dann auch die Funktionsmodule "Export" und "Import" andocken. Oder aber es dockt ein Modul "Kopieren" am zentralen Modul an und liest über den Weg I/O->MySQL Daten ein und schreibt sie über I/O->XML wieder weg. Die Frage ist dabei natürlich, wie man sowas geregelt kriegt. Wie meldet das I/O-Modul, dass es sowohl XML als auch MySQL anbieten kann? Und wie entscheidet das Kopier-Modul, von wo nach wo es kopieren will? Konkrete Aussagen gibts ohne konkrete Aufgaben nicht.

        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.

        Meine Vorstellung ist, dass es einen gewissen Installationsvorgang für jedes Modul geben sollte, der das Modul im System bekannt macht. Entweder einmal statisch beim wirklichen Hinzufügen des Moduls, oder immer wieder dynamisch beim Benutzen des Moduls. Die erste Methode würde z.B. darin bestehen, in einer zentralen Datei eine Zeile hinzuzufügen, die das Modul anmeldet. Die zweite Methode wäre dagegen zwar performance-fressender, aber immer auf dem aktuellen Stand, was die Module angeht.

        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?

        Entweder bindest du immer alle vorhandenen installierten Module ein, und bei der Einbindung liefern diese Module durch eine Installationsfunktion die notwendigen Angaben für die zentrale Registrierung, oder bei der Installation der Module wird eine zentrale Datei entsprechend erweitert, in die das Modul und alle dazugehörigen, allgemeinen Daten (wie z.B. Menüeinträge) gespeichert werden. Oder jedes Modul besitzt eine Funktion, welche z.B. die Menüeinträge zurückliefert.

        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?

        Nein, warum? Auch dynamische Seiten können damit arbeiten. Notfalls greift ein globales URL-Mapping mit mod_rewrite, welches den Sprachbestandteil der URL als Parameter ummodelt.

        Ich weiß nicht, was hier die ideale[tm] Lösung für URLs ist. Die Sprachinformation kann dort hineingehören - sie muss es aber auch nicht, denn nicht zuletzt in HTML gibt es das lang-Attribut. Nur bringt das wohl nicht unbedingt den gewünschten Effekt.

        Verläßt man sich hingegen ganz auf die Apache-Content-Negotiation, kann man als Besucher die Sprache nicht mehr wechseln. Es gibt deswegen nur zwei praktikable Methoden, die Information der gewünschten Sprache sicher zu übermitteln: Entweder als Teil der URL (im Pfad oder als Parameter), oder in Sessions bzw. Cookies (was prinzipiell das Gleiche ist - und schlecht obendrein).

        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.

        Wenn du die gewünschte Sprache speicherst, musst du diese Information entweder bei jeder Seitenanforderung wieder nachgucken, oder sie beim Request mitschicken. Wenn du sie mitschickst, kann das wie oben geschildert in der URL geschehen. Mit dem Vorteil, dass der Benutzer schnell mal wechseln kann, und nicht seine Benutzereinstellungen aufsuchen muß.

        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?

        Ich muß ehrlich sagen: Dein Projekt ist nach meinem Eindruck noch weit davon entfernt, auch nur in irgendeiner Weise modular zu sein. Da du es allerdings auch nicht näher erläutert hast, könnte dieser Eindruck daran liegen, dass das Projekt sich nicht unbedingt für den modularen Aufbau eignet.

        - Sven Rautenberg

        --
        Diese Signatur gilt nur am Freitag.
        1. Hallo Sven!

          Ich weiß nicht, was du programmieren willst. Insofern ist es schwierig, da irgendwas konkret zu sagen. Aber eines stimmt: Die einzelnen Module selbst haben mit anderen Modulen nicht zu kommunizieren, sondern nur mit dem Basismodul. Bzw. genauer gesagt: Mit ihrem Elternmodul. Denn es ist ja durchaus denkbar, dass du ein Ausgabemodul geschrieben hast, welches allgemein gehalten ist. Dieses Ausgabemodul kriegt jetzt Untermodule, die die Ausgabe als HTML, XHTML, LaTeX, PDF, GIF, ASCII etc. auf Bildschirm, Festplatte, Papier usw. erledigen können. Das Basismodul sorgt dafür, dass das Ausgabemodul die auszugebenden Daten kriegt. Das Ausgabemodul verwaltet die vorhandenen Submodule und reicht die Daten an das passende Modul weiter.

          Leider kann ich mir auch überhaupt nicht vorstellen, wei eien Modul eine Ausgabe erledigen soll! So soll z.B eine Tabelle mit Lieferanten angezeit werden. Was genau für so een HTML-Ausgabemodul jetzt machen und welche Daten müßte man dem übergeben? Die Datenquelle ist eine Datenbank. Die erste Frage, wie wird die Ausgabe überhaupt ausgelöst? Ich sage mal ich habe eine Startseite, mit einem Link auf "Lieferantenübersicht". Wenn man auf den Link klickt soll sich eien neue Seite im selben Layout öffnen, mit der Überschrift "Lieferantenübersicht" und einer HTML-Tabelle mit allen Lieferanten alphabetisch sortiert und mit je einem Link versehen um Details zu erfahren.
          Wieder von vorne angefangen: Was löst der 1. Link aus? Bei mir jetzt öffnet er eine neue Datei, "lieferanten_uebersicht.php" und in dieser Datei steht halt fest drin, das er die Daten wie oben beschreiben ausgeben soll. Wie würde das jetzt theoretisch mit Modulen aussehen?
          3 Module würden mir hier einfallen:

          1. DB-Modul
          2. HTML-Ausgabe-Modul
          3: Lieferantenübersichts-Modul.

          die wenigsten Probleme habe ich mit DB-Modul, das habe ich eine schöne Klasse und kann von überall hierüber auf die Datenbank zugreifen, welche auch immer dahinter steht. Schwieriger wird es mit der Ausgabe-Modul, wie soll das funktionieren? Und wie greife ich auf das Modul zu? Also mache ich den ersten Link wieder auf eine extra Seite lieferanten_ueberesicht.php, nur das ich hier nicht HTML hinschreibe und direkt auf mysql zugreife, sondern die entsprechnenden Daten über das DB-Modul aus der DB hole, und mit dem Ausgabe-Modul die Ausgabe erzeuge, nur wie? Sagen wir mal das Ausgabe-Modul ist eine Klasse, was sollte die dann können?  Also eine Methode "write_header", "write_footer", "write_navigation", und dann "write_headline('Lieferantenübersicht')", und wie gebe ich die Tabelle und anderen Text aus? Soll ich alle Daten die ich in der Tabelel ausgeben will aus der DB-Klasse als Array ausgeben, und diesen Array dann an die Ausgabe-Klasse übergeben, nur was nehme ich dann für Überschriften? Die originalen Datenbank-Spaltennamen sind nicht immer so der Hit, und bestimmte Zahlen wie Preise würde ich auch gerne vorher noch formatieren! Wie sollte man das machen? Vor allem, wenn ich den Inhalt der Seite vielleicht etwas strukturiert z.B. in einer verschachtelten Tabele augeben möcte, wie bilde ich das mit so einer Ausgabe-Klasse ab?
          Und das 3. Modul, das "Lieferantenübersichts-Modul" _selbst_ eine Klasse sein soll, wie ich das mit CK überlegt habe, dann ist mein Verständnis diesbezüglich wieder fast = 0. Das hat zwar seinen Sinn, so dass z.B. ein Menü-Eintrag erfolgt, oder ich global im Projekt eine Lieferanten-Liste über eine Methode bereitstellen kann, aber wie soll dann die Ausgabe funktionieren? Wohon führt der 1. Link von der Startseite? Wenn lieferanten_uebersicht.php jetzt nur noch eine Klasse enthält, an welcher Stelle steht dann das was beim Klick auf dem Link passieren soll, also die Ausgabe der Lieferantentabelle, wo wird die initiiert?
          Sorry das ich mich vermutlich selten dämlich anstelle, ich komme mir selbst zielmich bescheuert vor, aber ich _VERSTEHE_ es zum verrecken nicht.

          Und das würde sich dann sogar ganz gut machen, denn wenn du sowohl ein MySQL-Modul als auch ein XML-Modul geschrieben hast, kannst du deine MySQL-Datenbank mit einem Export-Modul einfach aus MySQL auslesen und in XML reinschreiben und hast so eine nette Export-Funktion. Auf einem anderen Server hast du vielleicht kein MySQL, sondern PostgreSQL, aber natürlich auch XML, und kannst so den Datenimport regeln. :)

          Interessante Variante, werde ich auf alle Fälle versuchen!

          Das schreibt und liest sich jetzt natürlich recht leicht - die zentrale Frage dabei ist immer: Wo docken die Module an?

          Ah, ja, die Frage stellt sich mir erst recht ;-)

          Im obigen Beispiel wäre es z.B. sinnvoll, wenn das MySQL- und das XML-Modul an einem DB-I/O-Modul andocken. Dort könnten dann auch die Funktionsmodule "Export" und "Import" andocken.

          Das mit der Datenbank habe ich inzwiwchen so mehr oder weniger verstanden, da bekomme ich das schon hin. Probleme bereitet mir vor allem die Ausgabe, und auch das Basismodul weiß ich nicht so Recht was das soll. Und auch die Module für Zusatzfunktionen wie den "Fragebogengenerator" weiß ich nict so recht. Was ich weiß ist inzwischen das ich hierfür eine Extra-Klasse verwende, die z.B. Methoden enthält um die komplette Menü-Struktur zu ermitteln, oder die Rechte festzulesgen. Aber mir fehlt noch eine Idee dafür, wie ich die eigentliche Funktionalität einbinde, also wie ich es machen soll, dass halt beim Klicken auf einen entsprechenden Menü-Eintrag auch eine HTML-Seite ausgegeben wird, das Aktionen ausgeführt werden können, das geht IMHO nicht mit der einen einzigen Klasse, oder? Oder wenn ich Aktionen ausführe, dann  muß ich ja auf GET/POST Parameter reagieren, wo mache ich das dann genau?

          Nein, warum? Auch dynamische Seiten können damit arbeiten. Notfalls greift ein globales URL-Mapping mit mod_rewrite, welches den Sprachbestandteil der URL als Parameter ummodelt.

          Eigentlich ziemlich schlau, dann bräuchte ich eigentlich doch keine Session!

          Es gibt deswegen nur zwei praktikable Methoden, die Information der gewünschten Sprache sicher zu übermitteln: Entweder als Teil der URL (im Pfad oder als Parameter), oder in Sessions bzw. Cookies (was prinzipiell das Gleiche ist - und schlecht obendrein).

          Was ist schlecht an Sessions? Bisher bräuchte ich sie nicht, hätte aber den Vorteil, das ich ganze Objekte in der Session speichern kann, so könnte ich z.B. Basisdaten wie root_path, menu_array... die ich alle immer wieder neu aus verschiedenen Dateien generieren müßte, bei jedem Seitenaufruf, könnte die dann in einem Objekt in der Session speichern und müßte das ganze nur einmal ermitteln. Wobei, ob der Server jetzt eine Session-Datei öffnet oder ich eine andere ist ja auch fast egal, oder?

          Ich muß ehrlich sagen: Dein Projekt ist nach meinem Eindruck noch weit davon entfernt, auch nur in irgendeiner Weise modular zu sein.

          Ja das ist es auch, aber vor allem durch meine Verständnisschwierigkeiten. Ich danke Euch wirklich sehr für Eure Beiträge und Ihr habt mir auch sehr geholfen, aber Ihr werdet gerne immer ziemlich abstrakt, und da fällt es mir dann manchmal durchaus schwer das ganze noch nachzuvollziehen, das gilt vor allem für CK(nicht böse gemeint ;-)). Leider bin ich kein Informatiker wodurch mir vermutlich einige Grundlagen fehlen, ich habe vor gut einem Jahr mit PHP angefangen, davor konnte ich nur Frontpage, nichtmal Basic oder VBA-Makros! Daher kann ich Euch auch verstehen wenn Ihr glaubt ich sei ein bisschen dämlich ;-)

          Da du es allerdings auch nicht näher erläutert hast, könnte dieser Eindruck daran liegen, dass das Projekt sich nicht unbedingt für den modularen Aufbau eignet.

          Das kommt drauf an was man unter modularem Aufbau versteht. Es soll keine Gorupware werden, die 100% modular aufgebaut sein muß, sondern es soll nur die Möglichkeit bestehen, 1-3 Erweiterungen einfach nachzuinstallieren oder zu entfernen. Es geht um eine Software im Bereich e-procurement, kein tolles e-comerce tool, sondern eine schlanke, auf speziellen Vorgaben programmierte Lösung. Es soll eine Basisversion geben, die nur eine Lieferantenverwaltung und ein ganz einfaches Ausschreibungs-tool enthält, dann soll das ganze aber auch erweitert werden können, zum einen um ein Tool für komplexere Ausschreibungen, und/oder eine Lieferantenqualifizierung, wofür man einen eigenen Fragebogen generieren kann, den Lieferanten ausfüllen sollen. Das wars eigentlich. Mein Problem war es jetzt, das Basisprogramm schon so zu programieren, dass ich die Erweiterungen mölichst einfach einfügen kann. Ob man das jetzt "module" nennt, oder "plugins" oder nur "Erweiterungen", das weiß ich nicht. Jedenfalls brauche ich keine so abstrakten Plugins, im Prinzip reicht mir ein variables Menü, die restlichen Zugriffe kann ich auch so einprogrammieren, und ja dann habe ich Redundanzen, und ja, dann muß ich die 2 Module ggfs. ändern wenn ich an der Basis oder Datenstruktur was ändert, na und? Das ist erheblich weniger Aufwand als die komplette Software-Struktur so radikal zu verändern. Die Diskussion ist eigentlich weit über das was ich für dieses Projekt wissen wollte hinaus gegangen, aber auch gerade weil es mich trotzdem sehr interessiert. Ob ich das jetzt hier verwende oder nicht weiß ich nicht, aber ich würde es sehr gerne langsam mal verstehen, so dass ich es wenigesten in Zukunft mal einsetzen kann ;-)

          Viele Grüße
          Andreas

          PS: Mozilla ist _G_E_N_I_A_L_ !!! Ich wollte gerade meinen PC aus dem Fenster werfen, nachdem ich diesen Beitrag eben in die die Zwischenablage kopieren wollte, binn nach dem markieren aber irgendwie auf [return] gekommen - alles war weg. Nachdem ich mich wieder beruhugt hatte, aber ich aus Frust einfach mal in das Menü "bearbeiten" geguckt -> da stand doch tatsächlich "rückgängig", und siehe da, der Beitrag war noch da! PERFEKT!

          1. Moin!

            Leider kann ich mir auch überhaupt nicht vorstellen, wie ein Modul eine Ausgabe erledigen soll! So soll z.B eine Tabelle mit Lieferanten angezeit werden. Was genau für so een HTML-Ausgabemodul jetzt machen und welche Daten müßte man dem übergeben? Die Datenquelle ist eine Datenbank. Die erste Frage, wie wird die Ausgabe überhaupt ausgelöst?

            Sinnvollerweise über ein Template.

            Es bietet sich sowieso an, die gesamte User-Steuerung über Templates zu regeln (und zum Parsen von Templates brauchst du natürlich auch wieder ein Modul - ich bin mir nicht sicher, ob das nicht sogar das Basismodul dafür ist).

            Denn irgendwo muß ja mal aufgeschrieben werden, was der Benutzer eigentlich so  machen darf, und was passieren muß, wenn er das macht. Dafür gibts eigentlich nur zwei Methoden: Entweder hast du eine "Action-Scripting-Language", in der du Benutzerverhalten, dessen Möglichkeiten etc. notierst und auf die dann zu benutzenden Templates verweist, oder du integrierst diese Informationen gleich ins Template.

            Klingt erstmal ziemlich abstrakt. Was gemeint ist: Du mußt definieren, dass irgendwo im Template ein {$HAUPTMENUE} integriert wird (das Hauptmenü hat natürlich auch sein Template, um dessen Aussehen zu bestimmen). Damit kannst du den Benutzer zwischen diversen Seiten wechseln lassen.

            Dann brauchst du z.B. eine {$DATENBANKABFRAGE:Auswahldialog}, welches einen Standard-Auswahldialog für eine gleich zu beginnende Datenbankabfrage generiert (natürlich mit seinem eigenen Template). Vielleicht hast du gewisse Standard-DB-Abfragen wie irgendeine TOP-10 mittels {$DATENBANKABFRAGE:Select-TOP-10-from-Artikelverkauft}.

            Natürlich müssen Templates "programmierbar" sein, also brauchst du irgendeine {$IF} ... {$ELSE} ... {$ENDIF}-Methode, um z.B. beim ersten Seitenaufruf den Auswahldialog und beim zweiten Seitenaufruf die Datenbankabfrage zu generieren.

            Was noch zu überlegen ist: Die Templates entstehen natürlich nicht aus dem Nichts heraus und machen mal eben, sondern dein Framework (schon wieder so ein schönes Wort) muß aus den Usereingaben der vorhergehenden Seiten (ob mit Sessions oder durch Auswertung der Formulareingaben) eine Umgebung herstellen, die deine Templates benutzen können, also z.B. alle Formularvariablen in einem Array $POST bzw. $GET zur Verfügung stellen - oder, weils vielleicht einfacher ist, in entpackten Variablen $username, $strasse, $tabelle etc. (also im Prinzip das, was in PHP mit register_globals = on passiert).

            Bedenke: Ich meine _nicht_, dass du die Templates als PHP-Seite programmieren sollst! Du sollst einen Parser schreiben (z.B. in PHP), der das Template einliest, die Variablenwerte ersetzt, die IF-Abfragen versteht, die eingebundenen Module aktiviert und befragt, und das Resultat dann als Seitenergebnis an den Browser schickt.

            Ich sage mal ich habe eine Startseite, mit einem Link auf "Lieferantenübersicht". Wenn man auf den Link klickt soll sich eien neue Seite im selben Layout öffnen, mit der Überschrift "Lieferantenübersicht" und einer HTML-Tabelle mit allen Lieferanten alphabetisch sortiert und mit je einem Link versehen um Details zu erfahren.

            Ok, und das soll hinter den Kulissen passieren: Wenn du den Link klickst, wird zwar die URL "/lieferanten/uebersicht.html" angefragt, diese URL wird aber intern von immer demselben Skript entgegengenommen und ausgewertet. Anscheinen soll das Template "/lieferanten/uebersicht" in Aktion treten. In diesem Template ist (neben etwas Design, was für die Funktion natürlich unwichtig ist) primär nur gespeichert, welche Datenbank wie abgefragt werden soll und wie das Abfrageergebnis aussehen soll (und dafür hast du entweder ein {$WHILE}...{$ENDWHILE}-Konstrukt, oder ein externes Template, welches pro Datensatz benutzt wird).

            Soll ich alle Daten die ich in der Tabelel ausgeben will aus der DB-Klasse als Array ausgeben, und diesen Array dann an die Ausgabe-Klasse übergeben, nur was nehme ich dann für Überschriften? Die originalen Datenbank-Spaltennamen sind nicht immer so der Hit, und bestimmte Zahlen wie Preise würde ich auch gerne vorher noch formatieren! Wie sollte man das machen? Vor allem, wenn ich den Inhalt der Seite vielleicht etwas strukturiert z.B. in einer verschachtelten Tabele augeben möcte, wie bilde ich das mit so einer Ausgabe-Klasse ab?

            Mit vernünftigen Direktiven im Template bzw. Formatierungsparametern kannst du entsprechende Module ansprechen, die dir diese Arbeit vor Ort abnehmen.

            Beispiel: {$PREIS(0,00)} könnte z.B. den Preis auf zwei Nachkommastellen mit Nullen auffüllen und weitere Nachkommastellen abschneiden. Oder du benutzt {$PREIS:10:2} (TurboPascal-Style): Preis soll in ein 10 Zeichen breites Feld passen (rechtsbündig ausgerichtet, wenn der Preis weniger Zeichen hat) und zwei Nachkommastellen besitzen.

            Das mit der Datenbank habe ich inzwiwchen so mehr oder weniger verstanden, da bekomme ich das schon hin. Probleme bereitet mir vor allem die Ausgabe, und auch das Basismodul weiß ich nicht so Recht was das soll.

            Die Ausgabe wird durch die Templates gesteuert (also der konkrete HTML-Code). Das Basismodul ist für das Anschmeißen der Ausgabe in den entsprechenden Modulen zuständig und nimmt alle Benutzereingaben entgegen und stellt sie den Modulen in einer Umgebung zur Verfügung (damit man sie z.B. in Templates ansprechen kann).

            Und auch die Module für Zusatzfunktionen wie den "Fragebogengenerator" weiß ich nict so recht. Was ich weiß ist inzwischen das ich hierfür eine Extra-Klasse verwende, die z.B. Methoden enthält um die komplette Menü-Struktur zu ermitteln, oder die Rechte festzulesgen. Aber mir fehlt noch eine Idee dafür, wie ich die eigentliche Funktionalität einbinde, also wie ich es machen soll, dass halt beim Klicken auf einen entsprechenden Menü-Eintrag auch eine HTML-Seite ausgegeben wird, das Aktionen ausgeführt werden können, das geht IMHO nicht mit der einen einzigen Klasse, oder? Oder wenn ich Aktionen ausführe, dann  muß ich ja auf GET/POST Parameter reagieren, wo mache ich das dann genau?

            Der Fragebogengenerator besteht aus zwei Teilen: 1. die passenden Templates, und 2. ein Modul mit den dazugehörigen Funktionen.

            Was ist schlecht an Sessions? Bisher bräuchte ich sie nicht, hätte aber den Vorteil, das ich ganze Objekte in der Session speichern kann, so könnte ich z.B. Basisdaten wie root_path, menu_array... die ich alle immer wieder neu aus verschiedenen Dateien generieren müßte, bei jedem Seitenaufruf, könnte die dann in einem Objekt in der Session speichern und müßte das ganze nur einmal ermitteln. Wobei, ob der Server jetzt eine Session-Datei öffnet oder ich eine andere ist ja auch fast egal, oder?

            An Sessions ist nichts sonderlich schlecht. Nur muß man sich entscheiden: Entweder braucht man sie wirklich - dann aber bitte durchgehend und überall. Oder man braucht sie nicht. Die meisten Webprojekte brauchen sie nicht.

            PS: Mozilla ist _G_E_N_I_A_L_ !!! Ich wollte gerade meinen PC aus dem Fenster werfen, nachdem ich diesen Beitrag eben in die die Zwischenablage kopieren wollte, binn nach dem markieren aber irgendwie auf [return] gekommen - alles war weg. Nachdem ich mich wieder beruhugt hatte, aber ich aus Frust einfach mal in das Menü "bearbeiten" geguckt -> da stand doch tatsächlich "rückgängig", und siehe da, der Beitrag war noch da! PERFEKT!

            Opera kann das aber auch. :-P Mozilla hat mit einigen Versionen Probleme damit.

            - Sven Rautenberg

            --
            Diese Signatur gilt nur am Freitag.
            1. Hi Sven!

              Ich hatte mir überlegt, ob es nicht vielleicht besser wäre, auf eine ferige Template-Lösung wie SMARTY zu setzen. Das wäre professioneller, performanter also ich das jetzt kurzfristig hinbekommen könnte, außerdem ist es erweiterbar, das ich noch eigene Funktionalitäten einbauen kann.
              Also habe ich eine Smarty-Template-Datei, in der der HTML-Code steht, und die dynamischen Elemente binde ich mit den entsprechenden Funktionen ein. Wobei sich hier die Frage stellt, wie ich oft wiederkehrende Elemente behandle, also vor allem dynamische Tabellen. Sollten solche HTML-Tabellen dann im Template immer gleich(redundant)  stehen, oder sollte ich vielleicht den kompletten HTML-Code über eine Methode einbinden, also ich füge in das Template nur eine Variable ein für {$Lieferantentabelle}, und im PHP-Code schreibe ich mit einer Methode HTML-Code in die Variable. Oder besser, ein extra Template für die Tabellen, in das dann die Variablen integriert werden, und dessen ausgabe dann in das eigentliche Tenmplate an der hierfür vergesehen Stelle eingebaut wird - ich glaube langsam zu verstehen...
              Aber wenn ich das jetzt so mache, dann brauche ich ja noch eine "Zwischenstufe", ich kann ja nicht direkt aus einem Smarty-Template auf eine Methode zugreifen oder? Also müßte ich noch das Ergebnis der Methode in eine Variable schreiben und die dann in das Templete einbinden, aber vielleicht geht das doch, so weit bin ich noch nicht bei smarty.

              Ok, und das soll hinter den Kulissen passieren: Wenn du den Link klickst, wird zwar die URL "/lieferanten/uebersicht.html" angefragt, diese URL wird aber intern von immer demselben Skript entgegengenommen und ausgewertet.

              Hm? Wieso das? Würde doch reichen wenn unter der angefragten Adresse das Modul liegt, welches sich das Template läd, ggfs. parst(bei smarty nue einmal pro Änderung!) und entsprechnden HTML-Code dann ausgibt. Aber wieso sollte man das über ein einziges Script regeln? Was hätte man davon? Und wie soll man das machen? Mit einer Rewrite-Rule? Also den ganzen Query-String als parameter an das basis-script übergeben und diesen dann selbst parsen? Aber das ist doch nun wirklich langsam etwas umständlich, oder? Vor allem - was mache ich beie ineem Datei-Upload? Oder überhaupt bei einenm POST-Request? Beides verwende ich häufig. Wie soll ich dann noch an die Parameter kommen? Und vor allem - an die hochgeladene Datei?

              Anscheinen soll das Template "/lieferanten/uebersicht" in Aktion treten. In diesem Template ist (neben etwas Design, was für die Funktion natürlich unwichtig ist) primär nur gespeichert, welche Datenbank wie abgefragt werden soll und wie das Abfrageergebnis aussehen soll (und dafür hast du entweder ein {$WHILE}...{$ENDWHILE}-Konstrukt, oder ein externes Template, welches pro Datensatz benutzt wird).

              Aber ist das ddnn nicht anders herum logischer? Ich lade mit dem Request-String das Modul direkt, und das Modul bindet entsprechend ein Template ein, um die erzeugte Ausgabe mit HTML zu umfassen.

              An Sessions ist nichts sonderlich schlecht. Nur muß man sich entscheiden: Entweder braucht man sie wirklich - dann aber bitte durchgehend und überall. Oder man braucht sie nicht. Die meisten Webprojekte brauchen sie nicht.

              ich _denke_ ich brauche sie nicht, da benutzername udn sprache eigentlich die einziegn User-abhängigen Dinge sind, die über den gesamten Besuch gespeichert werden müssen. Ich hatte halt nur gedacht das ich ander Einstellungen die ggfs. auf jeder Seite neu aus einer Config-File geparst werden müssen, bzw. dann noch über Funktionen aus den einzelnen Modulen geholt werden müssen, das man das lieber nur einmal macht und dann den so erzeugten Array über die Session-Funktion mitschleppt.

              Danke Dir sehr für die Hilfe. Nur weiß ich nicht ob sich so eine komplexe modulare Struktur lohnt nur weil ich 2 oder 3 Erweiterungen nachträglich einbinden können will. Meinst Du nicht auch das ich hier lieber auf fertige und für gut befundene(bestimmt nicht perfekt, vor allem für ein spezielles Projekt ist es nie perfekt, aber allemal besser als ich es in absehbarer Zeit hinbekäme!) Module verwende, also in diesem Fall smarty und pear, das verstehen dann im Fall der Fälle auch andere Leute besser als eine selbstgebastelte Lösung. Ich kenne mich aber mit beiden Lösungen noch nicht wirklich aus, ich teste gerade ein wenig damit und eigentlich bin ich bisher ganz zufrieden.

              Viele Grüße
              Andreas

              1. Hallo Andreas,

                ich klinke mich mal ein...

                Aber wenn ich das jetzt so mache, dann brauche ich ja noch eine "Zwischenstufe", ich kann ja nicht direkt aus einem Smarty-Template auf eine Methode zugreifen oder?

                Nein. D.h. jain, es gibt eine Möglichkeit, aber da wäre dann die Trennung zwischen Inhalt und Layout wieder weg... (und Du bräuchtest dann keine Templates mehr...)

                Also müßte ich noch das Ergebnis der Methode in eine Variable schreiben und die dann in das Templete einbinden,

                Exakt.

                aber vielleicht geht das doch, so weit bin ich noch nicht bei smarty.

                $output = $tpl->fetch("template.tpl"); ist das, wonach Du suchst.

                Nur weiß ich nicht ob sich so eine komplexe modulare Struktur lohnt nur weil ich 2 oder 3 Erweiterungen nachträglich einbinden können will.

                Ich denke, eine modulare Struktur lohnt sich immer. Du entscheidest, wie komplex sie wird.

                Meinst Du nicht auch das ich hier lieber auf fertige und für gut befundene Module verwende, also in diesem Fall smarty und pear, das verstehen dann im Fall der Fälle auch andere Leute besser als eine selbstgebastelte Lösung.

                Moment - Smarty und PEAR kannst Du *zusätzlich* zu Deinem Ansatz verwenden, als Hilfen, aber Smarty und PEAR als "Allheillösung" zu sehen, ist schlicht und ergreifend falsch. Smarty und PEAR nehmen Dir weder das Schnittstellendesign noch die Umsetzung ab, sie können Dir höchstens letztere erleichtern.

                Grüße,

                Christian

                --
                Sollen sich alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen und nicht mehr davon erfasst haben als eine Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst.
                                      -- Albert Einstein
                1. Hallo Christian!

                  Meinst Du nicht auch das ich hier lieber auf fertige und für gut befundene Module verwende, also in diesem Fall smarty und pear, das verstehen dann im Fall der Fälle auch andere Leute besser als eine selbstgebastelte Lösung.

                  Moment - Smarty und PEAR kannst Du *zusätzlich* zu Deinem Ansatz verwenden, als Hilfen, aber Smarty und PEAR als "Allheillösung" zu sehen, ist schlicht und ergreifend falsch. Smarty und PEAR nehmen Dir weder das Schnittstellendesign noch die Umsetzung ab, sie können Dir höchstens letztere erleichtern.

                  Hm? Daher habe ich das vermutlich in meinem Kopf nie so richtig unter einen Hut gekriegt ;-)
                  Also das PEAR nicht direkt verwendet werde sollte, war mir auch schon aufgefallen. Ist nur die Frage ob ich dann noch PEAR brauche, oder lieber selbst Module für die verschiedenen Datenbanken schreibe.
                  Bei Smarty ist das schon was anders, ich dachte gerade hier hätte ich die Möglichkeit einfach die Ausgabe über Templates zu steuern. Nur wie soll ich das parallel verwenden? Sven hat mir doch im Prinzip ein Äquivalent zu Smarty beschreiben, halt Templtes, die geparst werden, mit eigener Programmierlogik... das kann doch Smarty alles perfekt, ist sogar erweiterbar! Ich kann doch nicht 2 Level Templates und 2 Parser verwenden, as wäre doch nun wirklich Quatsch, also entweder oder habe ich gedacht.
                  Nur so wie Sven es beschreiben hat wird dann die eigene Template-Srache wieder so komplex, das ich am Ende doch lieber direkt PHP einsetze, nur eine eigene Sprache zu erfinden um aus Software-Design Gründen kein PHP zu verwenden finde ich doch etwas übertrieben, oder? Dann kann ja kein noprmaler Mensch außer mir mehr an den Templates arbeiten, auch wenn das logisch ist, IMHO sollten Templates so sein das da auch nicht-Programmierer dran arbeiten können, ohne programmier-Grundkenntnisse mitzubringen, halt Web_designer_ ;-)
                  ABer ich verstehe jetzt auch Dein Problem nicht so ganz, angenommen Sven schreibt in sein Template:

                  {$DATENBANKABFRAGE:Select-TOP-10-from-Artikelverkauft}

                  Dann hat er einen eigenen Parser geschreiben, der die entsprechende Aktion isoliert und ausführt, vermutlich wird er hier die Methode "Select-TOP-10-from-Artikelverkauft" von der Datenbankverbindungs-Klasse abfragen, oder vielleicht erst noch von der Modul-Klasse, die dann an die das ganze an die Datenbank-Klasse weitergibt, und das Roh-Datenergebnis direkt in Standard-Tabellen template einbettet, und der so gernerierte HTML-Code wird an der besagten Stelle in das ursprüngliche Template eingefügt, so würde ich mir das jetzt vorstellen.
                  Ich dagegen würde folgendes machen:
                  ich weise der der PHP-Variable $DATENBANKABFRAGE_Select-TOP-10-from-Artikelverkauft einen Methoden-Aufruf zu (im Modul, d.h. das Modul-Script hat eine Klasse und "normalen" PHP code der bei Smarty ja auch nötig ist um das Template zu laden), der dann genau dasselbe erledigt wie bei Sven. Was ist daran das Problem?

                  Viele Grüße und Danke für Eure Geduld!
                  Andreas

                  1. Hallo Andreas,

                    Also das PEAR nicht direkt verwendet werde sollte, war mir auch schon aufgefallen. Ist nur die Frage ob ich dann noch PEAR brauche, oder lieber selbst Module für die verschiedenen Datenbanken schreibe.

                    Das verstehe ich nicht so ganz, PEAR::DB kannst Du doch einsetzen, ich sehe das Problem nicht? Warum Code 2x schreiben?

                    Nur wie soll ich das parallel verwenden?

                    Wie willst Du *was* parallel verwenden?

                    Sven hat mir doch im Prinzip ein Äquivalent zu Smarty beschreiben, halt Templtes, die geparst werden, mit eigener Programmierlogik...

                    Jain. Du kannst mit Smarty auch Svens Anwendungsbereich abdecken (s.u.) Aber Smarty-Templates bieten vorrangig erst einmal Variablenersetzungen. Sven will ja dagegen Templates implementieren, die etwas vom Programm "anfordern". (bzw. so geparsed werden, dass der gleiche Effekt entsteht)

                    das kann doch Smarty alles perfekt, ist sogar erweiterbar! Ich kann doch nicht 2 Level Templates und 2 Parser verwenden, as wäre doch nun wirklich Quatsch, also entweder oder habe ich gedacht.

                    Eben.

                    Ich dagegen würde folgendes machen:
                    ich weise der der PHP-Variable $DATENBANKABFRAGE_Select-TOP-10-from-Artikelverkauft einen Methoden-Aufruf zu (im Modul, d.h. das Modul-Script hat eine Klasse und "normalen" PHP code der bei Smarty ja auch nötig ist um das Template zu laden), der dann genau dasselbe erledigt wie bei Sven. Was ist daran das Problem?

                    Ich weiß nicht, ob man in Smarty auf Methoden zugreifen kann, ich glaube nicht, aber Du kannst Funktionen in Smarty zugänglich machen:

                    function zeige_top_ten_artikel_an () {...}
                    $tpl->register_function ("top10artikel", "zeige_top_ten_artikel_an");
                    ------
                    {top10artikel}

                    Das würde Svens Konzpt mehr oder weniger in Smarty abbilden. Du könntest jedoch auch *alle* erdenklichen Abfragen *vorher* durchführen und diese dann Smarty als Variable zuweisen, aber das würde einen Overhead produzieren, der recht groß ist, vor allem, wenn nicht alle Funktionen gebraucht werden. Du könntest Funktionen auch variabel machen, wenn Du Parameter benutzt. Dann könntest Du eine Funktion in Smarty für die Datenbankausgabe definieren, welche dann einen Parameter besitzt, der den Namen der Abfrage enthält. Dich interessiert auf jeden Fall http://smarty.php.net/manual/en/api.register.function.html.

                    Grüße,

                    Christian

                    P.S.: ich bin etwas müde, sollte ins Bett, daher hafte ich (a) nicht für Rechtschreibfehle und (b) nicht für weitere Verwirrungen. ;-)

                    --
                    Sollen sich alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen und nicht mehr davon erfasst haben als eine Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst.
                                          -- Albert Einstein
                    1. Hallo!

                      Das verstehe ich nicht so ganz, PEAR::DB kannst Du doch einsetzen, ich sehe das Problem nicht? Warum Code 2x schreiben?

                      PEAR ist vielleicht nicht spezielle genug habe ich erst gedacht, aber eigentlich qatsch, hast Recht, die Daten werden ja in eigenen Klassen ermittelt, je nach Modul, und diese Methoden graufen dann auf PEAR zu,  das sollte klappen,

                      Nur wie soll ich das parallel verwenden?
                      Wie willst Du *was* parallel verwenden?

                      Svens Ansatz des Ausgabe-Moduls und Smarty, das sind IMHO 2 gegensätzige Ansätze die sich gegenseitig ausschließen. Sven würde - so wie ich das verstanden habe, keine direkten Befehle in eine Modul schreiben, d.h. das modul besteht nur aus einer Dateimit eienr Klasse, und einem Template. Das Basismodul parst das Template, udn führt die darin enhaltetenen Befehle aus, und gibt das Resultat an den Browser aus. Smarty macht das ja genau anders herum, bei Smarty läd man eine echte PHP Datei die nicht nur aus eienr Klasse bestehen kann, sondern das Template muß _aus_ dieser php-Datei geladen, und mit Variablen versorgt werden. D.h. das Basismudul mürde anstatt des Templates das Modul laden, also eine php-Datei mit ausführbarem Code zusätzlich zur Modul-Klasse. Dieser Code wie gesagt läd das Template, und führt entsprechend den Request-Parametern Aktionen aus, genauer gesagt greift es auf Methoden der Modul-Klasse zu und schreibt die Ergebnisse in Variablen, die an der dafür vorgesehenen Stele in das Smarty-Template eingebunden werden. Das sind IMHO zwei sehr verschiedene Ansätze.

                      Was ich bei Svens Ansatz noch nicht verstehe, was mache ich beispielsweise mit Datei-Uploads? Bei Sven gehen ja alle Requests an  ein Script, ein URL-Rewrite wäre an dieser Stelle schlecht weil ich so  doch nicht mehr an die Umgebungsvariablen $_FILES... kommen würde, da die nur dem Script an den der Request geht zur Verfügung stehen, oder?

                      Sven hat mir doch im Prinzip ein Äquivalent zu Smarty beschreiben, halt Templtes, die geparst werden, mit eigener Programmierlogik...

                      Jain. Du kannst mit Smarty auch Svens Anwendungsbereich abdecken (s.u.) Aber Smarty-Templates bieten vorrangig erst einmal Variablenersetzungen. Sven will ja dagegen Templates implementieren, die etwas vom Programm "anfordern". (bzw. so geparsed werden, dass der gleiche Effekt entsteht)

                      So langsam versehe ich auch warum, wenn man das so macht braucht man wirklich keinen PHP-Code außerhalb der Klasse des Moduls, da der Parser dann ja das alles was ich in das Scritpt schreiben würde übernimmt. Hm. Wäre vermutlich am saubersten, wobei:
                      Man kann ja auch in smarty eigene Funktionen einbauen! Das heißt ich müßte eien Funktion schreiben, die so ähnlich wie Svens Parser diese Dinge versteht, zdb das Laden des Templates mußt ja auch nicht im Modul stehen. Das heißt mein Basismodul läd beim Aufruf von /lieferanten/liste/ das entsprechende Modul, also die Klasse und das Smarty-Template, das basismodul startet das Template, dieses ruft dann die normalen Smarty und evtl ein paar eigene Funktionen auf, das müßte doch eigentlich gehen, oder?

                      Grüße
                      Andreas

                      1. Hallo Andreas,

                        Svens Ansatz des Ausgabe-Moduls und Smarty, das sind IMHO 2 gegensätzige Ansätze die sich gegenseitig ausschließen.

                        Die Grundansätze, ja.

                        Sven würde - so wie ich das verstanden habe, keine direkten Befehle in eine Modul schreiben, d.h. das modul besteht nur aus einer Dateimit eienr Klasse, und einem Template. Das Basismodul parst das Template, udn führt die darin enhaltetenen Befehle aus, und gibt das Resultat an den Browser aus.

                        Ja, genau. Ich persönlich neige aber eher dazu, alles in PHP-Scripten zusammenzubasteln und dann an eine Template weiterzugeben.

                        Smarty macht das ja genau anders herum, bei Smarty läd man eine echte PHP Datei die nicht nur aus eienr Klasse bestehen kann, sondern das Template muß _aus_ dieser php-Datei geladen, und mit Variablen versorgt werden.

                        Exakt. Dieser Ansatz ist mir persönlich sympatischer.

                        D.h. das Basismudul mürde anstatt des Templates das Modul laden, also eine php-Datei mit ausführbarem Code zusätzlich zur Modul-Klasse.

                        So würde ich es machen, genau.

                        Was ich bei Svens Ansatz noch nicht verstehe, was mache ich beispielsweise mit Datei-Uploads?

                        Warum? Wenn eine Methode einer Klasse aufgerufen wird, dann kann die doch prima auf $_FILES zugreifen, oder?

                        ein URL-Rewrite wäre an dieser Stelle schlecht weil ich so  doch nicht mehr an die Umgebungsvariablen $_FILES... kommen würde, da die nur dem Script an den der Request geht zur Verfügung stehen, oder?

                        Warum nicht? Solange es kein HTTP-Redirect ist sondern nur ein interner kann ich Deine Bedenken nicht verstehen.

                        [Smarty + Funktionen] das müßte doch eigentlich gehen, oder?

                        Funktonieren wird es, so wie Du es Dir vorstellst.

                        Hey, wenn ich jetzt so eine Antwort formuliere, bekomme ich auch Anregungen für meine eigenen Projekte. :-) Ich könnte nämlich die Methode Smarty+Funktionen bei bestimmten Stellen einsetzen, wo ich praktisch auf eine Seite mehrere Module laden will... Nette Idee... Hmmm...

                        Grüße,

                        Christian

                        --
                        Sollen sich alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen und nicht mehr davon erfasst haben als eine Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst.
                                              -- Albert Einstein
                        1. Hi!

                          Ich habe das ganze mal in der smarty Mailing-Liste zur Sprache gebracht (mit meinem eher gebrochenen englisch, aber ich wurde glaube ich verstanden ;-)), und da hat mir jemand folgendes Script gepostet:

                          <?php

                          /*
                           * Smarty plugin
                           * -------------------------------------------------------------
                           * Type:     function
                           * Name:     call
                           * Author:   Mark Priatel (mpriatel@rogers.com)
                           * Input:    obj = the object to call a method on
                           *           method = the method to call
                           *           arg1 .. arg4 (optional) = an argument for the method
                           *
                           * Examples: {call obj=$connection method='close'}
                           *           {call obj=$connection method='open' arg1='localhost'}
                           *           {call obj=$connection method='open' arg1='localhost'
                           *                 arg2='password' }
                           *
                           * -------------------------------------------------------------
                           */
                          function smarty_function_call($params, &$smarty)
                          {

                          $o = $params['obj'];
                           if ( !isset($o) ){
                            $smarty->trigger_error("function 'call' requires
                          argument 'obj'");
                            return;
                           }

                          $m = $params['method'];
                           if ( !isset($m) ){
                            $smarty->trigger_error("function 'call' requires
                          argument 'method'");
                            return;
                           }

                          $i = 1;
                            $args = array();
                            while( isset($params["arg$i"]) ){
                              array_push($args,$params["arg$i"]);
                              $i++;
                            }

                          switch( sizeof($args) ){
                              case 0: return $o->$m();
                              case 1: return $o->$m($args[0]);
                              case 2: return $o->$m($args[0],$args[1]);
                              case 3: return $o->$m($args[0],$args[1],$args[2]);
                              case 4: return $o->$m($args[0],$args[1],$args[2],$args[3]);
                            }

                          }
                          ?>

                          Anscheinend ist das durchaus über ein eigenes Plugin möglich, evtl. kann man das noch modifiieren dass man den Klassennamen nicht angeben muß, den könnte das Basismodul ja auch selbst ermitteln. Weiß zwar noch nicht wir genau man das einbindet, aber das werde ich schon noch rausfinden ;-)

                          Jedenfalls vielen Dank an Euch, Ihr habt mir sehr geholfen, ich denke ich habe hier einige Anhaltspunkte bekommen, wie ein modularer Aufbau auszusehen hat, und werde mich jetzt mal an die Umsetzzng machen.

                          Viele Grüße
                          Andreas

                          1. Hi!

                            Noch ein interessanter Link zum Thema: http://news.php.net/article.php?group=php.smarty.dev&article=375

                            Grüße
                            Andreas

    2. Hallo Sven, Hallo Andreas,

      Da drückt man einmal im Leben "Vorschau generieren", weil man einen längeren Text geschrieben hat, und dann vergisst man die Vorschau und schließt den Tab eine Minute später. *grmbl*

      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. Will man von einer deutschen Seite auf die zugehörige englische Seite, dann könnte man im Pfad einfach das "de" durch "en" ersetzen und hätte so "umgeschaltet". Die einfache Variante ist natürlich, dass jede Sprache unabhängig von den anderen Sprachen ist, und die Links einfach zur Startseite führen.

      Also dass mit den Verzeichnissen ist eine gute Idee, das könnte man prima mit mod_rewirte implementieren, würde ich sowieso verwenden: "Cool URIs don't change."

      Was die Textausgabe angeht: Variablen, Variablen, Variablen.

      ACK. Ich habe es bisher so gemacht, dass ich ein Unterverzeichnis languages hatte, dass die Dateien "de.php", "en.php", etc. enthält. Ich habe dann je nach Sprache nur diese eine Datei eingebunden. In der Datei wurde ein assoziativer Array definiert, der alle Meldungen und Texte enthielt. (und ich konnte dann darauf über $lang_array["phone_number"] auf "Telefonnummer" (Deutsch) bzw. "Phone number" (Englisch) zugreifen)

      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.

      Am besten wäre es, die Mehrsprachigkeit in die Kernfunktionen mit aufzunehmen und wenn es nur eine Sprache gibt, dann wird halt nur diese eine Sprache angezeigt. Du könntest dann statt nur Dateien auch Verzeichnisse nehmen. Dann hast Du pro Sprachkürzel ein Unterverzeichnis im languages-Verzeichnis. Dieses enthält dann mehrere Dateien, die dann jeweils den assoziativen Array weiter füllen. Das Framework bindet dann languages/<sprache>/base.php und languages/<sprache>/<modul>.php ein. Du könntest auch noch eine Datei languages/<sprache>/info.php verwenden, die für jede Sprache immer eingebunden wird, die die Infos zu den einzelnen Sprachen enthält. (Also vollständiger Name der Sprache, eventuell Standardtexte, etc.) Diese Infos können dann zur einzelnen Sprachauswahl verwendet werden.

      Ganz wichtig: Die Basis-Übersetzungen musst Du Dir gut überlegen und vor allem *gut dokumentieren*! Ich habe da Erfahrung, Du schreibst eine Meldung rein, brauchst die gleiche 3 Wochen später und errinserst Dich nicht mehr. Dann hast Du das Problem, dass Du Dich auch nicht mehr an den genauen Wortlaut der Nachricht erinnerst und deshalb Suchen/Ersetzen fehlschlägt. Daher wirst Du eine neue Nachricht einrichten, die einen anderen Wortlaut hat und redundant ist. Das gibt ein Riesenchaos - gerade an diesem Punkt muss man wirklich sehr viel Selbstdisziplin besitzen. Aber nicht nur bei diesen Details, auch gerade beim Programmieren - da immer gleich Übersetzungsvariablen verwenden und sich zumindest den Namen des Schlüssels für den assoziativen Array sich merken. Wenn das Projekt erst mal so richtig schön komplex ist, zahlt sich Selbsdisziplin und eine gute Konzeption von sehr häufig gebrauchten Dingen, wozu u.a. auch die Mehrsprachigkeit gehört, aus. Wenn man nämlich dann etwas ändern will, ist es ein Mordsaufwand, da kann man dann schon mal mit mindestens 30 Mantagen oder so rechnen.

      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.

      Meinst Du nicht auch, dass eine temporäre .htaccess mit deny from all reicht? Oder genauer: was spricht dagegen? :)

      Grüße,

      Christian

      --
      Sollen sich alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen und nicht mehr davon erfasst haben als eine Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst.
                            -- Albert Einstein