<?php
namespace XF\BbCode;
use function is_array;
abstract class Traverser
{
/**
* @var RuleSet
*/
protected $rules;
abstract public function renderTag(array $tag, array $options);
abstract public function renderString($string, array $options);
public function render($string, Parser $parser, RuleSet $rules, array $options = [])
{
$string = $this->setupParse($string, $parser, $rules, $options);
$ast = $parser->parse($string, $rules);
return $this->renderAst($ast, $rules, $options);
}
protected function setupParse($string, Parser $parser, RuleSet $rules, array &$options)
{
return $string;
}
public function renderAst(array $ast, RuleSet $rules, array $options = [])
{
$this->rules = $rules;
$options = $options + $this->getDefaultOptions();
$options['stack'] = [];
$this->setupRenderOptions($ast, $options);
$this->setupRender($ast, $options);
return $this->filterFinalOutput($this->renderSubTree($ast, $options));
}
public function getDefaultOptions()
{
return [];
}
protected function setupRenderOptions(array $ast, array &$options)
{
}
protected function setupRender(array $ast, array $options)
{
}
public function renderSubTree(array $tree, array $options)
{
$output = '';
foreach ($tree AS $element)
{
if (is_array($element))
{
$options['stack'][] = $element;
$output .= $this->renderTag($element, $options);
}
else
{
$output .= $this->renderString($element, $options);
}
}
return $output;
}
public function renderSubTreePlain(array $tree)
{
$output = '';
foreach ($tree AS $element)
{
if (is_array($element))
{
$output .= $element['original'][0]
. $this->renderSubTreePlain($element['children'])
. $element['original'][1];
}
else
{
$output .= $element;
}
}
return $output;
}
public function renderUnparsedTag(array $tag, array $options)
{
return $this->renderString($tag['original'][0], $options)
. $this->renderSubTree($tag['children'], $options)
. $this->renderString($tag['original'][1], $options);
}
public function filterFinalOutput($output)
{
return $output;
}
public function getRules()
{
return $this->rules;
}
}