Skip to content

Commit 523ffe9

Browse files
committed
[FEATURE] Add view helpers for URIs to arbitrary TS objects
Link and URI view helpers are added that makes it easy to create URIs to any TypoScript object path. With these it becomes tirvial to split rendering of a page into multiple parts for ESI or Ajax.
1 parent 2beaa2a commit 523ffe9

11 files changed

Lines changed: 259 additions & 26 deletions

Classes/Configuration/RecordRenderingConfigurationBuilder.php

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function __construct(RenderingContext $renderingContext)
4141
* @return string[]
4242
*
4343
*/
44-
public function configurationFor($extensionName, $pluginName, $contextRecord = 'currentPage')
44+
public function configurationFor(string $extensionName, string $pluginName, string $contextRecord = 'currentPage')
4545
{
4646
list($tableName, $uid) = $this->resolveTableNameAndUidFromContextString($contextRecord);
4747
$pluginSignature = $this->buildPluginSignature($extensionName, $pluginName);
@@ -52,22 +52,33 @@ public function configurationFor($extensionName, $pluginName, $contextRecord = '
5252
];
5353
}
5454

55+
/**
56+
* @param string $renderingPath
57+
* @param string $contextRecord
58+
*
59+
* @throws \Helhum\TyposcriptRendering\Configuration\ConfigurationBuildingException
60+
* @return string[]
61+
*
62+
*/
63+
public function configurationForPath(string $renderingPath, string $contextRecord = 'currentPage')
64+
{
65+
list($tableName, $uid) = $this->resolveTableNameAndUidFromContextString($contextRecord);
66+
return [
67+
'record' => $tableName . '_' . $uid,
68+
'path' => $renderingPath,
69+
];
70+
}
71+
5572
/**
5673
* Resolves the table name and uid for the record the rendering is based upon.
5774
* Falls back to current page if none is available
5875
*
5976
* @param string $contextRecord
6077
*
61-
* @throws ConfigurationBuildingException
6278
* @return string[] table name as first and uid as second index of the array
63-
*
6479
*/
65-
protected function resolveTableNameAndUidFromContextString($contextRecord)
80+
protected function resolveTableNameAndUidFromContextString(string $contextRecord)
6681
{
67-
if (!is_string($contextRecord)) {
68-
throw new ConfigurationBuildingException(sprintf('Context record must be of type string "%s" given.', gettype($contextRecord)), 1416846201);
69-
}
70-
7182
if ($contextRecord === 'currentPage') {
7283
$tableNameAndUid = ['pages', $this->renderingContext->getFrontendController()->id];
7384
} else {

Classes/Uri/TyposcriptRenderingUri.php

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,11 @@ private function parseViewHelperContext(ViewHelperContext $viewHelperContext): v
4040
$arguments = $viewHelperContext->getArguments();
4141
$controllerContext = $viewHelperContext->getControllerContext();
4242

43-
$pluginName = $arguments['pluginName'];
44-
$extensionName = $arguments['extensionName'];
43+
$pluginName = $arguments['pluginName'] ?? null;
44+
$extensionName = $arguments['extensionName'] ?? null;
4545
$contextRecord = $arguments['contextRecord'];
4646
$additionalParams = $arguments['additionalParams'];
47+
$renderingPath = $arguments['typoscriptObjectPath'] ?? null;
4748

4849
if ($pluginName === null) {
4950
$pluginName = $controllerContext->getRequest()->getPluginName();
@@ -61,7 +62,11 @@ private function parseViewHelperContext(ViewHelperContext $viewHelperContext): v
6162
$contextRecord = $viewHelperContext->getContentObject()->currentRecord;
6263
}
6364
}
64-
$renderingConfiguration = $this->buildTypoScriptRenderingConfiguration($extensionName, $pluginName, $contextRecord);
65+
if ($renderingPath === null) {
66+
$renderingConfiguration = $this->buildTypoScriptRenderingConfiguration($extensionName, $pluginName, $contextRecord);
67+
} else {
68+
$renderingConfiguration = $this->buildConfigurationForPath($renderingPath, $contextRecord);
69+
}
6570
$additionalParams['tx_typoscriptrendering']['context'] = json_encode($renderingConfiguration);
6671

6772
$uriBuilder = $controllerContext->getUriBuilder();
@@ -77,7 +82,16 @@ private function parseViewHelperContext(ViewHelperContext $viewHelperContext): v
7782
->setAddQueryStringMethod($arguments['addQueryStringMethod'])
7883
->setArgumentsToBeExcludedFromQueryString($arguments['argumentsToBeExcludedFromQueryString']);
7984

80-
$this->parseUri($uriBuilder->uriFor($arguments['action'], $arguments['arguments'], $arguments['controller'], $extensionName, $pluginName));
85+
$this->parseUri(
86+
$uriBuilder->uriFor(
87+
$arguments['action'] ?? null,
88+
$arguments['arguments'] ?? null,
89+
$arguments['controller'] ?? null,
90+
$extensionName,
91+
$pluginName
92+
),
93+
$renderingPath !== null
94+
);
8195
}
8296

8397
/**
@@ -95,4 +109,19 @@ public function buildTypoScriptRenderingConfiguration(string $extensionName, str
95109

96110
return $configurationBuilder->configurationFor($extensionName, $pluginName, $contextRecordId);
97111
}
112+
113+
private function buildConfigurationForPath(string $renderingPath, string $contextRecordId): array
114+
{
115+
$configurationBuilder = new RecordRenderingConfigurationBuilder(new RenderingContext($GLOBALS['TSFE']));
116+
117+
return $configurationBuilder->configurationForPath($renderingPath, $contextRecordId);
118+
}
119+
120+
protected function parseUri($uri, $removeControllerArgument = false)
121+
{
122+
if ($removeControllerArgument) {
123+
$uri = str_replace('&tx__%5Bcontroller%5D=Standard', '', $uri);
124+
}
125+
parent::parseUri($uri);
126+
}
98127
}

Classes/ViewHelpers/Link/ActionViewHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
2020

2121
/**
22-
* A view helper for creating links to extbase actions.
22+
* A view helper for creating links to render individual extbase actions.
2323
*
2424
* = Examples =
2525
*
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
declare(strict_types=1);
3+
namespace Helhum\TyposcriptRendering\ViewHelpers\Link;
4+
5+
/*
6+
* This file is part of the TypoScript Rendering TYPO3 extension.
7+
*
8+
* It is free software; you can redistribute it and/or modify it under
9+
* the terms of the GNU General Public License, either version 2
10+
* of the License, or any later version.
11+
*
12+
* For the full copyright and license information, please read
13+
* LICENSE file that was distributed with this source code.
14+
*
15+
*/
16+
17+
use Helhum\TyposcriptRendering\Uri\TyposcriptRenderingUri;
18+
use Helhum\TyposcriptRendering\Uri\ViewHelperContext;
19+
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
20+
21+
/**
22+
* A view helper for creating links to render arbitrary TypoScript objects.
23+
*
24+
* = Examples =
25+
*
26+
* <code title="link to the given TypoScript object">
27+
* <t:link.cObject typoscriptObjectPath="lib.userProfile">action link</f:link.action>
28+
* </code>
29+
* <output>
30+
* <a href="index.php?id=123&amp;tx_typoscriptrendering[context]={"record":"tt_content_123","path":"lib.userProfile"}&amp;cHash=xyz">action link</f:link.action>
31+
* (depending on the current page and your TS configuration)
32+
* </output>
33+
*/
34+
class CObjectViewHelper extends AbstractTagBasedViewHelper
35+
{
36+
/**
37+
* @var string
38+
*/
39+
protected $tagName = 'a';
40+
41+
/**
42+
* Arguments initialization
43+
*/
44+
public function initializeArguments()
45+
{
46+
parent::initializeArguments();
47+
$this->registerUniversalTagAttributes();
48+
$this->registerArgument('typoscriptObjectPath', 'string', 'TypoScript rendering path');
49+
$this->registerArgument('contextRecord', 'string', 'The record that the rendering should depend upon. e.g. current (default: record is fetched from current Extbase plugin), tt_content:12 (tt_content record with uid 12), pages:15 (pages record with uid 15), \'currentPage\' record of current page', false, 'current');
50+
$this->registerTagAttribute('name', 'string', 'Specifies the name of an anchor');
51+
$this->registerTagAttribute('rel', 'string', 'Specifies the relationship between the current document and the linked document');
52+
$this->registerTagAttribute('rev', 'string', 'Specifies the relationship between the linked document and the current document');
53+
$this->registerTagAttribute('target', 'string', 'Specifies where to open the linked document');
54+
$this->registerArgument('pageUid', 'int', 'Target page. See TypoLink destination');
55+
$this->registerArgument('pageType', 'int', 'Type of the target page. See typolink.parameter', false, 0);
56+
$this->registerArgument('noCache', 'bool', 'Set this to disable caching for the target page. You should not need this.', false, false);
57+
$this->registerArgument('section', 'string', 'The anchor to be added to the URI', false, '');
58+
$this->registerArgument('format', 'string', 'The requested format, e.g. ".html', false, '');
59+
$this->registerArgument('linkAccessRestrictedPages', 'bool', 'If set, links pointing to access restricted pages will still link to the page even though the page cannot be accessed.', false, false);
60+
$this->registerArgument('additionalParams', 'array', 'Additional query parameters that won\'t be prefixed like $arguments (overrule $arguments)', false, []);
61+
$this->registerArgument('absolute', 'bool', 'If set, the URI of the rendered link is absolute', false, false);
62+
$this->registerArgument('addQueryString', 'bool', 'If set, the current query parameters will be kept in the URI', false, false);
63+
$this->registerArgument('argumentsToBeExcludedFromQueryString', 'array', 'Arguments to be removed from the URI. Only active if $addQueryString = TRUE', false, []);
64+
$this->registerArgument('addQueryStringMethod', 'string', 'Set which parameters will be kept. Only active if $addQueryString = TRUE');
65+
}
66+
67+
/**
68+
* @return string Rendered link
69+
*/
70+
public function render()
71+
{
72+
$uri = (new TyposcriptRenderingUri())->withViewHelperContext(
73+
new ViewHelperContext(
74+
$this->renderingContext,
75+
$this->arguments
76+
)
77+
);
78+
79+
$this->tag->addAttribute('href', $uri);
80+
$this->tag->setContent($this->renderChildren());
81+
$this->tag->forceClosingTag(true);
82+
83+
return $this->tag->render();
84+
}
85+
}

