-1

Before all, sorry for my pretty bad english.

I'm trying to make a PHP template engine using regex & preg_match_all.

My regex looks like :

/\{:[\s]*?[\n]*?[\s]*?if(.*?):\}[\s]*?(.*?)[\s]*?(\{:[\s]?else[\s]?:\}[\s]*?(.*?)[\s]*?)\{:[\s]*?endif[\s]*?:\}/is

My PHP looks like :

preg_match_all('/\{:[\s]*?[\n]*?[\s]*?if(.*?):\}[\s]*?(.*?)[\s]*?(\{:[\s]?else[\s]?:\}[\s]*?(.*?)[\s]*?)\{:[\s]*?endif[\s]*?:\}/is', $template, $regs, PREG_PATTERN_ORDER);


for ($i = 0, $iMax = count($regs[0]); $i < $iMax; $i++) {
    $condition = $regs[1][$i];
    $trueval   = $regs[2][$i];
    $falseval  = $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);
    }
}

When in my template string I got only one if, something like this :

{: if $var > 3 :}
    The variable $var is > than 3
{: else :}
    The variable $var is < than 3
{: endif :}

It will work perfectly. But if in this if I put an other if, it will not work.

{: if $var > 3 :}
    The variable $var is > than 3
    {: if $var1 < 2 :}
        The variable $var1 < than 2
    {: else :}
        The variable $var1 > than 2
    {: endif :}
{: else :}
    The variable $var is < than 3
{: endif :}

In this case, the preg match all will not work properly, and will output me this :

{: if $var > 3 :}
    The variable $var is > than 3
    {: if $var1 < 2 :}
        The variable $var1 is < than 2
    {: else :}
        The variable $var1 is > than 2
    {: endif :}

It will stop at the first endif, not the good one. I have absolutely no idea on how to do this. If someone have an idea ? Thank you so much for your time and your help !

Zetta420
  • 1
  • 1

1 Answers1

0

I found a solution, withouth using any regex. I don't know if it's the best practice, but it works.

First of all, I split the text line by line :

$text = explode(PHP_EOL, $text);

Next, I foreach on this $text :

        $if = [];
    foreach ($test as $key => $line){
        if(StringUtils::contains($line, 'if') && (!StringUtils::contains($line, 'endif'))){
            $if[$key] = trim($line);
        }
    }

As you can see, I'm looking for some if in this text, and I put them in an array, with the line number for key.

Next, I do the last foreach, check the condition, and replace all :

        krsort($if);

    $var = 4;
    $var1 = 1;
    foreach ($if as $ifOffset => $ix){
        for($i = $ifOffset, $iMax = count($test); $i<$iMax; $i++){
            if(StringUtils::contains($test[$i], 'endif')){
                $content = StringUtils::getBetween($text, $test[$ifOffset], $test[$i]);
                $cond = trim(str_replace('if', '', StringUtils::getBetween($ix, '{:', ':}')));
                $res = eval('return ('.$cond.');');

                $ph = $test[$ifOffset].$content.$test[$i];

                if($res===true){
                    $text = str_replace($ph, $content, $text);
                }else{
                    $text = str_replace($ph, '', $text);
                }
                unset($if[$ifOffset]);
                break;
            }
        }
    }

The $var & $var1 are the variables I use in the conditions. Now, this :

    {:if $var > 3 :}

    <p>Bienvenue {{user}} !</p>

{:if $var1 < 2 :}
<p>Wow ! Tu as la permission !</p>
{:endif:}

{:endif:}

{:if $var > 3 :}

<p>Bienvenue {{user}} !</p>

{:if $var1 < 2 :}
<p>Wow ! Tu as la permission !</p>
{:endif:}

{:endif:}

Will output this :

Bienvenue {{user}} !

Wow ! Tu as la permission !

Bienvenue {{user}} !

Wow ! Tu as la permission !

Here we are !

For the "StringUtils::contains" function, there you go :

    public static function contains($text, ...$search){
    if(!empty($search)){
        foreach($search as $key => $value){
            if(strpos($text, $value) !== false){
                unset($search, $text, $key, $value);
                return true;
                break;
            }
        }
        unset($search, $text);
    }
    return false;
}

If someone got a better idea, why not, but it works well !

Zetta420
  • 1
  • 1