9 define('SAVANT2_ERROR_ASSIGN', -1);
10 define('SAVANT2_ERROR_ASSIGNREF', -2);
11 define('SAVANT2_ERROR_COMPILER', -3);
12 define('SAVANT2_ERROR_NOFILTER', -4);
13 define('SAVANT2_ERROR_NOPLUGIN', -5);
14 define('SAVANT2_ERROR_NOSCRIPT', -6);
15 define('SAVANT2_ERROR_NOTEMPLATE', -7);
16 define('SAVANT2_ERROR_COMPILE_FAIL', -8);
25 if (! isset($GLOBALS['_SAVANT2']['error'])) {
26 $GLOBALS['_SAVANT2']['error'] = array(
27 SAVANT2_ERROR_ASSIGN => 'assign() parameters not correct',
28 SAVANT2_ERROR_ASSIGNREF => 'assignRef() parameters not correct',
29 SAVANT2_ERROR_COMPILER => 'compiler not an object or has no compile() method',
30 SAVANT2_ERROR_NOFILTER => 'filter file not found',
31 SAVANT2_ERROR_NOPLUGIN => 'plugin file not found',
32 SAVANT2_ERROR_NOSCRIPT => 'compiled template script file not found',
33 SAVANT2_ERROR_NOTEMPLATE => 'template source file not found',
34 SAVANT2_ERROR_COMPILE_FAIL => 'template source failed to compile'
41 * Provides an object-oriented template system.
43 * Savant2 helps you separate model logic from view logic using PHP as
44 * the template language. By default, Savant2 does not compile templates.
45 * However, you may pass an optional compiler object to compile template
46 * source to include-able PHP code.
48 * Please see the documentation at {@link http://phpsavant.com/}, and be
51 * $Id: Savant2.php,v 1.32 2006/03/05 16:58:38 pmjones Exp $
53 * @author Paul M. Jones <pmjones@ciaweb.net>
57 * @version 2.4.3 stable
59 * @license LGPL http://www.gnu.org/copyleft/lesser.html
61 * This program is free software; you can redistribute it and/or modify
62 * it under the terms of the GNU Lesser General Public License as
63 * published by the Free Software Foundation; either version 2.1 of the
64 * License, or (at your option) any later version.
66 * This program is distributed in the hope that it will be useful, but
67 * WITHOUT ANY WARRANTY; without even the implied warranty of
68 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
69 * Lesser General Public License for more details.
78 * PHP5 ONLY: Whether or not to use __autoload(). Default is false.
86 var $_autoload = false;
91 * PHP5 ONLY: What method __call() will alias to.
93 * Generally 'plugin' or 'splugin' (as __call() is intended for those).
101 var $_call = 'plugin';
106 * The custom compiler (pre-processor) object, if any.
114 var $_compiler = null;
119 * The class type to use when instantiating error objects.
132 * Array of callbacks used to escape output.
148 var $_escape = array('htmlspecialchars');
153 * Whether or not to extract assigned variables into fetch() scope.
155 * When true, all variables and references assigned to Savant2 are
156 * extracted into the local scope of the template script at fetch()
157 * time, and may be addressed as "$varname" instead of
158 * "$this->varname". The "$this->varname" notation will also work.
160 * When false, you //must// use "$this->varname" in your templates to
161 * address a variable instead of "$varname". This has three
162 * benefits: speed (no time spent extracting variables), memory use
163 * (saves RAM by not making new references to variables), and clarity
164 * (any $this->varname is obviously an assigned var, and vars created
165 * within the template are not prefixed with $this).
173 var $_extract = false;
178 * The output of the template script.
191 * The set of search directories for resources (plugins/filters) and
201 'resource' => array(),
202 'template' => array()
208 * Array of resource (plugin/filter) object instances.
216 var $_resource = array(
224 * Whether or not to automatically self-reference in plugins and filters.
232 var $_reference = false;
237 * Whether or not to restrict template includes only to registered paths.
245 var $_restrict = false;
250 * The path to the compiled template script file.
252 * By default, the template source and template script are the same file.
265 * The name of the default template source file.
273 var $_template = null;
276 // -----------------------------------------------------------------
278 // Constructor and general property setters
280 // -----------------------------------------------------------------
289 * @param array $conf An associative array of configuration keys for
290 * the Savant2 object. Any, or none, of the keys may be set. The
293 * 'template_path' => The default path string or array of directories
294 * to search for templates.
296 * 'resource_path' => The default path string or array of directories
297 * to search for plugin and filter resources.
299 * 'error' => The custom error class that Savant2 should use
300 * when returning errors.
302 * 'extract' => Whether or not to extract variables into the local
303 * scope when executing a template.
305 * 'template' => The default template source name to use.
309 function Savant2($conf = array())
311 // set the default template search dirs
312 if (isset($conf['template_path'])) {
314 $this->setPath('template', $conf['template_path']);
316 // default directory only
317 $this->setPath('template', null);
320 // set the default filter search dirs
321 if (isset($conf['resource_path'])) {
323 $this->setPath('resource', $conf['resource_path']);
325 // default directory only
326 $this->setPath('resource', null);
329 // do we allow __autoload() use?
330 if (isset($conf['autoload'])) {
331 $this->setAutoload($conf['autoload']);
334 // set the error class
335 if (isset($conf['error'])) {
336 $this->setError($conf['error']);
339 // set the extraction flag
340 if (isset($conf['extract'])) {
341 $this->setExtract($conf['extract']);
344 // set the restrict flag
345 if (isset($conf['restrict'])) {
346 $this->setRestrict($conf['restrict']);
349 // set the Savant reference flag
350 if (isset($conf['reference'])) {
351 $this->setReference($conf['reference']);
354 // set the default template
355 if (isset($conf['template'])) {
356 $this->setTemplate($conf['template']);
359 // set the output escaping callbacks
360 if (isset($config['escape'])) {
361 call_user_func_array(
362 array($this, 'setEscape'),
363 (array) $config['escape']
370 * Sets whether or not __autoload() is used when loading classes.
374 * @param bool $flag True to use __autoload(), false to not use it.
380 function setAutoload($flag) {
381 $this->_autoload = (bool) $flag;
387 * Sets a custom compiler/pre-processor for template sources.
389 * By default, Savant2 does not use a compiler; use this to set your
390 * own custom compiler (pre-processor) for template sources.
394 * @param object $compiler The compiler object; it must have a
395 * "compile()" method. If null or false, the current compiler object
396 * is removed from Savant2.
400 * @throws object An error object with a SAVANT2_ERROR_COMPILER code.
404 function setCompiler(&$compiler)
407 // nullify any current compiler
408 $this->_compiler = null;
409 } elseif (is_object($compiler) && method_exists($compiler, 'compile')) {
410 // refer to a compiler object
411 $this->_compiler =& $compiler;
413 // no usable compiler passed
414 $this->_compiler = null;
415 return $this->error(SAVANT2_ERROR_COMPILER);
422 * Sets the method that __call() will alias to.
426 * @param string $method The Savant2 method for __call() to alias to,
427 * generally 'plugin' or 'splugin'.
433 function setCall($method = 'plugin')
435 $this->_call = $method;
441 * Sets the custom error class for Savant2 errors.
445 * @param string $error The name of the custom error class name; if
446 * null or false, resets the error class to 'Savant2_Error'.
452 function setError($error)
455 $this->_error = null;
457 $this->_error = $error;
464 * Turns path checking on/off.
468 * @param bool $flag True to turn on path checks, false to turn off.
474 function setRestrict($flag = false)
477 $this->_restrict = true;
479 $this->_restrict = false;
486 * Turns extraction of variables on/off.
490 * @param bool $flag True to turn on extraction, false to turn off.
496 function setExtract($flag = true)
499 $this->_extract = true;
501 $this->_extract = false;
508 * Sets the automated Savant reference for plugins and filters.
512 * @param bool $flag Whether to reference Savant2 or not.
518 function setReference($flag = false)
520 $this->_reference = $flag;
526 * Sets the default template name.
530 * @param string $template The default template name.
536 function setTemplate($template)
538 $this->_template = $template;
544 * Internal version of class_exists() to allow for differing behaviors.
546 * Under PHP4, there is only 1 param to class_exists(); in PHP5, there
547 * are two. However, if you pass 2 params to the PHP4 version, you get
548 * a parameter count warning; hence, this method.
550 * Under PHP5, checks $this->_autload to see if __autoload() should be
555 * @param string $class A class name.
557 * @return bool Whether or not the class exists.
561 function _classExists($class) {
562 if (PHP_VERSION < '5') {
564 return class_exists($class);
567 return class_exists($class, $this->_autoload);
572 // -----------------------------------------------------------------
574 // Output escaping and management.
576 // -----------------------------------------------------------------
581 * Clears then sets the callbacks to use when calling $this->escape().
583 * Each parameter passed to this function is treated as a separate
584 * callback. For example:
587 * $savant->setEscape(
589 * 'htmlspecialchars',
590 * array('StaticClass', 'method'),
591 * array($object, $method)
603 $this->_escape = func_get_args();
609 * Adds to the callbacks used when calling $this->escape().
611 * Each parameter passed to this function is treated as a separate
612 * callback. For example:
615 * $savant->addEscape(
617 * 'htmlspecialchars',
618 * array('StaticClass', 'method'),
619 * array($object, $method)
631 $args = func_get_args();
632 $this->_escape = array_merge($this->_escape, $args);
638 * Gets the array of output-escaping callbacks.
642 * @return array The array of output-escaping callbacks.
648 return $this->_escape;
654 * Applies escaping to a value.
656 * You can override the predefined escaping callbacks by passing
657 * added parameters as replacement callbacks.
660 * // use predefined callbacks
661 * $result = $savant->escape($value);
663 * // use replacement callbacks
664 * $result = $savant->escape(
667 * 'htmlspecialchars',
668 * array('StaticClass', 'method'),
669 * array($object, $method)
675 * @param mixed $value The value to be escaped.
681 function escape($value)
683 // were custom callbacks passed?
684 if (func_num_args() == 1) {
686 // no, only a value was passed.
687 // loop through the predefined callbacks.
688 foreach ($this->_escape as $func) {
689 $value = call_user_func($func, $value);
694 // yes, use the custom callbacks instead.
695 $callbacks = func_get_args();
698 array_shift($callbacks);
700 // loop through custom callbacks.
701 foreach ($callbacks as $func) {
702 $value = call_user_func($func, $value);
713 * Prints a value after escaping it for output.
715 * You can override the predefined escaping callbacks by passing
716 * added parameters as replacement callbacks.
719 * // use predefined callbacks
722 * // use replacement callbacks
726 * 'htmlspecialchars',
727 * array('StaticClass', 'method'),
728 * array($object, $method)
734 * @param mixed $value The value to be escaped and printed.
740 function eprint($value)
742 $args = func_get_args();
743 echo call_user_func_array(
744 array($this, 'escape'),
752 * Alias to eprint() and identical in every way.
756 * @param mixed $value The value to be escaped and printed.
764 $args = func_get_args();
765 return call_user_func_array(
766 array($this, 'eprint'),
773 // -----------------------------------------------------------------
775 // Path management and file finding
777 // -----------------------------------------------------------------
782 * Sets an entire array of search paths.
786 * @param string $type The type of path to set, typcially 'template'
789 * @param string|array $new The new set of search paths. If null or
790 * false, resets to the current directory only.
796 function setPath($type, $new)
798 // clear out the prior search dirs
799 $this->_path[$type] = array();
801 // convert from string to path
802 if (is_string($new) && ! strpos($new, '://')) {
803 // the search config is a string, and it's not a stream
804 // identifier (the "://" piece), add it as a path
806 $new = explode(PATH_SEPARATOR, $new);
809 settype($new, 'array');
812 // always add the fallback directories as last resort
813 switch (strtolower($type)) {
815 $this->addPath($type, '.');
818 $this->addPath($type, dirname(__FILE__) . '/Savant2/');
822 // actually add the user-specified directories
823 foreach ($new as $dir) {
824 $this->addPath($type, $dir);
831 * Adds a search directory for templates.
835 * @param string $dir The directory or stream to search.
841 function addPath($type, $dir)
843 // no surrounding spaces allowed!
846 // add trailing separators as needed
847 if (strpos($dir, '://') && substr($dir, -1) != '/') {
850 } elseif (substr($dir, -1) != DIRECTORY_SEPARATOR) {
852 $dir .= DIRECTORY_SEPARATOR;
855 // add to the top of the search dirs
856 array_unshift($this->_path[$type], $dir);
862 * Gets the array of search directories for template sources.
866 * @return array The array of search directories for template sources.
870 function getPath($type = null)
875 return $this->_path[$type];
882 * Searches a series of paths for a given file.
884 * @param array $type The type of paths to search (template, plugin,
887 * @param string $file The file name to look for.
889 * @return string|bool The full path and file name for the target file,
890 * or boolean false if the file is not found in any of the paths.
894 function findFile($type, $file)
896 // get the set of paths
897 $set = $this->getPath($type);
899 // start looping through them
900 foreach ($set as $path) {
902 // get the path to the file
903 $fullname = $path . $file;
905 // are we doing path checks?
906 if (! $this->_restrict) {
908 // no. this is faster but less secure.
909 if (file_exists($fullname) && is_readable($fullname)) {
915 // yes. this is slower, but attempts to restrict
916 // access only to defined paths.
918 // is the path based on a stream?
919 if (strpos($path, '://') === false) {
920 // not a stream, so do a realpath() to avoid
921 // directory traversal attempts on the local file
922 // system. Suggested by Ian Eure, initially
923 // rejected, but then adopted when the secure
924 // compiler was added.
925 $path = realpath($path); // needed for substr() later
926 $fullname = realpath($fullname);
929 // the substr() check added by Ian Eure to make sure
930 // that the realpath() results in a directory registered
931 // with Savant so that non-registered directores are not
932 // accessible via directory traversal attempts.
933 if (file_exists($fullname) && is_readable($fullname) &&
934 substr($fullname, 0, strlen($path)) == $path) {
940 // could not find the file in the set of paths
945 // -----------------------------------------------------------------
947 // Variable and reference assignment
949 // -----------------------------------------------------------------
954 * Sets variables for the template.
956 * This method is overloaded; you can assign all the properties of
957 * an object, an associative array, or a single value by name.
959 * You are not allowed to set variables that begin with an underscore;
960 * these are either private properties for Savant2 or private variables
961 * within the template script itself.
965 * $Savant2 = new Savant2();
968 * $Savant2->var1 = 'something';
969 * $Savant2->var2 = 'else';
971 * // assign by name and value
972 * $Savant2->assign('var1', 'something');
973 * $Savant2->assign('var2', 'else');
975 * // assign by assoc-array
976 * $ary = array('var1' => 'something', 'var2' => 'else');
977 * $Savant2->assign($obj);
979 * // assign by object
980 * $obj = new stdClass;
981 * $obj->var1 = 'something';
982 * $obj->var2 = 'else';
983 * $Savant2->assign($obj);
987 * Greg Beaver came up with the idea of assigning to public class
994 * @throws object An error object with a SAVANT2_ERROR_ASSIGN code.
1000 // this method is overloaded.
1001 $arg = func_get_args();
1003 // must have at least one argument. no error, just do nothing.
1004 if (! isset($arg[0])) {
1009 if (is_object($arg[0])) {
1010 // assign public properties
1011 foreach (get_object_vars($arg[0]) as $key => $val) {
1012 if (substr($key, 0, 1) != '_') {
1019 // assign by associative array
1020 if (is_array($arg[0])) {
1021 foreach ($arg[0] as $key => $val) {
1022 if (substr($key, 0, 1) != '_') {
1029 // assign by string name and mixed value.
1031 // we use array_key_exists() instead of isset() becuase isset()
1032 // fails if the value is set to null.
1033 if (is_string($arg[0]) &&
1034 substr($arg[0], 0, 1) != '_' &&
1035 array_key_exists(1, $arg)) {
1036 $this->$arg[0] = $arg[1];
1038 return $this->error(SAVANT2_ERROR_ASSIGN, $arg);
1045 * Sets references for the template.
1047 * // assign by name and value
1048 * $Savant2->assignRef('ref', $reference);
1050 * // assign directly
1051 * $Savant2->ref =& $reference;
1053 * Greg Beaver came up with the idea of assigning to public class
1058 * @param string $key The name for the reference in the template.
1060 * @param mixed &$val The referenced variable.
1064 * @throws object An error object with a SAVANT2_ERROR_ASSIGNREF code.
1068 function assignRef($key, &$val)
1070 if (is_string($key) && substr($key, 0, 1) != '_') {
1071 $this->$key =& $val;
1073 return $this->error(
1074 SAVANT2_ERROR_ASSIGNREF,
1075 array('key' => $key, 'val' => $val)
1083 * Unsets assigned variables and references.
1087 * @param mixed $var If null, clears all variables; if a string, clears
1088 * the one variable named by the string; if a sequential array, clears
1089 * the variables names in that array.
1095 function clear($var = null)
1097 if (is_null($var)) {
1098 // clear all variables
1099 $var = array_keys(get_object_vars($this));
1101 // clear specific variables
1102 settype($var, 'array');
1105 // clear out the selected variables
1106 foreach ($var as $name) {
1107 if (substr($name, 0, 1) != '_' && isset($this->$name)) {
1108 unset($this->$name);
1116 * Gets the current value of one, many, or all assigned variables.
1118 * Never returns variables starting with an underscore; these are
1119 * reserved for internal Savant2 use.
1123 * @param mixed $key If null, returns a copy of all variables and
1124 * their values; if an array, returns an only those variables named
1125 * in the array; if a string, returns only that variable.
1127 * @return mixed If multiple variables were reqested, returns an
1128 * associative array where the key is the variable name and the
1129 * value is the variable value; if one variable was requested,
1130 * returns the variable value only.
1134 function getVars($key = null)
1136 if (is_null($key)) {
1137 $key = array_keys(get_object_vars($this));
1140 if (is_array($key)) {
1141 // return a series of vars
1143 foreach ($key as $var) {
1144 if (substr($var, 0, 1) != '_' && isset($this->$var)) {
1145 $tmp[$var] = $this->$var;
1150 // return a single var
1151 if (substr($key, 0, 1) != '_' && isset($this->$key)) {
1158 // -----------------------------------------------------------------
1160 // Template processing
1162 // -----------------------------------------------------------------
1167 * Loads a template script for execution (does not execute the script).
1169 * This will optionally compile the template source into a PHP script
1170 * if a compiler object has been passed into Savant2.
1172 * Also good for including templates from the template paths within
1173 * another template, like so:
1175 * include $this->loadTemplate('template.tpl.php');
1179 * @param string $tpl The template source name to look for.
1181 * @param bool $setScript Default false; if true, sets the $this->_script
1182 * property to the resulting script path (or null on error). Normally,
1183 * only $this->fetch() will need to set this to true.
1185 * @return string The full path to the compiled template script.
1187 * @throws object An error object with a SAVANT2_ERROR_NOTEMPLATE code.
1191 function loadTemplate($tpl = null, $setScript = false)
1193 // set to default template if none specified.
1194 if (is_null($tpl)) {
1195 $tpl = $this->_template;
1198 // find the template source.
1199 $file = $this->findFile('template', $tpl);
1201 return $this->error(
1202 SAVANT2_ERROR_NOTEMPLATE,
1203 array('template' => $tpl)
1207 // are we compiling source into a script?
1208 if (is_object($this->_compiler)) {
1209 // compile the template source and get the path to the
1210 // compiled script (will be returned instead of the
1212 $result = $this->_compiler->compile($file);
1214 // no compiling requested, return the source path
1218 // is there a script from the compiler?
1219 if (! $result || $this->isError($result)) {
1222 $this->_script = null;
1225 // return an error, along with any error info
1226 // generated by the compiler.
1227 return $this->error(
1228 SAVANT2_ERROR_NOSCRIPT,
1231 'compiler' => $result
1238 $this->_script = $result;
1249 * This is a an alias to loadTemplate() that cannot set the script.
1253 * @param string $tpl The template source name to look for.
1255 * @return string The full path to the compiled template script.
1257 * @throws object An error object with a SAVANT2_ERROR_NOTEMPLATE code.
1261 function findTemplate($tpl = null)
1263 return $this->loadTemplate($tpl, false);
1269 * Executes a template script and returns the results as a string.
1271 * @param string $_tpl The name of the template source file ...
1272 * automatically searches the template paths and compiles as needed.
1274 * @return string The output of the the template script.
1276 * @throws object An error object with a SAVANT2_ERROR_NOSCRIPT code.
1280 function fetch($_tpl = null)
1282 // clear prior output
1283 $this->_output = null;
1285 // load the template script
1286 $_result = $this->loadTemplate($_tpl, true);
1288 // is there a template script to be processed?
1289 if ($this->isError($_result)) {
1293 // unset so as not to introduce into template scope
1297 // never allow a 'this' property
1298 if (isset($this->this)) {
1302 // are we extracting variables into local scope?
1303 if ($this->_extract) {
1304 // extract references to this object's public properties.
1305 // this allows variables assigned by-reference to refer all
1306 // the way back to the model logic. variables assigned
1307 // by-copy only refer back to the property.
1308 foreach (array_keys(get_object_vars($this)) as $_prop) {
1309 if (substr($_prop, 0, 1) != '_') {
1310 // set a variable-variable to an object property
1312 $$_prop =& $this->$_prop;
1316 // unset private loop vars
1320 // start capturing output into a buffer
1323 // include the requested template filename in the local scope
1324 // (this will execute the view logic).
1325 include $this->_script;
1327 // done with the requested template; get the buffer and
1329 $this->_output = ob_get_contents();
1333 return $this->applyFilters();
1339 * Execute and display a template script.
1341 * @param string $tpl The name of the template file to parse;
1342 * automatically searches through the template paths.
1346 * @throws object An error object with a SAVANT2_ERROR_NOSCRIPT code.
1352 function display($tpl = null)
1354 $result = $this->fetch($tpl);
1355 if ($this->isError($result)) {
1363 // -----------------------------------------------------------------
1367 // -----------------------------------------------------------------
1372 * Loads a plugin class and instantiates it within Savant2.
1376 * @param string $name The plugin name (not including Savant2_Plugin_
1379 * @param array $conf An associative array of plugin configuration
1382 * @param bool $savantRef Default false. When true, sets the $Savant
1383 * property of the filter to a reference to this Savant object.
1387 * @throws object An error object with a SAVANT2_ERROR_NOPLUGIN code.
1391 function loadPlugin($name, $conf = array(), $savantRef = null)
1393 // if no $savantRef is provided, use the default.
1394 if (is_null($savantRef)) {
1395 $savantRef = $this->_reference;
1398 // some basic information
1399 $class = "Savant2_Plugin_$name";
1400 $file = "$class.php";
1403 if (! $this->_classExists($class)) {
1405 $result = $this->findFile('resource', $file);
1407 return $this->error(
1408 SAVANT2_ERROR_NOPLUGIN,
1409 array('plugin' => $name)
1412 include_once $result;
1416 // is it instantiated?
1417 if (! isset($this->_resource['plugin'][$name]) ||
1418 ! is_object($this->_resource['plugin'][$name]) ||
1419 ! is_a($this->_resource['plugin'][$name], $class)) {
1422 $this->_resource['plugin'][$name] = new $class($conf);
1424 // add a Savant reference if requested
1426 $this->_resource['plugin'][$name]->Savant = $this;
1435 * Unloads one or more plugins from Savant2.
1439 * @param string|array $name The plugin name (not including Savant2_Plugin_
1440 * prefix). If null, unloads all plugins; if a string, unloads that one
1441 * plugin; if an array, unloads all plugins named as values in the array.
1447 function unloadPlugin($name = null)
1449 if (is_null($name)) {
1450 $this->_resource['plugin'] = array();
1452 settype($name, 'array');
1453 foreach ($name as $key) {
1454 if (isset($this->_resource['plugin'][$key])) {
1455 unset($this->_resource['plugin'][$key]);
1464 * Executes a plugin with arbitrary parameters and returns the
1469 * @param string $name The plugin name (not including Savant2_Plugin_
1472 * @return mixed The plugin results.
1474 * @throws object An error object with a SAVANT2_ERROR_NOPLUGIN code.
1480 function splugin($name)
1482 // attempt to load the plugin
1483 $result = $this->loadPlugin($name);
1484 if ($this->isError($result)) {
1488 // call the plugin's "plugin()" method with arguments,
1489 // dropping the first argument (the plugin name)
1490 $args = func_get_args();
1492 return call_user_func_array(
1493 array(&$this->_resource['plugin'][$name], 'plugin'), $args
1500 * Executes a plugin with arbitrary parameters and displays the
1505 * @param string $name The plugin name (not including Savant2_Plugin_
1510 * @throws object An error object with a SAVANT2_ERROR_NOPLUGIN code.
1514 function plugin($name)
1516 $args = func_get_args();
1518 $result = call_user_func_array(
1519 array(&$this, 'splugin'),
1523 if ($this->isError($result)) {
1533 * PHP5 ONLY: Magic method alias to plugin().
1535 * E.g., instead of $this->plugin('form', ...) you would use
1536 * $this->form(...). You can set this to use any other Savant2 method
1537 * by issuing, for example, setCall('splugin') to use splugin() ... which
1538 * is really the only other sensible choice.
1542 * @param string $func The plugin name.
1544 * @param array $args Arguments passed to the plugin.
1548 * @throws object An error object with a SAVANT2_ERROR_NOPLUGIN code.
1552 function __call($func, $args)
1554 // add the plugin name to the args
1555 array_unshift($args, $func);
1557 // call the plugin() method
1558 return call_user_func_array(
1559 array(&$this, $this->_call),
1565 // -----------------------------------------------------------------
1569 // -----------------------------------------------------------------
1574 * Loads a filter class and instantiates it within Savant2.
1578 * @param string $name The filter name (not including Savant2_Filter_
1581 * @param array $conf An associative array of filter configuration
1584 * @param bool $savantRef Default false. When true, sets the $Savant
1585 * property of the filter to a reference to this Savant object.
1589 * @throws object An error object with a SAVANT2_ERROR_NOFILTER code.
1593 function loadFilter($name, $conf = array(), $savantRef = null)
1595 // if no $savantRef is provided, use the default.
1596 if (is_null($savantRef)) {
1597 $savantRef = $this->_reference;
1600 // some basic information
1601 $class = "Savant2_Filter_$name";
1602 $file = "$class.php";
1605 if (! $this->_classExists($class)) {
1607 $result = $this->findFile('resource', $file);
1609 return $this->error(
1610 SAVANT2_ERROR_NOFILTER,
1611 array('filter' => $name)
1614 include_once $result;
1618 // is it instantiated?
1619 if (! isset($this->_resource['filter'][$name]) ||
1620 ! is_object($this->_resource['filter'][$name]) ||
1621 ! is_a($this->_resource['filter'][$name], $class)) {
1624 $this->_resource['filter'][$name] = new $class($conf);
1626 // add a Savant reference if requested
1628 $this->_resource['filter'][$name]->Savant = $this;
1637 * Unloads one or more filters from Savant2.
1641 * @param string|array $name The filter name (not including Savant2_Filter_
1642 * prefix). If null, unloads all filters; if a string, unloads that one
1643 * filter; if an array, unloads all filters named as values in the array.
1649 function unloadFilter($name = null)
1651 if (is_null($name)) {
1652 $this->_resource['filter'] = array();
1654 settype($name, 'array');
1655 foreach ($name as $key) {
1656 if (isset($this->_resource['filter'][$key])) {
1657 unset($this->_resource['filter'][$key]);
1666 * Apply all loaded filters, in order, to text.
1670 * @param string $text The text to which filters should be applied.
1671 * If null, sets the text to $this->_output.
1673 * @return string The text after being passed through all loded
1678 function applyFilters($text = null)
1680 // set to output text if no text specified
1681 if (is_null($text)) {
1682 $text = $this->_output;
1685 // get the list of filter names...
1686 $filter = array_keys($this->_resource['filter']);
1688 // ... and apply them each in turn.
1689 foreach ($filter as $name) {
1690 $this->_resource['filter'][$name]->filter($text);
1698 // -----------------------------------------------------------------
1702 // -----------------------------------------------------------------
1707 * Returns an error object.
1711 * @param int $code A SAVANT2_ERROR_* constant.
1713 * @param array $info An array of error-specific information.
1715 * @return object An error object of the type specified by
1720 function &error($code, $info = array())
1722 // the error config array
1725 'text' => 'Savant2: ',
1726 'info' => (array) $info
1729 // set an error message from the globals
1730 if (isset($GLOBALS['_SAVANT2']['error'][$code])) {
1731 $conf['text'] .= $GLOBALS['_SAVANT2']['error'][$code];
1733 $conf['text'] .= '???';
1736 // set up the error class name
1737 if ($this->_error) {
1738 $class = 'Savant2_Error_' . $this->_error;
1740 $class = 'Savant2_Error';
1743 // set up the error class file name
1744 $file = $class . '.php';
1747 if (! $this->_classExists($class)) {
1749 // find the error class
1750 $result = $this->findFile('resource', $file);
1752 // could not find the custom error class, revert to
1753 // Savant_Error base class.
1754 $class = 'Savant2_Error';
1755 $result = dirname(__FILE__) . '/Savant2/Error.php';
1758 // include the error class
1759 include_once $result;
1762 // instantiate and return the error class
1763 $err = new $class($conf);
1770 * Tests if an object is of the Savant2_Error class.
1774 * @param object &$obj The object to be tested.
1776 * @return boolean True if $obj is an error object of the type
1777 * Savant2_Error, or is a subclass that Savant2_Error. False if not.
1781 function isError(&$obj)
1783 if (is_object($obj)) {
1784 if (is_a($obj, 'Savant2_Error') ||
1785 is_subclass_of($obj, 'Savant2_Error')) {