Classes/ViewHelpers/Uri/ActionViewHelper.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@
1616

1717
use Helhum\TyposcriptRendering\Uri\TyposcriptRenderingUri;
1818
use Helhum\TyposcriptRendering\Uri\ViewHelperContext;
19+
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
1920
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
2021
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
2122

2223
/**
23-
* A view helper for creating Ajax URIs to extbase actions.
24+
* A view helper for creating URIs to render individual extbase actions.
2425
*
2526
* = Examples =
2627
*
@@ -32,7 +33,7 @@
3233
* (depending on the current page and your TS configuration)
3334
* </output>
3435
*/
35-
class ActionViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper
36+
class ActionViewHelper extends AbstractViewHelper
3637
{
3738
use CompileWithRenderStatic;
3839

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
declare(strict_types=1);
3+
namespace Helhum\TyposcriptRendering\ViewHelpers\Uri;
4+
5+
/*
6+
* This file is part of the TypoScript Rendering TYPO3 extension.
7+
*
8+
* It is free software; you can redistribute it and/or modify it under
9+
* the terms of the GNU General Public License, either version 2
10+
* of the License, or any later version.
11+
*
12+
* For the full copyright and license information, please read
13+
* LICENSE file that was distributed with this source code.
14+
*
15+
*/
16+
17+
use Helhum\TyposcriptRendering\Uri\TyposcriptRenderingUri;
18+
use Helhum\TyposcriptRendering\Uri\ViewHelperContext;
19+
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
20+
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
21+
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
22+
23+
/**
24+
* A view helper for creating URIs to render arbitrary TypoScript objects.
25+
*
26+
* = Examples =
27+
*
28+
* <code title="URI to the given rendering path">
29+
* <t:uri.cObject renderingPath="lib.userProfile"/>
30+
* </code>
31+
* <output>
32+
* index.php?id=123&tx_typoscriptrendering[context]={"record":"tt_content_123","path":"lib.userProfile"}&cHash=xyz
33+
* (depending on the current page and your TS configuration)
34+
* </output>
35+
*/
36+
class CObjectViewHelper extends AbstractViewHelper
37+
{
38+
use CompileWithRenderStatic;
39+
40+
/**
41+
* Initialize arguments
42+
*
43+
* @api
44+
*/
45+
public function initializeArguments()
46+
{
47+
$this->registerArgument('typoscriptObjectPath', 'string', 'TypoScript rendering path');
48+
$this->registerArgument('contextRecord', 'string', 'The record that the rendering should depend upon. e.g. current (default: record is fetched from current Extbase plugin), tt_content:12 (tt_content record with uid 12), pages:15 (pages record with uid 15), \'currentPage\' record of current page', false, 'current');
49+
$this->registerArgument('pageUid', 'int', 'Target page. See TypoLink destination');
50+
$this->registerArgument('pageType', 'int', 'Type of the target page. See typolink.parameter', false, 0);
51+
$this->registerArgument('noCache', 'bool', 'Set this to disable caching for the target page. You should not need this.', false, false);
52+
$this->registerArgument('section', 'string', 'The anchor to be added to the URI', false, '');
53+
$this->registerArgument('format', 'string', 'The requested format, e.g. ".html', false, '');
54+
$this->registerArgument('linkAccessRestrictedPages', 'bool', 'If set, links pointing to access restricted pages will still link to the page even though the page cannot be accessed.', false, false);
55+
$this->registerArgument('additionalParams', 'array', 'additional query parameters that won\'t be prefixed like $arguments (overrule $arguments)', false, []);
56+
$this->registerArgument('absolute', 'bool', 'If set, an absolute URI is rendered', false, false);
57+
$this->registerArgument('addQueryString', 'bool', 'If set, the current query parameters will be kept in the URI', false, false);
58+
$this->registerArgument('argumentsToBeExcludedFromQueryString', 'array', 'arguments to be removed from the URI. Only active if $addQueryString = TRUE', false, []);
59+
$this->registerArgument('addQueryStringMethod', 'string', 'Set which parameters will be kept. Only active if $addQueryString = TRUE');
60+
}
61+
62+
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
63+
{
64+
$uri = (new TyposcriptRenderingUri())->withViewHelperContext(
65+
new ViewHelperContext(
66+
$renderingContext,
67+
$arguments
68+
)
69+
);
70+
71+
return (string)$uri;
72+
}
73+
}

Tests/Functional/Fixtures/Frontend/Basic.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,27 @@ lib.link {
2626
parameter = 1
2727
}
2828
}
29+
lib.foo = TEXT
30+
lib.foo.value = FOO
2931

