From 50a5a309c5d3d29301fb0a21fde37cc7c5bae86d Mon Sep 17 00:00:00 2001 From: Claus Due Date: Thu, 14 Feb 2019 17:21:43 +0100 Subject: [PATCH] [FEATURE] Allow defining arguments for f:render with f:variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch allows you to define arguments that get passed to f:render by using f:variable in the tag contents. ```xml Special value for arg1 variable Special value for arg2 variable ``` Any argument specified with f:variable this way will override the argument of the same name if it was passed in the “arguments” array as well. The combined result will be used as variables for the sub-rendering call. References: #427 --- .../ViewHelperVariableContainer.php | 25 +++++++++++++++++++ src/ViewHelpers/RenderViewHelper.php | 14 +++++++++++ src/ViewHelpers/VariableViewHelper.php | 3 +++ 3 files changed, 42 insertions(+) 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); + } } }