Created
June 20, 2015 16:01
-
-
Save ducktype/f05b4feb4501cbbf7a36 to your computer and use it in GitHub Desktop.
My own PHP native template engine in ~90 lines of code!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
---------------------------------------------- | |
TEMPLATE EXAMPLES: | |
---------------------------------------------- | |
---------------------------------------- | |
htmlpage_base2.ptpl | |
---------------------------------------- | |
BASE2 | |
<? $block('main_content') ?> | |
BASE2 main_content BLOCK | |
<? $endblock() ?> | |
---------------------------------------- | |
htmlpage_base.ptpl | |
---------------------------------------- | |
<? $extends('htmlpage_base2.ptpl') ?> | |
<nav> | |
NAV HEAD | |
</nav> | |
<? $block('main_content') ?> | |
DEFAULT <?=$model['a']?> TEST | |
<? $endblock() ?> | |
<hr> | |
FOOTER | |
---------------------------------------- | |
index.ptpl | |
---------------------------------------- | |
<? $extends('htmlpage_base.ptpl') ?> | |
BASE1 HEAD | |
<? $block('main_content') ?> | |
<? $block(null,['spaceless']) ?> | |
PRE | |
<main> | |
INCLUDE WITH DIFFERENT MODEL: | |
<?=$include('htmlpage_base.ptpl',['a'=>'NX'])?> | |
</main> | |
<? $block('main_content3') ?> | |
<span> | |
B1 | |
</span> | |
<span> | |
B2 | |
</span> | |
<? $endblock() ?> | |
POST | |
<? $endblock() ?> | |
<? $endblock() ?> | |
<?=$model['a']?> | |
BASE1 FOOTER | |
---------------------------------------- | |
email_notify.ptpl | |
---------------------------------------- | |
<? $block('subject') ?> | |
Subject with model data <?=$model[user][name]?> <?=$model[user][surname]?>! | |
<? $endblock() ?> | |
<? $block('body_html') ?> | |
MESSAGE BODY HTML | |
<?=print_r($model,true)?> | |
<? $endblock() ?> | |
<? $block('body_text') ?> | |
MESSAGE BODY TEXT | |
<? $endblock() ?> | |
---------------------------------------------- | |
USAGE: | |
---------------------------------------------- | |
$ptpl = new \PTpl("/template/base_path",array( | |
'global_variable1' => 'global_value1', | |
'global_variable2' => 'global_value2', | |
)); | |
$tpl_globals = array('model'=>array( | |
'model_value1' => 'value1', | |
'model_value2' => 'value2', | |
)); | |
$tpl_output_string = $ptpl->render("index.ptpl",$tpl_globals); | |
$tpl_data = $ptpl->render("index.ptpl",$tpl_globals,true); | |
---------------------------------------------- | |
OUTPUT FILTERS: | |
---------------------------------------------- | |
THERE IS A ALSO AN OUTPUT FILTER MECHANISM: | |
by default the block output is trimmed and an additional 'spaceless' filter is available | |
you can pass an array of filter names to the second argument of $block() | |
also note that the $block() first argument (the block name) is optional for example you can do: | |
<? $block(null,['spaceless']) ?> | |
for filter definitions and apply global filters see: | |
$ptpl->output_filters_def | |
and | |
$ptpl->->global_output_filters | |
*/ | |
class PTpl { | |
public $bp = null; | |
public $global_extract_model; | |
public $output_filters_def; | |
public $global_output_filters; | |
function __construct($bp,$global_extract_model=null) { | |
$this->bp = $bp; | |
$this->global_extract_model = $global_extract_model?:array(); | |
$this->output_filters_def = array( | |
'trim' => 'trim', | |
'spaceless' => array($this,'spacelessOutputFilter') | |
); | |
$this->global_output_filters = array( | |
'trim', | |
); | |
} | |
public function spacelessOutputFilter($input,$block_info) { | |
return preg_replace('#>\s+<#','><',$input); | |
} | |
function render($path,$extract_model=array()) { | |
$extract_model = array_merge($this->global_extract_model,$extract_model); | |
extract($extract_model); | |
$self = $this; | |
$str_from = array('\\','/'); | |
$str_to = array(DIRECTORY_SEPARATOR,DIRECTORY_SEPARATOR); | |
$tpl_basepath = $this->bp; | |
$tpl_basepath = trim($tpl_basepath,'\\/'); | |
$tpl_extends = null; | |
$block_stack = array(); | |
$blocks = array(); | |
$extends = function($tpl_path) use(&$tpl_extends) { | |
$tpl_extends = $tpl_path; | |
}; | |
$block = function() use(&$block_stack) { | |
$block_args = func_get_args(); | |
array_push($block_stack,$block_args); | |
ob_start(); | |
}; | |
$endblock = function() use(&$blocks,&$block_stack,$self) { | |
$block_output = ob_get_clean(); | |
$block_args = array_pop($block_stack); | |
$block_name = $block_args[0]; | |
$output_filters = $block_args[1]; | |
$output_filters = array_merge($self->global_output_filters?:array(), | |
$output_filters?:array()); | |
foreach ($output_filters as $of_name) { | |
$of_callable = $self->output_filters_def[$of_name]; | |
if(!$of_callable) | |
continue; | |
$block_output = call_user_func_array($of_callable,array($block_output,$block_args)); | |
} | |
if(!$block_name) { | |
echo $block_output; | |
return; | |
} else { | |
if(!array_key_exists($block_name,$blocks) || $block_name=='_output') | |
$blocks[$block_name] = $block_output; | |
echo $blocks[$block_name]; | |
} | |
}; | |
$include = function($tpl_path,&$inc_model=null) use($self,&$extract_model) { | |
$tpl_data = $self->render($tpl_path,$inc_model?:$extract_model); | |
return $tpl_data['_output']; | |
}; | |
$prev_level = ob_get_level(); | |
ob_start(); | |
try { | |
$curr_tpl = $path; | |
while($curr_tpl) { | |
$tpl_extends = null; | |
$tpl_full_path = $tpl_basepath.DIRECTORY_SEPARATOR.$curr_tpl; | |
$tpl_full_path = str_replace($str_from,$str_to,$tpl_full_path); | |
$block('_output'); | |
include $tpl_full_path; | |
$endblock('_output'); | |
$curr_tpl = $tpl_extends?:null; | |
} | |
} catch(\Exception $ex) { | |
$blocks['_error'] = $ex; | |
} | |
while(ob_get_level()!=$prev_level) { | |
ob_end_clean(); | |
} | |
return $blocks; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment