‪TYPO3CMS  ‪main
AbstractFormElement.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
19 use TYPO3\CMS\Backend\Form\Behavior\OnFieldChangeTrait;
22 use TYPO3\CMS\Backend\Utility\BackendUtility;
32 
37 {
38  use OnFieldChangeTrait;
39 
45  protected ‪$defaultInputWidth = 30;
46 
52  protected ‪$minimumInputWidth = 10;
53 
59  protected ‪$maxInputWidth = 50;
60 
62 
68  {
69  $this->nodeFactory = ‪$nodeFactory;
70  }
71 
77  protected function ‪renderFieldInformation(): array
78  {
79  $options = ‪$this->data;
80  $fieldInformation = ‪$this->defaultFieldInformation;
81  $fieldInformationFromTca = $options['parameterArray']['fieldConf']['config']['fieldInformation'] ?? [];
82  ArrayUtility::mergeRecursiveWithOverrule($fieldInformation, $fieldInformationFromTca);
83  $options['renderType'] = 'fieldInformation';
84  $options['renderData']['fieldInformation'] = $fieldInformation;
85  return $this->nodeFactory->create($options)->render();
86  }
87 
93  protected function ‪renderFieldControl(): array
94  {
95  $options = ‪$this->data;
96  $fieldControl = ‪$this->defaultFieldControl;
97  $fieldControlFromTca = $options['parameterArray']['fieldConf']['config']['fieldControl'] ?? [];
98  ArrayUtility::mergeRecursiveWithOverrule($fieldControl, $fieldControlFromTca);
99  $options['renderType'] = 'fieldControl';
100  $options['renderData']['fieldControl'] = $fieldControl;
101  return $this->nodeFactory->create($options)->render();
102  }
103 
109  protected function ‪renderFieldWizard(): array
110  {
111  $options = ‪$this->data;
112  $fieldWizard = ‪$this->defaultFieldWizard;
113  $fieldWizardFromTca = $options['parameterArray']['fieldConf']['config']['fieldWizard'] ?? [];
114  ArrayUtility::mergeRecursiveWithOverrule($fieldWizard, $fieldWizardFromTca);
115  $options['renderType'] = 'fieldWizard';
116  $options['renderData']['fieldWizard'] = $fieldWizard;
117  return $this->nodeFactory->create($options)->render();
118  }
119 
123  protected function ‪renderLabel(string $for): string
124  {
125  $label = htmlspecialchars($this->data['parameterArray']['fieldConf']['label'] ?? '');
126  if (‪$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] && $this->‪getBackendUser()->isAdmin()) {
127  $fieldName = $this->data['flexFormFieldName'] ?? $this->data['fieldName'];
128  $label .= ' <code>[' . htmlspecialchars($fieldName) . ']</code>';
129  }
130  return '<label for="' . htmlspecialchars($for) . '" class="form-label t3js-formengine-label">' . $label . '</label>';
131  }
132 
137  protected function ‪wrapWithFieldsetAndLegend(string $innerHTML): string
138  {
139  $legend = htmlspecialchars($this->data['parameterArray']['fieldConf']['label'] ?? '');
140  if ($this->‪getBackendUser()->shallDisplayDebugInformation()) {
141  $fieldName = $this->data['flexFormFieldName'] ?? $this->data['fieldName'];
142  $legend .= ' <code>[' . htmlspecialchars($fieldName) . ']</code>';
143  }
144  $html = [];
145  $html[] = '<fieldset>';
146  $html[] = '<legend class="form-legend t3js-formengine-legend">' . $legend . '</legend>';
147  $html[] = $innerHTML;
148  $html[] = '</fieldset>';
149  return implode(LF, $html);
150  }
151 
167  protected function ‪hasNullCheckboxButNoPlaceholder(): bool
168  {
169  $hasNullCheckboxNoPlaceholder = false;
170  $parameterArray = $this->data['parameterArray'];
171  $mode = $parameterArray['fieldConf']['config']['mode'] ?? '';
172  if (empty($this->data['flexFormDataStructureIdentifier'])
173  && ($parameterArray['fieldConf']['config']['nullable'] ?? false)
174  && ($mode !== 'useOrOverridePlaceholder')
175  ) {
176  $hasNullCheckboxNoPlaceholder = true;
177  }
178  return $hasNullCheckboxNoPlaceholder;
179  }
180 
199  protected function ‪hasNullCheckboxWithPlaceholder(): bool
200  {
201  $hasNullCheckboxWithPlaceholder = false;
202  $parameterArray = $this->data['parameterArray'];
203  $mode = $parameterArray['fieldConf']['config']['mode'] ?? '';
204  if (empty($this->data['flexFormDataStructureIdentifier'])
205  && ($parameterArray['fieldConf']['config']['nullable'] ?? false)
206  && ($mode === 'useOrOverridePlaceholder')
207  ) {
208  $hasNullCheckboxWithPlaceholder = true;
209  }
210  return $hasNullCheckboxWithPlaceholder;
211  }
212 
221  protected function ‪formatValue($format, $itemValue, $formatOptions = []): string
222  {
223  switch ($format) {
224  case 'date':
225  if ($itemValue) {
226  $option = isset($formatOptions['option']) ? trim($formatOptions['option']) : '';
227  if ($option) {
228  if (isset($formatOptions['strftime']) && $formatOptions['strftime']) {
229  $user = $this->‪getBackendUser();
230  if ($user->user['lang'] ?? false) {
231  $locale = GeneralUtility::makeInstance(Locales::class)->createLocale($user->user['lang']);
232  } else {
233  $locale = new Locale();
234  }
235  $value = (new DateFormatter())->strftime($option, (int)$itemValue, $locale);
236  } else {
237  $value = date($option, (int)$itemValue);
238  }
239  } else {
240  $value = date('d-m-Y', (int)$itemValue);
241  }
242  } else {
243  $value = '';
244  }
245  if (isset($formatOptions['appendAge']) && $formatOptions['appendAge']) {
246  $age = BackendUtility::calcAge(
247  ‪$GLOBALS['EXEC_TIME'] - $itemValue,
248  $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.minutesHoursDaysYears')
249  );
250  $value .= ' (' . $age . ')';
251  }
252  $itemValue = $value;
253  break;
254  case 'datetime':
255  // compatibility with "eval" (type "input")
256  if ($itemValue !== '' && $itemValue !== null) {
257  $itemValue = BackendUtility::datetime((int)$itemValue);
258  }
259  break;
260  case 'time':
261  // compatibility with "eval" (type "input")
262  if ($itemValue !== '' && $itemValue !== null) {
263  $itemValue = BackendUtility::time((int)$itemValue, false);
264  }
265  break;
266  case 'timesec':
267  // compatibility with "eval" (type "input")
268  if ($itemValue !== '' && $itemValue !== null) {
269  $itemValue = BackendUtility::time((int)$itemValue);
270  }
271  break;
272  case 'year':
273  // compatibility with "eval" (type "input")
274  if ($itemValue !== '' && $itemValue !== null) {
275  $itemValue = date('Y', (int)$itemValue);
276  }
277  break;
278  case 'int':
279  $baseArr = ['dec' => 'd', 'hex' => 'x', 'HEX' => 'X', 'oct' => 'o', 'bin' => 'b'];
280  $base = isset($formatOptions['base']) ? trim($formatOptions['base']) : '';
281  $format = $baseArr[$base] ?? 'd';
282  $itemValue = sprintf('%' . $format, $itemValue);
283  break;
284  case 'float':
285  // default precision
286  $precision = 2;
287  if (isset($formatOptions['precision'])) {
288  $precision = ‪MathUtility::forceIntegerInRange($formatOptions['precision'], 1, 10, $precision);
289  }
290  $itemValue = sprintf('%.' . $precision . 'f', $itemValue);
291  break;
292  case 'number':
293  $format = isset($formatOptions['option']) ? '%' . trim($formatOptions['option']) : '';
294  $itemValue = sprintf($format, $itemValue);
295  break;
296  case 'md5':
297  $itemValue = md5($itemValue);
298  break;
299  case 'filesize':
300  // We need to cast to int here, otherwise empty values result in empty output,
301  // but we expect zero.
302  $value = GeneralUtility::formatSize((int)$itemValue);
303  if (!empty($formatOptions['appendByteSize'])) {
304  $value .= ' (' . $itemValue . ')';
305  }
306  $itemValue = $value;
307  break;
308  case 'user':
309  $func = trim($formatOptions['userFunc']);
310  if ($func) {
311  $params = [
312  'value' => $itemValue,
313  'args' => $formatOptions['userFunc'],
314  'config' => [
315  'type' => 'none',
316  'format' => $format,
317  'format.' => $formatOptions,
318  ],
319  ];
320  $itemValue = GeneralUtility::callUserFunction($func, $params, $this);
321  }
322  break;
323  default:
324  // Do nothing e.g. when $format === ''
325  }
326  // Make sure we have a string in the end. $itemValue could be null, for instance.
327  return (string)$itemValue;
328  }
329 
336  protected function ‪formMaxWidth($size = 48)
337  {
338  $compensationForLargeDocuments = 1.33;
339  $compensationForFormFields = 12;
340 
341  $compensatedSize = round($size * $compensationForLargeDocuments);
342  return (int)ceil($compensatedSize * $compensationForFormFields);
343  }
344 
353  protected function ‪resolveJavaScriptEvaluation(array $resultArray, string $name, ?object $evalObject): array
354  {
355  if (!is_object($evalObject) || !method_exists($evalObject, 'returnFieldJS')) {
356  return $resultArray;
357  }
358 
359  $javaScriptEvaluation = $evalObject->returnFieldJS();
360  if ($javaScriptEvaluation instanceof JavaScriptModuleInstruction) {
361  // just use the module name and export-name
362  $resultArray['javaScriptModules'][] = ‪JavaScriptModuleInstruction::create(
363  $javaScriptEvaluation->getName(),
364  $javaScriptEvaluation->getExportName()
365  )->invoke('registerCustomEvaluation', $name);
366  }
367 
368  return $resultArray;
369  }
370 
371  /***********************************************
372  * CheckboxElement related methods
373  ***********************************************/
374 
387  protected function ‪checkBoxParams(
388  string $itemName,
389  int $formElementValue,
390  int $checkbox,
391  int $checkboxesCount,
392  array $fieldChangeFuncs = [],
393  bool $invert = false
394  ): string {
395  array_unshift($fieldChangeFuncs, new UpdateBitmaskOnFieldChange(
396  $checkbox,
397  $checkboxesCount,
398  $invert,
399  $itemName
400  ));
401  $checkboxPow = 2 ** $checkbox;
402  $checked = $formElementValue & $checkboxPow;
403  $attrs = $this->getOnFieldChangeAttrs('click', $fieldChangeFuncs);
404  if ($checked xor $invert) {
405  $attrs['checked'] = 'checked';
406  }
407  return GeneralUtility::implodeAttributes($attrs, true);
408  }
409 
416  protected function ‪calculateColumnMarkup(int $cols): array
417  {
418  $colWidth = (int)floor(12 / $cols);
419  $colClass = 'col';
420  $colClear = [];
421  if ($colWidth === 6) {
422  $colClass = 'col col-sm-6';
423  $colClear = [
424  2 => 'd-sm-block',
425  ];
426  } elseif ($colWidth === 4) {
427  $colClass = 'col col-sm-4';
428  $colClear = [
429  3 => 'd-sm-block',
430  ];
431  } elseif ($colWidth === 3) {
432  $colClass = 'col col-sm-6 col-md-3';
433  $colClear = [
434  2 => 'd-sm-block d-md-none',
435  4 => 'd-sm-block d-md-block d-lg-none',
436  ];
437  } elseif ($colWidth <= 2) {
438  $colClass = 'col col-sm-6 col-md-3 col-lg-2';
439  $colClear = [
440  2 => 'd-sm-block',
441  4 => 'd-sm-block d-md-block d-lg-none',
442  6 => 'd-sm-block d-md-block d-lg-block d-xl-none',
443  ];
444  }
445  return [$colClass, $colClear];
446  }
447 
451  protected function ‪appendValueToLabelInDebugMode(string|int $label, string|int $value): string
452  {
453  if ($value !== '' && $this->‪getBackendUser()->shallDisplayDebugInformation()) {
454  return trim($label . ' [' . $value . ']');
455  }
456 
457  return trim((string)$label);
458  }
459 
460  protected function ‪getLanguageService(): ‪LanguageService
461  {
462  return ‪$GLOBALS['LANG'];
463  }
464 
465  protected function ‪getBackendUser(): ‪BackendUserAuthentication
466  {
467  return ‪$GLOBALS['BE_USER'];
468  }
469 }
‪TYPO3\CMS\Backend\Form\AbstractNode\$defaultFieldInformation
‪array $defaultFieldInformation
Definition: AbstractNode.php:41
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldInformation
‪array renderFieldInformation()
Definition: AbstractFormElement.php:73
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\$nodeFactory
‪NodeFactory $nodeFactory
Definition: AbstractFormElement.php:57
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\getBackendUser
‪getBackendUser()
Definition: AbstractFormElement.php:461
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\injectNodeFactory
‪injectNodeFactory(NodeFactory $nodeFactory)
Definition: AbstractFormElement.php:63
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction\create
‪static create(string $name, string $exportName=null)
Definition: JavaScriptModuleInstruction.php:47
‪TYPO3\CMS\Backend\Form\AbstractNode\$defaultFieldControl
‪array $defaultFieldControl
Definition: AbstractNode.php:48
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement
Definition: AbstractFormElement.php:37
‪TYPO3\CMS\Backend\Form\AbstractNode\$defaultFieldWizard
‪array $defaultFieldWizard
Definition: AbstractNode.php:55
‪TYPO3\CMS\Core\Localization\Locales
Definition: Locales.php:36
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\$defaultInputWidth
‪int $defaultInputWidth
Definition: AbstractFormElement.php:43
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction
Definition: JavaScriptModuleInstruction.php:23
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\$maxInputWidth
‪int $maxInputWidth
Definition: AbstractFormElement.php:55
‪TYPO3\CMS\Backend\Form\Element
Definition: AbstractFormElement.php:16
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\resolveJavaScriptEvaluation
‪resolveJavaScriptEvaluation(array $resultArray, string $name, ?object $evalObject)
Definition: AbstractFormElement.php:349
‪TYPO3\CMS\Core\Localization\DateFormatter
Definition: DateFormatter.php:27
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\formatValue
‪string formatValue($format, $itemValue, $formatOptions=[])
Definition: AbstractFormElement.php:217
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\wrapWithFieldsetAndLegend
‪wrapWithFieldsetAndLegend(string $innerHTML)
Definition: AbstractFormElement.php:133
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\$minimumInputWidth
‪int $minimumInputWidth
Definition: AbstractFormElement.php:49
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\calculateColumnMarkup
‪calculateColumnMarkup(int $cols)
Definition: AbstractFormElement.php:412
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldControl
‪array renderFieldControl()
Definition: AbstractFormElement.php:89
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\getLanguageService
‪getLanguageService()
Definition: AbstractFormElement.php:456
‪TYPO3\CMS\Backend\Form\AbstractNode\$data
‪array $data
Definition: AbstractNode.php:35
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\formMaxWidth
‪int formMaxWidth($size=48)
Definition: AbstractFormElement.php:332
‪TYPO3\CMS\Backend\Form\Behavior\UpdateBitmaskOnFieldChange
Definition: UpdateBitmaskOnFieldChange.php:24
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\appendValueToLabelInDebugMode
‪appendValueToLabelInDebugMode(string|int $label, string|int $value)
Definition: AbstractFormElement.php:447
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\checkBoxParams
‪string checkBoxParams(string $itemName, int $formElementValue, int $checkbox, int $checkboxesCount, array $fieldChangeFuncs=[], bool $invert=false)
Definition: AbstractFormElement.php:383
‪TYPO3\CMS\Backend\Form\NodeFactory
Definition: NodeFactory.php:40
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:26
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderLabel
‪renderLabel(string $for)
Definition: AbstractFormElement.php:119
‪TYPO3\CMS\Core\Localization\Locale
Definition: Locale.php:30
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Backend\Form\AbstractNode
Definition: AbstractNode.php:29
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange(mixed $theInt, int $min, int $max=2000000000, int $defaultValue=0)
Definition: MathUtility.php:34
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldWizard
‪array renderFieldWizard()
Definition: AbstractFormElement.php:105
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\hasNullCheckboxWithPlaceholder
‪hasNullCheckboxWithPlaceholder()
Definition: AbstractFormElement.php:195
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\hasNullCheckboxButNoPlaceholder
‪hasNullCheckboxButNoPlaceholder()
Definition: AbstractFormElement.php:163