<?php
namespace Phad;
/**
* Template Compiler for compiling PHP Scripts from a template, a view, and an array of arguments to fill in the template
*/
class TemplateCompiler {
/**
* @param $item the Phad view you want to compile
* @param $template the template you want to compile it with
* @return string Fully compiled view
*/
public function compile(string $item, string $template): string {
$doc = new \Taeluf\PHTML($item);
$parser = new \Phad\DomParser();
// needs fixing for multiple items
$items = $parser->parse_doc($doc);
return $doc.'';
}
/**
* Process all `/* @@if.start.name *\/` placeholders. Modifies `$template` and `$template_fillers`
*
* Replaces `@@if1.start.whatever` with `@@start.whatever` and adds `@@__if1_#` before `if()`.
* Adds `__if1_#` entries to `$template_fillers`
*
* @param &$template the template to parse and modify
* @param &$template_fillers variable to put special template fillers into. Also should contain keys for each of your `@@if1.start.whatever` statements indicating `true/false` for displaying `whatever` or not
*/
public function precompile_ifs(string &$template, ?array &$template_fillers){
$reg = '/\/\*\*? ?\@\@if([0-9]{0,2}).start\.([a-zA-Z\_0-9]+) ?\*\//';
preg_match_all($reg, $template, $matches);
$params = [];
$template_fillers_index = 0;
$ifs_activated = [];
foreach ($matches[0] as $index=>$full_match){
$if_index = $matches[1][$index];
$key = $matches[2][$index];
$ifs[$if_index][$key] = $full_match;
$start_pos = strpos($template, $full_match);
$after_start_pos = $start_pos + strlen($full_match);
$if_pos = strpos($template, 'if', $after_start_pos);
$ifs_key = '__ifs'.$if_index.'_'.$index;
$template =
substr($template,0,$start_pos)
. '/* @@start.'.$key.' */'
.substr($template,$after_start_pos, $if_pos - $after_start_pos)
.'/* @@'.$ifs_key.' */'
.substr($template,$if_pos);
;
// $params[$key] = 'else';
if (isset($template_fillers[$key])&&$template_fillers[$key]===true){
$replacement = 'else';
if ($template_fillers_index==0)$replacement = '';
$template_fillers[$ifs_key] = $replacement;
$template_fillers_index++;
$ifs_activated[$if_index] = $template_fillers_index;
}
}
foreach ($ifs_activated as $if_index=>$num_ifs){
$template_fillers['else'.$if_index] = 'else ';
}
}
/**
* Fill a template (final template compilation step)
*
* @param $template the template code to fill in
* @param $template_args args found inside the template. @see(get_template_args())
* @param $template_fillers `key=>value` array of strings to insert into `$template` in place of `$template_args[$key]`
*
* @return filled-in template
*/
public function fill_template(string $template, array $template_args, array $template_fillers){
// sort from largest placeholder value to smallest
uksort($template_args,
function($ka,$kb) use ($template_args){
$al = strlen($template_args[$ka]);
$bl = strlen($template_args[$kb]);
return $bl-$al;
}
);
// get replacement value from $template_fillers, then the placeholder in the template
foreach ($template_args as $key=>$placeholder){
$replacement = $template_fillers[$key]??'';
// if ($replacement===true)continue;
if ($replacement===false)$replacement = '';
// var_dump($replacement);
// var_dump("Placeholder:".$placeholder);
$template = str_replace($placeholder, $replacement, $template);
}
return $template;
}
/**
* Get array of arguments found inside the template (which will later be replaced)
*
* @param $template the template to inspect
* @param &$template_fillers `key=>value` array for filling the template. Will be modified.
*
* @return `key=>value` array of arguments in the template where `key` is the argument name and `value` is the placeholder string written in the template
*/
public function get_template_args(string $template, ?array &$template_fillers){
$comment_args = $this->get_comment_args($template);
$var_args = $this->get_var_args($template);
$start_end = $this->get_start_end_args($template, $template_fillers);
$params = array_merge($comment_args, $var_args, $start_end);
return $params;
}
/**
* Get args like `/* @@start.name *\/` (and @@end) and modify the template & template fillers as needed
*
* @param $template the template to process
* @param &$template_fillers `key=>value` array ... should contain `true/false` values for each key of `@@start.key`
*
* @return array of template args for `@@start/@@end` pairs
*/
public function get_start_end_args(string $template, ?array &$template_fillers){
# looks like /* @@param */
$reg = '/\/\*\*? ?\@\@start\.([a-zA-Z\_0-9]+) ?\*\//';
preg_match_all($reg, $template, $matches);
foreach ($matches[0] as $index=>$full_match){
$key = $matches[1][$index];
$start_pos_before = strpos($template, $full_match);
$start_pos_after = $start_pos_before + strlen($full_match);
$end = str_replace('start','end', $full_match);
$end_pos_before = strpos($template, $end);
$end_pos_after = $end_pos_before + strlen($end);
$full_string_length = $end_pos_after - $start_pos_before;
$full_string = substr($template, $start_pos_before, $full_string_length);
$params[$key] = $full_string;
if (isset($template_fillers[$key])&&$template_fillers[$key]===true){
$template_fillers[$key] = substr($template,$start_pos_after, $end_pos_before - $start_pos_after);
} else if (!isset($template_fillers[$key])){
$template_fillers[$key] = '';
}
}
// print_r($params);
// exit;
return $params??[];
}
/**
* Get template args like `@$$Arg`
* @param $template the template to process
* @rereturn `key=>value` array like `['Arg'=>'@$$Arg']`
*/
public function get_var_args(string $template){
$reg = '/\@\$\$([a-zA-Z\_0-9]+)/';
preg_match_all($reg, $template, $matches);
$params = array_combine($matches[1], $matches[0]);
return $params;
}
/**
* Get template args like /* @@arg *\/ # minus the backslash
* @param $template the template to process
* @return `key=>value` array like `['Arg'=>'/* @@arg *\/']`
*/
public function get_comment_args(string $template){
# looks like /* @@param */
$reg = '/\/\*\*? ?\@\@([a-zA-Z\_0-9]+) ?\*\//';
preg_match_all($reg, $template, $matches);
$params = array_combine($matches[1], $matches[0]);
return $params;
}
}