[BUGFIX] Use late static binding for compilable viewhelpers
[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
23 /**
24 * A ViewHelper to create links from fields supported by the link wizard
25 *
26 * == Example ==
27 *
28 * {link} contains "19 _blank - "testtitle with whitespace" &X=y"
29 *
30 * <code title="minimal usage">
31 * <f:link.typolink parameter="{link}">
32 * Linktext
33 * </f:link.typolink>
34 * <output>
35 * <a href="index.php?id=19&X=y" title="testtitle with whitespace" target="_blank">
36 * Linktext
37 * </a>
38 * </output>
39 * </code>
40 *
41 * <code title="Full parameter usage">
42 * <f:link.typolink parameter="{link}" target="_blank" class="ico-class" title="some title" additionalParams="&u=b" additionalAttributes="{type:'button'}">
43 * Linktext
44 * </f:link.typolink>
45 * </code>
46 * <output>
47 * <a href="index.php?id=19&X=y&u=b" title="some title" target="_blank" class="ico-class" type="button">
48 * Linktext
49 * </a>
50 * </output>
51 *
52 */
53 class TypolinkViewHelper extends AbstractViewHelper implements CompilableInterface {
54
55 /**
56 * Render
57 *
58 * @param string $parameter stdWrap.typolink style parameter string
59 * @param string $target
60 * @param string $class
61 * @param string $title
62 * @param string $additionalParams
63 * @param array $additionalAttributes
64 *
65 * @return string
66 */
67 public function render($parameter, $target = '', $class = '', $title = '', $additionalParams = '', $additionalAttributes = array()) {
68 return static::renderStatic(
69 array(
70 'parameter' => $parameter,
71 'target' => $target,
72 'class' => $class,
73 'title' => $title,
74 'additionalParams' => $additionalParams,
75 'additionalAttributes' => $additionalAttributes
76 ),
77 $this->buildRenderChildrenClosure(),
78 $this->renderingContext
79 );
80 }
81
82 /**
83 * @param array $arguments
84 * @param callable $renderChildrenClosure
85 * @param RenderingContextInterface $renderingContext
86 * @return mixed|string
87 * @throws \InvalidArgumentException
88 * @throws \UnexpectedValueException
89 */
90 static public function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) {
91 $parameter = $arguments['parameter'];
92 $target = $arguments['target'];
93 $class = $arguments['class'];
94 $title = $arguments['title'];
95 $additionalParams = $arguments['additionalParams'];
96 $additionalAttributes = $arguments['additionalAttributes'];
97
98 // Merge the $parameter with other arguments
99 $typolinkParameter = self::createTypolinkParameterArrayFromArguments($parameter, $target, $class, $title, $additionalParams);
100
101 // array(param1 -> value1, param2 -> value2) --> "param1=value1 param2=>value2" for typolink.ATagParams
102 $extraAttributes = array();
103 foreach ($additionalAttributes as $attributeName => $attributeValue) {
104 $extraAttributes[] = $attributeName . '="' . htmlspecialchars($attributeValue) . '"';
105 }
106 $aTagParams = implode(' ', $extraAttributes);
107
108 // If no link has to be rendered, the inner content will be returned as such
109 $content = $renderChildrenClosure();
110
111 if ($parameter) {
112 /** @var ContentObjectRenderer $contentObject */
113 $contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
114 $contentObject->start(array(), '');
115 $content = $contentObject->stdWrap(
116 $content,
117 array(
118 'typolink.' => array(
119 'parameter' => implode(' ', $typolinkParameter),
120 'ATagParams' => $aTagParams,
121 )
122 )
123 );
124 }
125
126 return $content;
127 }
128
129 /**
130 * Transforms ViewHelper arguments to typo3link.parameters.typoscript option as array.
131 *
132 * @param string $parameter Example: 19 _blank - "testtitle with whitespace" &X=y
133 * @param string $target
134 * @param string $class
135 * @param string $title
136 * @param string $additionalParams
137 *
138 * @return array Final merged typolink.parameter as array to be imploded with empty string later
139 */
140 static protected function createTypolinkParameterArrayFromArguments($parameter, $target = '', $class = '', $title = '', $additionalParams = '') {
141 // Explode $parameter by whitespace and remove any " around resulting array values
142 $parameterArray = GeneralUtility::unQuoteFilenames($parameter, TRUE);
143
144 if (empty($parameterArray)) {
145 return array();
146 }
147
148 // Extend to 4 elements
149 $typolinkConfiguration = array_pad($parameterArray, 4, '-');
150
151 // Override target if given in target argument
152 if ($target) {
153 $typolinkConfiguration[1] = $target;
154 }
155
156 // Combine classes if given in both "parameter" string and "class" argument
157 if ($class) {
158 $typolinkConfiguration[2] = $typolinkConfiguration[2] !== '-' ? $typolinkConfiguration[2] . ' ' : '';
159 $typolinkConfiguration[2] .= $class;
160 }
161
162 // Override title if given in title argument
163 if ($title) {
164 $typolinkConfiguration[3] = $title;
165 }
166
167 // Combine additionalParams
168 if ($additionalParams) {
169 $typolinkConfiguration[4] .= $additionalParams;
170 }
171
172 // Unset unused parameters again from the end, wrap all given values with "
173 $reverseSortedParameters = array_reverse($typolinkConfiguration, TRUE);
174 $aValueWasSet = FALSE;
175 foreach ($reverseSortedParameters as $position => $value) {
176 if ($value === '-' && !$aValueWasSet) {
177 unset($typolinkConfiguration[$position]);
178 } else {
179 $aValueWasSet = TRUE;
180 if ($value !== '-') {
181 $typolinkConfiguration[$position] = '"' . $value . '"';
182 }
183 }
184 }
185
186 return $typolinkConfiguration;
187 }
188
189 }