Fluid
Fluid copied to clipboard
RFC: TagBasedViewHelper in compiled context
Challenge
TagBasedViewHelpers are currently not specifically compilable and will be called via the ViewHelperInvoker in compiled templates. Due to how such ViewHelpers are initialised (the process has additional requirements to initialise a tag builder and allow additional arguments) combined with needing to call them statically, we are prevented from generating a consistent static call that will be possible to implement in such ViewHelpers (e.g. renderStatic).
Technical background
A method to render ViewHelpers statically already exists - renderStatic - but it receives no additional input variables beside arguments, render children closure and rendering context. In order to properly render a tag we would need the following:
- Wrapping to create a tag builder in
renderStaticand calling a delegate method on the ViewHelper which in addition to current arguments receives this tag builder instance. - An alternative publicly callable method which receives the same input arguments.
The second alternative method would be preferable since compiling can then become a matter of calling this new static method from within compiled templates, passing it either a globally available tag builder or a fresh tag builder per instance.
Tag Builder peculiarities
The tag builder itself has two peculiarities which come into play:
- The tag builder has a
resetmethod but this is not automatically called and is not consistently called in initialisation methods of either the base AbstractTagBasedViewHelper class or any currently known implementations which are not overrides of existing tag based ViewHelpers. The exception is overrides which need to create a fresh tag and thus callresetbefore re-initialising the tag builder. - The tag builder has a
setTagNamemethod which must be called with a tag name - which is currently defined non-statically in the ViewHelper that renders the tag (or provided explicitly to the tag builder during initialisation or re-initialisation after override).
These two perspectives together mean that 1) if using a global instance of tag builder for performance reasons, the tag builder must be reset on each call, and 2) the tag name must be possible to set consistently in the default method as well as allow customising the tag name. The solution thus must take precautions to handle this in the static callable context.
Suggested solution
The following sketched solution (two variants) is suggested to fulfil the requirements:
We add a public static method renderTag which receives the tag builder, tag name, attributes, arguments, render children closure and rendering context
public static function renderTag(TagBuilder $tag, $tagName, array $attributes, array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) {
// renders a tag using static calls and passed instances
}
Which in a compiled template is initialised with:
// extract of compiled code in for example a section rendering method on compiled template:
// $tagBuilder is inserted in the compiled template if parser/compiler detects any tag based VH
$tagBuilder->reset();
$tagBuilder->setTagName('staticnamefromclass');
$attributes = []; // generated with call to static method on ViewHelper
$arguments = []; // already generated by compiling
// $renderChildrenClosure generated by compiling
// $renderingContext is globally available
$output .= MyViewHelperClass::renderTag($tagBuilder, 'staticnamefromclass', $attributes, $arguments, $renderChildrenClosure, $renderingContext);
The solution would have the added benefit that the method to generate attributes can be overridden on subclasses which want to process those separately. The tag name is taken from the class while it gets compiled - and is possible to override in the top of an overridden renderTag method.
The AbstractTagBasedViewHelper class would then receive a default method to process attributes through a public method (not yet defined, awaiting comments). A Trait would be created but not implemented in the AbstractTagBasedViewHelper - instead it would be opt-in for any TagBasedViewHelper subclass (as it gets converted to be able to render the tag statically).
Requested comments
The following type of comments are requested:
- Objections related to the implementation (concerns about potential breaking, concerns about not fitting common use cases, etc.)
- Suggestions for alternative solutions to fulfil the same requirements, but improving performance, developer API friendliness, etc.
- Questions to elaborate the impact of the proposed solution in specific areas (required class migrations, etc.)
- Simple thumbs up / thumbs down vote if you understand the proposal and simply agree or disagree that it should be implemented.
Thanks in advance to participants!
i'm generally for the getting tag based viewhelpers to compile, i'm not really sure, if we might run into complications with this, i'll sleep over it :)
Proof of concept for TagBasedViewHelper conversion to Trait in the form of RendersTag:
https://github.com/TYPO3/Fluid/pull/230
Hey.
Works in this area never really materialized. I personally think we shouldn't make the existing VH API more complex, but should instead strive to reduce complexity.
I hope it's ok to close here for now.