tags:

views:

111

answers:

2

I started writing my own small scaled framework and i have gotten to the templating part of it. So far i have been able to do simple variable replacing with the following code:

public function view($page, $vars)
{
    if(!file_exists('system/views/' . $page . '.php'))
    {
        trigger_error("No Template found", E_USER_ERROR);
    }

    $tempArray = file_get_contents('system/views/' . $page . '.php');

    foreach($vars as $key => $value)
    {
        $tempArray = str_replace('{' . $key . '}', $value, $tempArray);
    }

    print $tempArray;
    unset($tempArray);
}

Which works fine, but what i am looking for now is if i wanted to loop to show unknown number of records from a database and i tried a coupler of ideas but none seem to have worked so far

+1  A: 

As Zed already said there are lots of templating languages for PHP, the most popular one being Smarty and I don't know if it would really make sense to reinvent the wheel except for learning purposes. The loops you want to do are actually way more complex than just replacing elements. I'm pretty sure you can somehow do it with lots of regular expressions, but at some point you will end up with writing your own scripting language (like the Smarty guys did) with parsing your view file, creating a Syntax tree, evaluating it and compile it to a new PHP file. This is quite complex so I recommend to either use an existing templating engine or use PHP as the templating language itself (if strictly folowing the MVC pattern that might work even though there are lots of discussions about that).

With a regular expression you could parse everything between {for ...}{/for} to access an item with a given variable name, where after {for and } a definition of your variable occurrs and after } and before {/for} your html definition. That would be something like a foreach loop which you can't even nest into each other.

{for item=$varname}
    <p>{item.othervalue}</p>
{/for}
Daff
I am mainly doing it to learn, surely there must be some way of doing it that doesn't involve going to an extreame like that?
Marc Towler
I added a small example how it might look. But if you want to really learn it you may want to go to one extreme... the easiest to just use PHP as your templating language or the extreme one with creating your own templating engine.
Daff
thanks for the example, this seems the route that i was looking at going down
Marc Towler
+1  A: 

First of all, you should rethink your variable rewriting. There's several cases where your method doesn't end as expected, when you have some dependencies between them. Additionaly, everything gets replaced regardless of a variable being in a loop or not.

If you want something like {while(condition)}code{/while}, you need to be aware that recursion is also possible and therefore it's not as simple as matching a regex on it.

A simple approach would be the following:

  • Find the start of a token (variable, whileloop) and remember the position where you find it
  • If it is a variable and you are in the most outer scope (not in a loop), process it by doing a replacement. Adjust your pointer so that you don't read the replacement afterwards to avoid replacing things that you don't want to.
  • If it is a loop
    • extract the condition between the brackets and store it somewher
    • additionaly, store the current location
    • Push the token onto a stack to remember the current recursion level.
    • Remove a token from the stack when you encounter the {/while} token.
    • Now proceed recursively, pushing all nested loop tokens on the stack and removing them as they end. Stop when you are at the outermost level again.
    • Evaluate the condition of the loop. As long as it is true, create new copies from the source text between the start token and the end token and process them by using recursion.
    • Concatenate the intermediate results and replace everything from {while} to {/while} with this concatenation. Adjust your pointer so that you're pointing after the loop and continue :)

Hope that this helps. I know that it sounds a bit painful, but if you understand the concept, you should be able to do it (although it is not super-efficient and compiling template engines like smarty will always be in advance since they parse the template file just once and compile it to PHP code).

@Daff: you could find the tokens with regular expressions, but using one regex to match on a whole loop construct doesn't work due to the recursions (unless your regex has a recursive extension).

Etan