diff --git a/src/Core/ViewHelper/ViewHelperVariableContainer.php b/src/Core/ViewHelper/ViewHelperVariableContainer.php index 5e60dc973..30dd2d452 100644 --- a/src/Core/ViewHelper/ViewHelperVariableContainer.php +++ b/src/Core/ViewHelper/ViewHelperVariableContainer.php @@ -6,6 +6,7 @@ * See LICENSE.txt that was shipped with this package. */ +use TYPO3Fluid\Fluid\Core\Variables\VariableProviderInterface; use TYPO3Fluid\Fluid\View\ViewInterface; /** @@ -29,6 +30,30 @@ class ViewHelperVariableContainer */ protected $view; + public function pushDelegateVariableContainer($viewHelperClassName, VariableProviderInterface $variableProvider) + { + if (!isset($this->objects[$viewHelperClassName]['delegateVariableProviderStack'])) { + $this->objects[$viewHelperClassName]['delegateVariableProviderStack'] = []; + } + $this->objects[$viewHelperClassName]['delegateVariableProviderStack'][] = $variableProvider; + } + + public function getTopmostDelegateVariableContainer($viewHelperClassName) + { + if (!isset($this->objects[$viewHelperClassName]['delegateVariableProviderStack'])) { + return null; + } + return end($this->objects[$viewHelperClassName]['delegateVariableProviderStack']); + } + + public function popDelegateVariableContainer($viewHelperClassName) + { + if (isset($this->objects[$viewHelperClassName]['delegateVariableProviderStack'])) { + return array_pop($this->objects[$viewHelperClassName]['delegateVariableProviderStack']); + } + return null; + } + /** * Add a variable to the Variable Container. Make sure that $viewHelperName is ALWAYS set * to your fully qualified ViewHelper Class Name diff --git a/src/ViewHelpers/RenderViewHelper.php b/src/ViewHelpers/RenderViewHelper.php index ebcab45f4..e94bfd11b 100644 --- a/src/ViewHelpers/RenderViewHelper.php +++ b/src/ViewHelpers/RenderViewHelper.php @@ -121,7 +121,21 @@ public static function renderStatic(array $arguments, \Closure $renderChildrenCl $delegate = $arguments['delegate']; /** @var RenderableInterface $renderable */ $renderable = $arguments['renderable']; + + + // Prepare a delegate variable provider that will be possible to extract after rendering the child closure. + // Any variable defined therein gets used as argument and overrides any argument of the same name. + // Note: not using late static binding here is a conscious decision: if late static binding had been used + // then f:variable would not be able to reference this ViewHelper class' stack variable correctly. + $viewHelperVariableContainer = $renderingContext->getViewHelperVariableContainer(); + $collector = $renderingContext->getVariableProvider()->getScopeCopy($variables); + + $viewHelperVariableContainer->pushDelegateVariableContainer(self::class, $collector); + $tagContent = $renderChildrenClosure(); + + $variables = $viewHelperVariableContainer->popDelegateVariableContainer(self::class)->getAll(); + if ($arguments['contentAs']) { $variables[$arguments['contentAs']] = $tagContent; } diff --git a/src/ViewHelpers/VariableViewHelper.php b/src/ViewHelpers/VariableViewHelper.php index 5f0debc41..429aa75a7 100644 --- a/src/ViewHelpers/VariableViewHelper.php +++ b/src/ViewHelpers/VariableViewHelper.php @@ -57,6 +57,9 @@ public static function renderStatic( ) { $value = $renderChildrenClosure(); $renderingContext->getVariableProvider()->add($arguments['name'], $value); + if ($delegateVariableProvider = $renderingContext->getViewHelperVariableContainer()->getTopmostDelegateVariableContainer(RenderViewHelper::class)) { + $delegateVariableProvider->add($arguments['name'], $value); + } } }