Found at: http://publish.ez.no/article/articleprint/12

Block Templates



Separating content from presentation is much talked about, and the way to solve that has been using one of the many template classes out there.

Files


You'll find the files to this article on the following pages:

PHP Base Lib Credits
template.inc
table_file.tpl

Which Templates?


In the PHP Base Library you'll find one of the earliest and most mature implementations in PHP. You've probably read one or two articles on this issue allready and are starting to ask what more can I learn?

Well, very easy, you can learn how to use block level templates.

If you don't know block level templates you probably know the glut of template files which might explode when you're trying to do serious work with templates. You know one file for each looping output in your code:

  • table.tpl
  • tablerow.tpl

    The block level templates set out to fix this problem for you by using blocks inside the template file.

    A simple template file (table_file.tpl) might look like this, with blocks:


    This is a page with a table:
    <!-- BEGIN table_one_template -->
    <table>
    
    <!-- BEGIN table_row_template -->
    <tr>
    <td>
    {an_item}
    </td>
    </tr>
    <!-- END table_row_template -->
    
    </table>
    <!-- END table_one_template -->


    Each BEGIN and END pair starts a block template. So you've just saved yourself a file. Not much but you could argue that an empty table might need an error message, and that would be another template block. Now you've saved two. And whatif you need more tables.

    The best benefit is that the designer and you will find it easier to work with one file, it is pretty easy to grasp how things are related in this way.

    How do you use this inside your php code? Well, easy enough:


    <?php
    // Include the file with the class.
    
    include( "template.inc" ); // Remember to add a path if needed.
    
    // Create a new template object, the argument given is the path to the directory
    // with your templates.
    
    $tpl = new Template( "." );
    
    // Tell the template object which file you'll be using. "table_file" is a
    // handle, "table.tpl" is the file name.
    // I suggest you use _file in the handle of the file so that you don't confuse
    // it with other handles or variables.
    
    $tpl->set_file( array( "table_file" => "table.tpl" ) );
    
    // Tell the template object about the blocks you'll be using. The function will
    // extract the template (arg 2) from the parent (arg 1) and use a variable
    // (arg 3) instead.
    
    // "table_file" is the parent of this block, "table_one_template" is the name of
    // the block and "table_one" is the variable.
    
    $tpl->set_block( "table_file", "table_one_template", "table_one" );
    
    // "table_one_template" is the parent of this block, "table_row_template" is the
    // name of the block and "table_row" is the variable.
    
    $tpl->set_block( "table_one_template", "table_row_template", "table_row" );
    
    for( $i = 0; $i < 10; $i++ )
    {
        // This will sett the variable "an_item" with the information "This is
        // iteration $i" (where $i, of course, is changed for each loop).
        
        $tpl->set_var( "an_item", "This is iteration $i" );
        
        // This will replace the "table_row" variable with all the stuff in
        // "table_row_template". The last true says that we should append the new
        // content to the allready existing content.
        
        $tpl->parse( "table_row", "table_row_template", true );
    }
    
    // This will replace the "table_one" variable with all the stuff in
    // "table_one_template". That is, all the stuff we put into "table_row" ++
        
    $tpl->parse( "table_one", "table_one_template" );
    
    // Now just parse and print the whole file.
    
    $tpl->pparse( "output", "table_file" );
    ?>


    Simple, huh?

    A caveat, btw, don't ever try to parse something which don't exist. Well no, you say, but if you try to be smart and use classes and then open only the templates you need before returning to another function which will print it, then you'll probably learn it the hard way.

    I did.

    On the next page you will find credits and then the template.inc file.

    Credits for template.inc

    These credits is for PHP Base Library.

    
    $Id: CREDITS,v 1.2 2000/07/12 18:22:30 kk Exp $
    
    Boris Erdmann
    boris@erdmann.com
    Development, all classes
    
    Kristian Köhntopp
    NetUSE AG
    kk@netuse.de
    Development, all classes
    
    Sascha Schumann
    sascha@schumann.cx
    Code and documentation. mSQL+Sybase-ct support. BLOB maybe-API.
    General release pusher for PHPLIB-6.
    
    The PHP3 development team
    http://www.php.net/credits.php3
    The PHP3 language interpreter
    
    Rasmus Lerdorf
    rasmus@lerdorf.on.ca
    Initial idea for serialize()  function
    
    KH Wild
    kwild@wicom.at
    First useable session array in PHP3
    
    Stefan Powell
    spowell@701.com
    Suggested MD5 Challenge/Response authentication scheme 
    for login screens.
    
    Henri Torgemane
    Henri.Torgemane@etu.utc.fr
    Provided the MD5 implementation for JavaScript, see
    http://www.geocities.com/SiliconValley/7116/jv_md5.html
    for his original code.
    
    Andre Anneck
    TSE Teleservice GmbH
    anneck@tse-online.de
    Debugging, Early Adopter, Guinea Pig
    
    Tom Henry
    Strategic Business Systems
    tomhenry@direct-connection.com
    Debugging, Early Adopter, Guinea Pig
    
    Jeremiah Bellomy
    jbellomy@cmpu.net
    Pointed out some very interesting problems with variable precedence.
    
    Scott McMullan
    mcmullan@warp-core.vf.lmco.com
    Porting to Sybase. Much structural cleanup.
    
    Cameron Taggart
    cameront@wolfenet.com
    Porting to ODBC.
    
    Guarneri Carmelo
    melting-soft
    carmelo@melting-soft.com
    Contributed ODBC support and sample database definitions.
    
    Szandor van Verseveld
    verseveld@nederland.net
    Contributed initial Postgres support.
    
    Daniel J. Lashua
    djl@stftx9.irngtx.tel.gte.com
    Unregister function in Session class.
    
    Luis Francisco Gonzales Hernandez
    luisgh@cogs.susx.ac.uk
    Contributed Oracle support.
    
    Jan Legenhausen
    jleg@nrw.net
    Contributed new_user.php3
    
    Jay Bloodworth
    jay@pathways.sde.state.sc.us
    Contributed the OOH Forms library as a part of PHPLIB.
    
    Andrey Nikiforov
    Andrey.Nikiforov@uvtb.ru
    Diverse corrections and improvements all over the place.
    
    Giancarlo Pinerolo
    ping@aconet.it
    PHPLIB and PHP as a Apache module documentation.
    
    Lindsay Haisley
    FMP Computer Services
    fmouse@fmp.com
    Suggestions and code for better management of addition GET data
    in GET mode. Documentation improvements.
    
    Padraic Renaghan
    padraic@renaghan.com
    Suggested improved cache control logic.
    
    Muze
    abstractdb@muze.nl
    Learned several nice ideas from their database abstraction.
    
    Jim Zajkowski
    jim@jimz.com
    Contributed md5-hashed password storage.
    
    Adam Thompson
    Commerce Design Inc.
    athompso@commerced.com
    Many PHP "uninitialized variable" warning cleanups.
    Support for automatically handling mixed addslashes() and
    base64_encode() data in active_sessions during cutover or testing.
    
    Massimiliano Masserelli
    Internet Images srl
    negro@interim.it
    Some code maintenance and debugging.
    
    Stefan Sels
    phplib@sels.com
    Contributed db_oci8.inc interface to Oracle with OCI8 functions
    
    Hans-Peter Oeri 
    theprofessor@oeri.ch
    Contributed auth_preauth logic.
    
    Jeffrey Galbraith
    http://www.xendra.com
    xendra@bigfoot.com
    OO modularization of Table.inc and additional table related functionality.
    


    template.inc

    The template.inc file is from PHP Base Library. It is released under Gnu GPL.


    <?php
    /*
     * Session Management for PHP3
     *
     * (C) Copyright 1999-2000 NetUSE GmbH
     *                    Kristian Koehntopp
     *
     * $Id: template.inc,v 1.5 2000/07/12 18:22:35 kk Exp $
     *
     */ 
    
    class Template {
      var $classname = "Template";
    
      /* if set, echo assignments */
      var $debug     = false;
    
      /* $file[handle] = "filename"; */
      var $file  = array();
    
      /* relative filenames are relative to this pathname */
      var $root   = "";
    
      /* $varkeys[key] = "key"; $varvals[key] = "value"; */
      var $varkeys = array();
      var $varvals = array();
    
      /* "remove"  => remove undefined variables
       * "comment" => replace undefined variables with comments
       * "keep"    => keep undefined variables
       */
      var $unknowns = "remove";
      
      /* "yes" => halt, "report" => report error, continue, "no" => ignore error quietly */
      var $halt_on_error  = "yes";
      
      /* last error message is retained here */
      var $last_error     = "";
    
    
      /***************************************************************************/
      /* public: Constructor.
       * root:     template directory.
       * unknowns: how to handle unknown variables.
       */
      function Template($root = ".", $unknowns = "remove") {
        $this->set_root($root);
        $this->set_unknowns($unknowns);
      }
    
      /* public: setroot(pathname $root)
       * root:   new template directory.
       */  
      function set_root($root) {
        if (!is_dir($root)) {
          $this->halt("set_root: $root is not a directory.");
          return false;
        }
        
        $this->root = $root;
        return true;
      }
    
      /* public: set_unknowns(enum $unknowns)
       * unknowns: "remove", "comment", "keep"
       *
       */
      function set_unknowns($unknowns = "keep") {
        $this->unknowns = $unknowns;
      }
    
      /* public: set_file(array $filelist)
       * filelist: array of handle, filename pairs.
       *
       * public: set_file(string $handle, string $filename)
       * handle: handle for a filename,
       * filename: name of template file
       */
      function set_file($handle, $filename = "") {
        if (!is_array($handle)) {
          if ($filename == "") {
            $this->halt("set_file: For handle $handle filename is empty.");
            return false;
          }
          $this->file[$handle] = $this->filename($filename);
        } else {
          reset($handle);
          while(list($h, $f) = each($handle)) {
            $this->file[$h] = $this->filename($f);
          }
        }
      }
    
      /* public: set_block(string $parent, string $handle, string $name = "")
       * extract the template $handle from $parent, 
       * place variable {$name} instead.
       */
      function set_block($parent, $handle, $name = "") {
        if (!$this->loadfile($parent)) {
          $this->halt("subst: unable to load $parent.");
          return false;
        }
        if ($name == "")
          $name = $handle;
    
        $str = $this->get_var($parent);
        $reg = "/<!--\s+BEGIN $handle\s+-->(.*)\n\s*<!--\s+END $handle\s+-->/sm";
        preg_match_all($reg, $str, $m);
        $str = preg_replace($reg, "{" . "$name}", $str);
        $this->set_var($handle, $m[1][0]);
        $this->set_var($parent, $str);
      }
      
      /* public: set_var(array $values)
       * values: array of variable name, value pairs.
       *
       * public: set_var(string $varname, string $value)
       * varname: name of a variable that is to be defined
       * value:   value of that variable
       */
      function set_var($varname, $value = "") {
        if (!is_array($varname)) {
          if (!empty($varname))
            if ($this->debug) print "scalar: set *$varname* to *$value*<br>\n";
            $this->varkeys[$varname] = "/".$this->varname($varname)."/";
            $this->varvals[$varname] = $value;
        } else {
          reset($varname);
          while(list($k, $v) = each($varname)) {
            if (!empty($k))
              if ($this->debug) print "array: set *$k* to *$v*<br>\n";
              $this->varkeys[$k] = "/".$this->varname($k)."/";
              $this->varvals[$k] = $v;
          }
        }
      }
    
      /* public: subst(string $handle)
       * handle: handle of template where variables are to be substituted.
       */
      function subst($handle) {
        if (!$this->loadfile($handle)) {
          $this->halt("subst: unable to load $handle.");
          return false;
        }
    
        $str = $this->get_var($handle);
        $str = @preg_replace($this->varkeys, $this->varvals, $str);
        return $str;
      }
      
      /* public: psubst(string $handle)
       * handle: handle of template where variables are to be substituted.
       */
      function psubst($handle) {
        print $this->subst($handle);
        
        return false;
      }
    
      /* public: parse(string $target, string $handle, boolean append)
       * public: parse(string $target, array  $handle, boolean append)
       * target: handle of variable to generate
       * handle: handle of template to substitute
       * append: append to target handle
       */
      function parse($target, $handle, $append = false) {
        if (!is_array($handle)) {
          $str = $this->subst($handle);
          if ($append) {
            $this->set_var($target, $this->get_var($target) . $str);
          } else {
            $this->set_var($target, $str);
          }
        } else {
          reset($handle);
          while(list($i, $h) = each($handle)) {
            $str = $this->subst($h);
            $this->set_var($target, $str);
          }
        }
        
        return $str;
      }
      
      function pparse($target, $handle, $append = false) {
        print $this->parse($target, $handle, $append);
        return false;
      }
      
      /* public: get_vars()
       */
      function get_vars() {
        reset($this->varkeys);
        while(list($k, $v) = each($this->varkeys)) {
          $result[$k] = $this->varvals[$k];
        }
        
        return $result;
      }
      
      /* public: get_var(string varname)
       * varname: name of variable.
       *
       * public: get_var(array varname)
       * varname: array of variable names
       */
      function get_var($varname) {
        if (!is_array($varname)) {
          return $this->varvals[$varname];
        } else {
          reset($varname);
          while(list($k, $v) = each($varname)) {
            $result[$k] = $this->varvals[$k];
          }
          
          return $result;
        }
      }
      
      /* public: get_undefined($handle)
       * handle: handle of a template.
       */
      function get_undefined($handle) {
        if (!$this->loadfile($handle)) {
          $this->halt("get_undefined: unable to load $handle.");
          return false;
        }
        
        preg_match_all("/\{([^}]+)\}/", $this->get_var($handle), $m);
        $m = $m[1];
        if (!is_array($m))
          return false;
    
        reset($m);
        while(list($k, $v) = each($m)) {
          if (!isset($this->varkeys[$v]))
            $result[$v] = $v;
        }
        
        if (count($result))
          return $result;
        else
          return false;
      }
    
      /* public: finish(string $str)
       * str: string to finish.
       */
      function finish($str) {
        switch ($this->unknowns) {
          case "keep":
          break;
          
          case "remove":
            $str = preg_replace('/{[^ \t\r\n}]+}/', "", $str);
          break;
    
          case "comment":
            $str = preg_replace('/{([^ \t\r\n}]+)}/', "<!-- Template $handle: Variable \1 undefined -->", $str);
          break;
        }
        
        return $str;
      }
    
      /* public: p(string $varname)
       * varname: name of variable to print.
       */
      function p($varname) {
        print $this->finish($this->get_var($varname));
      }
    
      function get($varname) {
        return $this->finish($this->get_var($varname));
      }
        
      /***************************************************************************/
      /* private: filename($filename)
       * filename: name to be completed.
       */
      function filename($filename) {
        if (substr($filename, 0, 1) != "/") {
          $filename = $this->root."/".$filename;
        }
        
        if (!file_exists($filename))
          $this->halt("filename: file $filename does not exist.");
    
        return $filename;
      }
      
      /* private: varname($varname)
       * varname: name of a replacement variable to be protected.
       */
      function varname($varname) {
        return preg_quote("{".$varname."}");
      }
    
      /* private: loadfile(string $handle)
       * handle:  load file defined by handle, if it is not loaded yet.
       */
      function loadfile($handle) {
        if (isset($this->varkeys[$handle]) and !empty($this->varvals[$handle]))
          return true;
    
        if (!isset($this->file[$handle])) {
          $this->halt("loadfile: $handle is not a valid handle.");
          return false;
        }
        $filename = $this->file[$handle];
    
        $str = implode("", @file($filename));
        if (empty($str)) {
          $this->halt("loadfile: While loading $handle, $filename does not exist or is empty.");
          return false;
        }
    
        $this->set_var($handle, $str);
        
        return true;
      }
    
      /***************************************************************************/
      /* public: halt(string $msg)
       * msg:    error message to show.
       */
      function halt($msg) {
        $this->last_error = $msg;
        
        if ($this->halt_on_error != "no")
          $this->haltmsg($msg);
        
        if ($this->halt_on_error == "yes")
          die("<b>Halted.</b>");
        
        return false;
      }
      
      /* public, override: haltmsg($msg)
       * msg: error message to show.
       */
      function haltmsg($msg) {
        printf("<b>Template Error:</b> %s<br>\n", $msg);
      }
    }
    ?>

    table_file.tpl

    It is released under Gnu GPL.

    <!-- BEGIN table_one_template -->
    <table>
    
    <!-- BEGIN table_row_template -->
    <tr>
    <td>
    {an_item}
    </td>
    </tr>
    <!-- END table_row_template -->
    
    </table>
    <!-- END table_one_template -->


    | Back to normal page view |