Bison Template Engine

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Bison Template Engine

    Hallo,
    Für alle die es interessiert möchte ich hier kurz eine neue Template-Engine vorstellen:
    Als Teil eines CMS habe ich Bison entwickelt und micht entschlossen, es offen zu machen.
    Die Performance ist duch serialisierung der Template-Datei in meinen Benchmarks noch etwas besser als z.B. bei Smarty.
    Diese Version stufe ich noch als beta ein, da sie nicht ausführlich getestet wurde und der Umfang noch nicht vollständig ist. Ausserdem möchte ich zum Release noch ein paar Anwendungsbeispiele liefern können.
    Achso: das Design der Seite steht nicht zur Diskussion.

    Das sind die Aktuellen Features:
    * Variablen, Loops und IF-Blöcke
    * Includes, Blockdeklaration und Rekursion
    * MySQL - Abfrageergebnisse können direkt geLOOPt werden
    * Creole ResultSet kann geLOOPt werden
    * Beliebig viele Dimensionen und Schachtelung der Blöcke
    * Serialisierung der Template-Datei (Caching)
    * Template-Debugging (Fehlermeldungen mit Zeilennummer)
    * Interpretierung einer Ausdrucks-Sprache (IF-Bedingungen)
    * Durchlaufnummer eines Loops ist verfügbar
    * Ausgabe als HTML-Mail
    * Funktionen zur Variablen-Modifikation

    - Durchlaufnummer:
    Wenn es einen LOOP rows gibt, so steht die Variable #rows für die Aktuelle Durchlaufnummer (Zeile)

    - Ausdrucks-Sprache:
    IF-Bedingungen Variablen können Boolesche Operatoren (||, &&, ...), Vergleichsoperatoren (<, ==, !=, ...) und Arithmetische Operatoren (+, -, *, /, %) enthalten:
    {if (bar * foo == 10 && #rows == 1)}

    Was vielleicht noch interessant ist: Da ich das Projekt langfristig angelegt habe ist es für PHP5 entwickelt und müsste für PHP4 erst angepasst werden.

    Es würde mich sehr freuen, wenn sich ein paar Tester finden könnten. Mich interessieren vor allem Bugs, mögliche weitere Features, Gesamteidruck, Probleme bei der Installation und alles andere. Also schonmal vielen Dank!

    Zu guter letzt hier der Link: http://bison.fjackstadt.de
    Unter Hilfe gibt es auch einen Link zur User-Dokumentation

    grüße, Frido
    Zuletzt geändert von frido37; 25.07.2005, 14:54.

  • #2
    Hallo frido37,

    nachdem ich mir deine Template Engine angeschaut habe, schreibe ich hier meine ersten Eindrücke.

    Positiv finde ich:
    • Template Engine für PHP 5
    • Unterstützung von verschiedenen Datenquellen für Loop


    Folgende Sachen sollten noch implementiert werden:
    • Plugin Interface für eigene Tags. So fehlt mir z.B. die Unterstützung von Iterators in Loop
    • eventuell sollte noch Caching eingebaut werden


    Negative Eindrücke:
    • Konfiguration ist nur durch Anpassung einer Objektvariable möglich. Eine Konfigatei wäre vielleicht sinnvoll
    • It's just yet antother template engine. Mir fehlen die einzigartigen Ansätze oder Ideen, warum es noch eine Template Engine geben und ich sie benutzen soll. Mit deiner Template Syntax ist es nicht möglich das Grunddesign mit einem der WYSIWYG Editoren zu erstellen.

    Kommentar


    • #3
      • eigene Tags: Die Tags sollen nur die Grundsteuerungselemente sein, alle weiteren Funktionalitäten sollten mit funktionen implementiert weren. Welche Erweiterungen stelltst Du dir hier beispielsweise vor, die als Plugin-Tag implementiert werden können?
      • Iterator-Implementierungen Loopen: geht meiner Meinung nach nicht direkt, da nicht jeder Iterator Arrays liefert. Man müsste sichergehen, dass die iterierten Elemente "brauchbare" Variablenwerte oder weitere Loops liefern. Dafür kann man eventuell ein Array-Interface schreiben, ich werde das prüfen.
      • Caching: Aktuell werden die Dateien interpretiert und in einer Objektstruktur abgelegt, die gecacht (serialisiert) wird. Dadurch muss nicht jedes mal die Datei eingelesen werden. Ein weiterer Chache-Level hat sich nicht als besonders effizient erwiesen. Momentan ist Bison damit etwa 15% schneller als Smarty, wobei die Performance auch von der Art der Anwendung abhängt. So spielt es eine Rolle, ob eher eine große Template-Datei vorliegt oder viele Variablen und oft wiederholte Loops auftreten.
      • Konfiguration: Die Editierung im Kopf der Klasse (Statische Variablen) ist nicht besonders unkomfortabel, aber bei wachsender Zahl von Konfigurationsoptionen wird es irgenwann eine Klasse geben, wo nur Config-Variablen drin stehen.
      • Das Besondere an Bison ist meiner Meinung nach die Interpretiert Ausdruckssprache, mit der sich gleichermaßen Variablenmodifikationen, kleine Berechnungen und IF-Bedingungen realisieren lassen.
      • WYSIWYG: Auf diesem Gebiet fehl mir offen gesagt die Kompetenz. Kann mir jemand auf die Sprünge helfen worauf es ankommt? Bison ist so ausgelegt, dass es unterschiedliche Template-Sprachen unterstützen kann. So ließe sich ein FileReader für vLib, Smarty, PHPLib etc. ergänzen, so dass verschiedene Template-Sprachen unterstützt würden. Aber immer schön der Reihe nach...

      Kommentar


      • #4
        hmm, Ich kenne mehere Classen, die mehr können und in b file passen. Wenn ich dise Klasse in eine Webanwendung integriere will, muss ich 5 zusätzliche Includes machen.
        Ich hab die regulären Ausdrücke und "wilden" Überprüfungen nicht gezähl, aber sind auf sicher zu viele. Ich kann mir nicht vorstellen, dass man mit dieser Klasse große Anwendungen betreiben kann ohne einen Killer-Server zu besitzen.
        h.a.n.d.
        Schmalle

        http://impressed.by
        http://blog.schmalenberger.it



        Wichtige Anmerkung: Ich habe keine Probleme mit Alkohol ...
        ... nur ohne :-)

        Kommentar


        • #5
          Da hast Du in den Quellcode gesehen ohne ihn zu verstehen. Die verschiedenen Dateien bestehen nur der Übersicht halber, man könnte das natürlich auch in eine schreiben. Es genügt übrigens die Datei Bison.php einzubinden, wie in den Beispielen zu sehen.
          Der parser wird nur angeworfen wenn eine Template-Datei geändert wurde, sonst wird die fertig geparste Datei aus dem Cache genutzt. Die anderen Klassen (Loop, IfElse, Expression) sind dazu da, eine geparste Datei abzbilden und die Ausgabe zu erzeugen sowie die Eingabedaten bei der der Ausgabe zu organisieren.
          Hier sind die meisten Variablen Referenzen, so dass kein unnötiger Speicher belegt wird.
          Im Endeffekt wird die Datei einmal geparst (das dauert ca. 0.05 sec. länger als die Ausgabe), Existiert eine Kopie der Dateistruktur fertig geparst im Cache, in die direkt die Variablen gesetzt werden. Über diese Struktur erfolgt auch die Ausgabe. Das ist eine sehr mächtige und höchst effiziente Methode.
          Du kannst ja mal die Zeit ausgeben lassen - dann wirst Du merken dass Du keinen Killer-Server brauchst
          Im übrigen - vom Umfang her hebt sich Bison nicht heraus - ist ja nur ein Beta-Test.
          Wenn Du etwas haben möchtest wird es integriert - das ist dank der objektorientierten Struktur einfach.

          Im übrigen gilt auch hier:
          Viel Code heißt nicht hoher Aufwand
          Nicht verstehen heißt nicht dass es keinen Sinn hat

          Kommentar


          • #6
            Gibt's das Ding schon für PHP4?

            Würde mir das gerne mal anschauen und in meine kleine Benchmarkseite integrieren, wenn's recht ist.

            Mal zu dem, was du geschrieben hast:
            Das direkte Abarbeiten von mySQL und Creole Ergebnissen ist gut und schön, aber das hat meiner Meinung nach nichts in der Basisklasse verloren, da du das auch immer dann mit dir rumschleppst und prüfst, wenn das nicht der Fall ist.
            Mach das lieber in eine abgeleitete Klasse oder als Plugin, wenn deine Engine damit zurechtkommt.

            Für die Mail-Geschichte gilt das gleiche.



            Was meines Erachtens auf jeden Fall reingehört ist die Möglichkeit, ein include dynamisch zu halten, damit meine ich sowas:
            Code:
            Hier steht das Template {var subtemplate}:<br />
            {include subtemplate}
            Die Engine sollte hier nicht nach einem Template suchen, das subtemplate heißt, sondern nach einem Template, dessen Name dem Wert der Templatevariablen subtemplate entspricht

            Rekursion wäre auch was schönes, da weiß ich nicht, ob deine Engine das schon kann.
            Gemeint ist (ich versuche mich mal an deiner Syntax):
            Code:
            {loop menu}
              {if #menu == 1}<ul></if}
              <li>
                {item}
                {recursion menu}
              </li>
              {if #menu == #menu_count}</ul></if}
            Ich könnte dann ein n-dimensionales Array übergeben, dass die momentane Menüstruktur enthält und z. B. so aufgebaut ist
            Code:
            Array
            (
                [0] => Array
                    (
                        [item] => Punkt 1
                    )
            
                [1] => Array
                    (
                        [item] => Punkt 2
                        [menu] => Array
                            (
                                [0] => Array
                                    (
                                        [item] => Punkt 2.1
                                    )
            
                                [1] => Array
                                    (
                                        [item] => Punkt 2.2
                                    )
            
                            )
            
                    )
            
                [2] => Array
                    (
                        [item] => Punkt 3
                    )
            
            )
            Momentan musst du für jede mögliche Stufe ein loop fest ins Template einbauen oder?

            Ich seh grade, dass du das wahrscheinlich nicht kannst, weil du keine Möglichkeit hast, festzustellen, ob der aktuelle Durchlauf der letzte ist und du daher das schließende Tag nicht setzen kannst.


            Zu meiner Schande muss ich gestehen, dass ich mir nicht vorstellen kann, wie so ein geparsted Template aussieht. PHP-Code so wie in Smarty erzeugt ist es ja wohl nicht, oder?
            Kannst du mal für loop-einfach.tpl das Geparste posten bitte?
            Code:
            <html>
            	<body>
            		Spieler des Tages:<br>
            		{loop namen}
            			{var #namen}. {var vorname} {var name}<br>
            		{/loop}
            	</body>
            </html>

            Und nicht vergessen: Die PHP4-Version würd' mich interessieren.

            P.S. Schmalle hat schon recht, es werden immer auf jeden Fall alle Bestandteile der Engine eingebunden, sonst würde dein unserialize ja auch nicht funktionieren
            Ich denke, also bin ich. - Einige sind trotzdem...

            Kommentar


            • #7
              Ersteinmal vielen Dank für den guten Beitrag!
              Unterstützung der Loopstrukturen werden noch geändert, mein Ziel ist eine Struktur die auf der Iterator-Klasse aufbaut und dann in der Loop-Klasse für alle Loop-Typen einheitliche angesprochen wird.
              Plugins und Erweiterbarkeit ist ein wichtiger Punkt, es wird wohl etwas dauern bis mächtige Plugins möglich sind.
              Die Mailausgabe bekommt noch eine eigene Klasse so dass Anhänge, mehrere Empfänger etc. darüber möglich sind.
              Die dynamische Einbindung auch eine sehr gute Idee, das ist nicht schwierig und kommt bald. Dann müssen statische Includes in Anführugszeichen geschrieben werden.
              Rekursion habe ich selbst noch nie verwendet, da die Tiefe in der Praxis meist beschränkt ist. Trotzdem würde es mich reizen dafür eine Lösung zu finden. In Zukunft werden Blöcke definiert, die rekursiv included werden können:
              Code:
              <h3>Eine Liste mit Rekursion</h3>
              {block menu}
              <ul>
              	{loop menu}
              		<li>
              			{if item}{var item}{/if}
              			{if menu}{include "menu"}{/if}
              		</li>
              	{/loop}
              </ul>
              {/block}
              Geparst sieht das Template so aus:
              Code:
              Loop Object
              (
                  [elem:private] => Array
                      (
                          [0] => Data Object
                              (
                                  [data:private] => <html>
              	<body>
              		Spieler des Tages:<br>
              		
                              )
              
                          [1] => Loop Object
                              (
                                  [elem:private] => Array
                                      (
                                          [0] => Data Object
                                              (
                                                  [data:private] => 
              			
                                              )
              
                                          [1] => Expression Object
                                              (
                                                  [parent:private] => Loop Object
               *RECURSION*
                                                  [expression:private] => Variable Object
                                                      (
                                                          [name:private] => #namen
                                                          [parent:private] => Expression Object
               *RECURSION*
                                                      )
              
                                                  [data:private] => 
                                              )
              
                                          [2] => Data Object
                                              (
                                                  [data:private] => . 
                                              )
              
                                          [3] => Expression Object
                                              (
                                                  [parent:private] => Loop Object
               *RECURSION*
                                                  [expression:private] => Variable Object
                                                      (
                                                          [name:private] => vorname
                                                          [parent:private] => Expression Object
               *RECURSION*
                                                      )
              
                                                  [data:private] => 
                                              )
              
                                          [4] => Data Object
                                              (
                                                  [data:private] =>  
                                              )
              
                                          [5] => Expression Object
                                              (
                                                  [parent:private] => Loop Object
               *RECURSION*
                                                  [expression:private] => Variable Object
                                                      (
                                                          [name:private] => name
                                                          [parent:private] => Expression Object
               *RECURSION*
                                                      )
              
                                                  [data:private] => 
                                              )
              
                                          [6] => Data Object
                                              (
                                                  [data:private] => <br>
              		
                                              )
              
                                      )
              
                                  [name:private] => namen
                                  [data:private] => 
                                  [parent:private] => Loop Object
               *RECURSION*
                              )
              
                          [2] => Data Object
                              (
                                  [data:private] => 
              	</body>
              </html>
                              )
              
                      )
              
                  [name:private] => root
                  [data:private] => 
                  [parent:private] => 
              )
              Das erhält man wenn man die in die Objekte geparste Datei mit print_r ausgibt. Das wird dann serialisiert und abgespeichert.
              Die unserialize-Funiktion und die includes sind nicht besonders komplex, so dass sich das Template schnell darstellen lässt.

              Eine PHP4-Version ist schon recht weit, allerdings ist die Unterstützung von Zeigern in PHP4 sehr anders, daher sind die Unterschiede so groß dass die PHP4-Version nicht so oft erscheinen kann.

              Falls Interesse besteht kann ich die PHP4-Version online stellen, ich habe leider nicht genug Zeit dafür viel zu tun.
              Zuletzt geändert von frido37; 03.07.2005, 15:40.

              Kommentar


              • #8
                Ja stell doch einfach mal online.... Finde die Ideen recht interessant
                Für alle die Fehler suchen, gibts gratis tolle Debuggingmöglichkeiten:
                var_dump(), print_r(), debug_backtrace und echo.
                Außerdem gibt es für unsere Neueinsteiger ein hervorragendes PHP Tutorial zu PHP 4 und PHP 5 (OOP)
                Es heißt $array['index'] und nicht $array[index]! Und nein, das ist nicht egal!
                Dieses Thema lesen, um Ärger im Forum und verzögerte Hilfen zu vermeiden.

                Kommentar


                • #9
                  Die PHP5-Version gibt es ja wie schon oben geschieben auf der Homepage
                  http://bison.fjackstadt.de

                  Die PHP4-Version ist sehr mit Vorsicht zu genießen und hier zu erreichen:
                  http://bison.fjackstadt.de/downloads..._v0.5alpha.zip

                  Kommentar


                  • #10
                    Mir stellt sich hier doch die Frage was denn jetzt an sich schneller, besser, erstrebenswerter, [...] ist..... Diese Templateengine hier mit mindestens 6 includes (mindestens 5 + die hauptklasse... evtl. noch die parserklasse wären 7...) oder soetwas wie in der art von smarty, jedenfalls der cache so ähnlich, d.h. nicht als Objekt.....

                    Was würdet ihr vorziehen? (Außer Frido, bei dem isses ja klar )
                    Für alle die Fehler suchen, gibts gratis tolle Debuggingmöglichkeiten:
                    var_dump(), print_r(), debug_backtrace und echo.
                    Außerdem gibt es für unsere Neueinsteiger ein hervorragendes PHP Tutorial zu PHP 4 und PHP 5 (OOP)
                    Es heißt $array['index'] und nicht $array[index]! Und nein, das ist nicht egal!
                    Dieses Thema lesen, um Ärger im Forum und verzögerte Hilfen zu vermeiden.

                    Kommentar


                    • #11
                      Was würdet ihr vorziehen?
                      meine eigene
                      h.a.n.d.
                      Schmalle

                      http://impressed.by
                      http://blog.schmalenberger.it



                      Wichtige Anmerkung: Ich habe keine Probleme mit Alkohol ...
                      ... nur ohne :-)

                      Kommentar


                      • #12
                        Ja sicher.... ich frage mich halt nur welche "Idee" des Caching am effektivsten ist, da ich mich sehr für dieses Thema interessiere...

                        Vielleicht magst du mir ja Tips geben?
                        Für alle die Fehler suchen, gibts gratis tolle Debuggingmöglichkeiten:
                        var_dump(), print_r(), debug_backtrace und echo.
                        Außerdem gibt es für unsere Neueinsteiger ein hervorragendes PHP Tutorial zu PHP 4 und PHP 5 (OOP)
                        Es heißt $array['index'] und nicht $array[index]! Und nein, das ist nicht egal!
                        Dieses Thema lesen, um Ärger im Forum und verzögerte Hilfen zu vermeiden.

                        Kommentar


                        • #13
                          Also ich gehe beim Caching "back to the roots". Das heisst ich erzeuge den klassischen "Mischcode", und includiere diesen im eigentlichen Script.

                          Nach dem Parsen sieht das ungefähr so aus:
                          PHP-Code:
                          echo $tpl->tpl_arselect('arten','ART','ART','ART',$tpl->chk_tplvar('ART',$ebene,$row),'onChange="neuLaden()"',$ebene,$row);
                           echo <<<END

                                <input type="button" value="Wechseln" onClick="neuLaden()">
                                 </fieldset>
                                <br />
                               <fieldset><legend>Neuer Eintrag in 
                          END;
                          echo 
                          $tpl->echovar('ART',$ebene,$row);
                           echo <<<END
                          </legend>
                               <table>
                                <tr>
                                 <td>Wert: </td>
                                 <td><input type="text" name="NEU" value="
                          END;
                          echo 
                          $tpl->tpl_htm($tpl->chk_tplvar('NEU',$ebene,$row),$ebene,$row);
                           echo <<<END
                          "></td>
                                 <td>&nbsp;</td>
                                <tr>
                                 <td>Position</td>
                                 <td><input type="text" name="RH" value="
                          END;
                          echo 
                          $tpl->tpl_htm($tpl->chk_tplvar('RH',$ebene,$row),$ebene,$row);
                           echo <<<END
                          "></td>
                                 <td><a href="javascript:save()" title="Speichern"><img src="
                          END;
                          echo 
                          $tpl->echovar('ICONS',$ebene,$row);
                           echo <<<END
                          /save.gif" border="0" 
                                 width="20" height="30"></a></td>
                                </tr>
                               </table>
                               </fieldset>
                               </td>
                              </tr>
                             </table><br />
                                
                          END; 
                          Das kann natürlich keiner lesen. Aber das ist ja auch vollkommen Banane. Die Templates und System Dateien sind natürlich sauber :-)
                          h.a.n.d.
                          Schmalle

                          http://impressed.by
                          http://blog.schmalenberger.it



                          Wichtige Anmerkung: Ich habe keine Probleme mit Alkohol ...
                          ... nur ohne :-)

                          Kommentar


                          • #14
                            Original geschrieben von Shurakai
                            Ja sicher.... ich frage mich halt nur welche "Idee" des Caching am effektivsten ist, da ich mich sehr für dieses Thema interessiere...

                            Vielleicht magst du mir ja Tips geben?
                            Cachen tu' ich nichts, es gibt ein "Plugin", mit dem kann ich ein komplettes Template cachen, d. h., es wird die Ausgabe abgespeichert und immer wieder zurückgegebn, teilweises Cachen ist (noch) nicht drin.

                            Bevorzugen würde ich auch meine eigene, in meinen Tests ist sie auch schneller als das Bison.

                            Ein kleines Template mit Inhalt
                            Code:
                            Hier stehen ein paar Variablen:
                            
                            <ul>
                            	<li>{var_1}</li>
                            	<li>{var_2}'</li>
                            	<li>{var_3}</li>
                            	<li>{var_4}</li>
                            </ul>
                            
                            Und hier geht's weiter: {var_1121}
                            wird zu
                            PHP-Code:
                            <?php 
                            /*
                            Template compiled using ExT 3.0.1.6
                            Compilation date: Mon,  4 Jul 2005 15:26:44 +0200
                            Compilation time: 5.273 ms
                            Template: test_var.tpl
                            */


                            /* No modifiers needed */


                            /* template function */
                            function ext3_____test_var_tpl(&$ext3, &$data$use_lang_folder) {
                             if (!
                            is_array($data)) $data = array();
                            if (!isset(
                            $data['var_1'])) $data['var_1'] = NULL;
                            if (!isset(
                            $data['var_2'])) $data['var_2'] = NULL;
                            if (!isset(
                            $data['var_3'])) $data['var_3'] = NULL;
                            if (!isset(
                            $data['var_4'])) $data['var_4'] = NULL;
                            if (!isset(
                            $data['var_1121'])) $data['var_1121'] = NULL;
                            $result 'Hier stehen ein paar Variablen:

                            <ul>
                                <li>'
                            .$data['var_1'].'</li>
                                <li>'
                            .$data['var_2'].'</li>
                                <li>'
                            .$data['var_3'].'</li>
                                <li>'
                            .$data['var_4'].'</li>
                            </ul>

                            Und hier geht\\\'s weiter: '
                            .$data['var_1121']; 

                            return 
                            $result;} ?>
                            (das Hochkomma ist natürlich maskiert)

                            Und das binde ich dann da ein, wo ich es brauche, indem ich $tpl->fetch('test_var.tpl') sage
                            Ich denke, also bin ich. - Einige sind trotzdem...

                            Kommentar


                            • #15
                              Original geschrieben von schmalle
                              meine eigene
                              Ja, ich auch ...

                              Aber mal zu Deiner - hast Du mal irgendwo eine Beschreibung/Features gepostet?

                              Kommentar

                              Lädt...
                              X