$val) $out.='$'.$key.'='. (preg_match('/\{\{(.+?)\}\}/',$val)? $this->token($val): Base::instance()->stringify($val)).'; '; return ''; } /** * Template -include- tag handler * @return string * @param $node array **/ protected function _include(array $node) { $attrib=$node['@attrib']; return 'token($attrib['if']).') '):''). ('echo $this->render('. (preg_match('/\{\{(.+?)\}\}/',$attrib['href'])? $this->token($attrib['href']): Base::instance()->stringify($attrib['href'])).','. '$this->mime,get_defined_vars()); ?>'); } /** * Template -exclude- tag handler * @return string **/ protected function _exclude() { return ''; } /** * Template -ignore- tag handler * @return string * @param $node array **/ protected function _ignore(array $node) { return $node[0]; } /** * Template -loop- tag handler * @return string * @param $node array **/ protected function _loop(array $node) { $attrib=$node['@attrib']; unset($node['@attrib']); return 'token($attrib['from']).';'. $this->token($attrib['to']).';'. $this->token($attrib['step']).'): ?>'. $this->build($node). ''; } /** * Template -repeat- tag handler * @return string * @param $node array **/ protected function _repeat(array $node) { $attrib=$node['@attrib']; unset($node['@attrib']); return 'token($attrib['counter'])).'=0; '):''). 'foreach (('. $this->token($attrib['group']).'?:array()) as '. (isset($attrib['key'])? ($this->token($attrib['key']).'=>'):''). $this->token($attrib['value']).'):'. (isset($ctr)?(' '.$ctr.'++;'):'').' ?>'. $this->build($node). ''; } /** * Template -check- tag handler * @return string * @param $node array **/ protected function _check(array $node) { $attrib=$node['@attrib']; unset($node['@attrib']); // Grab and blocks foreach ($node as $pos=>$block) if (isset($block['true'])) $true=array($pos,$block); elseif (isset($block['false'])) $false=array($pos,$block); if (isset($true,$false) && $true[0]>$false[0]) // Reverse and blocks list($node[$true[0]],$node[$false[0]])=array($false[1],$true[1]); return 'token($attrib['if']).'): ?>'. $this->build($node). ''; } /** * Template -true- tag handler * @return string * @param $node array **/ protected function _true(array $node) { return $this->build($node); } /** * Template -false- tag handler * @return string * @param $node array **/ protected function _false(array $node) { return ''.$this->build($node); } /** * Template -switch- tag handler * @return string * @param $node array **/ protected function _switch(array $node) { $attrib=$node['@attrib']; unset($node['@attrib']); foreach ($node as $pos=>$block) if (is_string($block) && !preg_replace('/\s+/','',$block)) unset($node[$pos]); return 'token($attrib['expr']).'): ?>'. $this->build($node). ''; } /** * Template -case- tag handler * @return string * @param $node array **/ protected function _case(array $node) { $attrib=$node['@attrib']; unset($node['@attrib']); return 'token($attrib['value']): Base::instance()->stringify($attrib['value'])).': ?>'. $this->build($node). 'token($attrib['break']).') ':''). 'break; ?>'; } /** * Template -default- tag handler * @return string * @param $node array **/ protected function _default(array $node) { return ''. $this->build($node). ''; } /** * Assemble markup * @return string * @param $node array|string **/ protected function build($node) { if (is_string($node)) return parent::build($node); $out=''; foreach ($node as $key=>$val) $out.=is_int($key)?$this->build($val):$this->{'_'.$key}($val); return $out; } /** * Extend template with custom tag * @return NULL * @param $tag string * @param $func callback **/ function extend($tag,$func) { $this->tags.='|'.$tag; $this->custom['_'.$tag]=$func; } /** * Call custom tag handler * @return string|FALSE * @param $func callback * @param $args array **/ function __call($func,array $args) { if ($func[0]=='_') return call_user_func_array($this->custom[$func],$args); if (method_exists($this,$func)) return call_user_func_array(array($this,$func),$args); user_error(sprintf(self::E_Method,$func)); } /** * Parse string for template directives and tokens * @return string|array * @param $text string **/ function parse($text) { // Build tree structure for ($ptr=0,$len=strlen($text),$tree=array(),$node=&$tree, $stack=array(),$depth=0,$tmp='';$ptr<$len;) if (preg_match('/^<(\/?)(?:F3:)?'. '('.$this->tags.')\b((?:\h+[\w-]+'. '(?:\h*=\h*(?:"(?:.+?)"|\'(?:.+?)\'))?|'. '\h*\{\{.+?\}\})*)\h*(\/?)>/is', substr($text,$ptr),$match)) { if (strlen($tmp)) $node[]=$tmp; // Element node if ($match[1]) { // Find matching start tag $save=$depth; $found=FALSE; while ($depth>0) { $depth--; foreach ($stack[$depth] as $item) if (is_array($item) && isset($item[$match[2]])) { // Start tag found $found=TRUE; break 2; } } if (!$found) // Unbalanced tag $depth=$save; $node=&$stack[$depth]; } else { // Start tag $stack[$depth]=&$node; $node=&$node[][$match[2]]; if ($match[3]) { // Process attributes preg_match_all( '/(?:\b([\w-]+)\h*'. '(?:=\h*(?:"(.+?)"|\'(.+?)\'))?|'. '(\{\{.+?\}\}))/s', $match[3],$attr,PREG_SET_ORDER); foreach ($attr as $kv) if (isset($kv[4])) $node['@attrib'][]=$kv[4]; else $node['@attrib'][$kv[1]]= (empty($kv[2])? (empty($kv[3])?NULL:$kv[3]):$kv[2]); } if ($match[4]) // Empty tag $node=&$stack[$depth]; else $depth++; } $tmp=''; $ptr+=strlen($match[0]); } else { // Text node $tmp.=substr($text,$ptr,1); $ptr++; } if (strlen($tmp)) // Append trailing text $node[]=$tmp; // Break references unset($node); unset($stack); return $tree; } /** * Class constructor * return object **/ function __construct() { $ref=new ReflectionClass(__CLASS__); $this->tags=''; foreach ($ref->getmethods() as $method) if (preg_match('/^_(?=[[:alpha:]])/',$method->name)) $this->tags.=(strlen($this->tags)?'|':''). substr($method->name,1); } }