Nurullah Yel
Nurullah Yel

Reputation: 73

If-tags for own php template engine

I am trying to make an own template engine in PHP.

For that I created a class which parses through the template files and looks for the delimiters, that I set, beforehand (f.e. { and }). It works fine with variabels and including files.

Now, I want to add some functionalities like if tags, where I can forward a boolean variable, that decides if the template part inside the if tags is gonna be shown or not. I worked more than two days on this little problem, but I just couldn't solve it.

EDIT: Sry it seems like I didn't provide enough info. Here's my template engine:

class EZmanly {
private $templateDir = 'templates/';

private $leftDelimiter = '{$';
private $rightDelimiter = '}';

private $leftDelimiterFunc = '{';
private $rightDelimiterFunc = '}';

private $leftDelimiterCom = '\{\*';
private $rightDelimiterCom = '\*\}';

private $leftDelimiterIf = '\{if';
private $rightDelimiterIf = '\}';
private $elseDemlimiter = '\{else\}';
private $endDelimitirIf = '\{end if\}';

/* Der Pfad der Datei*/
private $templateFile = '';

/* Der Dateiname */
private $templateName = '';

/* Der Inhalt des Tempaltes in der Datei */
private $template = '';

public function __construct(/*$tplDir*/) {
    #if( !empty($tplDir) ) {
        $this->templateDir = 'templates/'/*$tplDir*/;
    #}
}

public function loadTpl($file) {
    $this->templateName = $file.".tpl";
    $this->templateFile = $this->templateDir.$file.".tpl";

    if( !empty($this->templateFile) ) {
        if( file_exists($this->templateFile) ) {
            $this->template = file_get_contents($this->templateFile);
        }
        else {
            return fase;
        }
    }
    else {
        return false;
    }

    $this->parseFunctions();
}

public function assign($replace, $replacement) {
    $this->template = str_replace($this->leftDelimiter.$replace.$this->rightDelimiter, $replacement, $this->template);
}

public function parseFunctions() {
    while(preg_match( "/".$this->leftDelimiterFunc."include file=\"(.*)\.(.*)\"".$this->rightDelimiterFunc."/", $this->template)) {

        $this->template = preg_replace("/" .$this->leftDelimiterFunc."include file=\"(.*)\.(.*)\"".$this->rightDelimiterFunc."/isUe", "file_get_contents(\$this->templateDir.'\\1'.'.'.'\\2')", $this->template);
    }
    while(preg_match( "/".$this->leftDelimiterFunc."include file=\"(.*)\.(.*)\"".$this->rightDelimiterFunc."/", $this->template)) {

        $this->template = preg_replace("/" .$this->leftDelimiterFunc."include file=\"(.*)\.(.*)\"".$this->rightDelimiterFunc."/isUe", "file_get_contents(\$this->templateDir.'\\1'.'.'.'\\2')", $this->template);
    }
    while(preg_match_all("/\{IF(.*?)\}[\s]*?(.*)[\s]*?(\{ELSE\}[\s]*?(.*?)[\s]*?)\{ENDIF\}/i",$this->template, $matches, PREG_PATTERN_ORDER)) {

        for($i=0; $i < count($matches[4][$i]); $i++) {
            $condition = $matches[1][$i];
            $trueval = $matches[2][$i];
            $falseval = isset($matches[4][$i]) ? $matches[4][$i] : false;
            $result = eval("return(".$condition.");");

            if($result===true) {
                $this->template = str_replace($matches[0][$i], $trueval, $this->template);
            }
            else {
                $this->template = str_replace($matches[0][$i], $falseval, $this->template);
            }
        }
    }
    while(preg_match_all("/\{IF(.*?)\}[\s]*?(.*)[\s]*?\{ENDIF\}/i", $this->template, $matches, PREG_PATTERN_ORDER)) {

        for($i=0; $i < count($matches[0]); $i++) {
            $condition = $matches[1][$i];
            $trueval = $matches[2][$i];
            $result = eval("return(".$condition.");");

            if($result==true) {
                $this->template = str_replace($matches[0][$i], $trueval, $this->template);
            }
            else {
                $this->template = str_replace($matches[0][$i], "", $this->template);
            }
        }
    }
    # TODO: if functions in the templates for flags (true/false OR 1/0)

    $this->template = preg_replace("/".$this->leftDelimiterCom."(.*)".$this->rightDelimiterCom."/", "", $this->template);
}

public function display() {
    echo $this->template;
}

}

