<?php

/**
 * Proposition for mininal interface for template engines
 *
 * What would a common interface to template engines be good for?
 *
 * First, all template engines are different, either by the concept they use
 * or by their API... This doesn't make life easy for application developers.
 * It's either be bound to a specific template or write a plethora of interfaces
 * (and of course each and every developers will write gateways differently.)
 * This is where this interface comes in: Trying to define once and for all
 * a minimal common API to template engines. Note the word MINIMAL is essential
 * here, since we can't and don't want to be everything to every template
 * engines...
 *
 * For instance, you could write a mailer package that sends templated HTML
 * e-mails. Relying on the interface defined here, the mailer could be reused
 * by any developer and let them decide which template engine they want to use
 * (as long as the template engine implements the interface.)
 *
 * Here I have extended existing  template engine classes, however the best way
 * would be to have the engine class itself implement the interface.
 * I worked in PHP5 to take advantage of some of the new OO features,
 * but PHP4 BC could easily be established by removing the "implements" keywords,
 * emulating some functions if needed, making sure objects are passed by
 * reference and writing the constructors, usually like this:
 * <code>
 *  class SomeClass {
 *      /**
 *       * PHP4-BC contructor
 *       * @see __construct()
 *       *{@*}
 *      function SomeClass($param) {
 *          $this->__construct($param);
 *      }
 *      ...
 *  }
 * </code>
 *
 * Some block-type template engines required the creation of template classes
 * to isolate the block building process. This process is really part of the
 * template itself and an application using such an interface need not be
 * aware of it. Using encapsulation also gives a better implementation of
 * the MVC design concept.
 *
 * My implementation of the interface for each engine may not be the best,
 * I have only did this in a few hours without prior knowledge of most engines.
 * So far, I've only worked with a subset of the available template engines
 * out there:
 *  - Integrated Templates (IT)
 *  - Flexy
 *  - PHPLib
 *  - PHPTAL
 *  - Savant
 *  - Sigma
 *  - SimpleT
 *  - SmartTemplate
 *  - Smarty
 *  - Xipe
 *
 * For efficiency some engines make use of a "pull" approach (vs. capture of
 * all data then push to template). However, in my view this "pull" links
 * too much the "view" part to the "model" part (in the Model-View-Controller
 * concept). To remedy this, those engines should use the new PHP5 iterators
 * instead to keep their efficiency. This way, instead of "pushing" the data
 * to the template, only the "collection" reference would be passed and the
 * template would use the iterator (typically "foreach") to go through the data.
 * This is the same difference as passing all the database records in an array
 * vs. passing the DB result set resource, but with more transparency, i.e.
 * the same process to walk through the data is used.
 *
 * This interface could also be implemented for image generating packages
 * or any other type of output generating packages (provided that
 * they have some sort of templating mechanism in place.) For example
 * an image generating package, could encapsulate the various steps to
 * build the image into a template class (much like the block-based HTML
 * template engines.)
 *
 * Also, since I use interfaces it looks like a lot of code is duplicated.
 * While this is true, this is the only way to implement interfaces since
 * template engines are not sub-classes of a master "HTML_Template" class.
 * Note that even if it was the case, the interface declaration would still
 * be a good idea to implement graphic generating packages...
 * The impact of the implementation of the interface is actually quite low
 * since it serves as a bridge between the declaration and the code already
 * existing in the template engine. Therefore having this interface implemented
 * directly into the template engine classes wouldn't do them much "damage"
 * performance-wise.
 * Some template engines are also very much alike (branching from some original
 * project) so a lot of code seems redundant. Some code could have made it into
 * a higher class but then that would tie these engines back together, which
 * seems contradictory to there initial developement (i.e. getting away from
 * a common branch...)
 *
 * The methods of the interface are PEAR compliant, that is they
 * return a PEAR_Error object in case of problem. Some people may not like it
 * but I think it's a nice way to blend in, IMHO.
 *
 * As with any universally-oriented packages, this package cannot make use
 * of most advanced features of template engines. However, since the idea
 * is to make the template engines behave like black boxes, the applications
 * using this interface should not rely on the advance features one template
 * might offer. If an application wants to take advantage of such or such
 * feature, then a factory method is more appropriate, but of course then the
 * application has to add the new template engines to its "catalog". The idea
 * here, again, is to not care about what template engines are used as long as
 * they implement the interface.
 *
 * Need caching? My advice: use an separate caching package to manage a
 * cache at the application level. PEAR's Cache_Lite is a great candidate for
 * that. You can configure some template engines (for instance Smarty) to
 * automatically cache the output. These features are still available as long
 * as it's automatic. No cache ID are handled through this interface...
 *
 * @link http://www.11abacus.com/dev/pear/HTML_Template_Interface.phps
 * @author Philippe .dot. Jausions @at@ 11abacus .dot. com
 * @link http://www.11abacus.com/
 * @category Template
 * @copyright Copyright &copy; 2004, Philippe Jausions
 * @license http://www.php.net/license/3_0.txt PHP 3.0 License
 **/

/**
 * Proposed interface definition
 **/
