CodeIgniter Forums
Template Parser Class Improvement - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Archived Discussions (https://forum.codeigniter.com/forumdisplay.php?fid=20)
+--- Forum: Archived Development & Programming (https://forum.codeigniter.com/forumdisplay.php?fid=23)
+--- Thread: Template Parser Class Improvement (/showthread.php?tid=5263)

Pages: 1 2 3 4 5 6 7 8 9


Template Parser Class Improvement - El Forum - 01-14-2008

[eluser]adamp1[/eluser]
Does anyone know if you can have embedded recursive levels in the template parser? IE:
Code:
<h2>Page Title</h2>
{subtitle}
<h4>{title}</h4>
  {para}
   <p>{text}</p>
  {/para}
{/subtitle}



Template Parser Class Improvement - El Forum - 01-14-2008

[eluser]Michael Wales[/eluser]
I believe it would - it's just parsing a multi-dimensional array.

Why not try it and let us know?


Template Parser Class Improvement - El Forum - 01-14-2008

[eluser]adamp1[/eluser]
OK yer did some testing, it seems to work. Sadly there is no way that it will delete the {variable} text if 'variable' is not given.

Code:
<h1>Title</h1>
{subtitle}
<h4>{title}</h4>
{para}
<p>{text}</p>
{/para}
{/subtitle}

If you feed this replacement array

Code:
$template = array('subtitle'=> array(
  array('title'=>'SubTitle 1', 'para'=> array(
    array('text'=>'1.1 Text'),
    array('text'=>'1.2 Text'))),
  array('title'=>'SubTitle 2', 'para'=> array(
    array('text'=>'2.1 Text'),
    array('text'=>'2.2 Text')))
));

You get the following

Code:
<h1>Title</h1>
<h4>SubTitle 1</h4>
<p>1.1 Text</p>
<p>1.2 Text</p>
<h4>SubTitle 2</h4>
<p>2.1 Text</p>
<p>2.2 Text</p>



Template Parser Class Improvement - El Forum - 01-14-2008

[eluser]adamp1[/eluser]
Seems also you cannot replace a variable with a number, it must be a string.

Also why does the parser not remove non-replaced variables and variable pairs? This seems a simple little feature. Why would the programmer want {variable} names left in after a parse??

Im not very good with Regular Expr's, but having a look at the problem cannot see if there is a way to find the variable tags.

This is Easy to find,
Code:
{loop}
  Item: {value}
{/loop}

This is harder since it will normally try and replace everything between {loop} & {/loop2}, we can get around this by excluding the "/"
Code:
{loop}
  Item: {value}
{/loop}
Other Text
{loop2}
  Item: {value}
{/loop2}

But for it to replace a parse string correctly, IE nested loops, I just can't work out the Regex
Code:
{loop}
  Item: {value}
  {loop2}
    Item: {value}
  {/loop2}
{/loop}
Other Text
{loo3}
  Item: {value}
  {loop4}
    Item: {value}
  {/loop4}
{/loop3}

I don't know about other people but this feature would be useful, otherwise the parser class seems rather pointless. It may not even be possible.


Template Parser Class Improvement - El Forum - 01-14-2008

[eluser]Rick Jolly[/eluser]
The parser is notoriously limited. It's very easy to use {insert your favorite template engine here} with CI.


Template Parser Class Improvement - El Forum - 01-15-2008

[eluser]adamp1[/eluser]
Right well after some work I think I have a solution which works. It replaces all none assigned {variable} tags and {variable}{/variable} pairs.

To get it to work you need to add several lines to the Parser.php library

In the parse method find the lines:
Code:
if ($return == FALSE)
{
    $CI->output->final_output = $template;
}

Now add just before that block this
Code:
if (preg_match_all("(".$this->l_delim."([^".$this->r_delim."/]*)".$this->r_delim.")", $template, $m)){

    foreach($m[1] as $value)
    {
        $template = preg_replace ("(".$this->l_delim.$value.$this->r_delim."((?!".$this->l_delim.$value.$this->r_delim.")|.|[\r\n])*".$this->l_delim."/".$value.$this->r_delim.")", "", $template);
        $template = str_replace ("{".$value."}", "", $template);
    }
}

What it does is it replaces all variable pair combinations top down. This includes all nested pairs inside the parent. It also replaces any single {variable} replacement strings.

It does not replace the ##THIS TEXT## in the following example:
Code:
{test}
Test
{/test}
##THIS TEXT##
{test}
Test
{/test}

Maybe they can check over the code addition and implement it into the next release, don't know about others but it seems a rather usefull addition.


Template Parser Class Improvement - El Forum - 01-18-2008

[eluser]Derek Allard[/eluser]
Looks nice adamp1, and I can see how it would be useful. Could you distribute this as MY_parser.php for a version and solicit some community feedback? After that, we'll happily consider it.


Template Parser Class Improvement - El Forum - 01-18-2008

[eluser]adamp1[/eluser]
Sure I will give it a go later tonight.


Template Parser Class Improvement - El Forum - 01-19-2008

[eluser]adamp1[/eluser]
Right hers the file you wanted, wonder if anyone could test it and make sure my method to replace unused variable tags is OK.

Hope its useful to someone

Code:
&lt;?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* CodeIgniter
*
* An open source application development framework for PHP 4.3.2 or newer
*
* @package        CodeIgniter
* @author        Rick Ellis
* @copyright    Copyright (c) 2006, EllisLab, Inc.
* @license        http://www.codeignitor.com/user_guide/license.html
* @link        http://www.codeigniter.com
* @since        Version 1.0
* @filesource
*/

// ------------------------------------------------------------------------

/**
* MY Parser Class
*
* Added a feature so when a template is passed, if all the variable
* replacement tags are not replaced they are removed from the
* returned output. Thus making the returned string cleaner.
*
* @package        CodeIgniter
* @subpackage    Libraries
* @category        Parser
* @author            Adam Price
*/

class MY_Parser extends CI_Parser{
    /**
     *  Parse a template
     *
     * Parses pseudo-variables contained in the specified template,
     * replacing them with the data in the second param
     *
     * Changed: I have added a few extra lines to replace un-replaced
     * variable tags
     *
     * @access    public
     * @param    string
     * @param    array
     * @param    bool
     * @return    string
     */
    function parse($template, $data, $return = FALSE)
    {
        $CI =& get_instance();
        $template = $CI->load->view($template, $data, TRUE);

        if ($template == '')
        {
            return FALSE;
        }

        foreach ($data as $key => $val)
        {
            if (is_string($val))
            {
                $template = $this->_parse_single($key, $val, $template);
            }
            elseif (is_array($val))
            {
                $template = $this->_parse_pair($key, $val, $template);
            }
        }

        // START NEW CODE
        if (preg_match_all("(".$this->l_delim."([^".$this->r_delim."/]*)".$this->r_delim.")", $template, $m)){

            foreach($m[1] as $value)
            {
                $template = preg_replace ("(".$this->l_delim.$value.$this->r_delim."((?!".$this->l_delim.$value.$this->r_delim.")|.|[\r\n])*".$this->l_delim."/".$value.$this->r_delim.")", "", $template);
                $template = str_replace ("{".$value."}", "", $template);
            }
        }
        // END NEW CODE

        if ($return == FALSE)
        {
            $CI->output->final_output = $template;
        }

        return $template;
    }
}



Template Parser Class Improvement - El Forum - 01-20-2008

[eluser]isaiahdw[/eluser]
Somewhat related to this topic, I've added simple conditional functionality to the parser library.

It works like this:

CODE:
Code:
{if 10 > 8}10 is greater then 8<br />{/if}
{if "test"==test}Test is equal to test<br />{/if}
{if test!=asdfsd}Test is not equal to asdfsd<br />{/if}
{if something=={test}}Test is equal to "{test}"<br />{/if}
{if test}Test is set<br />{/if}
{if randomjunk}This should never show<br />{else}This should always show{/if}
</p>
<hr />
{array}
ID: {id}, {if {sale_price} > 0}Sale Price: {sale_price}{else}Price: {price}{/if}<br />
{/array}
{if "something something"=="something something"}Testing {else}test{/if}

OUTPUT:
Code:
10 is greater then 8
Test is equal to test
Test is not equal to asdfsd
Test is equal to "something"
This should always show
ID: 21, Price: 28
ID: 22, Price: 48
ID: 23, Sale Price: 20
Testing

Here is an updated copy of adamp1's MY_Parser library with conditional support: http://www.iitechs.com/MY_Parser.phps

I use the parser library to to format emails and I can't use php in the email templates because they need to be editable by people that don't know php.

If you want to store the template in your database and not as a view file you can just remove the "$template = $CI->load->view($template, $data, TRUE);" line from the parse function and then use it like this $this->parser->parse($string_from_database, $data....)

Let me know if you find any problems with it!