And here's an example on the php:

$flgEmpty = true;
$flgMail = true;
$flgUrl = false;

$newManly = new EZmanly();

$newManly->loadTpl('advertPost');

$newManly->assign('title', 'Anzeige aufgeben');
$newManly->assign('filepath', 'http://localhost/webdev');
$newManly->assign('flgMail', $flgMail);

$newManly->display();

And here the tpl:

{IF $flgMail==true}
    <p>Dies ist ein Test</p>
{ENDIF}

But it doesn't work :( if i just display variables or use including files works

Upvotes: 0

Views: 1510

Answers (1)

hherger
hherger

Reputation: 1680

Try this.

Syntax:

  • {variable_name}
    Variable names are PHP variable names. E.g. {var1} corresponds to $var1 in the PHP script.
  • {IF?condition} … {ELSE} … {ENDIF}
    condition must be a valid PHP condition term. It is evaluated at runtime. So, all PHP constructs and references ($-variables) are valid that would be valid in the script itself.
  • {IF?condition} … {ENDIF}

Note:

  • Conditions are evaluated at runtime using the eval() command. This could be a security issue. Be careful, and make sure you do not import a template from a source you do not know or you cannot absolutely trust.
  • IF-constructs may not be nested.

<?php

    $a = 22;
    $b = 33;
    $var1 = 99999;
    $var2 = 'Variable2';

    $template = 'Variable 1 = {var1}, variable 2 = {var2}
{IF?$a == 22}A = 22{ELSE}A != 22{ENDIF}<br />
<div>{IF?$a >= 22}
A = 22
{ELSE}
A != 22
{ENDIF}</div>
{IF?$b<0}B > 0{ENDIF}';

    echo '<h3>Template before</h3><pre>'.htmlentities($template).'</pre>';

    // IF - ELSE - ENDIF
    preg_match_all('/\{IF\?(.*?)\}[\s]*?(.*)[\s]*?(\{ELSE\}[\s]*?(.*?)[\s]*?)\{ENDIF\}/i', $template, $regs, PREG_PATTERN_ORDER);
    for ($i = 0; $i < count($regs[0]); $i++) {
        $condition = $regs[1][$i];
        $trueval   = $regs[2][$i];
        $falseval  = (isset($regs[4][$i])) ? $regs[4][$i] : false;
        $res = eval('return ('.$condition.');');
        if ($res===true) {
            $template = str_replace($regs[0][$i],$trueval,$template);
        } else {
            $template = str_replace($regs[0][$i],$falseval,$template);
        }
    }

    // IF - ENDIF
    preg_match_all('/\{IF\?(.*?)\}[\s]*?(.*)[\s]*?{ENDIF\}/i', $template, $regs, PREG_PATTERN_ORDER);
    for ($i = 0; $i < count($regs[0]); $i++) {
        $condition = $regs[1][$i];
        $trueval   = $regs[2][$i];
        $res = eval('return ('.$condition.');');
        if ($res===true) {
            $template = str_replace($regs[0][$i],$trueval,$template);
        } else {
            $template = str_replace($regs[0][$i],'',$template);
        }
    }

    // Variables
    preg_match_all('/\{(.*?)\}/i', $template, $regs, PREG_SET_ORDER);
    for ($i = 0; $i < count($regs[0]); $i++) {
        $varname = $regs[$i][1];
        if (isset($$varname)) {
            $value = $$varname;
            $template = str_replace($regs[$i][0],$$varname,$template);
        } else {
            $template = str_replace($regs[$i][0],'',$template);
        }
    }

    echo '<h3>Template after</h3><pre>'.htmlentities($template).'</pre>';

?>

Output:

Template before

Variable 1 = {var1}, variable 2 = {var2}
{IF?$a == 22}A = 22{ELSE}A != 22{ENDIF}<br />
<div>{IF?$a >= 22}
A = 22
{ELSE}
A != 22
{ENDIF}</div>
{IF?$b<0}B > 0{ENDIF}

Template after

Variable 1 = 99999, variable 2 = Variable2
A = 22<br />
<div>    A = 22
</div>

And, btw., there are more embracing, and more complex, template engines available. For one of the best, to my opinion, see http://twig.sensiolabs.org/.

Upvotes: 1

Related Questions