Skip to content

Commit

Permalink
Merge branch 'recursion'
Browse files Browse the repository at this point in the history
  • Loading branch information
Aleksandr-ru committed Apr 5, 2017
2 parents e1b9da3 + b74f1da commit 7611f83
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 6 deletions.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Another simple template parser

* Blocks of markup as object
* Block repeat (setBlock appends new block and returns handle to it)
* Recursive blocks (see example below)
* Empty block placeholders
* Independent variables in blocks and main template
* Variable data escaping (filtering) in template, see markup below
Expand Down Expand Up @@ -159,6 +160,35 @@ for($i=1; $i<=3; $i++) {
$to->showOutput();
```

## Recursive blocks
Since 2.4 there is an abilty to make your blocks recursive. For example:

*recursive.html*

```
<body>
<!-- BEGIN blockname -->
[a recursive block]
<!-- RECURSION blockname -->
<!-- END blockname -->
</body>
```

The code:

```
$to = TemplateObject::loadTemplate('recursive.html');
$to->setBlock('blockname')->setBlock('blockname')->setBlock('blockname');
$to->showOutput();
```

Output:

```
[a recursive block] [a recursive block] [a recursive block]
```


## Function quick reference

### *static* loadTemplate(string $file) : TemplateObject
Expand Down
57 changes: 51 additions & 6 deletions TemplateObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
* Based on features of HTML_Template_IT by Ulf Wendel, Pierre-Alain Joye.
*
* @author Rebel
* @copyright (c) 2016 Aleksandr.ru
* @copyright (c) 2017 Aleksandr.ru
* @link https://github.com/Aleksandr-ru/TemplateObject Project page
* @link https://pear.php.net/package/HTML_Template_IT Original HTML_Template_IT
* @link http://aleksandr.ru Author's website
*
* @version 2.3
* @version 2.4
*/
class TemplateObject
{
Expand Down Expand Up @@ -49,6 +49,15 @@ class TemplateObject
*/
const REGEXP_BLOCK = '@<!--\s*BEGIN\s+(?P<name>[a-z][a-z0-9_]*)(?P<options>(\s+[a-z0-9_]+)*)\s*-->(?P<data>.*)(<!--\s*EMPTY\s\g{name}\s*-->(?P<empty>.*))?<!--\s*END\s\g{name}\s*-->@ismU';

/**
* Regexp to parse markup like
*
* ```
* <!-- RECURSION blockname -->
* ```
*/
const REGEXP_RECURSION = '@<!--\s*RECURSION\s+(?P<name>[a-z][a-z0-9_]*)\s*-->@iU';

/**
* Regexp to parse markup like
*
Expand Down Expand Up @@ -84,7 +93,14 @@ class TemplateObject
* the teplate and output holder
*/
protected $tmpl, $out;


/**
* Original template holder for recursion
* @var string
*/
protected $template;


/**
* @var $includes
* @var $base_dir
Expand Down Expand Up @@ -162,12 +178,13 @@ function __construct($data = '', $base_dir = '')
{
$this->__destruct();

$this->tmpl = $data;
$this->template = $this->tmpl = $data;
$this->base_dir = $base_dir ? $base_dir : getcwd();

$this->parseExtend();
$this->parseIncludes();
$this->parseBlocks();
$this->parseRecursion();
$this->parseVariables();
}

Expand All @@ -176,6 +193,7 @@ function __construct($data = '', $base_dir = '')
*/
function __destruct()
{
$this->template = '';
$this->tmpl = $this->out = '';
$this->includes = array();
$this->base_dir = '';
Expand Down Expand Up @@ -504,7 +522,7 @@ protected function parseBlocks()

/**
* Callback for parseBlocks function
* Adds a block data and replaces it with placeholder
* Adds a block data and replaces markup with placeholder
*
* @param array $arr data from preg_replace_callback
*
Expand All @@ -516,10 +534,37 @@ protected function parseBlockCallback($arr)
$this->blocks[$arr['name']] = array(
'data' => $arr['data'],
'empty' => isset($arr['empty']) ? $arr['empty'] : '',
'options' => preg_split("@\s+@", strtolower($arr['options']), -1, PREG_SPLIT_NO_EMPTY)
'options' => preg_split("@\s+@", strtolower($arr['options']), -1, PREG_SPLIT_NO_EMPTY),
);
return sprintf(self::PLACEHOLDER_BLOCK, $arr['name']);
}

/**
* Parse recursion markup and replace it with block placeholdes
*/
protected function parseRecursion()
{
$this->tmpl = preg_replace_callback(self::REGEXP_RECURSION, array($this, 'parseRecursionCallback'), $this->tmpl);
}

/**
* Callback for parseRecursion function
* Adds a recursive block and replaces markup with placeholder
*
* @param array $arr data from preg_replace_callback
*
* @return string
* @see parseRecursion()
*/
protected function parseRecursionCallback($arr)
{
$this->blocks[$arr['name']] = array(
'data' => $this->template,
'empty' => '',
'options' => array(),
);
return sprintf(self::PLACEHOLDER_BLOCK, $arr['name']);
}

/**
* Parse variable markup and replace it with placeholders
Expand Down
35 changes: 35 additions & 0 deletions tests/recursion.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<title>TemplateObject &ndash; recursion TEST</title>
</head>
<body>
<p>Refresh page to see different results</p>
<hr>

<ul>
<!-- BEGIN block -->
<li>
Recursion level {{LEVEL}}
<ul>
<!-- RECURSION block -->
</ul>
</li>
<!-- END block -->
</ul>

<hr>

<!-- BEGIN block2 -->
[block-2]
<!-- RECURSION block2 -->
<!-- END block2 -->

<hr>

<!-- BEGIN block3 -->
[block-3, level {{LEVEL}}]
<!-- RECURSION block3 -->
<!-- END block3 -->
</body>
</html>
34 changes: 34 additions & 0 deletions tests/recursion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
require('../TemplateObject.php');
$to = TemplateObject::loadTemplate('recursion.html');

define('MAX_LEVEL', 5);
recursion($to);

$to->setBlock('block2')->setBlock('block2')->setBlock('block2');

$a = array(
'block3' => array(
'LEVEL' => 1,
'block3' => array(
'LEVEL' => 2,
'block3' => array(
'LEVEL' => 3,
),
),
),
);
$to->setVarArray($a);

$to->showOutput();

function recursion(&$tmpl, $level = 0)
{
$rows = rand(1, 3);
for($i=1; $i<=$rows; $i++) {
$b = $tmpl->setBlock('block');
$b->setVariable('LEVEL', $level);
$go_deep = !$level || rand(0, 1);
if($go_deep && $level < MAX_LEVEL) recursion($b, ++$level);
}
}

0 comments on commit 7611f83

Please sign in to comment.