#native_company# #native_desc#
#native_cta#

Guise Template Class

By Tim
on June 23, 2008

Version: 2.0

Type: Class

Category: Other

License: GNU General Public License

Description: Guise is a template class written in PHP that allows you to keep HTML seperate from your PHP code. This is especially helpful for larger projects or when you’re working with a team in keeping things organized and readable.

<?php
/**
 * Guise Template Class 2.0
 * (c)2008 TD Fellows
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */

/**#@+
 * Constants
 */
/**
 * New Line
 */
define( 'GUISE_NL', "n" );

/**
 * @author TD Fellows <[email protected]>
 * @copyright 2008 TD Fellows
 * @version 2.0
 * @package Guise
 */
class Guise
{
    /**
     * The last occuring error.
     *
     * @access public
     * @var string
     */
    public $errstr = '';

    /**#@+
     * Private variables
     * @access private
     */

    /**
     * With Debugging enabled, errors will be verbose.
     *
     * @var boolean
     */
    private $debugging = false;

    /**
     * Array containing structured template data.
     *
     * @var array
     */
    private $template_items = array();

    /**
     * Array containing structured template data.
     *
     * @var array
     */
    private $block_templates = array();

    /**
     * Root template directory.
     *
     * @var string
     */
    private $template_root = '';

    /**#@-*/

    /**#@+
     * Public functions
     * @access public
     */

    /**
    * Constructor.
    *
    * @param string $path Path to template directory
    * @param boolean $debug Enables debugging
    */
    public function Guise( $path = '/', $debug = false )
    {
        if ( !$this->set_root( $path ) ) {
            return false;
        } else {
            $this->debugging = $debug;
            return true;
        }
    }

    /**
    * Clear item and block template arrays.
    */
    public function clear()
    {
        $this->template_items = array();
        $this->block_templates = array();
    }

    /**
    * Set template root directory. {@link $template_root}
    *
    * @param string $path Path to template directory
    * @return boolean
    */
    public function set_root( $path )
    {
        if ( substr( $path, -1 ) != '/' ) {
            $path .= '/';
        }
        if ( is_dir( $path ) ) {
            $this->template_root = $path;
            return true;
        } else {
            $this->set_error( 'Guise->set_root', "(<b>$root</b>) is not a valid directory." );
            return false;
        }
    }

    /**
    * Add an item or array to the item array.
    *
    * @param string $item_name Name of variable or array
    * @param string $item_value Value of variable
    * @return boolean
    */
    public function add_item( $item_name, $item_value = null )
    {
        if ( is_array( $item_name ) ) {
            foreach( $item_name as $key => $value ) {
                $this->template_items[$key] = $value;
            }
            return true;
        } else {
            if ( empty( $item_name ) ) {
                $this->set_error( 'Guise->add_item', 'item name must not be empty.' );
                return false;
            } else {
                $this->template_items[$item_name] = $item_value;
                return true;
            }
        }
    }