3032
lib.fluid = FLUIDTEMPLATE
3133
lib.fluid.file = EXT:typoscript_rendering/Tests/Functional/Fixtures/Frontend/Template.html
3234

3335
lib.viewHelper = FLUIDTEMPLATE
3436
lib.viewHelper.file = EXT:typoscript_rendering/Tests/Functional/Fixtures/Frontend/ViewHelperTemplate.html
37+
3538
lib.linkViewHelper = FLUIDTEMPLATE
3639
lib.linkViewHelper.file = EXT:typoscript_rendering/Tests/Functional/Fixtures/Frontend/LinkViewHelperTemplate.html
40+
41+
lib.cObjectUriViewHelper = FLUIDTEMPLATE
42+
lib.cObjectUriViewHelper.file = EXT:typoscript_rendering/Tests/Functional/Fixtures/Frontend/CObjectUriViewHelperTemplate.html
43+
44+
lib.cObjectLinkViewHelper = FLUIDTEMPLATE
45+
lib.cObjectLinkViewHelper.file = EXT:typoscript_rendering/Tests/Functional/Fixtures/Frontend/CObjectLinkViewHelperTemplate.html
46+
3747
lib.oldViewHelper = FLUIDTEMPLATE
3848
lib.oldViewHelper.file = EXT:typoscript_rendering/Tests/Functional/Fixtures/Frontend/OldViewHelperTemplate.html
49+
3950
tt_content.typoscriptrendering_plugintest.20 = TEXT
4051

