<?php
define('H2O_VERSION', '0.3');
defined('DS') or define('DS', DIRECTORY_SEPARATOR);
defined('H2O_ROOT') or define('H2O_ROOT', dirname(__FILE__) . DS);
require H2O_ROOT.'h2o/datatype.php';
require H2O_ROOT.'h2o/loaders.php';
require H2O_ROOT.'h2o/nodes.php';
require H2O_ROOT.'h2o/tags.php';
require H2O_ROOT.'h2o/errors.php';
require H2O_ROOT.'h2o/filters.php';
require H2O_ROOT.'h2o/context.php';
require H2O_ROOT.'h2o/parser.php';
/**
* Example:
* $h2o = new H2O('./template.html', array("loader"=>'file'));
*
*
* $h2o = new H2O('template.html', array("loader"=>'hash'));
*/
class H2o {
var $searchpath;
var $context;
var $loader = false;
static $tags = array();
static $filters = array();
static $extensions = array();
static function getOptions($options = array()) {
return array_merge(array(
'loader' => 'file',
'cache' => 'file', // file | apc | memcache
'cache_prefix' => 'h2o_',
'cache_ttl' => 3600, // file | apc | memcache
'searchpath' => false,
'autoescape' => true,
// Enviroment setting
'BLOCK_START' => '{%',
'BLOCK_END' => '%}',
'VARIABLE_START' => '{{',
'VARIABLE_END' => '}}',
'COMMENT_START' => '{*',
'COMMENT_END' => '*}',
'TRIM_TAGS' => true
), $options);
}
function __construct($file = null, $options = array()) {
# Init a environment
$this->options = $this->getOptions($options);
$loader = $this->options['loader'];
if (!$loader)
return true;
if (is_object($loader)) {
$this->loader = $loader;
$this->loader->setOptions($this->options);
} else {
$loader = "H2o_{$loader}_Loader";
if (!class_exists($loader, false))
throw new Exception('Invalid template loader');
if (isset($options['searchpath'])){
$this->searchpath = $options['searchpath'];
} else if ($file) {
$this->searchpath = dirname(realpath($file)).DS;
} else {
$this->searchpath = getcwd().DS;
}
$loader_searchpath = is_array($this->searchpath) ? $this->searchpath : array($this->searchpath);
$this->loader = new $loader($loader_searchpath, $this->options);
}
$this->loader->runtime = $this;
if (isset($options['i18n'])) {
h2o::load('i18n');
$this->i18n = new H2o_I18n($this->searchpath, $options['i18n']);
}
if ($file) {
$this->nodelist = $this->loadTemplate($file);
}
}
function loadTemplate($file) {
return $this->nodelist = $this->loader->read_cache($file);
}
function loadSubTemplate($file) {
return $this->loader->read($file);
}
# Build a finalized nodelist from template ready to be cached
function parse($source, $filename = '', $env = null) {
if (!$env)
$env = $this->options;
if (!class_exists('H2o_Parser', false))
require H2O_ROOT.'h2o/parser.php';
$parser = new H2o_Parser($source, $filename, $this, $env);
$nodelist = $parser->parse();
return $nodelist;
}
function set($context, $value = null) {
# replace with new context object
if (is_object($context) && $context instanceof H2o_Context) {
return $this->context = $context;
}
# Init context
if (!$this->context) {
$this->context = new H2o_Context($this->defaultContext(), $this->options);
}
# Extend or set value
if (is_array($context)) {
return $this->context->extend($context);
}
elseif (is_string($context)) {
return $this->context[$context] = $value;
}
return false;
}
# Render the nodelist
function render($context = array()) {
$this->set($context);
$this->stream = new StreamWriter;
$this->nodelist->render($this->context, $this->stream);
return $this->stream->close();
}
static function parseString($source, $options = array()) {
$instance = new H2o(null, array_merge($options, array('loader' => false)));
$instance->nodelist = $instance->parse($source);
return $instance;
}
static function &createTag($tag, $args = null, $parser, $position = 0) {
if (!isset(self::$tags[$tag])) {
throw new H2o_Error($tag . " tag doesn't exist");
}
$tagClass = self::$tags[$tag];
$tag = new $tagClass($args, $parser, $position);
return $tag;
}
/**
* Register a new tag
*
*
* h2o::addTag('tag_name', 'ClassName');
*
* h2o::addTag(array(
* 'tag_name' => 'MagClass',
* 'tag_name2' => 'TagClass2'
* ));
*
* h2o::addTag('tag_name'); // Tag_name_Tag
*
* h2o::addTag(array('tag_name',
* @param unknown_type $tag
* @param unknown_type $class
*/
static function addTag($tag, $class = null) {
$tags = array();
if (is_string($tag)) {
if (is_null($class))
$class = ucwords("{$tag}_Tag");
$tags[$tag] = $class;
} elseif (is_array($tag)) {
$tags = $tag;
}
foreach ($tags as $tag => $tagClass) {
if (is_integer($tag)) {
unset($tags[$tag]);
$tag = $tagClass;
$tagClass = ucwords("{$tagClass}_Tag");
}
if (!class_exists($tagClass, false)) {
throw new H2o_Error("{$tagClass} tag is not found");
}
$tags[$tag] = $tagClass;
}
self::$tags = array_merge(self::$tags, $tags);
}
/**
* Register a new filter to h2o runtime
*
* @param unknown_type $filter
* @param unknown_type $callback
* @return unknown
*/
static function addFilter($filter, $callback = null) {
if (is_array($filter)) {
$filters = $filter;
foreach($filters as $key => $filter) {
if (is_numeric($key))
$key = $filter;
self::addFilter($key, $filter);
}
return true;
} elseif (is_string($filter) && class_exists($filter, false) && is_subclass_of($filter, 'FilterCollection')) {
foreach (get_class_methods($filter) as $f) {
if (is_callable(array($filter, $f)))
self::$filters[$f] = array($filter, $f);
}
return true;
}
if (is_null($callback))
$callback = $filter;
if (!is_callable($callback)) {
return false;
}
self::$filters[$filter] = $callback;
}
static function addLookup($callback) {
if (is_callable($callback)) {
H2o_Context::$lookupTable[] = $callback;
} else die('damm it');
}
static function load($extension, $file = null) {
if (!$file) {
$file = H2O_ROOT.'ext'.DS.$extension.'.php';
}
if (is_file($file)) {
include_once ($file);
self::$extensions[$extension] = $file;
}
}
function defaultContext() {
return array('h2o' => new H2o_Info);
}
}
/**
* Convenient wrapper for loading template file or string
* @param $name
* @param $options - H2o options
* @return Instance of H2o Template
*/
function h2o($name, $options = array()) {
$is_file = '/([^\s]*?)(\.[^.\s]*$)/';
if (!preg_match($is_file, $name)) {
return H2o::parseString($name, $options);
}
$instance = new H2o($name, $options);
return $instance;
}
?>