Der Entwurf für eine Templateklasse

Die Erklärungen und Beispiele findet der geneigte Webentwickler im Blog beim Interaktionsdesigner.

<?
  
  /**
   * Template!
   * 
   * @author  Paul Lunow <paul@kiwi-service.de>
   * @version 0.2  03/13/09
   *
   */
  class template {
    
    /**
     *  Datei die als Template dient
     *  @var string
     */
    protected $_file = "";
    
    /**
     * Gespeicherte, variable Daten
     * @var object
     */
    protected $_data;
    
    /**
     * Verwendete Schlüssel im Template
     * @var array
     */
    protected $_keys = array();
    
    /**
     * Verwendete, aber nicht definierte Schlüssel im Template
     * @var array
     */
    protected $_keys_unset = array();
    
    /**
     * Speichert den ggf. auftretenden Fehler
     * @var string
     */
    protected $_error = "";
    
    /**
     * Fertig geparstes Template
     * @var string
     */
    protected $_output = "";
    
    
    /**
     * Konstruktor
     * 
     * @param string $file  Datei welche als Template dient
     * @param object $content Objekt mit allen variablen Inhalten; kann auch später gesetzt werden.
     * @param boolean $parse Sollen die übergebenen Daten sofort geparst werden?
     * @return boolean  Hats geklappt oder nicht?
     */
    function __construct($file, $content = "", $parse = true) {
      
      try {
        //Prüfen der Templatedatei
        if(!is_file($file))
          throw new Exception("Das Template <i>$file</i> konnte nicht gefunden werden.");
        
        //Für weitere verwendung speichern
        $this->_file = $file;
        
        //Daten übergeben?
        if(count($content) > 0 && !empty($content)) {
          //Daten hinzufügen
          $this->addData($content);
          if($parse) {
            //Template parsen
            $this->parse();
          }
        }
        
        //Alles in Ordnung
        return true;
      
      } catch(exception $e) {
        $this->_error = $e->getMessage();
        return false;
      }
      
    }
    
    /**
     *  Datei laden und mit Inhalten mappen
     */
    function parse() {
      
      //Daten vorhanden?
      if(empty($this->_data)) {
        $this->error('Es wurden keine Daten definiert.');
        return false;
      }
      
      $this->beforeParse();
      ob_start();
      
      //Template laden
      include($this->_file);
      
      //Speichern
      $this->_output = ob_get_contents();
      
      ob_end_clean();
      $this->afterParse();
      
    }
    
    /**
     * Zugriff auf Variablen Eigenschaften
     * 
     * @param string $name
     * @return value
     */
    function __get($name) {
      //Zugriff auf interne Variablen (beginnen mit Unterstrich) verhindern!
      if(substr($name, 0, 1) == '_') {
        return $this->error('Verwendete Namen dürfen nicht mit einem Unterstrich beginnen!');
      }
      
      if(isset($this->_data->$name)) {
        //Variable vorhanden
        if(!in_array($name, $this->_keys))
          $this->_keys[] = $name;
        return $this->out($this->_data->$name, true);
      }
      else {
        //Variable nicht gefunden
        if(!in_array($name, $this->_keys_unset))
          $this->_keys_unset[] = $name;
        return $this->out($name, false);
      }
    }
    
    /**
     *  Neue Daten für den Container hinzufügen
     *  Vorhandene Daten werden einfach überschrieben
     *
     *  @param string $key
     *  @param mixed $value
     */
    function __set($key, $value) {
      if(substr($key, 0, 1) == '_') {
        $this->error('Variablen für das Template dürfen nicht mit einem Unterstrich beginnen! ('.$key.' = '.$value.')');
        return false;
      }
      $this->_data->$key = $value;
    }
    
    /**
     *  Fügt neue Daten an den Datencontainer an
     *
     *  @param mixed $data
     */
    function addData($data) {
      foreach($data as $key => $value) {
        $this->_data->$key = $value;
      }
    }
    
    
    /**
     * Gibt die im Template benutzten Variablen zurück
     * 
     * @param string Standard 'set' für alle oder 'unset' für alle die nicht definiert wurden
     * @return array $keys
     */
    function keys($mod = 'set') {
      switch($mod) {
        case 'all':
        case 'set':
          return $this->_keys;
          break;
        
        case 'unset': 
          return $this->_keys_unset;
          break;
        
        default:
          return $this->error('Der gewählte Modus '.$mod.' ist unbekannt!');
      }
    }
    
    /**
     * Gibt das geparste Template zurück
     * Ist ein Fehler aufgetreten, gibts den Fehler
     * 
     * @return string Template
     */
    function __toString() {
      //Keine Ausgabe vorhanden? Versuche ein zu erzeugen
      if(!$this->_output) {
        $this->parse();
      }
      
      //Fehler vorhanden?
      if($this->error())
        return $this->error();

      return $this->_output;
    }
    
    /**
     *  Gibt einen Wert aus dem Datenarray zurück an das Template
     *  Vorhanden um überschreiben zu werden!!
     *
     *  @param mixed $value Was auch immer gespeichert ist
     *  @param boolean $set True wenn der Wert gefunden wurde - false wenn er nicht vorhanden ist, in $value steht dann der Name der Eigenschaft
     */
    function out($value, $set) {
      if(!$set)
        return '{'.$value.'?}';
      
      return $value;
    }
    
    /**
     *  Wird vor dem Parsen ausgeführt
     *  Vorhanden um überschrieben zu werden!
     */
    function beforeParse() {}
    
    /**
     *  Wird nach dem Parsen ausgeführt
     *  Vorhanden um überschrieben zu werden!
     */
    function afterParse() {}
    
    /**
     * Speichert eine Fehlermeldung und/oder gibt den aktuellen Fehler zurück
     * 
     * @param $msg Fehlermeldung
     * @return string Fehlermeldung
     */
    function error($msg = "") {
      if($msg)
        $this->_error = $msg;
      
      return $this->_error;
    }
    
  }


?>