TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
fluid/Classes/ViewHelpers/FormViewHelper.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Fluid\ViewHelpers;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
45 {
49  protected $tagName = 'form';
50 
54  protected $hashService;
55 
60 
64  protected $extensionService;
65 
73 
77  public function injectHashService(\TYPO3\CMS\Extbase\Security\Cryptography\HashService $hashService)
78  {
79  $this->hashService = $hashService;
80  }
81 
85  public function injectMvcPropertyMappingConfigurationService(\TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfigurationService $mvcPropertyMappingConfigurationService)
86  {
87  $this->mvcPropertyMappingConfigurationService = $mvcPropertyMappingConfigurationService;
88  }
89 
93  public function injectExtensionService(\TYPO3\CMS\Extbase\Service\ExtensionService $extensionService)
94  {
95  $this->extensionService = $extensionService;
96  }
97 
101  public function initializeArguments()
102  {
103  parent::initializeArguments();
104  $this->registerArgument('action', 'string', 'Target action');
105  $this->registerArgument('arguments', 'array', 'Arguments', false, []);
106  $this->registerArgument('controller', 'string', 'Target controller');
107  $this->registerArgument('extensionName', 'string', 'Target Extension Name (without "tx_" prefix and no underscores). If NULL the current extension name is used');
108  $this->registerArgument('pluginName', 'string', 'Target plugin. If empty, the current plugin name is used');
109  $this->registerArgument('pageUid', 'int', 'Target page uid');
110  $this->registerArgument('object', 'mixed', 'Object to use for the form. Use in conjunction with the "property" attribute on the sub tags');
111  $this->registerArgument('pageType', 'int', 'Target page type', false, 0);
112  $this->registerArgument('noCache', 'bool', 'set this to disable caching for the target page. You should not need this.', false, false);
113  $this->registerArgument('noCacheHash', 'bool', 'set this to suppress the cHash query parameter created by TypoLink. You should not need this.', false, false);
114  $this->registerArgument('section', 'string', 'The anchor to be added to the action URI (only active if $actionUri is not set)', false, '');
115  $this->registerArgument('format', 'string', 'The requested format (e.g. ".html") of the target page (only active if $actionUri is not set)', false, '');
116  $this->registerArgument('additionalParams', 'array', 'additional action URI query parameters that won\'t be prefixed like $arguments (overrule $arguments) (only active if $actionUri is not set)', false, []);
117  $this->registerArgument('absolute', 'bool', 'If set, an absolute action URI is rendered (only active if $actionUri is not set)', false, false);
118  $this->registerArgument('addQueryString', 'bool', 'If set, the current query parameters will be kept in the action URI (only active if $actionUri is not set)', false, false);
119  $this->registerArgument('argumentsToBeExcludedFromQueryString', 'array', 'arguments to be removed from the action URI. Only active if $addQueryString = TRUE and $actionUri is not set', false, []);
120  $this->registerArgument('addQueryStringMethod', 'string', 'Method to use when keeping query parameters (GET or POST, only active if $actionUri is not set', false, 'GET');
121  $this->registerArgument('fieldNamePrefix', 'string', 'Prefix that will be added to all field names within this form. If not set the prefix will be tx_yourExtension_plugin');
122  $this->registerArgument('actionUri', 'string', 'can be used to overwrite the "action" attribute of the form tag');
123  $this->registerArgument('objectName', 'string', 'name of the object that is bound to this form. If this argument is not specified, the name attribute of this form is used to determine the FormObjectName');
124  $this->registerArgument('hiddenFieldClassName', 'string', 'hiddenFieldClassName');
125  $this->registerTagAttribute('enctype', 'string', 'MIME type with which the form is submitted');
126  $this->registerTagAttribute('method', 'string', 'Transfer type (GET or POST)');
127  $this->registerTagAttribute('name', 'string', 'Name of form');
128  $this->registerTagAttribute('onreset', 'string', 'JavaScript: On reset of the form');
129  $this->registerTagAttribute('onsubmit', 'string', 'JavaScript: On submit of the form');
131  }
132 
138  public function render()
139  {
140  $this->setFormActionUri();
141  if (strtolower($this->arguments['method']) === 'get') {
142  $this->tag->addAttribute('method', 'get');
143  } else {
144  $this->tag->addAttribute('method', 'post');
145  }
150  $formContent = $this->renderChildren();
151 
152  if ($this->arguments['hiddenFieldClassName'] !== null) {
153  $content = LF . '<div class="' . htmlspecialchars($this->arguments['hiddenFieldClassName']) . '">';
154  } else {
155  $content = LF . '<div>';
156  }
157 
158  $content .= $this->renderHiddenIdentityField($this->arguments['object'], $this->getFormObjectName());
159  $content .= $this->renderAdditionalIdentityFields();
160  $content .= $this->renderHiddenReferrerFields();
161 
162  // Render the trusted list of all properties after everything else has been rendered
163  $content .= $this->renderTrustedPropertiesField();
164 
165  $content .= LF . '</div>' . LF;
166  $content .= $formContent;
167  $this->tag->setContent($content);
173  return $this->tag->render();
174  }
175 
179  protected function setFormActionUri()
180  {
181  if ($this->hasArgument('actionUri')) {
182  $formActionUri = $this->arguments['actionUri'];
183  } else {
184  $pageUid = (int)$this->arguments['pageUid'] > 0 ? (int)$this->arguments['pageUid'] : null;
185  $uriBuilder = $this->renderingContext->getControllerContext()->getUriBuilder();
186  $formActionUri = $uriBuilder
187  ->reset()
188  ->setTargetPageUid($pageUid)
189  ->setTargetPageType($this->arguments['pageType'])
190  ->setNoCache($this->arguments['noCache'])
191  ->setUseCacheHash(!$this->arguments['noCacheHash'])
192  ->setSection($this->arguments['section'])
193  ->setCreateAbsoluteUri($this->arguments['absolute'])
194  ->setArguments((array)$this->arguments['additionalParams'])
195  ->setAddQueryString($this->arguments['addQueryString'])
196  ->setAddQueryStringMethod($this->arguments['addQueryStringMethod'])
197  ->setArgumentsToBeExcludedFromQueryString((array)$this->arguments['argumentsToBeExcludedFromQueryString'])
198  ->setFormat($this->arguments['format'])
199  ->uriFor(
200  $this->arguments['action'],
201  $this->arguments['arguments'],
202  $this->arguments['controller'],
203  $this->arguments['extensionName'],
204  $this->arguments['pluginName']
205  );
206  $this->formActionUriArguments = $uriBuilder->getArguments();
207  }
208  $this->tag->addAttribute('action', $formActionUri);
209  }
210 
217  protected function renderAdditionalIdentityFields()
218  {
219  if ($this->viewHelperVariableContainer->exists(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'additionalIdentityProperties')) {
220  $additionalIdentityProperties = $this->viewHelperVariableContainer->get(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'additionalIdentityProperties');
221  $output = '';
222  foreach ($additionalIdentityProperties as $identity) {
223  $output .= LF . $identity;
224  }
225  return $output;
226  }
227  return '';
228  }
229 
237  protected function renderHiddenReferrerFields()
238  {
239  $request = $this->renderingContext->getControllerContext()->getRequest();
240  $extensionName = $request->getControllerExtensionName();
241  $vendorName = $request->getControllerVendorName();
242  $controllerName = $request->getControllerName();
243  $actionName = $request->getControllerActionName();
244  $actionRequest = [
245  '@extension' => $extensionName,
246  '@controller' => $controllerName,
247  '@action' => $actionName,
248  ];
249 
250  $result = LF;
251  $result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[@extension]') . '" value="' . $extensionName . '" />' . LF;
252  if ($vendorName !== null) {
253  $result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[@vendor]') . '" value="' . $vendorName . '" />' . LF;
254  $actionRequest['@vendor'] = $vendorName;
255  }
256  $result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[@controller]') . '" value="' . $controllerName . '" />' . LF;
257  $result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[@action]') . '" value="' . $actionName . '" />' . LF;
258  $result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[arguments]') . '" value="' . htmlspecialchars($this->hashService->appendHmac(base64_encode(serialize($request->getArguments())))) . '" />' . LF;
259  $result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[@request]') . '" value="' . htmlspecialchars($this->hashService->appendHmac(serialize($actionRequest))) . '" />' . LF;
260 
261  return $result;
262  }
263 
268  {
269  $formObjectName = $this->getFormObjectName();
270  if ($formObjectName !== null) {
271  $this->viewHelperVariableContainer->add(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formObjectName', $formObjectName);
272  }
273  }
274 
279  {
280  $formObjectName = $this->getFormObjectName();
281  if ($formObjectName !== null) {
282  $this->viewHelperVariableContainer->remove(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formObjectName');
283  }
284  }
285 
293  protected function getFormObjectName()
294  {
295  $formObjectName = null;
296  if ($this->hasArgument('objectName')) {
297  $formObjectName = $this->arguments['objectName'];
298  } elseif ($this->hasArgument('name')) {
299  $formObjectName = $this->arguments['name'];
300  }
301  return $formObjectName;
302  }
303 
308  {
309  if ($this->hasArgument('object')) {
310  $this->viewHelperVariableContainer->add(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formObject', $this->arguments['object']);
311  $this->viewHelperVariableContainer->add(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'additionalIdentityProperties', []);
312  }
313  }
314 
319  {
320  if ($this->hasArgument('object')) {
321  $this->viewHelperVariableContainer->remove(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formObject');
322  $this->viewHelperVariableContainer->remove(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'additionalIdentityProperties');
323  }
324  }
325 
330  {
331  $fieldNamePrefix = $this->getFieldNamePrefix();
332  $this->viewHelperVariableContainer->add(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'fieldNamePrefix', $fieldNamePrefix);
333  }
334 
340  protected function getFieldNamePrefix()
341  {
342  if ($this->hasArgument('fieldNamePrefix')) {
343  return $this->arguments['fieldNamePrefix'];
344  } else {
345  return $this->getDefaultFieldNamePrefix();
346  }
347  }
348 
353  {
354  $this->viewHelperVariableContainer->remove(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'fieldNamePrefix');
355  }
356 
361  {
362  $this->viewHelperVariableContainer->add(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formFieldNames', []);
363  }
364 
369  {
370  $this->viewHelperVariableContainer->remove(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formFieldNames');
371  if ($this->viewHelperVariableContainer->exists(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'renderedHiddenFields')) {
372  $this->viewHelperVariableContainer->remove(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'renderedHiddenFields');
373  }
374  }
375 
381  protected function renderRequestHashField()
382  {
383  $formFieldNames = $this->viewHelperVariableContainer->get(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formFieldNames');
384  $this->postProcessUriArgumentsForRequestHash($this->formActionUriArguments, $formFieldNames);
385  $requestHash = $this->requestHashService->generateRequestHash($formFieldNames, $this->getFieldNamePrefix());
386  // in v4, we need to prefix __hmac as well to make it show up in the request object.
387  return '<input type="hidden" name="' . $this->prefixFieldName('__hmac') . '" value="' . htmlspecialchars($requestHash) . '" />';
388  }
389 
393  protected function postProcessUriArgumentsForRequestHash($arguments, &$results, $currentPrefix = '', $level = 0)
394  {
395  if (count($arguments)) {
396  foreach ($arguments as $argumentName => $argumentValue) {
397  if (is_array($argumentValue)) {
398  $prefix = $level == 0 ? $argumentName : $currentPrefix . '[' . $argumentName . ']';
399  $this->postProcessUriArgumentsForRequestHash($argumentValue, $results, $prefix, $level + 1);
400  } else {
401  $results[] = $level == 0 ? $argumentName : $currentPrefix . '[' . $argumentName . ']';
402  }
403  }
404  }
405  }
406 
412  protected function getDefaultFieldNamePrefix()
413  {
414  $request = $this->renderingContext->getControllerContext()->getRequest();
415  if ($this->hasArgument('extensionName')) {
416  $extensionName = $this->arguments['extensionName'];
417  } else {
418  $extensionName = $request->getControllerExtensionName();
419  }
420  if ($this->hasArgument('pluginName')) {
421  $pluginName = $this->arguments['pluginName'];
422  } else {
423  $pluginName = $request->getPluginName();
424  }
425  if ($extensionName !== null && $pluginName != null) {
426  return $this->extensionService->getPluginNamespace($extensionName, $pluginName);
427  } else {
428  return '';
429  }
430  }
431 
436  {
437  if ($this->viewHelperVariableContainer->exists(\TYPO3\CMS\Fluid\ViewHelpers\Form\CheckboxViewHelper::class, 'checkboxFieldNames')) {
438  $this->viewHelperVariableContainer->remove(\TYPO3\CMS\Fluid\ViewHelpers\Form\CheckboxViewHelper::class, 'checkboxFieldNames');
439  }
440  }
441 
447  protected function renderTrustedPropertiesField()
448  {
449  $formFieldNames = $this->viewHelperVariableContainer->get(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formFieldNames');
450  $requestHash = $this->mvcPropertyMappingConfigurationService->generateTrustedPropertiesToken($formFieldNames, $this->getFieldNamePrefix());
451  return '<input type="hidden" name="' . $this->prefixFieldName('__trustedProperties') . '" value="' . htmlspecialchars($requestHash) . '" />';
452  }
453 }
injectHashService(\TYPO3\CMS\Extbase\Security\Cryptography\HashService $hashService)
injectExtensionService(\TYPO3\CMS\Extbase\Service\ExtensionService $extensionService)
injectMvcPropertyMappingConfigurationService(\TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfigurationService $mvcPropertyMappingConfigurationService)
postProcessUriArgumentsForRequestHash($arguments, &$results, $currentPrefix= '', $level=0)
registerTagAttribute($name, $type, $description, $required=false, $default=null)