Page 1 of 1

Template engine: transform template syntax to PHP

Posted: Wed Jan 23, 2008 1:29 pm
by Agirre
For my current site I'm developing a template engine. Let me explan the basics: my template syntax consist out of:

Code: Select all

{variables}
 
{include: file}
 
{* comments *}
 
{block: blockname}
[i]block-content[/i]
{blockname/}
 
Looks a bit like TemplatePower, which I would have used if it did support cache. On the other hand, writing your own is a great experience. I like the caching system of PHPBB, where template syntax is converted to PHP and then saved in cache. Exactly what I want.

But I've ran into the following problem: how to code nested blocks in PHP? I tried:

Code: Select all

 
for($blockname = 0; $blockname < $this->_blocks['blockname'][$parent1iteration][$parent2iteration]; $blockname++) ...
 
This works, but it looks all messy and ugly to me. It uses a lot of arrays and I'm quite sure there has to be a more efficient and cleaner way to program this, because now the script has to remember the blocks structure (who the parents are). Hopefully someone has an idea how to code it properly?

My current _parse() of the template class (I excluded all the non-block parsing parts):

Code: Select all

    /**
    * Parses content, $this->_content is the raw template file
    */
    private function _parse() {
        /**
        * Parse blocks
        */
        $this->_content = preg_replace_callback($this->_regex['block'], array('self', '_parseBlock'), $this->_content);
 
        /**
        * Put files block structure on top, because we have to remember our blockstructure
        */
        $structure = '/*block structure*/ $this->_blocks = array_merge($this->_blocks, array(';
        foreach($this->_blocks as $block => $childs) {
            $structure .= '\'' . $block . '\'=>\'' . $childs . '\',';
        }
        $structure .= '));';
 
        $this->_content = $this->_phpOpen . $structure . $this->_phpClose . $this->_content;
    }
 
    /**
    * Parses blocks
    * @param $blockContent
    * @param $root
    * @return parsed block
    */
    public function _parseBlock($blockContent, $root = NULL) {
 
        $block = $blockContent[1];
 
        if(!isset($root)) {
            $root = $block;
        }
        else {
            $root .= '.' . $block;
        }
        $this->_blocks[$block] = $root;
 
        /**
        * Find child blocks (continue while match found)
        */
        $childContent = $blockContent[2];
        if(preg_match($this->_regex['block'], $childContent) == 1) {
            $childContent = preg_replace_callback($this->_regex['block'], create_function('$matches','global $tpl; return $tpl->_parseBlock($matches, \'' . $root . '\');'), $childContent);
        }
 
        /**
        * Now make the real code change, first we get the root needed by for-statements
        */
        $blockRoot = explode('.', $this->_blocks[$block], -1);
        $blockRoot = (!empty($blockRoot) ? '[$' . implode('][$', $blockRoot) . ']' : '');
        $blockRoot = '$this->_blockCount[\'' . $block . '\']' . $blockRoot;
 
        return $this->_phpOpen . 'for($' . $block . ' = 0; $' . $block . ' < ' . $blockRoot . '; $' . $block . '++) {' . $this->_phpClose . $block . $childContent . $this->_phpOpen . '} /*end ' . $block .' loop*/' . $this->_phpClose;
 
    }
 
As you can see, it uses create_function (with global $tpl (we assume $tpl->new Template()) ), which is like eval = evil, so I'm not happy with what I've coded here, although it might work if I work it out completely.

Re: Template engine: transform template syntax to PHP

Posted: Wed Jan 23, 2008 2:24 pm
by Christopher
Search these forums. There are some good threads on how to do nested block parsing.

Re: Template engine: transform template syntax to PHP

Posted: Wed Jan 23, 2008 2:26 pm
by Zoxive
Why not skip the whole "template" engine, and just use php.

PHP itself is a template language, just use php's alternative syntax.

It will save you alot of hassle, and CPU Cycles.

Re: Template engine: transform template syntax to PHP

Posted: Wed Jan 23, 2008 3:17 pm
by Agirre
arborint wrote:Search these forums. There are some good threads on how to do nested block parsing.
First thing I did, it came up with some interesting pages (viewtopic.php?f=1&t=76278&hilit=nested+template), but I still get stuck in the part on how to code these nested blocks in PHP. Splitting them is no problem.
Zoxive wrote:Why not skip the whole "template" engine, and just use php.

PHP itself is a template language, just use php's alternative syntax.

It will save you alot of hassle, and CPU Cycles.
I know, but I most likely will sell my site when it's finished, so I need a way to keep designing and coding seperate.

Re: Template engine: transform template syntax to PHP

Posted: Wed Jan 23, 2008 3:29 pm
by Zoxive
Agirre wrote:I know, but I most likely will sell my site when it's finished, so I need a way to keep designing and coding seperate.
You still can. Most commonly with a Model View Controller (MVC).
Just keep your logic outside of the view.

But there is always some type of basic logic in templates.

Re: Template engine: transform template syntax to PHP

Posted: Wed Jan 23, 2008 4:20 pm
by Christopher
Agirre wrote:First thing I did, it came up with some interesting pages (viewtopic.php?f=1&t=76278&hilit=nested+template), but I still get stuck in the part on how to code these nested blocks in PHP. Splitting them is no problem.
I do something like

Code: Select all

$output = $template->render('blockname');

Re: Template engine: transform template syntax to PHP

Posted: Sun Jan 27, 2008 6:41 am
by Agirre
arborint wrote: I do something like

Code: Select all

$output = $template->render('blockname');
Thought about the basics in the last couple of days. It seems best to render each block after it's 'complete'. Going to examine XTemplate, because I like the way it works. After, I'm going to rewrite my class with the ideas I've now.

Btw, to avoid calling render('blockname') I think about parsing the previous block when the block is called again. Works the same and avoid some extra code.