interface Template_Interface
{
    
/**
     * Sets the template to be used.
     *
     * The type of the parameter is dependent on the template engine.
     *
     * @param  mixed $template a template (object, file name, resource...)
     * @return bool TRUE or FALSE on error
     * @access public
     **/
    
abstract public function useTemplate($template);

    
/**
     * Sets one or more values to be used by the template
     *
     * @param  mixed  $name associative array or name/identifier of data
     * @param  mixed  $data data associated identified by $name, when $name
     *                      is not an associative array.
     * @return bool TRUE or FALSE on error
     * @access public
     **/
    
abstract public function setData($name$data null);

    
/**
     * Sets one value (by reference) to be used by the template
     *
     * @param  string $name name/identifier of data
     * @param  mixed  $data reference to data associated identified by $name
     * @return bool TRUE or FALSE on error
     * @access public
     **/
    
abstract public function setDataByRef($name, &$data);

    
/**
     * Clears all previously set data
     *
     * @return bool TRUE or FALSE on error
     * @access public
     **/
    
abstract public function clearData();

    
/**
     * Returns the MIME type of the result generated by the template
     *
     * @return string|bool MIME type or FALSE on error
     * @access public
     **/
    
abstract public function getMimeType();

    
/**
     * Outputs the result of the template
     *
     * @return bool TRUE or FALSE on error
     * @access public
     **/
    
abstract public function output();

    
/**
     * Returns the result of the template as a string
     *
     * @return string|bool String result or FALSE on error
     * @access public
     **/
    
abstract public function toString();

// End [INTERFACE] Template_Interface




/* + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
 +                                                                   +
 * TemplateInterfaced for some classes                               *
 +                                                                   +
 * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */
/**
 * This class is for templating system that don't use a template
 * engine but simple templates themselves, for instance PHPTAL and
 * SmartTemplate.
 *
 * For some templating system you'll need to extend this class and the
 * openTemplate() method would take an actual object of the original
 * template class.
 *
 * @package TemplateInterfaced
 **/
abstract class TemplateInterfaced implements Template_Interface
{
    
/**
     * To hold data to be used in template
     *
     * @access protected
     * @var array
     */
    
protected $_templateData;

    
/**
     * To hold a reference to the template
     *
     * @access protected
     * @var mixed
     */
    
protected $_templateReference;

    
/**
     * To hold a options to use for the constructor
     *
     * @access protected
     * @var array
     */
    
protected $_templateOptions;

    
/**
     * Open the template to be used.
     *
     * @access public
     * @param  mixed  $template A template file name or object
     * @return mixed  TRUE or a PEAR_Error object on error
     **/
    
abstract public function openTemplate($template);

    
/**
     * Set one or more value to be used by the template
     *
     * @access public
     * @param  mixed  $name Associative array or name/identifier of data
     * @param  mixed  $data Data associated identified by $name, when $name
     *                      is not an associative array.
     **/
    
public function setData($name$data null)
    {
        if (
is_array($name)) {
            
$this->_templateData array_merge($this->_templateData$name);
        } else {
            
$this->_templateData[$name] = $data;
        }
    }

    
/**
     * Set one value (by reference) to be used by the template
     *
     * @access public
     * @param  string $name Name/identifier of data
     * @param  mixed  $data Reference to data associated identified by $name
     **/
    
public function setDataByRef($name, &$data)
    {
        
$this->_templateData[$name] =& $data;
    }

    
/**
     * Clear all previously set data
     *
     * @access public
     **/
    
public function clearData()
    {
        
$this->_templateData = array();
    }

    
/**
     * Return the MIME type of the result generated by the template
     *
     * If the template passed to openTemplate() is an object
     * this method check if the object has a method name getMimeType()
     * otherwise, we assume text/html.
     * Other templating engine can implement this method differently.
     *
     * @access public
     * @return string MIME Type or PEAR_Error object on error
     **/
    
public function getMimeType() {
        if (
is_null($this->_templateReference)) {
            return 
PEAR::raiseError('You must call openTemplate() first.');
        }
        if (
is_object($this->_templateReference)
            && 
method_exists($this->_templateReference'getMimeType')) {
            return 
$this->_templateReference->getMimeType();

        } else {
            return 
'text/html';
        }
    }

    
/**
     * Output the result of the template
     *
     * @access public
     * @return mixed TRUE or PEAR_Error on error
     **/
    
abstract public function output();

    
/**
     * Output the result of the template to a file
     *
     * @access public
     * @param  mixed  $filename Path to file or file resource
     * @return mixed  How many bytes where put or PEAR_Error object on error
     * @see fopen()
     **/
    
public function toFile($filename)
    {
        
$output $this->toString();
        if (
PEAR::isError($output)) {
            return 
$output;
        }

        if (
is_resource($filename)) {
            
$file $filename;

        } else {
            
$file = @fopen($filename'wb');
            if (!
$file) {
                return 
PEAR::raiseError('Couldn\'t open file to write template result to.');
            }
        }

        
$mgc get_magic_quotes_runtime();
        
set_magic_quotes_runtime(0);
        
$length = @fwrite($file$output);
        
set_magic_quotes_runtime($mgc);

        if (
$length === false) {
            
$return PEAR::raiseError('Couldn\'t write template result to file.');
        } else {
            
$return $length;
        }

        if (!
is_resource($filename)
            && !@
fclose($file)
            && 
is_integer($return)) {
            
$return PEAR::raiseError('Couldn\'t close file with template result.');
        }

        return 
$return;
    }

    
/**
     * Return the result of the template as a string
     *
     * @access public
     * @return string
     **/
    
abstract public function toString();

// End [CLASS] TemplateInterfaced

?>