    /**
    * Compile files with structured array.
    *
    * @param string $files List of files to be parsed seperated by commas.
    * @return string|boolean
    */
    public function compile( $files )
    {
        $handle = 0;
        $page = '';
        $line = '';
        $file_list = explode( ',', $files );
        foreach( $file_list as $file ) {
            if ( substr( $file, 1, 2 ) != ":/" && substr( $file, 0, 1 ) != "/" ) {
                $file = $this->template_root.$file;
            }
            if ( !file_exists( $file ) ) {
                $this->set_error( 'Guise->compile', "(<b>$file</b>) no such file." );
                return false;
            } else {
                $handle = @fopen( $file, 'r' );
            }
            if ( $handle ) {
                while ( !feof( $handle ) ) {
                    $line = fgets( $handle );
                    if ( preg_match( '/^(.*?)(<block(.*?)name=("|')(.*?)("|')(.*?)>)(.*?)$/i', $line, $block_matches ) ) {
                        $line = $this->load_blocks( $handle, $block_matches );
                    }
                    if ( preg_match_all( '/<item(.*?)name=("|')(.*?)("|')(.*?)>/i', $line, $vars ) ) {
                        foreach( $vars[0] as $key => $value ) {
                            $line = str_replace( $value, $this->template_items[$vars[3][$key]], $line );
                        }
                    }
                    if ( preg_match_all( '/("|')(item.([a-z0-9_]*))("|')/i', $line, $vars ) ) {
                        foreach( $vars[2] as $key => $value ) {
                            $line = str_replace( $value, $this->template_items[$vars[3][$key]], $line );
                        }
                    }
                    $page .= $line;
                }
            } else {
                $this->set_error( 'Guise->compile', "(<b>$file</b>) unable to open stream." );
                return false;
            }
        }
        $page = $this->compile_blocks( $this->template_items, $page );
        $page = $this->cleanup( $page );
        return $page;
    }

    /**#@-*/

    /**#@+
     * Private functions
     * @access private
     */

    /**
    * Remove left over template information.
    *
    * @param string $string The string to be cleaned
    * @return string
    */
    private function cleanup( $string )
    {
        $matches = array(
            "/<item(.*?)>/i",
            "/<block(.*?)>/i"
        );
        $string = preg_replace( $matches, "", $string );
        if ( preg_match( '/</block>/', $string ) ) {
            $this->set_error( 'Guise->compile', 'invalid block usage. One or more blocks may not be parsed.' );
        }
        return $string;
    }

    /**
    * Set last occuring error, echo on debug.
    *
    * @param string $subject Where the error was encountered
    * @param string $error Error string
    */
    private function set_error( $subject, $error )
    {
        $this->last_error = "<br /><b>Warning</b>: $subject, $error<br />";
        if ( $this->debugging ) {
            echo $this->last_error;
        }
    }

    /**
    * Move block templates from the main template to an array.
    *
    * @param integer $handle File handle
    * @param string $block_matches Array from preg_match matching start of block
    * @return string
    */
    private function load_blocks( $handle, $block_matches )
    {
        if ( trim( $block_matches[1] ) != '' ) {
            $source_tpl = $block_matches[1];
        }
        if ( trim( $block_matches[8] ) != '' ) {
            $block_tpl = $block_matches[8].GUISE_NL;
        }
        $block_name = $block_matches[5];
        if ( empty( $block_name ) ) {
            $this->set_error( 'Guise->compile', 'invalid BLOCK format. NAME attribute must contain a value.' );
            $source_tpl = $block_matches[0];
            return $source_tpl;
        } else {
            $source_tpl .= "<block name='$block_name'>";
        }
        while ( !feof( $handle ) ) {
            $line = fgets( $handle );
            if ( preg_match( '/^(.*?)</block>(.*?)$/i', $line, $end_matches ) ) {
                if ( trim( $end_matches[1] ) != '' ) {
                    $block_tpl .= $end_matches[1];
                }
                $source_tpl .= $end_matches[2];
                break;
            } elseif ( preg_match( '/^(.*?)(<block(.*?)name=("|')(.*?)("|')(.*?)>)(.*?)$/i', $line, $child_matches ) ) {
                $block_tpl .= $this->load_blocks( $handle, $child_matches );
            } else {
                $block_tpl .= $line;
            }
        }
        $this->block_templates[$block_name] = $block_tpl;
        return $source_tpl;
    }

    /**
    * Compile blocks.
    *
    * @param array $start_array Point in the item array to begin parsing
    * @param string $source_tpl The source template, either a page or block
    * @return string
    */
    private function compile_blocks( $start_array, $source_tpl )
    {
        $result = $source_tpl;
        $cycle_result = '';
        $block_name = '';
        $block_tpl = '';
        foreach( $start_array as $start_key => $start_value ) {
            if ( is_array( $start_array[$start_key] ) ) {
                $block_name = $start_key;
                $block_tpl = $this->block_templates[$start_key];
                for ( $i=0; ;$i++ ) {
                    if ( array_key_exists( $i, $start_array[$block_name] ) ) {
                        $cycle_result = $block_tpl;
                        foreach( $start_array[$block_name][$i] as $contents_key => $contents_value ) {
                            if ( is_array( $contents_value ) ) {
                                $cycle_result = $this->compile_blocks(
                                    $start_array[$block_name][$i],
                                    $cycle_result );
                            } else {
                                $cycle_result = preg_replace(
                                    "/<item(.*?)name=("|')$contents_key("|')(.*?)>/i",
                                    $contents_value,
                                    $cycle_result );
                                $cycle_result = preg_replace(
                                    "/("|')(item.($contents_key))("|')/i",
                                    '"'.$contents_value.'"',
                                    $cycle_result );
                            }
                        }
                        $result = str_replace(
                            "<block name='$block_name'>",
                            $cycle_result."<block name='$block_name'>",
                            $result );
                    } else {
                        break;
                    }
                }
            }
        }
        return $result;
    }

    /**#@-*/
}
?>