How tag filters work
Tag filters are callbacks executed during parsing. They are called for each tag using the tag as the callback's sole argument. Tag filters can be used to invalidate tags or modify their attributes.
Add a custom tag filter
In the following example, we create a BBCode named block
that takes two attributes: width
and height
. Then we add a filter to this tag that invalidates the tag if the product of width
× height
is not between 100 and 1000.
$configurator = new s9e\TextFormatter\Configurator;
function myfilter($tag)
{
$product = $tag->getAttribute('width') * $tag->getAttribute('height');
if ($product < 100 || $product > 1000)
{
$tag->invalidate();
}
}
// Create a [block] BBCode to test our filter
$configurator->BBCodes->addCustom(
'[block width={INT} height={INT}]',
'<div style="width:{@width}px;height:{@height}px" class="block"></div>'
);
// Add our custom filter to this tag
$configurator->tags['block']->filterChain[] = 'myfilter';
// Get an instance of the parser and the renderer
extract($configurator->finalize());
$text = "[block width=10 height=10]\n"
. "[block width=99 height=99]";
$xml = $parser->parse($text);
$html = $renderer->render($xml);
echo $html;
<div style="width:10px;height:10px" class="block"></div>
[block width=99 height=99]
Filter order
By default, a tag's filter chain starts with two callbacks. They are:
s9e\TextFormatter\Parser\FilterProcessing::executeAttributePreprocessors
s9e\TextFormatter\Parser\FilterProcessing::filterAttributes
You can manage filters using the TagFilterChain API. Filters are executed in order, and attribute values are validated by the filterAttributes
callback. If you add your own filter before validation, any attributes created or modified by your filter will be validated as if it was normal user input. If you add your filter after the filterAttributes
callback, their value will not be validated, allowing you to set values that a user wouldn't be allowed to.
In the following example, we create a BBCode that accepts two optional attributes, set to be validated as numbers: x
and y
. We then add two tag filters: the first one sets x
's value to potato
(which is not a number) at the start of the chain before validation, and the second filter does the samefor y
but at the end of the chain after validation. In the end, x
's value gets removed as invalid while y
's value remains.
function setTagAttribute($tag, $attrName, $attrValue)
{
$tag->setAttribute($attrName, $attrValue);
}
$configurator = new s9e\TextFormatter\Configurator;
$configurator->BBCodes->addCustom('[test x={NUMBER1?} y={NUMBER2?}]', '');
// Add our custom filters to this tag
$configurator->tags['test']->filterChain->prepend('setTagAttribute($tag, "x", "potato")');
$configurator->tags['test']->filterChain->append ('setTagAttribute($tag, "y", "potato")');
// Get an instance of the parser and the renderer
extract($configurator->finalize());
$text = '[test x=1 y=2]';
$xml = $parser->parse($text);
echo $xml;
<r><TEST y="potato">[test x=1 y=2]</TEST></r>