Skip to content
Snippets Groups Projects
Commit ccb1c2c8 authored by Oliver Hader's avatar Oliver Hader Committed by Andreas Fernandez
Browse files

[FEATURE] Expose internal typoLinkParts in TypolinkViewHelper

Parameters being generated internally by TypoLink using
`<f:link.typolink parts-as="typoLinkParts">` view helper are
exposed as variable and can be used in Fluid templates again,
which are:

* url
* target
* class
* title
* additionalParams

Resolves: #90026
Releases: master
Change-Id: I6c3386ed1f177aeb98171056f5d8bd2991d6cf46
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/62769


Tested-by: default avatarTYPO3com <noreply@typo3.com>
Tested-by: default avatarSusanne Moog <look@susi.dev>
Tested-by: default avatarAndreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: default avatarSusanne Moog <look@susi.dev>
Reviewed-by: default avatarAndreas Fernandez <a.fernandez@scripting-base.de>
parent 893ee207
No related merge requests found
.. include:: ../../Includes.txt
=====================================================================
Feature: #90026 - Expose internal typoLinkParts in TypolinkViewHelper
=====================================================================
See :issue:`90026`
Description
===========
Parameters being generated internally by TypoLink using
:html:`<f:link.typolink parts-as="typoLinkParts">` view helper are exposed as
variable and can be used in Fluid templates again.
View helper attribute `parts-as` (default `typoLinkParts`) allows to define
variable name to be used containing the following internal parts:
* url
* target
* class
* title
* additionalParams
Details for these internal parts are documented for :ts:`typolink.parameter`
in `TypoScript reference`_
.. _TypoScript reference: https://docs.typo3.org/m/typo3/reference-typoscript/master/en-us/Functions/Typolink.html?highlight=typolink#parameter
Impact
======
Multiple instructions for attribute `parameter` (e.g. persisted to entity
record) can be used individually.
.. code-block: html
<f:link.typolink parameter="123 _top news title" parts-as="parts">
{parts.url}
{parts.target}
{parts.class}
{parts.title}
{parts.additionalParams}
</f:link.typolink>
.. index:: Fluid, Frontend, ext:fluid
...@@ -100,6 +100,7 @@ class TypolinkViewHelper extends AbstractViewHelper ...@@ -100,6 +100,7 @@ class TypolinkViewHelper extends AbstractViewHelper
$this->registerArgument('addQueryStringMethod', 'string', '', false, 'GET'); $this->registerArgument('addQueryStringMethod', 'string', '', false, 'GET');
$this->registerArgument('addQueryStringExclude', 'string', '', false, ''); $this->registerArgument('addQueryStringExclude', 'string', '', false, '');
$this->registerArgument('absolute', 'bool', 'Ensure the resulting URL is an absolute URL', false, false); $this->registerArgument('absolute', 'bool', 'Ensure the resulting URL is an absolute URL', false, false);
$this->registerArgument('parts-as', 'string', 'Variable name containing typoLink parts (if any)', false, 'typoLinkParts');
} }
/** /**
...@@ -118,6 +119,7 @@ class TypolinkViewHelper extends AbstractViewHelper ...@@ -118,6 +119,7 @@ class TypolinkViewHelper extends AbstractViewHelper
trigger_error('Using the argument "useCacheHash" in <f:link.typolink> ViewHelper has no effect anymore. Remove the argument in your fluid template, as it will result in a fatal error.', E_USER_DEPRECATED); trigger_error('Using the argument "useCacheHash" in <f:link.typolink> ViewHelper has no effect anymore. Remove the argument in your fluid template, as it will result in a fatal error.', E_USER_DEPRECATED);
} }
$parameter = $arguments['parameter'] ?? ''; $parameter = $arguments['parameter'] ?? '';
$partsAs = $arguments['parts-as'] ?? 'typoLinkParts';
$typoLinkCodec = GeneralUtility::makeInstance(TypoLinkCodecService::class); $typoLinkCodec = GeneralUtility::makeInstance(TypoLinkCodecService::class);
$typoLinkConfiguration = $typoLinkCodec->decode($parameter); $typoLinkConfiguration = $typoLinkCodec->decode($parameter);
...@@ -125,8 +127,14 @@ class TypolinkViewHelper extends AbstractViewHelper ...@@ -125,8 +127,14 @@ class TypolinkViewHelper extends AbstractViewHelper
$mergedTypoLinkConfiguration = static::mergeTypoLinkConfiguration($typoLinkConfiguration, $arguments); $mergedTypoLinkConfiguration = static::mergeTypoLinkConfiguration($typoLinkConfiguration, $arguments);
$typoLinkParameter = $typoLinkCodec->encode($mergedTypoLinkConfiguration); $typoLinkParameter = $typoLinkCodec->encode($mergedTypoLinkConfiguration);
// expose internal typoLink configuration to Fluid child context
$variableProvider = $renderingContext->getVariableProvider();
$variableProvider->add($partsAs, $typoLinkConfiguration);
// If no link has to be rendered, the inner content will be returned as such // If no link has to be rendered, the inner content will be returned as such
$content = (string)$renderChildrenClosure(); $content = (string)$renderChildrenClosure();
// clean up exposed variables
$variableProvider->remove($partsAs);
if ($parameter) { if ($parameter) {
$content = static::invokeContentObjectRenderer($arguments, $typoLinkParameter, $content); $content = static::invokeContentObjectRenderer($arguments, $typoLinkParameter, $content);
} }
......
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<f:link.typolink parameter="{parameter}"
parts-as="typoLinkParts">Individual {typoLinkParts.target} {typoLinkParts.class} {typoLinkParts.title}</f:link.typolink>
</html>
...@@ -343,4 +343,33 @@ class TypolinkViewHelperTest extends FunctionalTestCase ...@@ -343,4 +343,33 @@ class TypolinkViewHelperTest extends FunctionalTestCase
], ],
]; ];
} }
public function typoLinkPartsAreRenderedDataProvider(): array
{
return [
[
'http://typo3.org/ "_self" "<CSS>" "<Title>"',
'<a href="http://typo3.org/" title="&lt;Title&gt;" target="_self" class="&lt;CSS&gt;">Individual _self &lt;CSS&gt; &lt;Title&gt;</a>',
],
[
'http://typo3.org/ "<Target>" "<CSS>" "<Title>"', // target does not point to "self", adds noreferrer relationship
'<a href="http://typo3.org/" title="&lt;Title&gt;" target="&lt;Target&gt;" class="&lt;CSS&gt;" rel="noreferrer">Individual &lt;Target&gt; &lt;CSS&gt; &lt;Title&gt;</a>',
],
];
}
/**
* @param string $parameter
* @param string $expectation
*
* @test
* @dataProvider typoLinkPartsAreRenderedDataProvider
*/
public function typoLinkPartsAreRendered(string $parameter, string $expectation): void
{
$view = new StandaloneView();
$view->setTemplatePathAndFilename('typo3/sysext/fluid/Tests/Functional/ViewHelpers/Fixtures/link_typolink_parts.html');
$view->assignMultiple(['parameter' => $parameter]);
self::assertSame($expectation, trim($view->render()));
}
} }
...@@ -15,11 +15,13 @@ namespace TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\Link; ...@@ -15,11 +15,13 @@ namespace TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\Link;
* The TYPO3 project - inspiring people to share! * The TYPO3 project - inspiring people to share!
*/ */
use PHPUnit\Framework\MockObject\MockObject;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\Core\Rendering\RenderingContext; use TYPO3\CMS\Fluid\Core\Rendering\RenderingContext;
use TYPO3\CMS\Fluid\ViewHelpers\Link\TypolinkViewHelper; use TYPO3\CMS\Fluid\ViewHelpers\Link\TypolinkViewHelper;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\TestingFramework\Fluid\Unit\ViewHelpers\ViewHelperBaseTestcase; use TYPO3\TestingFramework\Fluid\Unit\ViewHelpers\ViewHelperBaseTestcase;
use TYPO3Fluid\Fluid\Core\Variables\VariableProviderInterface;
/** /**
* Class TypolinkViewHelperTest * Class TypolinkViewHelperTest
...@@ -27,7 +29,7 @@ use TYPO3\TestingFramework\Fluid\Unit\ViewHelpers\ViewHelperBaseTestcase; ...@@ -27,7 +29,7 @@ use TYPO3\TestingFramework\Fluid\Unit\ViewHelpers\ViewHelperBaseTestcase;
class TypolinkViewHelperTest extends ViewHelperBaseTestcase class TypolinkViewHelperTest extends ViewHelperBaseTestcase
{ {
/** /**
* @var TypolinkViewHelper|\PHPUnit\Framework\MockObject\MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface * @var TypolinkViewHelper|MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface
*/ */
protected $subject; protected $subject;
...@@ -37,8 +39,11 @@ class TypolinkViewHelperTest extends ViewHelperBaseTestcase ...@@ -37,8 +39,11 @@ class TypolinkViewHelperTest extends ViewHelperBaseTestcase
protected function setUp(): void protected function setUp(): void
{ {
$this->subject = $this->getAccessibleMock(TypolinkViewHelper::class, ['renderChildren']); $this->subject = $this->getAccessibleMock(TypolinkViewHelper::class, ['renderChildren']);
/** @var RenderingContext $renderingContext */ /** @var VariableProviderInterface|MockObject $variableProvider */
$variableProvider = $this->getMockBuilder(VariableProviderInterface::class)->getMock();
/** @var RenderingContext|MockObject $renderingContext */
$renderingContext = $this->getMockBuilder(RenderingContext::class)->disableOriginalConstructor()->getMock(); $renderingContext = $this->getMockBuilder(RenderingContext::class)->disableOriginalConstructor()->getMock();
$renderingContext->expects(self::any())->method('getVariableProvider')->willReturn($variableProvider);
$this->subject->setRenderingContext($renderingContext); $this->subject->setRenderingContext($renderingContext);
} }
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment