[BUGFIX] Avoid duplicated classes in typolink VH
[Packages/TYPO3.CMS.git] / typo3 / sysext / fluid / Classes / ViewHelpers / Link / TypolinkViewHelper.php
1 <?php
2 namespace TYPO3\CMS\Fluid\ViewHelpers\Link;
3
4 /* *
5 * This script is part of the TYPO3 project - inspiring people to share! *
6 * *
7 * TYPO3 is free software; you can redistribute it and/or modify it under *
8 * the terms of the GNU General Public License version 2 as published by *
9 * the Free Software Foundation. *
10 * *
11 * This script is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
13 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
14 * Public License for more details. *
15 * */
16
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18 use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
19 use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
20 use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
21 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
22 use TYPO3\CMS\Frontend\Service\TypoLinkCodecService;
23
24 /**
25 * A ViewHelper to create links from fields supported by the link wizard
26 *
27 * == Example ==
28 *
29 * {link} contains "19 _blank - "testtitle with whitespace" &X=y"
30 *
31 * <code title="minimal usage">
32 * <f:link.typolink parameter="{link}">
33 * Linktext
34 * </f:link.typolink>
35 * <output>
36 * <a href="index.php?id=19&X=y" title="testtitle with whitespace" target="_blank">
37 * Linktext
38 * </a>
39 * </output>
40 * </code>
41 *
42 * <code title="Full parameter usage">
43 * <f:link.typolink parameter="{link}" target="_blank" class="ico-class" title="some title" additionalParams="&u=b" additionalAttributes="{type:'button'}">
44 * Linktext
45 * </f:link.typolink>
46 * </code>
47 * <output>
48 * <a href="index.php?id=19&X=y&u=b" title="some title" target="_blank" class="ico-class" type="button">
49 * Linktext
50 * </a>
51 * </output>
52 *
53 */
54 class TypolinkViewHelper extends AbstractViewHelper implements CompilableInterface
55 {
56 /**
57 * Render
58 *
59 * @param string $parameter stdWrap.typolink style parameter string
60 * @param string $target
61 * @param string $class
62 * @param string $title
63 * @param string $additionalParams
64 * @param array $additionalAttributes
65 *
66 * @return string
67 */
68 public function render($parameter, $target = '', $class = '', $title = '', $additionalParams = '', $additionalAttributes = [])
69 {
70 return static::renderStatic(
71 [
72 'parameter' => $parameter,
73 'target' => $target,
74 'class' => $class,
75 'title' => $title,
76 'additionalParams' => $additionalParams,
77 'additionalAttributes' => $additionalAttributes
78 ],
79 $this->buildRenderChildrenClosure(),
80 $this->renderingContext
81 );
82 }
83
84 /**
85 * @param array $arguments
86 * @param callable $renderChildrenClosure
87 * @param RenderingContextInterface $renderingContext
88 * @return mixed|string
89 * @throws \InvalidArgumentException
90 * @throws \UnexpectedValueException
91 */
92 public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
93 {
94 $parameter = $arguments['parameter'];
95 $target = $arguments['target'];
96 $class = $arguments['class'];
97 $title = $arguments['title'];
98 $additionalParams = $arguments['additionalParams'];
99 $additionalAttributes = $arguments['additionalAttributes'];
100
101 // Merge the $parameter with other arguments
102 $typolinkParameter = self::createTypolinkParameterArrayFromArguments($parameter, $target, $class, $title, $additionalParams);
103
104 // array(param1 -> value1, param2 -> value2) --> param1="value1" param2="value2" for typolink.ATagParams
105 $extraAttributes = [];
106 foreach ($additionalAttributes as $attributeName => $attributeValue) {
107 $extraAttributes[] = $attributeName . '="' . htmlspecialchars($attributeValue) . '"';
108 }
109 $aTagParams = implode(' ', $extraAttributes);
110
111 // If no link has to be rendered, the inner content will be returned as such
112 $content = (string)$renderChildrenClosure();
113
114 if ($parameter) {
115 /** @var ContentObjectRenderer $contentObject */
116 $contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
117 $contentObject->start([], '');
118 $content = $contentObject->stdWrap(
119 $content,
120 [
121 'typolink.' => [
122 'parameter' => $typolinkParameter,
123 'ATagParams' => $aTagParams,
124 ]
125 ]
126 );
127 }
128
129 return $content;
130 }
131
132 /**
133 * Transforms ViewHelper arguments to typo3link.parameters.typoscript option as array.
134 *
135 * @param string $parameter Example: 19 _blank - "testtitle \"with whitespace\"" &X=y
136 * @param string $target
137 * @param string $class
138 * @param string $title
139 * @param string $additionalParams
140 *
141 * @return string The final TypoLink string
142 */
143 protected static function createTypolinkParameterArrayFromArguments($parameter, $target = '', $class = '', $title = '', $additionalParams = '')
144 {
145 $typoLinkCodec = GeneralUtility::makeInstance(TypoLinkCodecService::class);
146 $typolinkConfiguration = $typoLinkCodec->decode($parameter);
147 if (empty($typolinkConfiguration)) {
148 return $typolinkConfiguration;
149 }
150
151 // Override target if given in target argument
152 if ($target) {
153 $typolinkConfiguration['target'] = $target;
154 }
155
156 // Combine classes if given in both "parameter" string and "class" argument
157 if ($class) {
158 $classes = explode(' ', trim($typolinkConfiguration['class']) . ' ' . trim($class));
159 $typolinkConfiguration['class'] = implode(' ', array_unique(array_filter($classes)));
160 }
161
162 // Override title if given in title argument
163 if ($title) {
164 $typolinkConfiguration['title'] = $title;
165 }
166
167 // Combine additionalParams
168 if ($additionalParams) {
169 $typolinkConfiguration['additionalParams'] .= $additionalParams;
170 }
171
172 return $typoLinkCodec->encode($typolinkConfiguration);
173 }
174 }