Вход Регистрация
Файл: source/library/Savant3/Savant3.php
Строк: 960
<?php

/**

* Provides an object-oriented template system for PHP5.

* @package Savant3

* @author Paul M. Jones <pmjones@ciaweb.net>

* @license http://www.gnu.org/copyleft/lesser.html LGPL

* @version $Id: Savant3.php,v 1.42 2006/01/01 18:31:00 pmjones Exp $

*/


/**
* Always have these classes available.
*/
include_once dirname(__FILE__) . '/Savant3/Filter.php';
include_once 
dirname(__FILE__) . '/Savant3/Plugin.php';


/**

* Provides an object-oriented template system for PHP5.

* Savant3 helps you separate business logic from presentation logic
* using PHP as the template language. By default, Savant3 does not
* compile templates. However, you may pass an optional compiler object
* to compile template source to include-able PHP code.  It is E_STRICT
* compliant for PHP5.

* Please see the documentation at {@link http://phpsavant.com/}, and be
* sure to donate! :-)

* @author Paul M. Jones <pmjones@ciaweb.net>

* @package Savant3

* @version @package_version@

*/

class Savant3 {
    
    
    
/**
    * 
    * Array of configuration parameters.
    * 
    * @access protected
    * 
    * @var array
    * 
    */
    
    
protected $__config = array(
        
'template_path' => array(),
        
'resource_path' => array(),
        
'error_text'    => "nntemplate error, examine fetch() resultnn",
        
'exceptions'    => false,
        
'autoload'      => false,
        
'compiler'      => null,
        
'filters'       => array(),
        
'plugins'       => array(),
        
'template'      => null,
        
'plugin_conf'   => array(),
        
'extract'       => false,
        
'fetch'         => null,
        
'escape'        => array('htmlspecialchars'),
    );
    
    
    
// -----------------------------------------------------------------
    //
    // Constructor and magic methods
    //
    // -----------------------------------------------------------------
    
    
    /**
    * 
    * Constructor.
    * 
    * @access public
    * 
    * @param array $config An associative array of configuration keys for
    * the Savant3 object.  Any, or none, of the keys may be set.
    * 
    * @return object Savant3 A Savant3 instance.
    * 
    */
    
    
public function __construct($config null)
    {
        
// force the config to an array
        
settype($config'array');
        
        
// set the default template search path
        
if (isset($config['template_path'])) {
            
// user-defined dirs
            
$this->setPath('template'$config['template_path']);
        } else {
            
// no directories set, use the
            // default directory only
            
$this->setPath('template'null);
        }
        
        
// set the default resource search path
        
if (isset($config['resource_path'])) {
            
// user-defined dirs
            
$this->setPath('resource'$config['resource_path']);
        } else {
            
// no directories set, use the
            // default directory only
            
$this->setPath('resource'null);
        }
        
        
// set the error reporting text
        
if (isset($config['error_text'])) {
            
$this->setErrorText($config['error_text']);
        }
        
        
// set the autoload flag
        
if (isset($config['autoload'])) {
            
$this->setAutoload($config['autoload']);
        }
        
        
// set the extraction flag
        
if (isset($config['extract'])) {
            
$this->setExtract($config['extract']);
        }
        
        
// set the exceptions flag
        
if (isset($config['exceptions'])) {
            
$this->setExceptions($config['exceptions']);
        }
        
        
// set the template to use for output
        
if (isset($config['template'])) {
            
$this->setTemplate($config['template']);
        }
        
        
// set the output escaping callbacks
        
if (isset($config['escape'])) {
            
$this->setEscape($config['escape']);
        }
        
        
// set the default plugin configs
        
if (isset($config['plugin_conf']) && is_array($config['plugin_conf'])) {
            foreach (
$config['plugin_conf'] as $name => $opts) {
                
$this->setPluginConf($name$opts);
            }
        }
        
        
// set the default filter callbacks
        
if (isset($config['filters'])) {
            
$this->addFilters($config['filters']);
        }
    }
    
    
    
/**
    *
    * Executes a main plugin method with arbitrary parameters.
    * 
    * @access public
    * 
    * @param string $func The plugin method name.
    *
    * @param array $args The parameters passed to the method.
    *
    * @return mixed The plugin output, or a Savant3_Error with an
    * ERR_PLUGIN code if it can't find the plugin.
    * 
    */
    
    
public function __call($func$args)
    {
        
$plugin $this->plugin($func);
        
        if (
$this->isError($plugin)) {
            return 
$plugin;
        }
        
        
// try to avoid the very-slow call_user_func_array()
        // for plugins with very few parameters.  thanks to
        // Andreas Korthaus for profiling the code to find
        // the slowdown.
        
switch (count($args)) {
        
        case 
0:
            return 
$plugin->$func();
        
        case 
1:
            return 
$plugin->$func($args[0]);
            break;
            
        case 
2:
            return 
$plugin->$func($args[0], $args[1]);
            break;
            
        case 
3:
            return 
$plugin->$func($args[0], $args[1], $args[2]);
            break;
        
        default:
            return 
call_user_func_array(array($plugin$func), $args);
            break;
        }
    }
    
    
    
/**
    * 
    * Magic method to echo this object as template output.
    * 
    * Note that if there is an error, this will output a simple
    * error text string and will not return an error object.  Use
    * fetch() to get an error object when errors occur.
    * 
    * @access public
    *  
    * @return string The template output.
    * 
    */
    
    
public function __toString()
    {
        return 
$this->getOutput();
    }
    
    
    
/**
    * 
    * Reports the API version for this class.
    * 
    * @access public
    * 
    * @return string A PHP-standard version number.
    * 
    */
    
    
public function apiVersion()
    {
        return 
'@package_version@';
    }
    
    
    
/**
    * 
    * Returns an internal plugin object; creates it as needed.
    * 
    * @access public
    * 
    * @param string $name The plugin name.  If this plugin has not
    * been created yet, this method creates it automatically.
    *
    * @return mixed The plugin object, or a Savant3_Error with an
    * ERR_PLUGIN code if it can't find the plugin.
    * 
    */
    
    
public function plugin($name)
    {
        
// shorthand reference
        
$plugins =& $this->__config['plugins'];
        
$autoload $this->__config['autoload'];
        
        
// is the plugin method object already instantiated?
        
if (! array_key_exists($name$plugins)) {
            
            
// not already instantiated, so load it up.
            // set up the class name.
            
$class "Savant3_Plugin_$name";
            
            
// has the class been loaded?
            
if (! class_exists($class$autoload)) {
            
                
// class is not loaded, set up the file name.
                
$file "$class.php";
                
                
// make sure the class file is available from the resource path.
                
$result $this->findFile('resource'$file);
                if (! 
$result) {
                    
// not available, this is an error
                    
return $this->error(
                        
'ERR_PLUGIN',
                        array(
'method' => $name)
                    );
                } else {
                    
// available, load the class file
                    
include_once $result;
                }
            }
            
            
// get the default configuration for the plugin.
            
$plugin_conf =& $this->__config['plugin_conf'];
            if (! empty(
$plugin_conf[$name])) {
                
$opts $plugin_conf[$name];
            } else {
                
$opts = array();
            }
            
            
// add the Savant reference
            
$opts['Savant'] = $this;
            
            
// instantiate the plugin with its options.
            
$plugins[$name] = new $class($opts);
        }
    
        
// return the plugin object
        
return $plugins[$name];
    }
    
    
    
// -----------------------------------------------------------------
    //
    // Public configuration management (getters and setters).
    // 
    // -----------------------------------------------------------------
    
    
    /**
    *
    * Returns a copy of the Savant3 configuration parameters.
    *
    * @access public
    * 
    * @param string $key The specific configuration key to return.  If null,
    * returns the entire configuration array.
    * 
    * @return mixed A copy of the $this->__config array.
    * 
    */
    
    
public function getConfig($key null)
    {
        if (
is_null($key)) {
            
// no key requested, return the entire config array
            
return $this->__config;
        } elseif (empty(
$this->__config[$key])) {
            
// no such key
            
return null;
        } else {
            
// return the requested key
            
return $this->__config[$key];
        }
    }
    
    
    
/**
    * 
    * Sets __autoload() usage on or off.
    * 
    * @access public
    * 
    * @param bool $flag True to use __autoload(), false to not use it.
    * 
    * @return void
    * 
    */
    
    
public function setAutoload($flag)
    {
        
$this->__config['autoload'] = (bool) $flag;
    }
    
    
    
/**
    * 
    * Sets a custom compiler/pre-processor callback for template sources.
    * 
    * By default, Savant3 does not use a compiler; use this to set your
    * own custom compiler (pre-processor) for template sources.
    * 
    * @access public
    * 
    * @param mixed $compiler A compiler callback value suitable for the
    * first parameter of call_user_func().  Set to null/false/empty to
    * use PHP itself as the template markup (i.e., no compiling).
    * 
    * @return void
    * 
    */
    
    
public function setCompiler($compiler)
    {
        
$this->__config['compiler'] = $compiler;
    }
    
    
    
/**
    * 
    * Sets the custom error text for __toString().
    * 
    * @access public
    * 
    * @param string $text The error text when a template is echoed.
    * 
    * @return void
    * 
    */
    
    
public function setErrorText($text)
    {
        
$this->__config['error_text'] = $text;
    }
    
    
    
/**
    * 
    * Sets whether or not exceptions will be thrown.
    * 
    * @access public
    * 
    * @param bool $flag True to turn on exception throwing, false
    * to turn it off.
    * 
    * @return void
    * 
    */
    
    
public function setExceptions($flag)
    {
        
$this->__config['exceptions'] = (bool) $flag;
    }
    
    
    
/**
    * 
    * Sets whether or not variables will be extracted.
    * 
    * @access public
    * 
    * @param bool $flag True to turn on variable extraction, false
    * to turn it off.
    * 
    * @return void
    * 
    */
    
    
public function setExtract($flag)
    {
        
$this->__config['extract'] = (bool) $flag;
    }
    
    
    
/**
    *
    * Sets config array for a plugin.
    * 
    * @access public
    * 
    * @param string $plugin The plugin to configure.
    * 
    * @param array $config The configuration array for the plugin.
    * 
    * @return void
    *
    */
    
    
public function setPluginConf($plugin$config null)
    {
        
$this->__config['plugin_conf'][$plugin] = $config;
    }
    
    
    
/**
    *
    * Sets the template name to use.
    *
    * @access public
    *
    * @param string $template The template name.
    *
    * @return void
    *
    */
    
    
public function setTemplate($template)
    {
        
$this->__config['template'] = $template;
    }
    
    
    
// -----------------------------------------------------------------
    //
    // Output escaping and management.
    //
    // -----------------------------------------------------------------
    
    
    /**
    * 
    * Clears then sets the callbacks to use when calling $this->escape().
    * 
    * Each parameter passed to this function is treated as a separate
    * callback.  For example:
    * 
    * <code>
    * $savant->setEscape(
    *     'stripslashes',
    *     'htmlspecialchars',
    *     array('StaticClass', 'method'),
    *     array($object, $method)
    * );
    * </code>
    * 
    * @access public
    *
    * @return void
    *
    */
    
    
public function setEscape()
    {
        
$this->__config['escape'] = (array) @func_get_args();
    }
    
    
    
/**
    * 
    * Adds to the callbacks used when calling $this->escape().
    * 
    * Each parameter passed to this function is treated as a separate
    * callback.  For example:
    * 
    * <code>
    * $savant->addEscape(
    *     'stripslashes',
    *     'htmlspecialchars',
    *     array('StaticClass', 'method'),
    *     array($object, $method)
    * );
    * </code>
    * 
    * @access public
    *
    * @return void
    *
    */
    
    
public function addEscape()
    {
        
$args = (array) @func_get_args();
        
$this->__config['escape'] = array_merge(
            
$this->__config['escape'], $args
        
);
    }
    
    
    
/**
    *
    * Gets the array of output-escaping callbacks.
    *
    * @access public
    *
    * @return array The array of output-escaping callbacks.
    *
    */
    
    
public function getEscape()
    {
        return 
$this->__config['escape'];
    }
    
    
    
/**
    *
    * Applies escaping to a value.
    * 
    * You can override the predefined escaping callbacks by passing
    * added parameters as replacement callbacks.
    * 
    * <code>
    * // use predefined callbacks
    * $result = $savant->escape($value);
    * 
    * // use replacement callbacks
    * $result = $savant->escape(
    *     $value,
    *     'stripslashes',
    *     'htmlspecialchars',
    *     array('StaticClass', 'method'),
    *     array($object, $method)
    * );
    * </code>
    *
    * 
    * Unfortunately, a call to "echo htmlspecialchars()" is twice
    * as fast as a call to "echo $this->escape()" under the default
    * escaping (which is htmlspecialchars).  The benchmark showed
    * 0.007 seconds for htmlspecialchars(), and 0.014 seconds for
    * $this->escape(), on 300 calls each.
    * 
    * @access public
    * 
    * @param mixed $value The value to be escaped.
    * 
    * @return mixed
    *
    */
    
    
public function escape($value)
    {
        
// were custom callbacks passed?
        
if (func_num_args() == 1) {
        
            
// no, only a value was passed.
            // loop through the predefined callbacks.
            
foreach ($this->__config['escape'] as $func) {
                
// this if() shaves 0.001sec off of 300 calls.
                
if (is_string($func)) {
                    
$value $func($value);
                } else {
                    
$value call_user_func($func$value);
                }
            }
            
        } else {
        
            
// yes, use the custom callbacks
            
$callbacks func_get_args();
            
            
// drop $value
            
array_shift($callbacks);
            
            
// loop through custom callbacks.
            
foreach ($callbacks as $func) {
                
// this if() shaves 0.001sec off of 300 calls.
                
if (is_string($func)) {
                    
$value $func($value);
                } else {
                    
$value call_user_func($func$value);
                }
            }
            
        }
        
        return 
$value;
    }
    
    
    
/**
    *
    * Prints a value after escaping it for output.
    * 
    * You can override the predefined escaping callbacks by passing
    * added parameters as replacement callbacks.
    * 
    * <code>
    * // use predefined callbacks
    * $this->eprint($value);
    * 
    * // use replacement callbacks
    * $this->eprint(
    *     $value,
    *     'stripslashes',
    *     'htmlspecialchars',
    *     array('StaticClass', 'method'),
    *     array($object, $method)
    * );
    * </code>
    * 
    * @access public
    * 
    * @param mixed $value The value to be escaped and printed.
    * 
    * @return void
    *
    */
    
    
public function eprint($value)
    {
        
// avoid the very slow call_user_func_array() when there
        // are no custom escaping callbacks.  thanks to
        // Andreas Korthaus for profiling the code to find
        // the slowdown.
        
$num func_num_args();
        if (
$num == 1) {
            echo 
$this->escape($value);
        } else {
            
$args func_get_args();
            echo 
call_user_func_array(
                array(
$this'escape'),
                
$args
            
);
        }
    }
    
    
    
// -----------------------------------------------------------------
    //
    // File management
    //
    // -----------------------------------------------------------------
    
    
    /**
    *
    * Sets an entire array of search paths for templates or resources.
    *
    * @access public
    *
    * @param string $type The type of path to set, typically 'template'
    * or 'resource'.
    * 
    * @param string|array $path The new set of search paths.  If null or
    * false, resets to the current directory only.
    *
    * @return void
    *
    */
    
    
public function setPath($type$path)
    {
        
// clear out the prior search dirs
        
$this->__config[$type '_path'] = array();
        
        
// always add the fallback directories as last resort
        
switch (strtolower($type)) {
        case 
'template':
            
// the current directory
            
$this->addPath($type'.');
            break;
        case 
'resource':
            
// the Savant3 distribution resources
            
$this->addPath($typedirname(__FILE__) . '/Savant3/resources/');
            break;
        }
        
        
// actually add the user-specified directories
        
$this->addPath($type$path);
    }
    
    
    
/**
    *
    * Adds to the search path for templates and resources.
    *
    * @access public
    *
    * @param string|array $path The directory or stream to search.
    *
    * @return void
    *
    */
    
    
public function addPath($type$path)
    {
        
// convert from path string to array of directories
        
if (is_string($path) && ! strpos($path'://')) {
        
            
// the path config is a string, and it's not a stream
            // identifier (the "://" piece). add it as a path string.
            
$path explode(PATH_SEPARATOR$path);
            
            
// typically in path strings, the first one is expected
            // to be searched first. however, Savant3 uses a stack,
            // so the first would be last.  reverse the path string
            // so that it behaves as expected with path strings.
            
$path array_reverse($path);
            
        } else {
        
            
// just force to array
            
settype($path'array');
            
        }
        
        
// loop through the path directories
        
foreach ($path as $dir) {
        
            
// no surrounding spaces allowed!
            
$dir trim($dir);
            
            
// add trailing separators as needed
            
if (strpos($dir'://') && substr($dir, -1) != '/') {
                
// stream
                
$dir .= '/';
            } elseif (
substr($dir, -1) != DIRECTORY_SEPARATOR) {
                
// directory
                
$dir .= DIRECTORY_SEPARATOR;
            }
            
            
// add to the top of the search dirs
            
array_unshift(
                
$this->__config[$type '_path'],
                
$dir
            
);
        }
    }
    
    
    
/**
    * 
    * Searches the directory paths for a given file.
    * 
    * @param array $type The type of path to search (template or resource).
    * 
    * @param string $file The file name to look for.
    * 
    * @return string|bool The full path and file name for the target file,
    * or boolean false if the file is not found in any of the paths.
    *
    */
    
    
protected function findFile($type$file)
    {
        
// get the set of paths
        
$set $this->__config[$type '_path'];
        
        
// start looping through the path set
        
foreach ($set as $path) {
            
            
// get the path to the file
            
$fullname $path $file;
            
            
// is the path based on a stream?
            
if (strpos($path'://') === false) {
                
// not a stream, so do a realpath() to avoid
                // directory traversal attempts on the local file
                // system. Suggested by Ian Eure, initially
                // rejected, but then adopted when the secure
                // compiler was added.
                
$path realpath($path); // needed for substr() later
                
$fullname realpath($fullname);
            }
            
            
// the substr() check added by Ian Eure to make sure
            // that the realpath() results in a directory registered
            // with Savant so that non-registered directores are not
            // accessible via directory traversal attempts.
            
if (file_exists($fullname) && is_readable($fullname) &&
                
substr($fullname0strlen($path)) == $path) {
                return 
$fullname;
            }
        }
        
        
// could not find the file in the set of paths
        
return false;
    }
    
    
    
// -----------------------------------------------------------------
    //
    // Variable and reference assignment
    //
    // -----------------------------------------------------------------
    
    
    /**
    * 
    * Sets variables for the template (by copy).
    * 
    * This method is overloaded; you can assign all the properties of
    * an object, an associative array, or a single value by name.
    * 
    * You are not allowed to assign any variable named '__config' as
    * it would conflict with internal configuration tracking.
    * 
    * In the following examples, the template will have two variables
    * assigned to it; the variables will be known inside the template as
    * "$this->var1" and "$this->var2".
    * 
    * <code>
    * $Savant3 = new Savant3();
    * 
    * // assign by object
    * $obj = new stdClass;
    * $obj->var1 = 'something';
    * $obj->var2 = 'else';
    * $Savant3->assign($obj);
    * 
    * // assign by associative array
    * $ary = array('var1' => 'something', 'var2' => 'else');
    * $Savant3->assign($ary);
    * 
    * // assign by name and value
    * $Savant3->assign('var1', 'something');
    * $Savant3->assign('var2', 'else');
    * 
    * // assign directly
    * $Savant3->var1 = 'something';
    * $Savant3->var2 = 'else';
    * </code>
    * 
    * @access public
    * 
    * @return bool True on success, false on failure.
    * 
    */
    
    
public function assign()
    {
        
// get the arguments; there may be 1 or 2.
        
$arg0 = @func_get_arg(0);
        
$arg1 = @func_get_arg(1);
        
        
// assign from object
        
if (is_object($arg0)) {
            
// assign public properties
            
foreach (get_object_vars($arg0) as $key => $val) {
                
// can't assign to __config
                
if ($key != '__config') {
                    
$this->$key $val;
                }
            }
            return 
true;
        }
        
        
// assign from associative array
        
if (is_array($arg0)) {
            foreach (
$arg0 as $key => $val) {
                
// can't assign to __config
                
if ($key != '__config') {
                    
$this->$key $val;
                }
            }
            return 
true;
        }
        
        
// assign by name and value (can't assign to __config).
        
if (is_string($arg0) && func_num_args() > && $arg0 != '__config') {
            
$this->$arg0 $arg1;
            return 
true;
        }
        
        
// $arg0 was not object, array, or string.
        
return false;
    }
    
    
    
/**
    * 
    * Sets variables for the template (by reference).
    * 
    * You are not allowed to assign any variable named '__config' as
    * it would conflict with internal configuration tracking.
    * 
    * <code>
    * $Savant3 = new Savant3();
    * 
    * // assign by name and value
    * $Savant3->assignRef('var1', $ref);
    * 
    * // assign directly
    * $Savant3->ref =& $var1;
    * </code>
    * 
    * @access public
    * 
    * @return bool True on success, false on failure.
    * 
    */
    
    
public function assignRef($key, &$val)
    {
        
// assign by name and reference (can't assign to __config).
        
if ($key != '__config') {
            
$this->$key =& $val;
            return 
true;
        } else {
            return 
false;
        }
    }
    
    
    
// -----------------------------------------------------------------
    //
    // Template processing
    //
    // -----------------------------------------------------------------
    
    
    /**
    * 
    * Displays a template directly (equivalent to <code>echo $tpl</code>).
    * 
    * @access public
    * 
    * @param string $tpl The template source to compile and display.
    * 
    * @return void
    * 
    */
    
    
public function display($tpl null)
    {
        echo 
$this->getOutput($tpl);
    }
    
    
/**
     * Returns output, including error_text if an error occurs.
     * 
     * @param $tpl The template to process; if null, uses the
     * default template set with setTemplate().
     * 
     * @return string The template output.
     */
    
public function getOutput($tpl null)
    {
        
$output $this->fetch($tpl);
        if (
$this->isError($output)) {
            
$text $this->__config['error_text'];
            return 
$this->escape($text);
        } else {
            return 
$output;
        }
    }
    
    
    
/**
    * 
    * Compiles, executes, and filters a template source.
    * 
    * @access public
    * 
    * @param string $tpl The template to process; if null, uses the
    * default template set with setTemplate().
    * 
    * @return mixed The template output string, or a Savant3_Error.
    * 
    */
    
    
public function fetch($tpl null)
    {
        
// make sure we have a template source to work with
        
if (is_null($tpl)) {
            
$tpl $this->__config['template'];
        }
        
        
// get a path to the compiled template script
        
$result $this->template($tpl);
        
        
// did we get a path?
        
if (! $result || $this->isError($result)) {
        
            
// no. return the error result.
            
return $result;
            
        } else {
        
            
// yes.  execute the template script.  move the script-path
            // out of the local scope, then clean up the local scope to
            // avoid variable name conflicts.
            
$this->__config['fetch'] = $result;
            unset(
$result);
            unset(
$tpl);
            
            
// are we doing extraction?
            
if ($this->__config['extract']) {
                
// pull variables into the local scope.
                
extract(get_object_vars($this), EXTR_REFS);
            }
            
            
// buffer output so we can return it instead of displaying.
            
ob_start();
            
            
// are we using filters?
            
if ($this->__config['filters']) {
                
// use a second buffer to apply filters. we used to set
                // the ob_start() filter callback, but that would
                // silence errors in the filters. Hendy Irawan provided
                // the next three lines as a "verbose" fix.
                
ob_start();
                include 
$this->__config['fetch'];
                echo 
$this->applyFilters(ob_get_clean());
            } else {
                
// no filters being used.
                
include $this->__config['fetch'];
            }
            
            
// reset the fetch script value, get the buffer, and return.
            
$this->__config['fetch'] = null;
            return 
ob_get_clean();
        }
    }
    
    
    
/**
    *
    * Compiles a template and returns path to compiled script.
    * 
    * By default, Savant does not compile templates, it uses PHP as the
    * markup language, so the "compiled" template is the same as the source
    * template.
    * 
    * Used inside a template script like so:
    * 
    * <code>
    * include $this->template($tpl);
    * </code>
    * 
    * @access protected
    *
    * @param string $tpl The template source name to look for.
    * 
    * @return string The full path to the compiled template script.
    * 
    * @throws object An error object with a 'ERR_TEMPLATE' code.
    * 
    */
    
    
protected function template($tpl null)
    {
        
// set to default template if none specified.
        
if (is_null($tpl)) {
            
$tpl $this->__config['template'];
        }
        
        
// find the template source.
        
$file $this->findFile('template'$tpl);
        if (! 
$file) {
            return 
$this->error(
                
'ERR_TEMPLATE',
                array(
'template' => $tpl)
            );
        }
        
        
// are we compiling source into a script?
        
if ($this->__config['compiler']) {
            
// compile the template source and get the path to the
            // compiled script (will be returned instead of the
            // source path)
            
$result call_user_func(
                array(
$this->__config['compiler'], 'compile'),
                
$file
            
);
        } else {
            
// no compiling requested, use the source path
            
$result $file;
        }
        
        
// is there a script from the compiler?
        
if (! $result || $this->isError($result)) {
            
// return an error, along with any error info
            // generated by the compiler.
            
return $this->error(
                
'ERR_COMPILER',
                array(
                    
'template' => $tpl,
                    
'compiler' => $result
                
)
            );
        } else {
            
// no errors, the result is a path to a script
            
return $result;
        }
    }
    
    
    
// -----------------------------------------------------------------
    //
    // Filter management and processing
    //
    // -----------------------------------------------------------------
    
    
    /**
    * 
    * Resets the filter stack to the provided list of callbacks.
    * 
    * @access protected
    * 
    * @param array An array of filter callbacks.
    * 
    * @return void
    * 
    */
    
    
public function setFilters()
    {
        
$this->__config['filters'] = (array) @func_get_args();
    }
    
    
    
/**
    * 
    * Adds filter callbacks to the stack of filters.
    * 
    * @access protected
    * 
    * @param array An array of filter callbacks.
    * 
    * @return void
    * 
    */
    
    
public function addFilters()
    {
        
// add the new filters to the static config variable
        // via the reference
        
foreach ((array) @func_get_args() as $callback) {
            
$this->__config['filters'][] = $callback;
        }
    }
    
    
    
/**
    * 
    * Runs all filter callbacks on buffered output.
    * 
    * @access protected
    * 
    * @param string The template output.
    * 
    * @return void
    * 
    */
    
    
protected function applyFilters($buffer)
    {
       
$autoload $this->__config['autoload'];
        foreach (
$this->__config['filters'] as $callback) {
        
            
// if the callback is a static Savant3_Filter method,
            // and not already loaded, try to auto-load it.
            
if (is_array($callback) &&
                
is_string($callback[0]) &&
                
substr($callback[0], 015) == 'Savant3_Filter_' &&
                ! 
class_exists($callback[0], $autoload)) {
                
                
// load the Savant3_Filter_*.php resource
                
$file $callback[0] . '.php';
                
$result $this->findFile('resource'$file);
                if (
$result) {
                    include_once 
$result;
                }
            }
            
            
// can't pass a third $this param, it chokes the OB system.
            
$buffer call_user_func($callback$buffer);
        }
        
        return 
$buffer;
    }
    
    
    
// -----------------------------------------------------------------
    //
    // Error handling
    //
    // -----------------------------------------------------------------
    
    
    /**
    *
    * Returns an error object or throws an exception.
    * 
    * @access public
    * 
    * @param string $code A Savant3 'ERR_*' string.
    * 
    * @param array $info An array of error-specific information.
    * 
    * @param int $level The error severity level, default is
    * E_USER_ERROR (the most severe possible).
    * 
    * @param bool $trace Whether or not to include a backtrace, default
    * true.
    * 
    * @return object Savant3_Error
    * 
    */
    
    
public function error($code$info = array(), $level E_USER_ERROR,
        
$trace true)
    {
        
$autoload $this->__config['autoload'];
        
        
// are we throwing exceptions?
        
if ($this->__config['exceptions']) {
            if (! 
class_exists('Savant3_Exception'$autoload)) {
                include_once 
dirname(__FILE__) . '/Savant3/Exception.php';
            }
            throw new 
Savant3_Exception($code);
        }
        
        
        
// the error config array
        
$config = array(
            
'code'  => $code,
            
'info'  => (array) $info,
            
'level' => $level,
            
'trace' => $trace
        
);
        
        
// make sure the Savant3 error class is available
        
if (! class_exists('Savant3_Error'$autoload)) {
            include_once 
dirname(__FILE__) . '/Savant3/Error.php';
        }
        
        
// return it
        
$err = new Savant3_Error($config);
        return 
$err;
    }
    
    
    
/**
    *
    * Tests if an object is of the Savant3_Error class.
    * 
    * @access public
    * 
    * @param object $obj The object to be tested.
    * 
    * @return boolean True if $obj is an error object of the type
    * Savant3_Error, or is a subclass that Savant3_Error. False if not.
    *
    */
    
    
public function isError($obj)
    {
        
$autoload $this->__config['autoload'];
        
        
// is it even an object?
        
if (! is_object($obj)) {
            
// not an object, so can't be a Savant3_Error
            
return false;
        } else {
            
// make sure the Savant3 error class is available for
            // comparison
            
if (! class_exists('Savant3_Error'$autoload)) {
                include_once 
dirname(__FILE__) . '/Savant3/Error.php';
            }
            
// now compare the parentage
            
$is $obj instanceof Savant3_Error;
            
$sub is_subclass_of($obj'Savant3_Error');
            return (
$is || $sub);
        }
    }
}
?>
Онлайн: 0
Реклама