tutorials.de Buch-Aktion 05/2012
ERLEDIGT
NEIN
ANTWORTEN
6
ZUGRIFFE
1079
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Registriert seit
    Mar 2002
    Ort
    Stuttgart (Baden-Württemberg)
    Beiträge
    984
    Blog-Einträge
    7
    Hallo Folks. Da ich nun meine Templateklasse vollendet habe, wollte ich sie hier mal auf den Prüfstand geben. Ich habe versucht sie durch Kommentare verständlicher zu machen, was mir glaube ich nicht gelungen ist Aber vielleicht blickt ihr ja trotzdem durch. WIe gesagt, ich würde gerne Kritik / Verbesserungsvorschläge und Anregungen hören, Lob natürliuch auch haha, wenn es denn was zu loben gibt Vielleicht ist sie ja auch was für die PHP-Codeschnipsel Abteilung.
    Zu beachten ist, dass die Klasse nur für PHP5 geschrieben ist!

    Hier mal die Klasse:
    class.template.php
    PHP-Code:
    <?php
    error_reporting
    (E_ALL); /* Kann bei Bedarf durch Auskommentieren mit # deaktiviert werden */
    /*
     *
     *  sTemplate v 0.0.0.1 - Kleine Templateklasse
     *  Copyright (C) 2006  Maurício Hanika
     *
     *  This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation;
     *    either version 2 of the License, or (at your option) any later version.
     *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
     *    without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     *    See the GNU General Public License for more details.
     *
     *  You should have received a copy of the GNU General Public License along with this program;
     *    if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
     *
     *     Kleine Templateklasse, die verschachtelte Bloecke und if-else Anweisungen unterstuetzt. Desweiteren
     *    sind includes anderer Dateien in ein Template moeglich. Fuer ein Anwendungsbeispiel einfach in den
     *    Ordner gucken ;)
     *    Beachte bitte, dass wenn du einen if-Block definierst, ein {else} nicht doppelt vorkommen darf,
     *    also folgendes waere falsch:
     *     {if:einBlock}
     *        Kondition ist wahr!
     *         {else}Error {else}Kondition ist falsch!
     *     {endif:einBlock}
     *    Folgendes wuerde geparsed werden, wenn eine falsche Aussage vorliegt: 'Error {else}Kondition ist falsch!'.
     *                
     *    Wenn ihr verschachtelte Bloecke verwendet, beachtet bitte, dass bei der Zuweisung die Kind-Bloecke jeweils
     *    direkt nach ihrem Eltern-Block definiert werden, also:
     *     $tpl->setBlock('Liste1', array('list' => 'Punkt1'));
     *     $tpl->setBlock('Liste1.Child1', array('child' => 'Punkt 1.1'));    
     *
     *     $tpl->setBlock('Liste1', array('list' => 'Punkt2'));
     *     $tpl->setBlock('Liste1.Child1', array('child' => 'Punkt 2.1'));    
     *                    
     *    Folgendes wuerde nicht funktionieren, bzw. nicht den gewuenschten Effekt haben:
     *     $tpl->setBlock('Liste1', array('list' => 'Punkt1'));
     *     $tpl->setBlock('Liste1', array('list' => 'Punkt2'));
     *
     *     $tpl->setBlock('Liste1.Child1', array('child' => 'Punkt 1.1'));    
     *     $tpl->setBlock('Liste1.Child1', array('child' => 'Punkt 2.1'));    
     *    Der Parser wuesste nicht wozu die jeweiligen Unterpunkte gehoeren, bzw. er wuerde beide Unterpunkte 'Punkt2'
     *    unterordnen, da dieser zuvor definiert wurde.
     *    
     *  Changelog
     *        -v 0.0.0.2
     *            + Kleine Code Optimierung bei der Verarbeitung von verschachtelten Bloecken
     *            + Unsinnige chkphp() Funtion herausgenommen, da diese Klasse nur unter PHP5 laeuft
     *
     *
     *  @name:        sTemplate
     *  @version:    0.0.0.2
     *  @author:    Maurício Hanika
     *  @copyright: Maurício Hanika
    */


    /* Konfiguration, bitte nur aendern, wenn du weißt was du machst ;) */
    define('TPL_DELIMITER_START''{');        // Variablenbegrenzer vorn   
    define('TPL_DELIMITER_END''}');        // Variablenbegrenzer hinten

    class Template{

            protected 
    $data        '';        // Array mit eingelesenem Templatecode
            
    protected $vars        = array();    // Array mit den zu ersetzenden Variablen
            
    protected $blocks    = array();    // Array mit dynamischen Bloecken
            
    protected $ifBlocks = array();    // Array mit if-else Bloecken
        
        /*
         * @name: __construct
         * @desc: Konstruktor, ruft setTemplate auf
         */
        
    function __construct($data$isString=false){
          
          
    $this->setTemplate($data$isString);
          
        }

        
    /*
         * @name: setTemplate
         * @desc: Laedt ein Templatefile in $this->data, ist $isString auf true gesetzt und $data ein String, dann wird dieser anstelle einer Datei verwendet
         */    
        
    private function setTemplate($data$isString){

          if(
    $isString == false && file_exists($data)){
                
              
    $data file_get_contents($data);
              
          }
        
        
    $this->data = (string)$data
          
        }
        
        
    /*
         * @name: setVar
         * @desc: Setzt einem Placer {$search} zugehoerige Variable $replace
         */    
        
    public function setVar($search$replace){
          
          if(!empty(
    $search))
          
            
    $this->vars[$search] = (string)$replace;
          
        }
        
        
    /*
         * @name: setArray
         * @desc: Wie setVar, nur dass ein Array verarbeitet wird (Array('Key1' => $key1, 'Key2' => $key2, ...))
         */    
        
    public function setArray($array){
          
          foreach(
    $array as $search => $replace){
            
            if(!
    is_array($replace))
            
             
    $this->setVar($search$replace);
             
            else 
    /* Wird als Wert fuer $search ein Array gefunden, handelt es sich vermutlich um einen verschachtelten Block, oder um einen Fehler */
            
              
    if(preg_match('/\{loop:'.$search.'\}(.*)\{endloop:'.$search.'\}/siU'$this->data$block)){ /* Wird ein Block gefunden, parse ihn */

                 
    $this->replaceBlock($search$replace);
                 
             } else{ 
    /* Kein Block? Dann war's wohl ein Fehler */
               
                 
    trigger_error('Wert von <strong>{'.$search.'}</strong> ist ein Array. <strong>{'.$search.'}</strong> kann jedoch kein Array sein'E_USER_NOTICE); 
              
             }  
             
          }
          
        }
        
        
    /*
         * @name: setBlockVar
         * @desc: Setzt Variablen, die einem Block angehören.
         */    
        
    public function setBlockVar($bName$array){
          
          if(
    strstr($bName'.')){ /* Handelt es sich um einen verschachtelten Block? */
           
            
    $bName   explode('.'$bName);

            
    $str '';
            
                    for (
    $i 0$i count($bName); $i++) /* Danke fuer die Anregung an Fanste von tutorials.de - Hier wird aus einem Sting (z.B. Block1.Block1-1.Block1-1-1) ein mehrdimensionales Array gemacht */
                    
    {
                        
    $str .= '[\'' $bName[$i] . '\']';

                        eval(
    '$lastiteration = (!isset($this->blocks' $str ')) ? -1 : count($this->blocks' $str ') - 1;');
                    
                        
    $str .= '[' . (($lastiteration 0) ? : (($i == count($bName) - 1) ? $lastiteration $lastiteration)) . ']'/* Damit die Kindbloecke sich nicht ueberschreiben, zaehlen und Anzahl der Bloecke um eins erhoehen, also z.B. Kindblock[3] = array(...) */
                    
    }
            
            eval(
    '$this->blocks'.$str.' = $array;'); /* Sollte jemand einen Weg kennen, ohne eval() ein mehrdimensionales Array zu machen, waere ich fuer einen Hinweis sehr dankbar! */
            
          
    } else{ /* Nein, es liegt keine Verschachtelung vor */
            
              
    if(!isset($this->blocks[$bName]))
          
                  
    $this->blocks[$bName] = array();        
            
              
    $bSize count($this->blocks[$bName]);
          
              if(!empty(
    $bName) && is_array($array))
          
                  
    $this->blocks[$bName][$bSize] = $array;     
                 
          }
              
        }
        
        
    /*
         * @name: setIfBlock
         * @desc: Setzt einem if-Block zugehoerige Kondition $condition
         */    
        
    public function setIfBlock($ifBlock$condition){
          
          if(!empty(
    $ifBlock))
          
            
    $this->ifBlocks[$ifBlock] = $condition;
          
        }
        
    }
    ?>
    class.template.parser.php
    PHP-Code:
    <?php
    error_reporting
    (E_ALL); /* Kann bei Bedarf durch Auskommentieren mit # deaktiviert werden */
    /*
     *
     *  sTemplate v 0.0.0.1 - Kleine Templateklasse
     *  Copyright (C) 2006  Maurício Hanika
     *
     *  This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation;
     *    either version 2 of the License, or (at your option) any later version.
     *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
     *    without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     *    See the GNU General Public License for more details.
     *
     *  You should have received a copy of the GNU General Public License along with this program;
     *    if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
     *
     *     Kleine Templateklasse, die verschachtelte Bloecke und if-else Anweisungen unterstuetzt. Desweiteren
     *    sind includes anderer Dateien in ein Template moeglich. Fuer ein Anwendungsbeispiel einfach in den
     *    Ordner gucken ;)
     *    Beachte bitte, dass wenn du einen if-Block definierst, ein {else} nicht doppelt vorkommen darf,
     *    also folgendes waere falsch:
     *     {if:einBlock}
     *        Kondition ist wahr!
     *         {else}Error {else}Kondition ist falsch!
     *     {endif:einBlock}
     *    Folgendes wuerde geparsed werden, wenn eine falsche Aussage vorliegt: 'Error {else}Kondition ist falsch!'.
     *                
     *    Wenn ihr verschachtelte Bloecke verwendet, beachtet bitte, dass bei der Zuweisung die Kind-Bloecke jeweils
     *    direkt nach ihrem Eltern-Block definiert werden, also:
     *     $tpl->setBlock('Liste1', array('list' => 'Punkt1'));
     *     $tpl->setBlock('Liste1.Child1', array('child' => 'Punkt 1.1'));    
     *
     *     $tpl->setBlock('Liste1', array('list' => 'Punkt2'));
     *     $tpl->setBlock('Liste1.Child1', array('child' => 'Punkt 2.1'));    
     *                    
     *    Folgendes wuerde nicht funktionieren, bzw. nicht den gewuenschten Effekt haben:
     *     $tpl->setBlock('Liste1', array('list' => 'Punkt1'));
     *     $tpl->setBlock('Liste1', array('list' => 'Punkt2'));
     *
     *     $tpl->setBlock('Liste1.Child1', array('child' => 'Punkt 1.1'));    
     *     $tpl->setBlock('Liste1.Child1', array('child' => 'Punkt 2.1'));    
     *    Der Parser wuesste nicht wozu die jeweiligen Unterpunkte gehoeren, bzw. er wuerde beide Unterpunkte 'Punkt2'
     *    unterordnen, da dieser zuvor definiert wurde.
     *
     *  Changelog
     *        -v 0.0.0.2
     *            + Kleine Code Optimierung bei der Verarbeitung von verschachtelten Bloecken
     *            + Unsinnige chkphp() Funtion herausgenommen, da diese Klasse nur unter PHP5 laeuft
     *
     *
     *  @name:        sTemplate
     *  @version:    0.0.0.2
     *  @author:    Maurício Hanika
     *  @copyright: Maurício Hanika
    */
    require_once ('class.template.php');

    class 
    Parser extends Template{

        
    /*
         * @name: doIf
         * @desc: Verarbeitet If-Bloecke
         */      
          
    private function doIf($ifBlock$content){
           
          if(isset(
    $this->ifBlocks[$ifBlock])){
            
            if(
    $this->ifBlocks[$ifBlock])
              
              return (
    stristr($content'{else}')) ? substr($content0strpos($content'{else}')) : $content;
            
            else{
              
              if(
    stristr($content'{else}')){
                
                return 
    substr($contentstripos($content'{else}') + 6);
                
              }
              
            }
            
          } else{
            
            
    trigger_error('Zugehörige Kondition zum If-Block <strong>'.$ifBlock.'</strong> wurde nicht gefunden 'E_USER_WARNING);   
            
            return 
    false;
            
          }
            
        }

        
    /*
         * @name: replaceVars
         * @desc: Ersetzt Platzhalter im Template durch Variablen
         */    
        
    private function replaceVars($clearTpl){
          
          
    /* Replace the defined variables */
          
    foreach ($this->vars as $search => $replace){
                
                  
    $this->data str_replace(TPL_DELIMITER_START.$search.TPL_DELIMITER_END$replace$this->data); 
            
          }
          
          
    /* if ($clearTpl === true)
                
                $this->data = preg_replace('/<!--Begin:([a-zA-Z0-9]+)-->(.+)<!--End:\1-->/siU', '', $this->data);
                Ich suche noch eine gute Loesung hierfuer. Bei Ideen, e-Mail an: tickduck@gmx.de */
          
          
    return $this->data;
          
        } 

        
    /*
         * @name: replaceBlock
         * @desc: Ersetzt (verschachtelte) Bloecke in den Templates
         */        
        
    protected function replaceBlock($bName$array){
          
          
    preg_match('/\{loop:'.$bName.'\}(.*)\{endloop:'.$bName.'\}/siU'$this->data$block);
          
              
    $tmp '';
            foreach(
    $array as $tmpArray){
                
                
    $obj = new Parser($block[1], true);
              
                
    $obj->setArray($tmpArray); 
              
                
    $tmp .= $obj->parse(true);
                  
            }
                
            
    $this->data preg_replace('/\{loop:'.$bName.'\}(.*)\{endloop:'.$bName.'\}/siU'$tmp$this->data);            
              
        }
        
        
    /*
         * @name: parseIncludes
         * @desc: Dateien werden eingebunden
         */    
        
    private function parseIncludes(){      
          
          while(
    preg_match('/\{include:(.+)\}/siU'$this->data)){
            
            
    $this->data preg_replace('/\{include:(.+)\}/esiU'"implode('', file('\\1'))"$this->data);
           
          }      
          
        }

        
    /*
         * @name: parseIf
         * @desc: Holt die If-Bloecke aus den Templates und schickt sie zur Verarbeitung an die doIf-Funktion
         */        
        
    private function parseIf($ifBlock=''$condition=''){

          while(
    preg_match('/\{if:([a-zA-Z0-9]+)\}(.*)\{endif:\1\}/siU'$this->data)){

            
    $this->data preg_replace('/\{if:([a-zA-Z0-9]+)\}(.*)\{endif:\1\}/esiU''$this->doIf("\\1","\\2")'$this->data); 
            
          }
          
        }
        
        
    /*
         * @name: show
         * @desc: Ausgabe der $this-Variable, nur zu entwicklungstechnischem Zweck
         */    
        
    function show(){
          
          echo 
    '<pre>';
           
    print_r($this);
          echo 
    '</pre>';
          
        }
      
        
    /*
         * @name: parse
         * @desc: Alles fertig? Dann das Template parsen
         */    
        
    function parse($noParse=true$parseIncludes=true$clearTpl=true){
          
          if(
    $noParse === false){
             
            foreach (
    $this->blocks as $bName => $array){
              
                
    $this->replaceBlock($bName$array);
                  
            }    
            
            
    $this->parseIf();    
            
          }
          
          if(
    $clearTpl === true){
            
            
    // Muss noch implentiert werden (soll Kommentare in Templates, etc. entfernen)
            
          
    }
          
          if(
    $parseIncludes === true)
          
              
    $this->parseIncludes();

          return 
    $this->replaceVars($clearTpl);
          
        }  
    }
    ?>
    index.php, Beispielseite
    PHP-Code:
    <?php
    /*
     *  sTemplate v 0.0.0.1 - Kleine Templateklasse
     *  Copyright (C) 2006  Maurício Hanika
     *
     *  This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation;
     *    either version 2 of the License, or (at your option) any later version.
     *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
     *    without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     *    See the GNU General Public License for more details.
     *
     *  You should have received a copy of the GNU General Public License along with this program;
     *    if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
     *
     *
     *  @name:        sTemplate
     *  @version:    0.0.0.1
     *  @author:    Maurício Hanika
     *  @copyright: Maurício Hanika
     *    @desc:        Beispielanwendung fuer die sTemplate-Klasse
    */

    require_once('class.template.parser.php');

    $tpl = new Parser('index.htm'); # Fuer weitere Templates jeweils ein neues Objekt erstellen.

    # Variablen zuweisen #
    $tpl->setVar('title''Beispielseite');
    $tpl->setVar('class''sTemplate');
    $tpl->setVar('name''Maurício Hanika');
    $tpl->setVar('version''0.0.0.2');

    # Loop zuweisen. Bitte beachtet, dass Bloecke keinen . im Namen enthalten, ausser es handelt sich um einen Kindblock (z.B. Block1.Block1-1.Block1-1-1) #
    for($i=0$i 10$i++){
      
    $tpl->setBlockVar('count', array('count'     => $i,
                                         
    'text'     => ' ist der aktuelle Wert von $i'));
      
    $tpl->setBlockVar('count.level', array('lvl' => '<div style="padding-left: '.($i).'px;">''lvlE' => '</div>'));
    }

    # If-Else Block #
    $tpl->setIfBlock('tag', (date('G') > 12 && date('G') < 18));
    $tpl->setIfBlock('abend', (date('G') > 18 && date('G') < 24));

    echo 
    $tpl->parse(false /* Wenn true, dann werden nur Variablen ersetzt und Bloecke und if-Abfragen werden ignoriert */,
                     
    true /* Per {include:} zugewiesene Dateien einbinden */,
                     
    true/* Hat noch keine Bewandnis */);
    ?>
    index.htm, Beispieltemplate
    HTML-Code:
    <html>
    <head>
    <title>{title}</title>
    <style>
    <!--
    body, tr, td{
      font-family: 	verdana, arial, sans-serif;
      font-size:	10px;
    }
    -->
    </style>
    </head>
    <body>
    <h1>{title}</h1>
    <strong>{class}</strong> wurde von <strong>{name}</strong> entworfen und liegt in der <strong>Version {version}</strong> vor.
    <br />
    <br />
    Loop Beispiel:<br />
    <table border="1" >
    {loop:count}
    <tr>
     <td>{loop:level}{lvl} Level {count}. {count}{text}{lvlE}{endloop:level}</td>
    </tr>
    {endloop:count}
    </table>
    <br />
    If-Else Block:<br />
    <strong>
    {if:tag}
    Guten Tag!{else}
      {if:abend}
    	Guten Abend!{else}
    		Guten Morgen!
      {endif:abend}
    {endif:tag}
    </strong>
    <br />
    <br />
    Include (message.html):<br />
    {include:message.html}
    </body>
    </html>
     
    Gruß mAu


    ──────────────────────────
    Ich auf flickr

    * Unformatierten Quellcode schaue ich mir _nicht_ an!
    * Sollte ich euch bei einer Frage weitergeholfen haben, würde ich mich über eine positive Bewertung freuen.
    * Bitte die Netiquette beachten.
    * Vergesst nicht, beantwortete Fragen als erledigt zu markieren!


  2. #2
    Registriert seit
    Mar 2002
    Ort
    Stuttgart (Baden-Württemberg)
    Beiträge
    984
    Blog-Einträge
    7
    Keine Verbesserungsvorschläge? Auch nix für die Codeschnipsel? Schade...
     
    Gruß mAu


    ──────────────────────────
    Ich auf flickr

    * Unformatierten Quellcode schaue ich mir _nicht_ an!
    * Sollte ich euch bei einer Frage weitergeholfen haben, würde ich mich über eine positive Bewertung freuen.
    * Bitte die Netiquette beachten.
    * Vergesst nicht, beantwortete Fragen als erledigt zu markieren!


  3. #3
    seltsam_mit_hut seltsam_mit_hut ist offline Mitglied Bronze
    Registriert seit
    Apr 2006
    Beiträge
    29
    Auf den ersten Blick sieht es schick aus, nur leider ist das für mich etwas zu hoch! Habe mich bisher noch nicht in PHP 5 eingearbeitet und mit so eine Templete-Klasse habe ich auch noch nie gearbeitet...

    Aber wenn ich Zeit habe werde ich sie bestimmt mal offline testen und zerlegen und analysieren, schließlich lernt man so am besten!

    Ich würde es sehr gerne in den Codeschnippsel sehen, hier wird es sonst unter gehen.

    Gute Arbeit!
     

  4. #4
    CIX88 Tutorials.de Gastzugang
    Naja leider ist die Klasse nur begrenzt (wegen PHP5) einsetzbar.
    Musste erst kürzlich so eine ähnliche Klasse PHP4-Tauglich umschreiben
     

  5. #5
    Registriert seit
    Mar 2002
    Ort
    Stuttgart (Baden-Württemberg)
    Beiträge
    984
    Blog-Einträge
    7
    Ich wollte / will mich mit dieser Klasse etwas in OOP einarbeiten. Und da man ja dauernd liest, dass das von PHP unterstützte OOP erst seit PHP5 "richtiges" OOP ist, wollte ich gleich da einsteigen. Es ist schon beabsichtigt, dass sie nur unter PHP5 läuft.
     
    Gruß mAu


    ──────────────────────────
    Ich auf flickr

    * Unformatierten Quellcode schaue ich mir _nicht_ an!
    * Sollte ich euch bei einer Frage weitergeholfen haben, würde ich mich über eine positive Bewertung freuen.
    * Bitte die Netiquette beachten.
    * Vergesst nicht, beantwortete Fragen als erledigt zu markieren!


  6. #6
    Avatar von nkler
    nkler nkler ist offline Mitglied
    Registriert seit
    Jul 2004
    Ort
    Neuenkirchen (Niedersachsen)
    Beiträge
    17
    Ich werde die Klasse auch einmal testen.
     
    Lächle, und fürchte dich nicht vor dem nächsten Tag.

  7. #7
    Avatar von nkler
    nkler nkler ist offline Mitglied
    Registriert seit
    Jul 2004
    Ort
    Neuenkirchen (Niedersachsen)
    Beiträge
    17
    Wie wäre es wenn man mehrere Templatedateien einlesen kann.

    Also zum Beispiel

    Datei1 -> Header
    Datei2 -> Body
    Datei3 -> Footer
     
    Lächle, und fürchte dich nicht vor dem nächsten Tag.

Ähnliche Themen

  1. Verbesserungsvorschläge zu Login-Klasse
    Von CookieBuster im Forum PHP
    Antworten: 5
    Letzter Beitrag: 05.10.09, 14:48
  2. Verbesserungsvorschläge Cache-Klasse
    Von ZodiacXP im Forum PHP
    Antworten: 5
    Letzter Beitrag: 29.08.08, 18:01
  3. Klasse - Verbesserungsvorschläge
    Von Briefkasten im Forum PHP
    Antworten: 0
    Letzter Beitrag: 01.12.06, 21:03
  4. Antworten: 3
    Letzter Beitrag: 22.07.05, 15:59
  5. Antworten: 23
    Letzter Beitrag: 02.03.05, 22:35