4152
page = PAGE
@@ -51,7 +62,6 @@ page {
5162
}
5263

5364

54-
5565
[globalVar = GP:L = 1]
5666
config.sys_language_uid = 1
5767
[end]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<html xmlns="http://www.w3.org/1999/xhtml"
2+
xmlns:f="http://typo3.org/ns/TYPO3/Fluid/ViewHelpers"
3+
xmlns:t="http://typo3.org/ns/Helhum/TyposcriptRendering/ViewHelpers"
4+
data-namespace-typo3-fluid="true">
5+
<t:link.cObject typoscriptObjectPath="lib.foo" contextRecord="currentPage">Link</t:link.cObject>
6+
</html>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<html xmlns="http://www.w3.org/1999/xhtml"
2+
xmlns:f="http://typo3.org/ns/TYPO3/Fluid/ViewHelpers"
3+
xmlns:t="http://typo3.org/ns/Helhum/TyposcriptRendering/ViewHelpers"
4+
data-namespace-typo3-fluid="true">
5+
<t:uri.cObject typoscriptObjectPath="lib.foo" contextRecord="currentPage"/>
6+
</html>

Tests/Functional/RenderingTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,28 @@ public function viewHelperOutputsUri()
4747
$this->assertSame($expectedContent, $actualContentWithoutCHash);
4848
}
4949

50+
/**
51+
* @test
52+
*/
53+
public function cObjectUriViewHelperOutputsUri()
54+
{
55+
$requestArguments = ['url' => $this->getRenderUrl(1, 1, 'lib.cObjectUriViewHelper')];
56+
$actualContentWithoutCHash = preg_replace('/&amp;cHash=[a-z0-9]*/', '', trim($this->fetchFrontendResponse($requestArguments)->getContent()));
57+
$expectedContent = '/index.php?id=1&amp;L=1&amp;tx_typoscriptrendering%5Bcontext%5D=%7B%22record%22%3A%22pages_1%22%2C%22path%22%3A%22lib.foo%22%7D';
58+
$this->assertSame($expectedContent, $actualContentWithoutCHash);
59+
}
60+
61+
/**
62+
* @test
63+
*/
64+
public function cObjectLinkViewHelperOutputsUri()
65+
{
66+
$requestArguments = ['url' => $this->getRenderUrl(1, 1, 'lib.cObjectLinkViewHelper')];
67+
$actualContentWithoutCHash = preg_replace('/&amp;cHash=[a-z0-9]*/', '', trim($this->fetchFrontendResponse($requestArguments)->getContent()));
68+
$expectedContent = '<a href="/index.php?id=1&amp;L=1&amp;tx_typoscriptrendering%5Bcontext%5D=%7B%22record%22%3A%22pages_1%22%2C%22path%22%3A%22lib.foo%22%7D">Link</a>';
69+
$this->assertSame($expectedContent, $actualContentWithoutCHash);
70+
}
71+
5072
/**
5173
* @test
5274
*/

0 commit comments

Comments
 (0)