[TASK] Rename TCA type image_manipulation to imageManipulation
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / FormEngine.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form;
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
17 use TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider;
18 use TYPO3\CMS\Backend\Form\Element\AbstractFormElement;
19 use TYPO3\CMS\Backend\Form\Element\InlineElement;
20 use TYPO3\CMS\Backend\Form\Element\NoneElement;
21 use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
22 use TYPO3\CMS\Backend\Template\DocumentTemplate;
23 use TYPO3\CMS\Backend\Utility\BackendUtility;
24 use TYPO3\CMS\Backend\Utility\IconUtility;
25 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
26 use TYPO3\CMS\Core\Database\DatabaseConnection;
27 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
28 use TYPO3\CMS\Core\Html\HtmlParser;
29 use TYPO3\CMS\Core\Messaging\FlashMessage;
30 use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
31 use TYPO3\CMS\Core\Messaging\FlashMessageService;
32 use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
33 use TYPO3\CMS\Core\Utility\DiffUtility;
34 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
35 use TYPO3\CMS\Core\Utility\GeneralUtility;
36 use TYPO3\CMS\Core\Utility\MathUtility;
37 use TYPO3\CMS\Lang\LanguageService;
38
39
40 /**
41 * 'TCEforms' - Class for creating the backend editing forms.
42 *
43 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
44 * @coauthor René Fritz <r.fritz@colorcube.de>
45 */
46 class FormEngine {
47
48 /**
49 * @var bool
50 */
51 public $disableWizards = FALSE;
52
53 /**
54 * @var array|NULL
55 */
56 public $cachedAdditionalPreviewLanguages = NULL;
57
58 /**
59 * @var string
60 */
61 public $extJSCODE = '';
62
63 /**
64 * @var array
65 */
66 public $hiddenFieldAccum = array();
67
68 /**
69 * @var string
70 */
71 public $TBE_EDITOR_fieldChanged_func = '';
72
73 /**
74 * @var bool
75 */
76 public $loadMD5_JS = TRUE;
77
78 /**
79 * Array where records in the default language is stored. (processed by transferdata)
80 *
81 * @var array
82 */
83 public $defaultLanguageData = array();
84
85 /**
86 * Array where records in the default language is stored (raw without any processing. used for making diff)
87 *
88 * @var array
89 */
90 public $defaultLanguageData_diff = array();
91
92 /**
93 * @var array
94 */
95 public $additionalPreviewLanguageData = array();
96
97 /**
98 * Alternative return URL path (default is \TYPO3\CMS\Core\Utility\GeneralUtility::linkThisScript())
99 *
100 * @var string
101 */
102 public $returnUrl = '';
103
104 /**
105 * Can be set to point to a field name in the form which will be set to '1' when the form
106 * is submitted with a *save* button. This way the recipient script can determine that
107 * the form was submitted for save and not "close" for example.
108 *
109 * @var string
110 */
111 public $doSaveFieldName = '';
112
113 /**
114 * Can be set TRUE/FALSE to whether palettes (secondary options) are in the topframe or in form.
115 * TRUE means they are NOT IN-form. So a collapsed palette is one, which is shown in the top frame, not in the page.
116 *
117 * @var bool
118 */
119 public $palettesCollapsed = FALSE;
120
121 /**
122 * If this evaluates to TRUE, the forms are rendering only localization relevant fields of the records.
123 *
124 * @var string
125 */
126 public $localizationMode = '';
127
128 /**
129 * Overrule the field order set in TCA[types][showitem], eg for tt_content this value,
130 * 'bodytext,image', would make first the 'bodytext' field, then the 'image' field (if set for display)...
131 * and then the rest in the old order.
132 *
133 * @var string
134 */
135 public $fieldOrder = '';
136
137 /**
138 * When enabled all elements are rendered non-editable
139 *
140 * @var bool
141 */
142 protected $renderReadonly = FALSE;
143
144 // INTERNAL, static
145 /**
146 * The string to prepend formfield names with.
147 *
148 * @var string
149 */
150 public $prependFormFieldNames = 'data';
151
152 /**
153 * The string to prepend commands for tcemain::process_cmdmap with
154 *
155 * @var string
156 */
157 public $prependCmdFieldNames = 'cmd';
158
159 /**
160 * The string to prepend FILE form field names with
161 *
162 * @var string
163 */
164 public $prependFormFieldNames_file = 'data_files';
165
166 /**
167 * The string to prepend form field names that are active (not NULL)
168 *
169 * @var string
170 */
171 protected $prependFormFieldNamesActive = 'control[active]';
172
173 /**
174 * Set by readPerms() (caching)
175 *
176 * @var string
177 */
178 public $perms_clause = '';
179
180 /**
181 * Set by readPerms() (caching-flag)
182 *
183 * @var bool
184 */
185 public $perms_clause_set = FALSE;
186
187 /**
188 * Counter that is incremented before an RTE is created. Can be used for unique ids etc.
189 *
190 * @var int
191 */
192 public $RTEcounter = 0;
193
194 /**
195 * Total wrapping for the table rows
196 *
197 * @var string
198 */
199 public $totalWrap = '<hr />|<hr />';
200
201 /**
202 * Field template
203 *
204 * @var string
205 */
206 public $fieldTemplate = '<strong>###FIELD_NAME###</strong><br />###FIELD_ITEM###<hr />';
207
208 /**
209 * Template subpart for palette fields
210 *
211 * @var string
212 */
213 protected $paletteFieldTemplate = '';
214
215 /**
216 * Wrapping template code for a section
217 *
218 * @var string
219 * @deprecatd since TYPO3 CMS 7, will be removed in CMS 8
220 */
221 public $sectionWrap = '';
222
223 /**
224 * Template for palette headers
225 *
226 * @var string
227 */
228 public $palFieldTemplateHeader = '';
229
230 /**
231 * Template for palettes
232 *
233 * @var string
234 */
235 public $palFieldTemplate = '';
236
237 /**
238 * Set to the fields NOT to display, if any
239 *
240 * @var array|NULL
241 */
242 public $excludeElements = NULL;
243
244 /**
245 * During rendering of forms this will keep track of which palettes
246 * has already been rendered (so they are not rendered twice by mistake)
247 *
248 * @var array
249 */
250 public $palettesRendered = array();
251
252 /**
253 * This array of fields will be set as hidden-fields instead of rendered normally!
254 * For instance palette fields edited in the top frame are set as hidden fields
255 * since the main form has to submit the values.
256 * The top frame actually just sets the value in the main form!
257 *
258 * @var array
259 */
260 public $hiddenFieldListArr = array();
261
262 /**
263 * Used to register input-field names, which are required. (Done during rendering of the fields).
264 * This information is then used later when the JavaScript is made.
265 *
266 * @var array
267 */
268 public $requiredFields = array();
269
270 /**
271 * Used to register input-field names, which are required an have additional requirements.
272 * (e.g. like a date/time must be positive integer)
273 * The information of this array is merged with $this->requiredFields later.
274 *
275 * @var array
276 */
277 public $requiredAdditional = array();
278
279 /**
280 * Used to register the min and max number of elements
281 * for selector boxes where that apply (in the "group" type for instance)
282 *
283 * @var array
284 */
285 public $requiredElements = array();
286
287 /**
288 * Used to determine where $requiredFields or $requiredElements are nested (in Tabs or IRRE)
289 *
290 * @var array
291 */
292 public $requiredNested = array();
293
294 /**
295 * Keeps track of the rendering depth of nested records
296 *
297 * @var int
298 */
299 public $renderDepth = 0;
300
301 /**
302 * Color scheme buffer
303 *
304 * @var array
305 * @deprecatd since TYPO3 CMS 7, will be removed in CMS 8
306 */
307 public $savedSchemes = array();
308
309 /**
310 * holds the path an element is nested in (e.g. required for RTEhtmlarea)
311 *
312 * @var array
313 */
314 public $dynNestedStack = array();
315
316 // Internal, registers for user defined functions etc.
317 /**
318 * Additional HTML code, printed before the form
319 *
320 * @var array
321 */
322 public $additionalCode_pre = array();
323
324 /**
325 * Additional JavaScript, printed before the form
326 *
327 * @var array
328 * @deprecatd since TYPO3 CMS 7, will be removed in CMS 8
329 */
330 public $additionalJS_pre = array();
331
332 /**
333 * Additional JavaScript printed after the form
334 *
335 * @var array
336 */
337 public $additionalJS_post = array();
338
339 /**
340 * Additional JavaScript executed on submit; If you set "OK" variable it will raise an error
341 * about RTEs not being loaded and offer to block further submission.
342 *
343 * @var array
344 */
345 public $additionalJS_submit = array();
346
347 /**
348 * Additional JavaScript executed when section element is deleted.
349 * This is necessary, for example, to correctly clean up HTMLArea RTE (bug #8232)
350 *
351 * @var array
352 */
353 public $additionalJS_delete = array();
354
355 /**
356 * @var \TYPO3\CMS\Backend\Form\Element\InlineElement
357 */
358 public $inline;
359
360 /**
361 * Array containing hook class instances called once for a form
362 *
363 * @var array
364 */
365 public $hookObjectsMainFields = array();
366
367 /**
368 * Array containing hook class instances called for each field
369 *
370 * @var array
371 */
372 public $hookObjectsSingleField = array();
373
374 /**
375 * Rows getting inserted into the headers (when called from the EditDocumentController)
376 *
377 * @var array
378 */
379 public $extraFormHeaders = array();
380
381 /**
382 * Form template, relative to typo3 directory
383 *
384 * @var string
385 */
386 public $templateFile = '';
387
388 /**
389 * protected properties which were public
390 * use old property name as key and new property name as value
391 * e.g. 'foo_BarName' => 'fooBarName'
392 *
393 * For each property a getter and setter method must be implemented!
394 * @see __set() and __get()
395 * @var array
396 */
397 protected $protectedProperties = array(
398 'renderReadonly' => 'renderReadonly'
399 );
400
401 /**
402 * Constructor function, setting internal variables, loading the styles used.
403 *
404 */
405 public function __construct() {
406 // Create instance of InlineElement only if this a non-IRRE-AJAX call:
407 if (!isset($GLOBALS['ajaxID']) || strpos($GLOBALS['ajaxID'], InlineElement::class . '::') !== 0) {
408 $this->inline = GeneralUtility::makeInstance(InlineElement::class);
409 }
410 // Prepare user defined objects (if any) for hooks which extend this function:
411 $this->hookObjectsMainFields = array();
412 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getMainFieldsClass'])) {
413 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getMainFieldsClass'] as $classRef) {
414 $this->hookObjectsMainFields[] = GeneralUtility::getUserObj($classRef);
415 }
416 }
417 $this->hookObjectsSingleField = array();
418 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getSingleFieldClass'])) {
419 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getSingleFieldClass'] as $classRef) {
420 $this->hookObjectsSingleField[] = GeneralUtility::getUserObj($classRef);
421 }
422 }
423 $this->templateFile = 'sysext/backend/Resources/Private/Templates/FormEngine.html';
424 }
425
426 /**
427 * Fallback method to protect public properties
428 * This is only a temporary solution and will be removed in TYPO3 CMS 8
429 *
430 * @param string $name name of the property
431 * @param mixed $value value of the property
432 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
433 */
434 public function __set($name, $value) {
435 if (array_key_exists($name, $this->protectedProperties)) {
436 $method = 'set' . ucfirst($this->protectedProperties[$name]);
437 if (is_callable(array($this, $method))) {
438 GeneralUtility::deprecationLog('direct access to "FormEngine::$' . $name . '" is deprecated, use "FormEngine::' . $method . '()" instead.');
439 call_user_func_array(array($this, $method), array($value));
440 }
441 }
442 }
443
444 /**
445 * Fallback method to protect public properties
446 * This is only a temporary solution and will be removed in TYPO3 CMS 8
447 *
448 * @param string $name name of the property
449 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
450 */
451 public function __get($name) {
452 if (array_key_exists($name, $this->protectedProperties)) {
453 $method = 'get' . ucfirst($this->protectedProperties[$name]);
454 if (is_callable(array($this, $method))) {
455 GeneralUtility::deprecationLog('direct access to "FormEngine::$' . $name . '" is deprecated, use "FormEngine::' . $method . '()" instead.');
456 call_user_func(array($this, $method));
457 }
458 }
459 }
460
461 /**
462 * Set render read only flag
463 *
464 * @param bool $value
465 */
466 public function setRenderReadonly($value) {
467 $this->renderReadonly = (bool)$value;
468 }
469
470 /**
471 * Get render readonly flag
472 *
473 * @return bool
474 */
475 public function getRenderReadonly() {
476 return $this->renderReadonly;
477 }
478
479 /**
480 * Initialize various internal variables.
481 *
482 * @return void
483 */
484 public function initDefaultBEmode() {
485 $this->prependFormFieldNames = 'data';
486 $this->setNewBEDesign();
487 $this->inline->init($this);
488 }
489
490 /*******************************************************
491 *
492 * Rendering the forms, fields etc
493 *
494 *******************************************************/
495 /**
496 * Will return the TCEform element for just a single field from a record.
497 * The field must be listed in the currently displayed fields (as found in [types][showitem]) for the record.
498 * This also means that the $table/$row supplied must be complete so the list of fields to show can be found correctly
499 *
500 * @param string $table The table name
501 * @param array $row The record from the table for which to render a field.
502 * @param string $theFieldToReturn The field name to return the TCEform element for.
503 * @return string HTML output
504 * @see getMainFields()
505 */
506 public function getSoloField($table, $row, $theFieldToReturn) {
507 if (!isset($GLOBALS['TCA'][$table])) {
508 return '';
509 }
510 $typeNum = $this->getRTypeNum($table, $row);
511 if (isset($GLOBALS['TCA'][$table]['types'][$typeNum])) {
512 $itemList = $GLOBALS['TCA'][$table]['types'][$typeNum]['showitem'];
513 if ($itemList) {
514 $fields = GeneralUtility::trimExplode(',', $itemList, TRUE);
515 $excludeElements = ($this->excludeElements = $this->getExcludeElements($table, $row, $typeNum));
516 foreach ($fields as $fieldInfo) {
517 $parts = explode(';', $fieldInfo);
518 $theField = trim($parts[0]);
519 if (!in_array($theField, $excludeElements) && (string)$theField === (string)$theFieldToReturn) {
520 if ($GLOBALS['TCA'][$table]['columns'][$theField]) {
521 $sField = $this->getSingleField($table, $theField, $row, $parts[1], 1, $parts[3], $parts[2]);
522 return $sField['ITEM'];
523 }
524 }
525 }
526 }
527 }
528 return '';
529 }
530
531 /**
532 * Based on the $table and $row of content, this displays the complete TCEform for the record.
533 * The input-$row is required to be preprocessed if necessary by eg.
534 * the \TYPO3\CMS\Backend\Form\DataPreprocessor class. For instance the RTE content
535 * should be transformed through this class first.
536 *
537 * @param string $table The table name
538 * @param array $row The record from the table for which to render a field.
539 * @param int $depth Depth level
540 * @param array $overruleTypesArray Overrule types array. Can be used to override the showitem etc. configuration for the TCA types of the table. Can contain all settings which are possible in the TCA 'types' section. See e.g. $TCA['tt_content']['types'].
541 * @return string HTML output
542 * @see getSoloField()
543 */
544 public function getMainFields($table, array $row, $depth = 0, array $overruleTypesArray = array()) {
545 $languageService = $this->getLanguageService();
546 $this->renderDepth = $depth;
547 // Init vars:
548 $out_array = array(array());
549 $out_array_meta = array(
550 array(
551 'title' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.generalTab'),
552 ),
553 );
554 $out_pointer = 0;
555 $out_sheet = 0;
556 $this->palettesRendered = array();
557 $this->palettesRendered[$this->renderDepth][$table] = array();
558 // Hook: getMainFields_preProcess (requested by Thomas Hempel for use with the "dynaflex" extension)
559 foreach ($this->hookObjectsMainFields as $hookObj) {
560 if (method_exists($hookObj, 'getMainFields_preProcess')) {
561 $hookObj->getMainFields_preProcess($table, $row, $this);
562 }
563 }
564 $tabIdentString = '';
565 $tabIdentStringMD5 = '';
566 if ($GLOBALS['TCA'][$table]) {
567 // Load the description content for the table.
568 if ($this->doLoadTableDescr($table)) {
569 $languageService->loadSingleTableDescription($table);
570 }
571 // Get the current "type" value for the record.
572 $typeNum = $this->getRTypeNum($table, $row);
573 // Find the list of fields to display:
574 if ($GLOBALS['TCA'][$table]['types'][$typeNum]) {
575 $itemList = $GLOBALS['TCA'][$table]['types'][$typeNum]['showitem'];
576 if (is_array($overruleTypesArray) && isset($overruleTypesArray[$typeNum]['showitem'])) {
577 $itemList = $overruleTypesArray[$typeNum]['showitem'];
578 }
579 // If such a list existed...
580 if ($itemList) {
581 // Explode the field list and possibly rearrange the order of the fields, if configured for
582 $fields = GeneralUtility::trimExplode(',', $itemList, TRUE);
583 if ($this->fieldOrder) {
584 $fields = $this->rearrange($fields);
585 }
586 // Get excluded fields, added fiels and put it together:
587 $excludeElements = ($this->excludeElements = $this->getExcludeElements($table, $row, $typeNum));
588 $fields = $this->mergeFieldsWithAddedFields($fields, $this->getFieldsToAdd($table, $row, $typeNum), $table);
589 // If TCEforms will render a tab menu in the next step, push the name to the tab stack:
590 if (strstr($itemList, '--div--') !== FALSE) {
591 $tabIdentString = 'TCEforms:' . $table . ':' . $row['uid'];
592 $tabIdentStringMD5 = $this->getDocumentTemplate()->getDynTabMenuId($tabIdentString);
593 // Remember that were currently working on the general tab:
594 if (isset($fields[0]) && strpos($fields[0], '--div--') !== 0) {
595 $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-1');
596 }
597 }
598 // Traverse the fields to render:
599 $cc = 0;
600 foreach ($fields as $fieldInfo) {
601 // Exploding subparts of the field configuration:
602 // this is documented as this:
603 // fieldname;fieldlabel;paletteidorlinebreaktodisplay;extradata;colorscheme
604 // fieldname can also be "--div--" or "--palette--"
605 // the last option colorscheme was dropped with TYPO3 CMS 7
606
607 list($theField, $fieldLabel, $additionalPalette, $extraFieldProcessingData) = explode(';', $fieldInfo);
608
609 // Render the field:
610 if (!in_array($theField, $excludeElements)) {
611 if ($GLOBALS['TCA'][$table]['columns'][$theField]) {
612 $sFieldPal = '';
613 if ($additionalPalette && !isset($this->palettesRendered[$this->renderDepth][$table][$additionalPalette])) {
614 $sFieldPal = $this->getPaletteFields($table, $row, $additionalPalette);
615 $this->palettesRendered[$this->renderDepth][$table][$additionalPalette] = 1;
616 }
617 $sField = $this->getSingleField($table, $theField, $row, $fieldLabel, 0, $extraFieldProcessingData, $additionalPalette);
618 if ($sField) {
619 $sField .= $sFieldPal;
620 }
621 $out_array[$out_sheet][$out_pointer] .= $sField;
622 } elseif ($theField == '--div--') {
623 if ($cc > 0) {
624 // Remove last tab entry from the dynNestedStack:
625 $out_sheet++;
626 // Remove the previous sheet from stack (if any):
627 $this->popFromDynNestedStack('tab', $tabIdentStringMD5 . '-' . $out_sheet);
628 // Remember on which sheet we're currently working:
629 $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-' . ($out_sheet + 1));
630 $out_array[$out_sheet] = array();
631 $out_array_meta[$out_sheet]['title'] = $languageService->sL($fieldLabel);
632 // Register newline for Tab
633 $out_array_meta[$out_sheet]['newline'] = $additionalPalette == 'newline';
634 } else {
635 // Setting alternative title for "General" tab if "--div--" is the very first element.
636 $out_array_meta[$out_sheet]['title'] = $languageService->sL($fieldLabel);
637 // Only add the first tab to the dynNestedStack if there are more tabs:
638 if ($tabIdentString && strpos($itemList, '--div--', strlen($fieldInfo))) {
639 $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-1');
640 }
641 }
642 } elseif ($theField == '--palette--') {
643 if ($additionalPalette && !isset($this->palettesRendered[$this->renderDepth][$table][$additionalPalette])) {
644 // Render a 'header' if not collapsed
645 if ($GLOBALS['TCA'][$table]['palettes'][$additionalPalette]['canNotCollapse'] && $fieldLabel) {
646 $out_array[$out_sheet][$out_pointer] .= $this->getPaletteFields($table, $row, $additionalPalette, $languageService->sL($fieldLabel));
647 } else {
648 $out_array[$out_sheet][$out_pointer] .= $this->getPaletteFields($table, $row, $additionalPalette, '', '', $languageService->sL($fieldLabel));
649 }
650 $this->palettesRendered[$this->renderDepth][$table][$additionalPalette] = 1;
651 }
652 }
653 }
654 $cc++;
655 }
656 }
657 }
658 }
659 // Hook: getMainFields_postProcess (requested by Thomas Hempel for use with the "dynaflex" extension)
660 foreach ($this->hookObjectsMainFields as $hookObj) {
661 if (method_exists($hookObj, 'getMainFields_postProcess')) {
662 $hookObj->getMainFields_postProcess($table, $row, $this);
663 }
664 }
665 // Rendering Main palettes, if any
666 $mParr = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['mainpalette']);
667 $i = 0;
668 if (count($mParr)) {
669 foreach ($mParr as $mP) {
670 if (!isset($this->palettesRendered[$this->renderDepth][$table][$mP])) {
671 $temp_palettesCollapsed = $this->palettesCollapsed;
672 $this->palettesCollapsed = FALSE;
673 $label = $i == 0
674 ? $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.generalOptions')
675 : $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.generalOptions_more');
676 $out_array[$out_sheet][$out_pointer] .= $this->getPaletteFields($table, $row, $mP, $label);
677 $this->palettesCollapsed = $temp_palettesCollapsed;
678 $this->palettesRendered[$this->renderDepth][$table][$mP] = 1;
679 }
680 $i++;
681 if ($this->renderDepth) {
682 $this->renderDepth--;
683 }
684 }
685 }
686 // Return the imploded $out_array:
687 // Create parts array for the tab menu:
688 $parts = array();
689 foreach ($out_array as $idx => $sheetContent) {
690 $content = implode('', $sheetContent);
691 $parts[$idx] = array(
692 'label' => $out_array_meta[$idx]['title'],
693 'content' => $content,
694 'newline' => $out_array_meta[$idx]['newline']
695 );
696 }
697 if (count($parts) > 1) {
698 // Unset the current level of tab menus:
699 $this->popFromDynNestedStack('tab', $tabIdentStringMD5 . '-' . ($out_sheet + 1));
700 $output = $this->getDynTabMenu($parts, $tabIdentString);
701 } else {
702 // If there is only one tab/part there is no need to wrap it into the dynTab code
703 $output = isset($parts[0]) ? trim($parts[0]['content']) : '';
704 }
705 // Only one tab, so just implode and wrap the background image (= tab container) around:
706 if ($out_sheet === 0) {
707 $output = '<div class="tab-content">' . $output . '</div>';
708 }
709
710 return $output;
711 }
712
713 /**
714 * Will return the TCEform elements for a pre-defined list of fields.
715 * Notice that this will STILL use the configuration found in the list [types][showitem] for those fields which are found there. So ideally the list of fields given as argument to this function should also be in the current [types][showitem] list of the record.
716 * Used for displaying forms for the frontend edit icons for instance.
717 *
718 * @param string $table The table name
719 * @param array $row The record array.
720 * @param string $list Commalist of fields from the table. These will be shown in the specified order in a form.
721 * @return string TCEform elements in a string.
722 */
723 public function getListedFields($table, $row, $list) {
724 if ($this->doLoadTableDescr($table)) {
725 $this->getLanguageService()->loadSingleTableDescription($table);
726 }
727 $out = '';
728 $types_fieldConfig = BackendUtility::getTCAtypes($table, $row, 1);
729 $editFieldList = array_unique(GeneralUtility::trimExplode(',', $list, TRUE));
730 foreach ($editFieldList as $theFieldC) {
731 list($theField, $palFields) = preg_split('/\\[|\\]/', $theFieldC);
732 $theField = trim($theField);
733 $palFields = trim($palFields);
734 if ($GLOBALS['TCA'][$table]['columns'][$theField]) {
735 $parts = GeneralUtility::trimExplode(';', $types_fieldConfig[$theField]['origString']);
736 // Don't sent palette pointer - there are no options anyways for a field-list.
737 $sField = $this->getSingleField($table, $theField, $row, $parts[1], 0, $parts[3], 0);
738 $out .= $sField;
739 }
740 if ($palFields) {
741 $out .= $this->getPaletteFields($table, $row, '', '', implode(',', GeneralUtility::trimExplode('|', $palFields, TRUE)));
742 }
743 }
744 return $out;
745 }
746
747 /**
748 * Creates a palette (collection of secondary options).
749 *
750 * @param string $table The table name
751 * @param array $row The row array
752 * @param string $palette The palette number/pointer
753 * @param string $header Header string for the palette (used when in-form). If not set, no header item is made.
754 * @param string $itemList Optional alternative list of fields for the palette
755 * @param string $collapsedHeader Optional Link text for activating a palette (when palettes does not have another form element to belong to).
756 * @return string HTML code.
757 */
758 public function getPaletteFields($table, $row, $palette, $header = '', $itemList = '', $collapsedHeader = NULL) {
759 $out = '';
760 $parts = $this->loadPaletteElements($table, $row, $palette, $itemList);
761 // Put palette together if there are fields in it:
762 if (count($parts)) {
763 $realFields = 0;
764 foreach ($parts as $part) {
765 if ($part['NAME'] !== '--linebreak--') {
766 $realFields++;
767 break;
768 }
769 }
770 if ($realFields > 0) {
771
772 $code = $this->printPalette($parts);
773 $collapsed = $this->isPalettesCollapsed($table, $palette);
774 $isHiddenPalette = !empty($GLOBALS['TCA'][$table]['palettes'][$palette]['isHiddenPalette']);
775
776
777 if ($collapsed && $collapsedHeader !== NULL && !$isHiddenPalette) {
778 $code = $this->wrapCollapsiblePalette($code, 'FORMENGINE_' . $table . '_' . $palette . '_' . $row['uid'], $collapsed);
779 } else {
780 $code = '<div class="row">' . $code . '</div>';
781 }
782
783 $out = '
784 <!-- getPaletteFields -->
785 <fieldset class="'. ($isHiddenPalette ? 'hide' : 'form-section') . '">
786 ' . ($header ? '<h4 class="form-section-headline">' . htmlspecialchars($header) . '</h4>' : '') . '
787 ' . ($collapsedHeader ? '<h4 class="form-section-headline">' . htmlspecialchars($collapsedHeader) . '</h4>' : '') . '
788 ' . $code . '
789 </fieldset>';
790 }
791 }
792 return $out;
793 }
794
795 /**
796 * Returns the form HTML code for a database table field.
797 *
798 * @param string $table The table name
799 * @param string $field The field name
800 * @param array $row The record to edit from the database table.
801 * @param string $altName Alternative field name label to show.
802 * @param bool $palette Set this if the field is on a palette (in top frame), otherwise not. (if set, field will render as a hidden field).
803 * @param string $extra The "extra" options from "Part 4" of the field configurations found in the "types" "showitem" list. Typically parsed by $this->getSpecConfFromString() in order to get the options as an associative array.
804 * @param int $pal The palette pointer.
805 * @return mixed String (normal) or array (palettes)
806 */
807 public function getSingleField($table, $field, $row, $altName = '', $palette = FALSE, $extra = '', $pal = 0) {
808 $backendUser = $this->getBackendUserAuthentication();
809
810 // Hook: getSingleField_preProcess
811 foreach ($this->hookObjectsSingleField as $hookObj) {
812 if (method_exists($hookObj, 'getSingleField_preProcess')) {
813 $hookObj->getSingleField_preProcess($table, $field, $row, $altName, $palette, $extra, $pal, $this);
814 }
815 }
816 $out = '';
817 $PA = array();
818 $PA['altName'] = $altName;
819 $PA['palette'] = $palette;
820 $PA['extra'] = $extra;
821 $PA['pal'] = $pal;
822 // Get the TCA configuration for the current field:
823 $PA['fieldConf'] = $GLOBALS['TCA'][$table]['columns'][$field];
824 $PA['fieldConf']['config']['form_type'] = $PA['fieldConf']['config']['form_type'] ?: $PA['fieldConf']['config']['type'];
825
826 // Using "form_type" locally in this script
827 $skipThisField = $this->inline->skipField($table, $field, $row, $PA['fieldConf']['config']);
828
829 // Evaluate display condition
830 $displayConditionResult = TRUE;
831 if (is_array($PA['fieldConf']) && $PA['fieldConf']['displayCond'] && is_array($row)) {
832 /** @var $elementConditionMatcher ElementConditionMatcher */
833 $elementConditionMatcher = GeneralUtility::makeInstance(ElementConditionMatcher::class);
834 $displayConditionResult = $elementConditionMatcher->match($PA['fieldConf']['displayCond'], $row);
835 }
836 // Check if this field is configured and editable (according to excludefields + other configuration)
837 if (
838 is_array($PA['fieldConf'])
839 && !$skipThisField
840 && (!$PA['fieldConf']['exclude'] || $backendUser->check('non_exclude_fields', $table . ':' . $field))
841 && $PA['fieldConf']['config']['form_type'] != 'passthrough'
842 && ($backendUser->isRTE() || !$PA['fieldConf']['config']['showIfRTE'])
843 && $displayConditionResult
844 && (!$GLOBALS['TCA'][$table]['ctrl']['languageField'] || $PA['fieldConf']['l10n_display'] || ($PA['fieldConf']['l10n_mode'] !== 'exclude') || $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] <= 0)
845 && (!$GLOBALS['TCA'][$table]['ctrl']['languageField'] || !$this->localizationMode || $this->localizationMode === $PA['fieldConf']['l10n_cat'])
846 ) {
847 // Fetching the TSconfig for the current table/field. This includes the $row which means that
848 $PA['fieldTSConfig'] = FormEngineUtility::getTSconfigForTableRow($table, $row, $field);
849 // If the field is NOT disabled from TSconfig (which it could have been) then render it
850 if (!$PA['fieldTSConfig']['disabled']) {
851 // Override fieldConf by fieldTSconfig:
852 $PA['fieldConf']['config'] = FormEngineUtility::overrideFieldConf($PA['fieldConf']['config'], $PA['fieldTSConfig']);
853 // Init variables:
854 $PA['itemFormElName'] = $this->prependFormFieldNames . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
855 // Form field name, in case of file uploads
856 $PA['itemFormElName_file'] = $this->prependFormFieldNames_file . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
857 // Form field name, to activate elements
858 // If the "eval" list contains "null", elements can be deactivated which results in storing NULL to database
859 $PA['itemFormElNameActive'] = $this->prependFormFieldNamesActive . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
860 // The value to show in the form field.
861 $PA['itemFormElValue'] = $row[$field];
862 $PA['itemFormElID'] = $this->prependFormFieldNames . '_' . $table . '_' . $row['uid'] . '_' . $field;
863 // Set field to read-only if configured for translated records to show default language content as readonly
864 if ($PA['fieldConf']['l10n_display'] && GeneralUtility::inList($PA['fieldConf']['l10n_display'], 'defaultAsReadonly') && $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0) {
865 $PA['fieldConf']['config']['readOnly'] = TRUE;
866 $PA['itemFormElValue'] = $this->defaultLanguageData[$table . ':' . $row['uid']][$field];
867 }
868 if (strpos($GLOBALS['TCA'][$table]['ctrl']['type'], ':') === FALSE) {
869 $typeField = $GLOBALS['TCA'][$table]['ctrl']['type'];
870 } else {
871 $typeField = substr($GLOBALS['TCA'][$table]['ctrl']['type'], 0, strpos($GLOBALS['TCA'][$table]['ctrl']['type'], ':'));
872 }
873 // Create a JavaScript code line which will ask the user to save/update the form due to changing the element. This is used for eg. "type" fields and others configured with "requestUpdate"
874 if (
875 !empty($GLOBALS['TCA'][$table]['ctrl']['type'])
876 && $field === $typeField
877 || !empty($GLOBALS['TCA'][$table]['ctrl']['requestUpdate'])
878 && GeneralUtility::inList(str_replace(' ', '', $GLOBALS['TCA'][$table]['ctrl']['requestUpdate']), $field)
879 ) {
880 if ($backendUser->jsConfirmation(JsConfirmation::TYPE_CHANGE)) {
881 $alertMsgOnChange = 'if (confirm(TBE_EDITOR.labels.onChangeAlert) && TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
882 } else {
883 $alertMsgOnChange = 'if (TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
884 }
885 } else {
886 $alertMsgOnChange = '';
887 }
888 // Render as a hidden field?
889 if (in_array($field, $this->hiddenFieldListArr)) {
890 $this->hiddenFieldAccum[] = '<input type="hidden" name="' . $PA['itemFormElName'] . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />';
891 } else {
892 $languageService = $this->getLanguageService();
893 // Render as a normal field:
894 $PA['label'] = $PA['altName'] ?: $PA['fieldConf']['label'];
895 $PA['label'] = $PA['fieldTSConfig']['label'] ?: $PA['label'];
896 $PA['label'] = $PA['fieldTSConfig']['label.'][$languageService->lang] ?: $PA['label'];
897 $PA['label'] = $languageService->sL($PA['label']);
898 // JavaScript code for event handlers:
899 $PA['fieldChangeFunc'] = array();
900 $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'TBE_EDITOR.fieldChanged(\'' . $table . '\',\'' . $row['uid'] . '\',\'' . $field . '\',\'' . $PA['itemFormElName'] . '\');';
901 $PA['fieldChangeFunc']['alert'] = $alertMsgOnChange;
902 // If this is the child of an inline type and it is the field creating the label
903 if ($this->inline->isInlineChildAndLabelField($table, $field)) {
904 $inlineObjectId = implode(InlineElement::Structure_Separator, array(
905 $this->inline->inlineNames['object'],
906 $table,
907 $row['uid']
908 ));
909 $PA['fieldChangeFunc']['inline'] = 'inline.handleChangedField(\'' . $PA['itemFormElName'] . '\',\'' . $inlineObjectId . '\');';
910 }
911 // Based on the type of the item, call a render function:
912 $item = $this->getSingleField_SW($table, $field, $row, $PA);
913 // Add language + diff
914 if ($PA['fieldConf']['l10n_display'] && (GeneralUtility::inList($PA['fieldConf']['l10n_display'], 'hideDiff') || GeneralUtility::inList($PA['fieldConf']['l10n_display'], 'defaultAsReadonly'))) {
915 $renderLanguageDiff = FALSE;
916 } else {
917 $renderLanguageDiff = TRUE;
918 }
919 if ($renderLanguageDiff) {
920 $item = $this->renderDefaultLanguageContent($table, $field, $row, $item);
921 $item = $this->renderDefaultLanguageDiff($table, $field, $row, $item);
922 }
923 // If the record has been saved and the "linkTitleToSelf" is set, we make the field name into a link, which will load ONLY this field in the EditDocumentController
924 $label = htmlspecialchars($PA['label'], ENT_COMPAT, 'UTF-8', FALSE);
925 if (MathUtility::canBeInterpretedAsInteger($row['uid']) && $PA['fieldTSConfig']['linkTitleToSelf'] && !GeneralUtility::_GP('columnsOnly')) {
926 $lTTS_url = BackendUtility::getModuleUrl('record_edit', array(
927 'edit[' . $table . '][' . $row['uid'] . ']' => 'edit',
928 'columnsOnly' => $field,
929 'returnUrl' => $this->thisReturnUrl()
930 ));
931 $label = '<a href="' . htmlspecialchars($lTTS_url) . '">' . $label . '</a>';
932 }
933
934 if (isset($PA['fieldConf']['config']['mode']) && $PA['fieldConf']['config']['mode'] == 'useOrOverridePlaceholder') {
935 $placeholder = $this->getPlaceholderValue($table, $field, $PA['fieldConf']['config'], $row);
936 $onChange = 'typo3form.fieldTogglePlaceholder(' . GeneralUtility::quoteJSvalue($PA['itemFormElName']) . ', !this.checked)';
937 $checked = $PA['itemFormElValue'] === NULL ? '' : ' checked="checked"';
938
939 $this->additionalJS_post[] = 'typo3form.fieldTogglePlaceholder('
940 . GeneralUtility::quoteJSvalue($PA['itemFormElName']) . ', ' . ($checked ? 'false' : 'true') . ');';
941
942 $noneElement = GeneralUtility::makeInstance(NoneElement::class, $this);
943 $noneElementConfiguration = $PA;
944 $noneElementConfiguration['itemFormElValue'] = GeneralUtility::fixed_lgd_cs($placeholder, 30);
945 $noneElementHtml = $noneElement->render('', '', '', $noneElementConfiguration);
946
947 $item = '
948 <input type="hidden" name="' . htmlspecialchars($PA['itemFormElNameActive']) . '" value="0" />
949 <div class="checkbox">
950 <label>
951 <input type="checkbox" name="' . htmlspecialchars($PA['itemFormElNameActive']) . '" value="1" id="tce-forms-textfield-use-override-' . $field . '-' . $row['uid'] . '" onchange="' . htmlspecialchars($onChange) . '"' . $checked . ' />
952 ' . sprintf($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.placeholder.override'), BackendUtility::getRecordTitlePrep($placeholder, 20)) . '
953 </label>
954 </div>
955 <div class="t3js-formengine-placeholder-placeholder">
956 ' . $noneElementHtml . '
957 </div>
958 <div class="t3js-formengine-placeholder-formfield">' . $item . '</div>';
959 }
960
961 // Wrap the label with help text
962 $PA['label'] = ($label = BackendUtility::wrapInHelp($table, $field, $label));
963 // Create output value:
964 if ($PA['fieldConf']['config']['form_type'] == 'user' && $PA['fieldConf']['config']['noTableWrapping']) {
965 $out = $item;
966 } elseif ($PA['palette']) {
967 // Array:
968 $out = array(
969 'NAME' => $label,
970 'ID' => $row['uid'],
971 'FIELD' => $field,
972 'TABLE' => $table,
973 'ITEM' => $item,
974 'ITEM_DISABLED' => ($this->isDisabledNullValueField($table, $field, $row, $PA) ? ' disabled' : ''),
975 'ITEM_NULLVALUE' => $this->renderNullValueWidget($table, $field, $row, $PA),
976 );
977 } else {
978 $out = '
979 <fieldset class="form-section">
980 <!-- getSingleField -->
981 <div class="form-group t3js-formengine-palette-field">
982 <label class="t3js-formengine-label">
983 ' . $label . '
984 <img name="req_' . $table . '_' . $row['uid'] . '_' . $field . '" src="clear.gif" class="t3js-formengine-field-required" alt="" />
985 </label>
986 <div class="t3js-formengine-field-item ' . ($this->isDisabledNullValueField($table, $field, $row, $PA) ? ' disabled' : '') . '">
987 <div class="t3-form-field-disable"></div>
988 ' . $this->renderNullValueWidget($table, $field, $row, $PA) . '
989 ' . $item . '
990 </div>
991 </div>
992 </fieldset>
993 ';
994 }
995 }
996 }
997 }
998 // Hook: getSingleField_postProcess
999 foreach ($this->hookObjectsSingleField as $hookObj) {
1000 if (method_exists($hookObj, 'getSingleField_postProcess')) {
1001 $hookObj->getSingleField_postProcess($table, $field, $row, $out, $PA, $this);
1002 }
1003 }
1004 // Return value (string or array)
1005 return $out;
1006 }
1007
1008 /**
1009 * Rendering a single item for the form
1010 *
1011 * @param string $table Table name of record
1012 * @param string $field Fieldname to render
1013 * @param array $row The record
1014 * @param array $PA Parameters array containing a lot of stuff. Value by Reference!
1015 * @return string Returns the item as HTML code to insert
1016 * @access private
1017 * @see getSingleField(), getSingleField_typeFlex_draw()
1018 */
1019 public function getSingleField_SW($table, $field, $row, &$PA) {
1020 $PA['fieldConf']['config']['form_type'] = $PA['fieldConf']['config']['form_type'] ?: $PA['fieldConf']['config']['type'];
1021 // Using "form_type" locally in this script
1022 // Hook: getSingleField_beforeRender
1023 foreach ($this->hookObjectsSingleField as $hookObject) {
1024 if (method_exists($hookObject, 'getSingleField_beforeRender')) {
1025 $hookObject->getSingleField_beforeRender($table, $field, $row, $PA);
1026 }
1027 }
1028 $type = $PA['fieldConf']['config']['form_type'];
1029 if ($type === 'inline') {
1030 $item = $this->inline->getSingleField_typeInline($table, $field, $row, $PA);
1031 } else {
1032 $typeClassNameMapping = array(
1033 'input' => 'InputElement',
1034 'text' => 'TextElement',
1035 'check' => 'CheckboxElement',
1036 'radio' => 'RadioElement',
1037 'select' => 'SelectElement',
1038 'group' => 'GroupElement',
1039 'none' => 'NoneElement',
1040 'user' => 'UserElement',
1041 'flex' => 'FlexElement',
1042 'imageManipulation' => 'ImageManipulationElement',
1043 'unknown' => 'UnknownElement',
1044 );
1045 if (!isset($typeClassNameMapping[$type])) {
1046 $type = 'unknown';
1047 }
1048 $formElement = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\Element\\' . $typeClassNameMapping[$type], $this);
1049 if ($formElement instanceof AbstractFormElement) {
1050 $formElement->setGlobalOptions($this->getConfigurationOptionsForChildElements());
1051 }
1052 $item = $formElement->render($table, $field, $row, $PA);
1053 }
1054 return $item;
1055 }
1056
1057 /**
1058 * Returns an array of global form settings to be given to child elements.
1059 *
1060 * @return array
1061 */
1062 protected function getConfigurationOptionsForChildElements() {
1063 return array(
1064 'renderReadonly' => $this->getRenderReadonly(),
1065 'disabledWizards' => $this->disableWizards,
1066 'returnUrl' => $this->thisReturnUrl(),
1067 // Inline is handed over temporarily until FormEngine uses a real object tree
1068 'inline' => $this->inline,
1069 );
1070 }
1071
1072 /**********************************************************
1073 *
1074 * Rendering of each TCEform field type
1075 *
1076 ************************************************************/
1077
1078 /**
1079 * Renders a view widget to handle and activate NULL values.
1080 * The widget is enabled by using 'null' in the 'eval' TCA definition.
1081 *
1082 * @param string $table Name of the table
1083 * @param string $field Name of the field
1084 * @param array $row Accordant data of the record row
1085 * @param array $PA Parameters array with rendering instructions
1086 * @return string Widget (if any).
1087 */
1088 protected function renderNullValueWidget($table, $field, array $row, array $PA) {
1089 $widget = '';
1090
1091 $config = $PA['fieldConf']['config'];
1092 if (
1093 !empty($config['eval']) && GeneralUtility::inList($config['eval'], 'null')
1094 && (empty($config['mode']) || $config['mode'] !== 'useOrOverridePlaceholder')
1095 ) {
1096 $checked = $PA['itemFormElValue'] === NULL ? '' : ' checked="checked"';
1097 $onChange = htmlspecialchars(
1098 'typo3form.fieldSetNull(\'' . $PA['itemFormElName'] . '\', !this.checked)'
1099 );
1100
1101 $widget = '
1102 <div class="checkbox">
1103 <label>
1104 <input type="hidden" name="' . $PA['itemFormElNameActive'] . '" value="0" />
1105 <input type="checkbox" name="' . $PA['itemFormElNameActive'] . '" value="1" onchange="' . $onChange . '"' . $checked . ' /> &nbsp;
1106 </label>
1107 </div>';
1108 }
1109
1110 return $widget;
1111 }
1112
1113 /**
1114 * Determines whether the current field value is considered as NULL value.
1115 * Using NULL values is enabled by using 'null' in the 'eval' TCA definition.
1116 *
1117 * @param string $table Name of the table
1118 * @param string $field Name of the field
1119 * @param array $row Accordant data
1120 * @param array $PA Parameters array with rendering instructions
1121 * @return bool
1122 */
1123 protected function isDisabledNullValueField($table, $field, array $row, array $PA) {
1124 $result = FALSE;
1125
1126 $config = $PA['fieldConf']['config'];
1127 if ($PA['itemFormElValue'] === NULL && !empty($config['eval'])
1128 && GeneralUtility::inList($config['eval'], 'null')
1129 && (empty($config['mode']) || $config['mode'] !== 'useOrOverridePlaceholder')) {
1130
1131 $result = TRUE;
1132 }
1133
1134 return $result;
1135 }
1136
1137
1138 /************************************************************
1139 *
1140 * "Configuration" fetching/processing functions
1141 *
1142 ************************************************************/
1143 /**
1144 * Calculate and return the current "types" pointer value for a record
1145 *
1146 * @param string $table The table name. MUST be in $GLOBALS['TCA']
1147 * @param array $row The row from the table, should contain at least the "type" field, if applicable.
1148 * @return string Return the "type" value for this record, ready to pick a "types" configuration from the $GLOBALS['TCA'] array.
1149 * @throws \RuntimeException
1150 */
1151 public function getRTypeNum($table, $row) {
1152 $typeNum = 0;
1153 $field = $GLOBALS['TCA'][$table]['ctrl']['type'];
1154 if ($field) {
1155 if (strpos($field, ':') !== FALSE) {
1156 list($pointerField, $foreignTypeField) = explode(':', $field);
1157 $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$pointerField]['config'];
1158 $relationType = $fieldConfig['type'];
1159 if ($relationType === 'select') {
1160 $foreignUid = $row[$pointerField];
1161 $foreignTable = $fieldConfig['foreign_table'];
1162 } elseif ($relationType === 'group') {
1163 $values = FormEngineUtility::extractValuesOnlyFromValueLabelList($row[$pointerField]);
1164 list(, $foreignUid) = GeneralUtility::revExplode('_', $values[0], 2);
1165 $allowedTables = explode(',', $fieldConfig['allowed']);
1166 // Always take the first configured table.
1167 $foreignTable = $allowedTables[0];
1168 } else {
1169 throw new \RuntimeException('TCA Foreign field pointer fields are only allowed to be used with group or select field types.', 1325861239);
1170 }
1171 if ($foreignUid) {
1172 $foreignRow = BackendUtility::getRecord($foreignTable, $foreignUid, $foreignTypeField);
1173 $this->registerDefaultLanguageData($foreignTable, $foreignRow);
1174 if ($foreignRow[$foreignTypeField]) {
1175 $foreignTypeFieldConfig = $GLOBALS['TCA'][$table]['columns'][$field];
1176 $typeNum = $this->getLanguageOverlayRawValue($foreignTable, $foreignRow, $foreignTypeField, $foreignTypeFieldConfig);
1177 }
1178 }
1179 } else {
1180 $typeFieldConfig = $GLOBALS['TCA'][$table]['columns'][$field];
1181 $typeNum = $this->getLanguageOverlayRawValue($table, $row, $field, $typeFieldConfig);
1182 }
1183 }
1184 if (empty($typeNum)) {
1185 // If that value is an empty string, set it to "0" (zero)
1186 $typeNum = 0;
1187 }
1188 // If current typeNum doesn't exist, set it to 0 (or to 1 for historical reasons, if 0 doesn't exist)
1189 if (!$GLOBALS['TCA'][$table]['types'][$typeNum]) {
1190 $typeNum = $GLOBALS['TCA'][$table]['types']['0'] ? 0 : 1;
1191 }
1192 // Force to string. Necessary for eg '-1' to be recognized as a type value.
1193 $typeNum = (string)$typeNum;
1194 return $typeNum;
1195 }
1196
1197 /**
1198 * Used to adhoc-rearrange the field order normally set in the [types][showitem] list
1199 *
1200 * @param array $fields A [types][showitem] list of fields, exploded by ",
1201 * @return array Returns rearranged version (keys are changed around as well.)
1202 * @see getMainFields()
1203 */
1204 public function rearrange($fields) {
1205 $fO = array_flip(GeneralUtility::trimExplode(',', $this->fieldOrder, TRUE));
1206 $newFields = array();
1207 foreach ($fields as $cc => $content) {
1208 $cP = GeneralUtility::trimExplode(';', $content);
1209 if (isset($fO[$cP[0]])) {
1210 $newFields[$fO[$cP[0]]] = $content;
1211 unset($fields[$cc]);
1212 }
1213 }
1214 ksort($newFields);
1215 $fields = array_merge($newFields, $fields);
1216 return $fields;
1217 }
1218
1219 /**
1220 * Producing an array of field names NOT to display in the form,
1221 * based on settings from subtype_value_field, bitmask_excludelist_bits etc.
1222 * Notice, this list is in NO way related to the "excludeField" flag
1223 *
1224 * @param string $table Table name, MUST be in $GLOBALS['TCA']
1225 * @param array $row A record from table.
1226 * @param string $typeNum A "type" pointer value, probably the one calculated based on the record array.
1227 * @return array Array with fieldnames as values. The fieldnames are those which should NOT be displayed "anyways
1228 * @see getMainFields()
1229 */
1230 public function getExcludeElements($table, $row, $typeNum) {
1231 // Init:
1232 $excludeElements = array();
1233 // If a subtype field is defined for the type
1234 if ($GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field']) {
1235 $sTfield = $GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field'];
1236 if (trim($GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_excludelist'][$row[$sTfield]])) {
1237 $excludeElements = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_excludelist'][$row[$sTfield]], TRUE);
1238 }
1239 }
1240 // If a bitmask-value field has been configured, then find possible fields to exclude based on that:
1241 if ($GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_value_field']) {
1242 $sTfield = $GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_value_field'];
1243 $sTValue = MathUtility::forceIntegerInRange($row[$sTfield], 0);
1244 if (is_array($GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_excludelist_bits'])) {
1245 foreach ($GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_excludelist_bits'] as $bitKey => $eList) {
1246 $bit = substr($bitKey, 1);
1247 if (MathUtility::canBeInterpretedAsInteger($bit)) {
1248 $bit = MathUtility::forceIntegerInRange($bit, 0, 30);
1249 if ($bitKey[0] === '-' && !($sTValue & pow(2, $bit)) || $bitKey[0] === '+' && $sTValue & pow(2, $bit)) {
1250 $excludeElements = array_merge($excludeElements, GeneralUtility::trimExplode(',', $eList, TRUE));
1251 }
1252 }
1253 }
1254 }
1255 }
1256 // Return the array of elements:
1257 return $excludeElements;
1258 }
1259
1260 /**
1261 * Finds possible field to add to the form, based on subtype fields.
1262 *
1263 * @param string $table Table name, MUST be in $GLOBALS['TCA']
1264 * @param array $row A record from table.
1265 * @param string $typeNum A "type" pointer value, probably the one calculated based on the record array.
1266 * @return array An array containing two values: 1) Another array containing field names to add and 2) the subtype value field.
1267 * @see getMainFields()
1268 */
1269 public function getFieldsToAdd($table, $row, $typeNum) {
1270 // Init:
1271 $addElements = array();
1272 // If a subtype field is defined for the type
1273 $sTfield = '';
1274 if ($GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field']) {
1275 $sTfield = $GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field'];
1276 if (trim($GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_addlist'][$row[$sTfield]])) {
1277 $addElements = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_addlist'][$row[$sTfield]], TRUE);
1278 }
1279 }
1280 // Return the return
1281 return array($addElements, $sTfield);
1282 }
1283
1284 /**
1285 * Merges the current [types][showitem] array with the array of fields to add for the current subtype field of the "type" value.
1286 *
1287 * @param array $fields A [types][showitem] list of fields, exploded by ",
1288 * @param array $fieldsToAdd The output from getFieldsToAdd()
1289 * @param string $table The table name, if we want to consider it's palettes when positioning the new elements
1290 * @return array Return the modified $fields array.
1291 * @see getMainFields(),getFieldsToAdd()
1292 */
1293 public function mergeFieldsWithAddedFields($fields, $fieldsToAdd, $table = '') {
1294 if (count($fieldsToAdd[0])) {
1295 $c = 0;
1296 $found = FALSE;
1297 foreach ($fields as $fieldInfo) {
1298 list($fieldName, $label, $paletteName) = GeneralUtility::trimExplode(';', $fieldInfo);
1299 if ($fieldName === $fieldsToAdd[1]) {
1300 $found = TRUE;
1301 } elseif ($fieldName === '--palette--' && $paletteName && $table !== '') {
1302 // Look inside the palette
1303 if (is_array($GLOBALS['TCA'][$table]['palettes'][$paletteName])) {
1304 $itemList = $GLOBALS['TCA'][$table]['palettes'][$paletteName]['showitem'];
1305 if ($itemList) {
1306 $paletteFields = GeneralUtility::trimExplode(',', $itemList, TRUE);
1307 foreach ($paletteFields as $info) {
1308 $fieldParts = GeneralUtility::trimExplode(';', $info);
1309 $theField = $fieldParts[0];
1310 if ($theField === $fieldsToAdd[1]) {
1311 $found = TRUE;
1312 break 1;
1313 }
1314 }
1315 }
1316 }
1317 }
1318 if ($found) {
1319 array_splice($fields, $c + 1, 0, $fieldsToAdd[0]);
1320 break;
1321 }
1322 $c++;
1323 }
1324 }
1325 return $fields;
1326 }
1327
1328 /**
1329 * Loads the elements of a palette (collection of secondary options) in an array.
1330 *
1331 * @param string $table The table name
1332 * @param array $row The row array
1333 * @param string $palette The palette number/pointer
1334 * @param string $itemList Optional alternative list of fields for the palette
1335 * @return array The palette elements
1336 */
1337 public function loadPaletteElements($table, $row, $palette, $itemList = '') {
1338 $parts = array();
1339 // Getting excludeElements, if any.
1340 if (!is_array($this->excludeElements)) {
1341 $this->excludeElements = $this->getExcludeElements($table, $row, $this->getRTypeNum($table, $row));
1342 }
1343 // Load the palette TCEform elements
1344 if ($GLOBALS['TCA'][$table] && (is_array($GLOBALS['TCA'][$table]['palettes'][$palette]) || $itemList)) {
1345 $itemList = $itemList ? $itemList : $GLOBALS['TCA'][$table]['palettes'][$palette]['showitem'];
1346 if ($itemList) {
1347 $fields = GeneralUtility::trimExplode(',', $itemList, TRUE);
1348 foreach ($fields as $info) {
1349 $fieldParts = GeneralUtility::trimExplode(';', $info);
1350 $theField = $fieldParts[0];
1351 if ($theField === '--linebreak--') {
1352 $parts[]['NAME'] = '--linebreak--';
1353 } elseif (!in_array($theField, $this->excludeElements) && $GLOBALS['TCA'][$table]['columns'][$theField]) {
1354 $elem = $this->getSingleField($table, $theField, $row, $fieldParts[1], 1, '', $fieldParts[2]);
1355 if (is_array($elem)) {
1356 $parts[] = $elem;
1357 }
1358 }
1359 }
1360 }
1361 }
1362 return $parts;
1363 }
1364
1365 /************************************************************
1366 *
1367 * Display of localized content etc.
1368 *
1369 ************************************************************/
1370 /**
1371 * Will register data from original language records if the current record is a translation of another.
1372 * The original data is shown with the edited record in the form.
1373 * The information also includes possibly diff-views of what changed in the original record.
1374 * Function called from outside (see EditDocumentController + quick edit) before rendering a form for a record
1375 *
1376 * @param string $table Table name of the record being edited
1377 * @param array $rec Record array of the record being edited
1378 * @return void
1379 */
1380 public function registerDefaultLanguageData($table, $rec) {
1381 // Add default language:
1382 if (
1383 $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $rec[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0
1384 && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']
1385 && (int)$rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] > 0
1386 ) {
1387 $lookUpTable = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']
1388 ? $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']
1389 : $table;
1390 // Get data formatted:
1391 $this->defaultLanguageData[$table . ':' . $rec['uid']] = BackendUtility::getRecordWSOL(
1392 $lookUpTable,
1393 (int)$rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]
1394 );
1395 // Get data for diff:
1396 if ($GLOBALS['TCA'][$table]['ctrl']['transOrigDiffSourceField']) {
1397 $this->defaultLanguageData_diff[$table . ':' . $rec['uid']] = unserialize($rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigDiffSourceField']]);
1398 }
1399 // If there are additional preview languages, load information for them also:
1400 $prLang = $this->getAdditionalPreviewLanguages();
1401 foreach ($prLang as $prL) {
1402 /** @var $t8Tools TranslationConfigurationProvider */
1403 $t8Tools = GeneralUtility::makeInstance(TranslationConfigurationProvider::class);
1404 $tInfo = $t8Tools->translationInfo($lookUpTable, (int)$rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']], $prL['uid']);
1405 if (is_array($tInfo['translations']) && is_array($tInfo['translations'][$prL['uid']])) {
1406 $this->additionalPreviewLanguageData[$table . ':' . $rec['uid']][$prL['uid']] = BackendUtility::getRecordWSOL($table, (int)$tInfo['translations'][$prL['uid']]['uid']);
1407 }
1408 }
1409 }
1410 }
1411
1412 /**
1413 * Creates language-overlay for a field value
1414 * This means the requested field value will be overridden with the data from the default language.
1415 * Can be used to render read only fields for example.
1416 *
1417 * @param string $table Table name of the record being edited
1418 * @param array $row Record array of the record being edited in current language
1419 * @param string $field Field name represented by $item
1420 * @param array $fieldConf Content of $PA['fieldConf']
1421 * @return string Unprocessed field value merged with default language data if needed
1422 */
1423 public function getLanguageOverlayRawValue($table, $row, $field, $fieldConf) {
1424 $value = $row[$field];
1425 if (is_array($this->defaultLanguageData[$table . ':' . $row['uid']])) {
1426 if (
1427 $fieldConf['l10n_mode'] == 'exclude'
1428 || $fieldConf['l10n_mode'] == 'mergeIfNotBlank' && trim($this->defaultLanguageData[$table . ':' . $row['uid']][$field]) !== ''
1429 ) {
1430 $value = $this->defaultLanguageData[$table . ':' . $row['uid']][$field];
1431 }
1432 }
1433 return $value;
1434 }
1435
1436 /**
1437 * Renders the display of default language record content around current field.
1438 * Will render content if any is found in the internal array, $this->defaultLanguageData,
1439 * depending on registerDefaultLanguageData() being called prior to this.
1440 *
1441 * @param string $table Table name of the record being edited
1442 * @param string $field Field name represented by $item
1443 * @param array $row Record array of the record being edited
1444 * @param string $item HTML of the form field. This is what we add the content to.
1445 * @return string Item string returned again, possibly with the original value added to.
1446 * @see getSingleField(), registerDefaultLanguageData()
1447 */
1448 public function renderDefaultLanguageContent($table, $field, $row, $item) {
1449 if (is_array($this->defaultLanguageData[$table . ':' . $row['uid']])) {
1450 $defaultLanguageValue = BackendUtility::getProcessedValue($table, $field, $this->defaultLanguageData[$table . ':' . $row['uid']][$field], 0, 1, FALSE, $this->defaultLanguageData[$table . ':' . $row['uid']]['uid']);
1451 $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field];
1452 // Don't show content if it's for IRRE child records:
1453 if ($fieldConfig['config']['type'] != 'inline') {
1454 if ($defaultLanguageValue !== '') {
1455 $item .= '<div class="t3-form-original-language">' . FormEngineUtility::getLanguageIcon($table, $row, 0)
1456 . $this->getMergeBehaviourIcon($fieldConfig['l10n_mode'])
1457 . $this->previewFieldValue($defaultLanguageValue, $fieldConfig, $field) . '</div>';
1458 }
1459 $previewLanguages = $this->getAdditionalPreviewLanguages();
1460 foreach ($previewLanguages as $previewLanguage) {
1461 $defaultLanguageValue = BackendUtility::getProcessedValue($table, $field, $this->additionalPreviewLanguageData[$table . ':' . $row['uid']][$previewLanguage['uid']][$field], 0, 1);
1462 if ($defaultLanguageValue !== '') {
1463 $item .= '<div class="t3-form-original-language">'
1464 . FormEngineUtility::getLanguageIcon($table, $row, ('v' . $previewLanguage['ISOcode']))
1465 . $this->getMergeBehaviourIcon($fieldConfig['l10n_mode'])
1466 . $this->previewFieldValue($defaultLanguageValue, $fieldConfig, $field) . '</div>';
1467 }
1468 }
1469 }
1470 }
1471 return $item;
1472 }
1473
1474 /**
1475 * Renders the diff-view of default language record content compared with what the record was originally translated from.
1476 * Will render content if any is found in the internal array, $this->defaultLanguageData,
1477 * depending on registerDefaultLanguageData() being called prior to this.
1478 *
1479 * @param string $table Table name of the record being edited
1480 * @param string $field Field name represented by $item
1481 * @param array $row Record array of the record being edited
1482 * @param string $item HTML of the form field. This is what we add the content to.
1483 * @return string Item string returned again, possibly with the original value added to.
1484 * @see getSingleField(), registerDefaultLanguageData()
1485 */
1486 public function renderDefaultLanguageDiff($table, $field, $row, $item) {
1487 if (is_array($this->defaultLanguageData_diff[$table . ':' . $row['uid']])) {
1488 // Initialize:
1489 $dLVal = array(
1490 'old' => $this->defaultLanguageData_diff[$table . ':' . $row['uid']],
1491 'new' => $this->defaultLanguageData[$table . ':' . $row['uid']]
1492 );
1493 // There must be diff-data:
1494 if (isset($dLVal['old'][$field])) {
1495 if ((string)$dLVal['old'][$field] !== (string)$dLVal['new'][$field]) {
1496 // Create diff-result:
1497 $t3lib_diff_Obj = GeneralUtility::makeInstance(DiffUtility::class);
1498 $diffres = $t3lib_diff_Obj->makeDiffDisplay(
1499 BackendUtility::getProcessedValue($table, $field, $dLVal['old'][$field], 0, 1),
1500 BackendUtility::getProcessedValue($table, $field, $dLVal['new'][$field], 0, 1)
1501 );
1502 $item .= '<div class="t3-form-original-language-diff">
1503 <div class="t3-form-original-language-diffheader">' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.changeInOrig')) . '</div>
1504 <div class="t3-form-original-language-diffcontent">' . $diffres . '</div>
1505 </div>';
1506 }
1507 }
1508 }
1509 return $item;
1510 }
1511
1512 /************************************************************
1513 *
1514 * Form element helper functions
1515 *
1516 ************************************************************/
1517 /**
1518 * Creates style attribute content for optgroup tags in a selector box, primarily setting it
1519 * up to show the icon of an element as background image (works in mozilla).
1520 *
1521 * @param string $iconString Icon string for option item
1522 * @return string Style attribute content, if any
1523 */
1524 public function optgroupTagStyle($iconString) {
1525 if (!$iconString) {
1526 return '';
1527 }
1528 list($selIconFile, $selIconInfo) = FormEngineUtility::getIcon($iconString);
1529 if (empty($selIconFile)) {
1530 // Skip background style if image is unavailable
1531 return '';
1532 }
1533 $padLeft = $selIconInfo[0] + 4;
1534 if ($padLeft >= 18 && $padLeft <= 24) {
1535 // In order to get the same padding for all option tags even if icon sizes differ a little,
1536 // set it to 22, if it was between 18 and 24 pixels.
1537 $padLeft = 22;
1538 }
1539 $padTop = MathUtility::forceIntegerInRange(($selIconInfo[1] - 12) / 2, 0);
1540 return 'background: #ffffff url(' . $selIconFile . ') 0 0 no-repeat; padding-top: ' . $padTop . 'px; padding-left: ' . $padLeft . 'px;';
1541 }
1542
1543 /**
1544 * Add the id and the style property to the field palette
1545 *
1546 * @param string $code Palette Code
1547 * @param string $id Collapsible ID
1548 * @param string $collapsed Collapsed status
1549 * @return bool Is collapsed
1550 */
1551 public function wrapCollapsiblePalette($code, $id, $collapsed) {
1552 $display = $collapsed ? '' : ' in';
1553 $id = str_replace('.', '', $id);
1554 $out = '
1555 <!-- wrapCollapsiblePalette -->
1556 <p>
1557 <button class="btn btn-default" type="button" data-toggle="collapse" data-target="#' . $id . '" aria-expanded="false" aria-controls="' . $id . '">
1558 ' . IconUtility::getSpriteIcon('actions-system-options-view') . '
1559 ' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.moreOptions')) . '
1560 </button>
1561 </p>
1562 <div id="' . $id . '" class="form-section-collapse collapse' . $display . '">
1563 <div class="row">' . $code . '</div>
1564 </div>';
1565 return $out;
1566 }
1567
1568
1569 /**
1570 * Returns the "returnUrl" of the form. Can be set externally or will be taken from "GeneralUtility::linkThisScript()"
1571 *
1572 * @return string Return URL of current script
1573 */
1574 public function thisReturnUrl() {
1575 return $this->returnUrl ? $this->returnUrl : GeneralUtility::linkThisScript();
1576 }
1577
1578 /**
1579 * Returns the form field for a single HIDDEN field.
1580 * (Not used anywhere...?)
1581 *
1582 * @param string $table Table name
1583 * @param string $field Field name
1584 * @param array $row The row
1585 * @return string The hidden-field <input> tag.
1586 */
1587 public function getSingleHiddenField($table, $field, $row) {
1588 $item = '';
1589 if ($GLOBALS['TCA'][$table]['columns'][$field]) {
1590 $uid = $row['uid'];
1591 $itemName = $this->prependFormFieldNames . '[' . $table . '][' . $uid . '][' . $field . ']';
1592 $itemValue = $row[$field];
1593 $item = '<input type="hidden" name="' . $itemName . '" value="' . htmlspecialchars($itemValue) . '" />';
1594 }
1595 return $item;
1596 }
1597
1598 /**
1599 * Create dynamic tab menu
1600 *
1601 * @param array $menuItems Items for the tab menu, fed to template::getDynTabMenu()
1602 * @param string $identString ID string for the tab menu
1603 * @param int $dividersToTabsBehaviour If set to '1' empty tabs will be removed, If set to '2' empty tabs will be disabled, deprecated, and not in use anymore since TYPO3 CMS 7
1604 * @return string HTML for the menu
1605 */
1606 public function getDynTabMenu($menuItems, $identString, $dividersToTabsBehaviour = -1) {
1607 // if the third (obsolete) parameter is used, throw a deprecation warning
1608 if ($dividersToTabsBehaviour !== -1) {
1609 GeneralUtility::deprecationLog('The parameter $dividersToTabsBehaviour in FormEngine::getDynTabMenu is deprecated. Please remove this option from your code');
1610 }
1611 $docTemplate = $this->getDocumentTemplate();
1612 if (is_object($docTemplate)) {
1613 $docTemplate->backPath = '';
1614 return $docTemplate->getDynamicTabMenu($menuItems, $identString, 1, FALSE, FALSE);
1615 } else {
1616 $output = '';
1617 foreach ($menuItems as $menuItem) {
1618 if (!empty($menuItem['content'])) {
1619 $output .= '
1620 <h3>' . htmlspecialchars($menuItem['label']) . '</h3>
1621 ' . ($menuItem['description'] ? '<p>' . nl2br(htmlspecialchars($menuItem['description'])) . '</p>' : '') . '
1622 ' . $menuItem['content'];
1623 }
1624 }
1625 return $output;
1626 }
1627 }
1628
1629 /********************************************
1630 *
1631 * Template functions
1632 *
1633 ********************************************/
1634 /**
1635 * Sets the design to the backend design.
1636 * Backend
1637 *
1638 * @return void
1639 */
1640 public function setNewBEDesign() {
1641 $template = GeneralUtility::getUrl(PATH_typo3 . $this->templateFile);
1642 // Wrapping all table rows for a particular record being edited:
1643 $this->totalWrap = HtmlParser::getSubpart($template, '###TOTALWRAP###');
1644 // Wrapping a single field:
1645 $this->fieldTemplate = HtmlParser::getSubpart($template, '###FIELDTEMPLATE###');
1646 $this->paletteFieldTemplate = HtmlParser::getSubpart($template, '###PALETTEFIELDTEMPLATE###');
1647 $this->palFieldTemplate = HtmlParser::getSubpart($template, '###PALETTE_FIELDTEMPLATE###');
1648 $this->palFieldTemplateHeader = HtmlParser::getSubpart($template, '###PALETTE_FIELDTEMPLATE_HEADER###');
1649 }
1650
1651 /**
1652 * This inserts the content of $inArr into the field-template
1653 *
1654 * @param array $inArr Array with key/value pairs to insert in the template.
1655 * @param string $altTemplate Alternative template to use instead of the default.
1656 * @return string
1657 */
1658 public function intoTemplate($inArr, $altTemplate = '') {
1659 // Put into template_
1660 $fieldTemplateParts = explode('###FIELD_', $altTemplate ?: $this->fieldTemplate);
1661 $out = current($fieldTemplateParts);
1662 foreach ($fieldTemplateParts as $part) {
1663 list($key, $val) = explode('###', $part, 2);
1664 $out .= $inArr[$key];
1665 $out .= $val;
1666 }
1667 return $out;
1668 }
1669
1670 /**
1671 * Wraps all the table rows into a single table.
1672 * Used externally from scripts like EditDocumentController and PageLayoutController (which uses FormEngine)
1673 *
1674 * @param string $c Code to output between table-parts; table rows
1675 * @param array $rec The record
1676 * @param string $table The table name
1677 * @return string
1678 */
1679 public function wrapTotal($c, $rec, $table) {
1680 $parts = $this->replaceTableWrap(explode('|', $this->totalWrap, 2), $rec, $table);
1681 return $parts[0] . $c . $parts[1] . implode('', $this->hiddenFieldAccum);
1682 }
1683
1684 /**
1685 * Generates a token and returns an input field with it
1686 *
1687 * @param string $formName Context of the token
1688 * @param string $tokenName The name of the token GET/POST variable
1689 * @return string A complete input field
1690 */
1691 static public function getHiddenTokenField($formName = 'securityToken', $tokenName = 'formToken') {
1692 $formprotection = FormProtectionFactory::get();
1693 return '<input type="hidden" name="' . $tokenName . '" value="' . $formprotection->generateToken($formName) . '" />';
1694 }
1695
1696 /**
1697 * This replaces markers in the total wrap
1698 *
1699 * @param array $arr An array of template parts containing some markers.
1700 * @param array $rec The record
1701 * @param string $table The table name
1702 * @return string
1703 */
1704 public function replaceTableWrap($arr, $rec, $table) {
1705 $icon = IconUtility::getSpriteIconForRecord($table, $rec, array('title' => $this->getRecordPath($table, $rec)));
1706 // Make "new"-label
1707 $languageService = $this->getLanguageService();
1708 if (strstr($rec['uid'], 'NEW')) {
1709 $newLabel = ' <span class="typo3-TCEforms-newToken">' . $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.new', TRUE) . '</span>';
1710 // BackendUtility::fixVersioningPid Should not be used here because NEW records are not offline workspace versions...
1711 $truePid = BackendUtility::getTSconfig_pidValue($table, $rec['uid'], $rec['pid']);
1712 $prec = BackendUtility::getRecordWSOL('pages', $truePid, 'title');
1713 $pageTitle = BackendUtility::getRecordTitle('pages', $prec, TRUE, FALSE);
1714 $rLabel = '<em>[PID: ' . $truePid . '] ' . $pageTitle . '</em>';
1715 // Fetch translated title of the table
1716 $tableTitle = $languageService->sL($GLOBALS['TCA'][$table]['ctrl']['title']);
1717 if ($table === 'pages') {
1718 $label = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.createNewPage', TRUE);
1719 $pageTitle = sprintf($label, $tableTitle);
1720 } else {
1721 $label = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.createNewRecord', TRUE);
1722 if ($rec['pid'] == 0) {
1723 $label = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.createNewRecordRootLevel', TRUE);
1724 }
1725 $pageTitle = sprintf($label, $tableTitle, $pageTitle);
1726 }
1727 } else {
1728 $newLabel = ' <span class="typo3-TCEforms-recUid">[' . $rec['uid'] . ']</span>';
1729 $rLabel = BackendUtility::getRecordTitle($table, $rec, TRUE, FALSE);
1730 $prec = BackendUtility::getRecordWSOL('pages', $rec['pid'], 'uid,title');
1731 // Fetch translated title of the table
1732 $tableTitle = $languageService->sL($GLOBALS['TCA'][$table]['ctrl']['title']);
1733 if ($table === 'pages') {
1734 $label = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.editPage', TRUE);
1735 // Just take the record title and prepend an edit label.
1736 $pageTitle = sprintf($label, $tableTitle, $rLabel);
1737 } else {
1738 $label = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.editRecord', TRUE);
1739 $pageTitle = BackendUtility::getRecordTitle('pages', $prec, TRUE, FALSE);
1740 if ($rLabel === BackendUtility::getNoRecordTitle(TRUE)) {
1741 $label = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.editRecordNoTitle', TRUE);
1742 }
1743 if ($rec['pid'] == 0) {
1744 $label = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.editRecordRootLevel', TRUE);
1745 }
1746 if ($rLabel !== BackendUtility::getNoRecordTitle(TRUE)) {
1747 // Just take the record title and prepend an edit label.
1748 $pageTitle = sprintf($label, $tableTitle, $rLabel, $pageTitle);
1749 } else {
1750 // Leave out the record title since it is not set.
1751 $pageTitle = sprintf($label, $tableTitle, $pageTitle);
1752 }
1753 }
1754 $icon = $this->getControllerDocumentTemplate()->wrapClickMenuOnIcon($icon, $table, $rec['uid'], 1, '', '+copy,info,edit,view');
1755 }
1756 foreach ($arr as $k => $v) {
1757 // Make substitutions:
1758 $arr[$k] = str_replace(
1759 array(
1760 '###PAGE_TITLE###',
1761 '###ID_NEW_INDICATOR###',
1762 '###RECORD_LABEL###',
1763 '###TABLE_TITLE###',
1764 '###RECORD_ICON###'
1765 ),
1766 array(
1767 $pageTitle,
1768 $newLabel,
1769 $rLabel,
1770 htmlspecialchars($languageService->sL($GLOBALS['TCA'][$table]['ctrl']['title'])),
1771 $icon
1772 ),
1773 $arr[$k]
1774 );
1775 }
1776 return $arr;
1777 }
1778
1779 /**
1780 * Creates HTML output for a palette
1781 *
1782 * @param array $palArr The palette array to print
1783 * @return string HTML output
1784 */
1785 public function printPalette($palArr) {
1786
1787 // GROUP FIELDS
1788 $groupedFields = array();
1789 $row = 0;
1790 $lastLineWasLinebreak = TRUE;
1791 foreach ($palArr as $field){
1792 if ($field['NAME'] === '--linebreak--') {
1793 if (!$lastLineWasLinebreak) {
1794 $row++;
1795 $groupedFields[$row][] = $field;
1796 $row++;
1797 $lastLineWasLinebreak = TRUE;
1798 }
1799 } else {
1800 $lastLineWasLinebreak = FALSE;
1801 $groupedFields[$row][] = $field;
1802 }
1803 }
1804
1805 $out = '';
1806 // PROCESS FIELDS
1807 foreach ($groupedFields as $fields) {
1808
1809 $numberOfItems = count($fields);
1810 $cols = $numberOfItems;
1811 $colWidth = (int)floor(12 / $cols);
1812
1813 // COLS
1814 $colClass = "col-md-12";
1815 $colClear = array();
1816 if ($colWidth == 6) {
1817 $colClass = "col-sm-6";
1818 $colClear = array(
1819 2 => 'visible-sm-block visible-md-block visible-lg-block',
1820 );
1821 } elseif ($colWidth === 4) {
1822 $colClass = "col-sm-4";
1823 $colClear = array(
1824 3 => 'visible-sm-block visible-md-block visible-lg-block',
1825 );
1826 } elseif ($colWidth === 3) {
1827 $colClass = "col-sm-6 col-md-3";
1828 $colClear = array(
1829 2 => 'visible-sm-block',
1830 4 => 'visible-md-block visible-lg-block',
1831 );
1832 } elseif ($colWidth <= 2) {
1833 $colClass = "checkbox-column col-sm-6 col-md-3 col-lg-2";
1834 $colClear = array(
1835 2 => 'visible-sm-block',
1836 4 => 'visible-md-block',
1837 6 => 'visible-lg-block'
1838 );
1839 }
1840
1841 // RENDER FIELDS
1842 for ($counter = 0; $counter < $numberOfItems; $counter++) {
1843 $content = $fields[$counter];
1844 if ($content['NAME'] === '--linebreak--') {
1845 if ($counter !== $numberOfItems) {
1846 $out .= '<div class="clearfix"></div>';
1847 }
1848 } else {
1849
1850 // ITEM
1851 $out .= '
1852 <!-- printPalette -->
1853 <div class="form-group t3js-formengine-palette-field ' . $colClass . '">
1854 <label class="t3js-formengine-label">
1855 ' . $content['NAME'] . '
1856 <img name="req_' . $content['TABLE'] . '_' . $content['ID'] . '_' . $content['FIELD'] . '" src="clear.gif" class="t3js-formengine-field-required" alt="" />
1857 </label>
1858 ' . $content['ITEM_NULLVALUE'] . '
1859 <div class="t3js-formengine-field-item ' . $content['ITEM_DISABLED'] . '">
1860 <div class="t3-form-field-disable"></div>
1861 ' . $content['ITEM'] . '
1862 </div>
1863 </div>';
1864
1865 // BREAKPOINTS
1866 if ($counter + 1 < $numberOfItems && !empty($colClear)) {
1867 foreach ($colClear as $rowBreakAfter => $clearClass) {
1868 if (($counter + 1) % $rowBreakAfter === 0) {
1869 $out .= '<div class="clearfix '. $clearClass . '"></div>';
1870 }
1871 }
1872 }
1873 }
1874 }
1875 }
1876 return $out;
1877 }
1878
1879 /********************************************
1880 *
1881 * JavaScript related functions
1882 *
1883 ********************************************/
1884 /**
1885 * JavaScript code added BEFORE the form is drawn:
1886 *
1887 * @return string A <script></script> section with JavaScript.
1888 */
1889 public function JStop() {
1890 $out = '';
1891 // Additional top HTML:
1892 if (count($this->additionalCode_pre)) {
1893 $out .= implode('
1894
1895 <!-- NEXT: -->
1896 ', $this->additionalCode_pre);
1897 }
1898 return $out;
1899 }
1900
1901 /**
1902 * JavaScript code used for input-field evaluation.
1903 *
1904 * Example use:
1905 *
1906 * $msg .= 'Distribution time (hh:mm dd-mm-yy):<br /><input type="text" name="send_mail_datetime_hr"'
1907 * . ' onchange="typo3form.fieldGet(\'send_mail_datetime\', \'datetime\', \'\', 0,0);"'
1908 * . $this->getTBE()->formWidth(20) . ' /><input type="hidden" value="' . $GLOBALS['EXEC_TIME']
1909 * . '" name="send_mail_datetime" /><br />';
1910 * $this->extJSCODE .= 'typo3form.fieldSet("send_mail_datetime", "datetime", "", 0,0);';
1911 *
1912 * ... and then include the result of this function after the form
1913 *
1914 * @param string $formname The identification of the form on the page.
1915 * @param bool $update Just extend/update existing settings, e.g. for AJAX call
1916 * @return string A section with JavaScript - if $update is FALSE, embedded in <script></script>
1917 */
1918 public function JSbottom($formname = 'forms[0]', $update = FALSE) {
1919 $languageService = $this->getLanguageService();
1920 $jsFile = array();
1921 $elements = array();
1922 $out = '';
1923 // Required:
1924 foreach ($this->requiredFields as $itemImgName => $itemName) {
1925 $match = array();
1926 if (preg_match('/^(.+)\\[((\\w|\\d|_)+)\\]$/', $itemName, $match)) {
1927 $record = $match[1];
1928 $field = $match[2];
1929 $elements[$record][$field]['required'] = 1;
1930 $elements[$record][$field]['requiredImg'] = $itemImgName;
1931 if (isset($this->requiredAdditional[$itemName]) && is_array($this->requiredAdditional[$itemName])) {
1932 $elements[$record][$field]['additional'] = $this->requiredAdditional[$itemName];
1933 }
1934 }
1935 }
1936 // Range:
1937 foreach ($this->requiredElements as $itemName => $range) {
1938 if (preg_match('/^(.+)\\[((\\w|\\d|_)+)\\]$/', $itemName, $match)) {
1939 $record = $match[1];
1940 $field = $match[2];
1941 $elements[$record][$field]['range'] = array($range[0], $range[1]);
1942 $elements[$record][$field]['rangeImg'] = $range['imgName'];
1943 }
1944 }
1945 $this->TBE_EDITOR_fieldChanged_func = 'TBE_EDITOR.fieldChanged_fName(fName,formObj[fName+"_list"]);';
1946 if (!$update) {
1947 if ($this->loadMD5_JS) {
1948 $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/md5.js');
1949 }
1950 $pageRenderer = $this->getPageRenderer();
1951 // load the main module for FormEngine with all important JS functions
1952 $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/FormEngine', 'function(FormEngine) {
1953 FormEngine.setBrowserUrl(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('browser')) . ');
1954 }');
1955 $pageRenderer->loadPrototype();
1956 $pageRenderer->loadJquery();
1957 $pageRenderer->loadExtJS();
1958 $beUserAuth = $this->getBackendUserAuthentication();
1959 // Make textareas resizable and flexible ("autogrow" in height)
1960 $textareaSettings = array(
1961 'autosize' => (bool)$beUserAuth->uc['resizeTextareas_Flexible']
1962 );
1963 $pageRenderer->addInlineSettingArray('Textarea', $textareaSettings);
1964
1965 $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.evalfield.js');
1966 $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.tbe_editor.js');
1967 $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/ValueSlider.js');
1968 // Needed for FormEngine manipulation (date picker)
1969 $dateFormat = ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? array('MM-DD-YYYY', 'HH:mm MM-DD-YYYY') : array('DD-MM-YYYY', 'HH:mm DD-MM-YYYY'));
1970 $pageRenderer->addInlineSetting('DateTimePicker', 'DateFormat', $dateFormat);
1971
1972 // support placeholders for IE9 and lower
1973 $clientInfo = GeneralUtility::clientInfo();
1974 if ($clientInfo['BROWSER'] == 'msie' && $clientInfo['VERSION'] <= 9) {
1975 $this->loadJavascriptLib('sysext/core/Resources/Public/JavaScript/Contrib/placeholders.jquery.min.js');
1976 }
1977
1978 // @todo: remove scriptaclous once suggest is moved to RequireJS, see #55575
1979 $pageRenderer->loadScriptaculous();
1980 $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/tceforms.js');
1981 $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_suggest.js');
1982
1983 // If IRRE fields were processed, add the JavaScript functions:
1984 if ($this->inline->inlineCount) {
1985 // We want to load jQuery-ui inside our js. Enable this using requirejs.
1986 $pageRenderer->loadRequireJs();
1987 $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.inline.js');
1988 $out .= '
1989 inline.setPrependFormFieldNames("' . $this->inline->prependNaming . '");
1990 inline.setNoTitleString("' . addslashes(BackendUtility::getNoRecordTitle(TRUE)) . '");
1991 ';
1992 }
1993 $out .= '
1994 TBE_EDITOR.images.req.src = "' . IconUtility::skinImg('', 'gfx/required_h.gif', '', 1) . '";
1995 TBE_EDITOR.images.clear.src = "clear.gif";
1996
1997 TBE_EDITOR.formname = "' . $formname . '";
1998 TBE_EDITOR.formnameUENC = "' . rawurlencode($formname) . '";
1999 TBE_EDITOR.backPath = "";
2000 TBE_EDITOR.prependFormFieldNames = "' . $this->prependFormFieldNames . '";
2001 TBE_EDITOR.prependFormFieldNamesUENC = "' . rawurlencode($this->prependFormFieldNames) . '";
2002 TBE_EDITOR.prependFormFieldNamesCnt = ' . substr_count($this->prependFormFieldNames, '[') . ';
2003 TBE_EDITOR.isPalettedoc = null;
2004 TBE_EDITOR.doSaveFieldName = "' . ($this->doSaveFieldName ? addslashes($this->doSaveFieldName) : '') . '";
2005 TBE_EDITOR.labels.fieldsChanged = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.fieldsChanged')) . ';
2006 TBE_EDITOR.labels.fieldsMissing = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.fieldsMissing')) . ';
2007 TBE_EDITOR.labels.maxItemsAllowed = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.maxItemsAllowed')) . ';
2008 TBE_EDITOR.labels.refresh_login = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login')) . ';
2009 TBE_EDITOR.labels.onChangeAlert = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.onChangeAlert')) . ';
2010 TBE_EDITOR.labels.remainingCharacters = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.remainingCharacters')) . ';
2011 evalFunc.USmode = ' . ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? '1' : '0') . ';
2012
2013 TBE_EDITOR.customEvalFunctions = {};
2014
2015 ';
2016 }
2017 // Add JS required for inline fields
2018 if (count($this->inline->inlineData)) {
2019 $out .= '
2020 inline.addToDataArray(' . json_encode($this->inline->inlineData) . ');
2021 ';
2022 }
2023 // Registered nested elements for tabs or inline levels:
2024 if (count($this->requiredNested)) {
2025 $out .= '
2026 TBE_EDITOR.addNested(' . json_encode($this->requiredNested) . ');
2027 ';
2028 }
2029 // Elements which are required or have a range definition:
2030 if (count($elements)) {
2031 $out .= '
2032 TBE_EDITOR.addElements(' . json_encode($elements) . ');
2033 TBE_EDITOR.initRequired();
2034 ';
2035 }
2036 // $this->additionalJS_submit:
2037 if ($this->additionalJS_submit) {
2038 $additionalJS_submit = implode('', $this->additionalJS_submit);
2039 $additionalJS_submit = str_replace(array(CR, LF), '', $additionalJS_submit);
2040 $out .= '
2041 TBE_EDITOR.addActionChecks("submit", "' . addslashes($additionalJS_submit) . '");
2042 ';
2043 }
2044 $out .= LF . implode(LF, $this->additionalJS_post) . LF . $this->extJSCODE;
2045 // Regular direct output:
2046 if (!$update) {
2047 $spacer = LF . TAB;
2048 $out = $spacer . implode($spacer, $jsFile) . GeneralUtility::wrapJS($out);
2049 }
2050 return $out;
2051 }
2052
2053 /**
2054 * Prints necessary JavaScript for TCEforms (after the form HTML).
2055 * currently this is used to transform page-specific options in the TYPO3.Settings array for JS
2056 * so the JS module can access these values
2057 *
2058 * @return string
2059 */
2060 public function printNeededJSFunctions() {
2061 /** @var $pageRenderer \TYPO3\CMS\Core\Page\PageRenderer */
2062 $pageRenderer = $this->getControllerDocumentTemplate()->getPageRenderer();
2063
2064 // set variables to be accessible for JS
2065 $pageRenderer->addInlineSetting('FormEngine', 'formName', 'editform');
2066 $pageRenderer->addInlineSetting('FormEngine', 'backPath', '');
2067
2068 // Integrate JS functions for the element browser if such fields or IRRE fields were processed
2069 $pageRenderer->addInlineSetting('FormEngine', 'legacyFieldChangedCb', 'function() { ' . $this->TBE_EDITOR_fieldChanged_func . ' };');
2070
2071 return $this->JSbottom('editform');
2072 }
2073
2074 /**
2075 * Returns necessary JavaScript for the top
2076 *
2077 * @return string
2078 */
2079 public function printNeededJSFunctions_top() {
2080 return $this->JStop('editform');
2081 }
2082
2083 /**
2084 * Includes a javascript library that exists in the core /typo3/ directory. The
2085 * backpath is automatically applied.
2086 * This method acts as wrapper for $GLOBALS['SOBE']->doc->loadJavascriptLib($lib).
2087 *
2088 * @param string $lib Library name. Call it with the full path like "contrib/prototype/prototype.js" to load it
2089 * @return void
2090 */
2091 public function loadJavascriptLib($lib) {
2092 $this->getControllerDocumentTemplate()->loadJavascriptLib($lib);
2093 }
2094
2095 /**
2096 * Wrapper for access to the current page renderer object
2097 *
2098 * @return \TYPO3\CMS\Core\Page\PageRenderer
2099 */
2100 protected function getPageRenderer() {
2101 return $this->getControllerDocumentTemplate()->getPageRenderer();
2102 }
2103
2104 /********************************************
2105 *
2106 * Various helper functions
2107 *
2108 ********************************************/
2109
2110 /**
2111 * Returns TRUE if the given $row is new (i.e. has not been saved to the database)
2112 *
2113 * @param string $table
2114 * @param array $row
2115 * @return bool
2116 */
2117 protected function isNewRecord($table, $row) {
2118 return !MathUtility::canBeInterpretedAsInteger($row['uid']) && GeneralUtility::isFirstPartOfStr($row['uid'], 'NEW');
2119 }
2120
2121 /**
2122 * Return record path (visually formatted, using BackendUtility::getRecordPath() )
2123 *
2124 * @param string $table Table name
2125 * @param array $rec Record array
2126 * @return string The record path.
2127 * @see BackendUtility::getRecordPath()
2128 */
2129 public function getRecordPath($table, $rec) {
2130 BackendUtility::fixVersioningPid($table, $rec);
2131 list($tscPID, $thePidValue) = BackendUtility::getTSCpidCached($table, $rec['uid'], $rec['pid']);
2132 if ($thePidValue >= 0) {
2133 return BackendUtility::getRecordPath($tscPID, $this->readPerms(), 15);
2134 }
2135 return '';
2136 }
2137
2138 /**
2139 * Returns the select-page read-access SQL clause.
2140 * Returns cached string, so you can call this function as much as you like without performance loss.
2141 *
2142 * @return string
2143 */
2144 public function readPerms() {
2145 if (!$this->perms_clause_set) {
2146 $this->perms_clause = $this->getBackendUserAuthentication()->getPagePermsClause(1);
2147 $this->perms_clause_set = TRUE;
2148 }
2149 return $this->perms_clause;
2150 }
2151
2152 /**
2153 * Returns TRUE, if the palette, $palette, is collapsed (not shown, but found in top-frame) for the table.
2154 *
2155 * @param string $table The table name
2156 * @param int $palette The palette pointer/number
2157 * @return bool
2158 */
2159 public function isPalettesCollapsed($table, $palette) {
2160 if (is_array($GLOBALS['TCA'][$table]['palettes'][$palette]) && $GLOBALS['TCA'][$table]['palettes'][$palette]['isHiddenPalette']) {
2161 return TRUE;
2162 }
2163 if ($GLOBALS['TCA'][$table]['ctrl']['canNotCollapse']) {
2164 return FALSE;
2165 }
2166 if (is_array($GLOBALS['TCA'][$table]['palettes'][$palette]) && $GLOBALS['TCA'][$table]['palettes'][$palette]['canNotCollapse']) {
2167 return FALSE;
2168 }
2169 return $this->palettesCollapsed;
2170 }
2171
2172 /**
2173 * Returns TRUE if descriptions should be loaded always
2174 *
2175 * @param string $table Table for which to check
2176 * @return bool
2177 */
2178 public function doLoadTableDescr($table) {
2179 return $GLOBALS['TCA'][$table]['interface']['always_description'];
2180 }
2181
2182 /**
2183 * Renders an icon to indicate the way the translation and the original is merged (if this is relevant).
2184 *
2185 * If a field is defined as 'mergeIfNotBlank' this is useful information for an editor. He/she can leave the field blank and
2186 * the original value will be used. Without this hint editors are likely to copy the contents even if it is not necessary.
2187 *
2188 * @param string $l10nMode Localization mode from TCA
2189 * @return string
2190 */
2191 protected function getMergeBehaviourIcon($l10nMode) {
2192 $icon = '';
2193 if ($l10nMode === 'mergeIfNotBlank') {
2194 $icon = IconUtility::getSpriteIcon('actions-edit-merge-localization', array('title' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_misc.xlf:localizeMergeIfNotBlank')));
2195 }
2196 return $icon;
2197 }
2198
2199 /**
2200 * Rendering preview output of a field value which is not shown as a form field but just outputted.
2201 *
2202 * @param string $value The value to output
2203 * @param array $config Configuration for field.
2204 * @param string $field Name of field.
2205 * @return string HTML formatted output
2206 */
2207 public function previewFieldValue($value, $config, $field = '') {
2208 if ($config['config']['type'] === 'group' && ($config['config']['internal_type'] === 'file' || $config['config']['internal_type'] === 'file_reference')) {
2209 // Ignore uploadfolder if internal_type is file_reference
2210 if ($config['config']['internal_type'] === 'file_reference') {
2211 $config['config']['uploadfolder'] = '';
2212 }
2213 $show_thumbs = TRUE;
2214 $table = 'tt_content';
2215 // Making the array of file items:
2216 $itemArray = GeneralUtility::trimExplode(',', $value, TRUE);
2217 // Showing thumbnails:
2218 $thumbsnail = '';
2219 if ($show_thumbs) {
2220 $imgs = array();
2221 foreach ($itemArray as $imgRead) {
2222 $imgP = explode('|', $imgRead);
2223 $imgPath = rawurldecode($imgP[0]);
2224 $rowCopy = array();
2225 $rowCopy[$field] = $imgPath;
2226 // Icon + clickmenu:
2227 $absFilePath = GeneralUtility::getFileAbsFileName($config['config']['uploadfolder'] ? $config['config']['uploadfolder'] . '/' . $imgPath : $imgPath);
2228 $fileInformation = pathinfo($imgPath);
2229 $fileIcon = IconUtility::getSpriteIconForFile($imgPath, array('title' => htmlspecialchars($fileInformation['basename'] . ($absFilePath && @is_file($absFilePath) ? ' (' . GeneralUtility::formatSize(filesize($absFilePath)) . 'bytes)' : ' - FILE NOT FOUND!'))));
2230 $imgs[] =
2231 '<span class="text-nowrap">' .
2232 BackendUtility::thumbCode(
2233 $rowCopy,
2234 $table,
2235 $field,
2236 '',
2237 '',
2238 $config['config']['uploadfolder'], 0, ' align="middle"'
2239 ) .
2240 ($absFilePath ? $this->getControllerDocumentTemplate()->wrapClickMenuOnIcon($fileIcon, $absFilePath, 0, 1, '', '+copy,info,edit,view') : $fileIcon) . $imgPath .
2241 '</span>';
2242 }
2243 $thumbsnail = implode('<br />', $imgs);
2244 }
2245 return $thumbsnail;
2246 } else {
2247 return nl2br(htmlspecialchars($value));
2248 }
2249 }
2250
2251 /**
2252 * Generates and return information about which languages the current user should see in preview, configured by options.additionalPreviewLanguages
2253 *
2254 * @return array Array of additional languages to preview
2255 */
2256 public function getAdditionalPreviewLanguages() {
2257 if (!isset($this->cachedAdditionalPreviewLanguages)) {
2258 $this->cachedAdditionalPreviewLanguages = array();
2259 if ($this->getBackendUserAuthentication()->getTSConfigVal('options.additionalPreviewLanguages')) {
2260 $uids = GeneralUtility::intExplode(',', $this->getBackendUserAuthentication()->getTSConfigVal('options.additionalPreviewLanguages'));
2261 foreach ($uids as $uid) {
2262 if ($sys_language_rec = BackendUtility::getRecord('sys_language', $uid)) {
2263 $this->cachedAdditionalPreviewLanguages[$uid] = array('uid' => $uid);
2264 if (!empty($sys_language_rec['language_isocode'])) {
2265 $this->cachedAdditionalPreviewLanguages[$uid]['ISOcode'] = $sys_language_rec['language_isocode'];
2266 } elseif ($sys_language_rec['static_lang_isocode'] && ExtensionManagementUtility::isLoaded('static_info_tables')) {
2267 GeneralUtility::deprecationLog('Usage of the field "static_lang_isocode" is discouraged, and will stop working with CMS 8. Use the built-in language field "language_isocode" in your sys_language records.');
2268 $staticLangRow = BackendUtility::getRecord('static_languages', $sys_language_rec['static_lang_isocode'], 'lg_iso_2');
2269 if ($staticLangRow['lg_iso_2']) {
2270 $this->cachedAdditionalPreviewLanguages[$uid]['uid'] = $uid;
2271 $this->cachedAdditionalPreviewLanguages[$uid]['ISOcode'] = $staticLangRow['lg_iso_2'];
2272 }
2273 }
2274 }
2275 }
2276 }
2277 }
2278 return $this->cachedAdditionalPreviewLanguages;
2279 }
2280
2281 /**
2282 * Push a new element to the dynNestedStack. Thus, every object know, if it's
2283 * nested in a tab or IRRE level and in which order this was processed.
2284 *
2285 * @param string $type Type of the level, e.g. "tab" or "inline
2286 * @param string $ident Identifier of the level
2287 * @return void
2288 */
2289 public function pushToDynNestedStack($type, $ident) {
2290 $this->dynNestedStack[] = array($type, $ident);
2291 }
2292
2293 /**
2294 * Remove an element from the dynNestedStack. If $type and $ident
2295 * are set, the last element will only be removed, if it matches
2296 * what is expected to be removed.
2297 *
2298 * @param string $type Type of the level, e.g. "tab" or "inline
2299 * @param string $ident Identifier of the level
2300 * @return void
2301 */
2302 public function popFromDynNestedStack($type = NULL, $ident = NULL) {
2303 if ($type != NULL && $ident != NULL) {
2304 $last = end($this->dynNestedStack);
2305 if ($type == $last[0] && $ident == $last[1]) {
2306 array_pop($this->dynNestedStack);
2307 }
2308 } else {
2309 array_pop($this->dynNestedStack);
2310 }
2311 }
2312
2313 /**
2314 * Get the dynNestedStack as associative array.
2315 * The result is e.g. ['tab','DTM-ABCD-1'], ['inline','data[13][table][uid][field]'], ['tab','DTM-DEFG-2'], ...
2316 *
2317 * @param bool $json Return a JSON string instead of an array - default: FALSE
2318 * @param bool $skipFirst Skip the first element in the dynNestedStack - default: FALSE
2319 * @return mixed Returns an associative array by default. If $json is TRUE, it will be returned as JSON string.
2320 */
2321 public function getDynNestedStack($json = FALSE, $skipFirst = FALSE) {
2322 $result = $this->dynNestedStack;
2323 if ($skipFirst) {
2324 array_shift($result);
2325 }
2326 return $json ? json_encode($result) : $result;
2327 }
2328
2329 /**
2330 * Takes care of registering properties in requiredFields and requiredElements.
2331 * The current hierarchy of IRRE and/or Tabs is stored. Thus, it is possible to determine,
2332 * which required field/element was filled incorrectly and show it, even if the Tab or IRRE
2333 * level is hidden.
2334 *
2335 * @param string $type Type of requirement ('field' or 'range')
2336 * @param string $name The name of the form field
2337 * @param mixed $value For type 'field' string, for type 'range' array
2338 * @return void
2339 */
2340 public function registerRequiredProperty($type, $name, $value) {
2341 if ($type == 'field' && is_string($value)) {
2342 $this->requiredFields[$name] = $value;
2343 // requiredFields have name/value swapped! For backward compatibility we keep this:
2344 $itemName = $value;
2345 } elseif ($type == 'range' && is_array($value)) {
2346 $this->requiredElements[$name] = $value;
2347 $itemName = $name;
2348 } else {
2349 $itemName = '';
2350 }
2351 // Set the situation of nesting for the current field:
2352 $this->registerNestedElement($itemName);
2353 }
2354
2355 /**
2356 * Sets the current situation of nested tabs and inline levels for a given element.
2357 *
2358 * @param string $itemName The element the nesting should be stored for
2359 * @param bool $setLevel Set the reverse level lookup - default: TRUE
2360 * @return void
2361 */
2362 protected function registerNestedElement($itemName, $setLevel = TRUE) {
2363 $dynNestedStack = $this->getDynNestedStack();
2364 if (count($dynNestedStack) && preg_match('/^(.+\\])\\[(\\w+)\\]$/', $itemName, $match)) {
2365 array_shift($match);
2366 $this->requiredNested[$itemName] = array(
2367 'parts' => $match,
2368 'level' => $dynNestedStack
2369 );
2370 }
2371 }
2372
2373 /**
2374 * Return the placeholder attribute for an input field.
2375 *
2376 * @param string $table
2377 * @param string $field
2378 * @param array $config
2379 * @param array $row
2380 * @return string
2381 */
2382 public function getPlaceholderAttribute($table, $field, array $config, array $row) {
2383 $value = $this->getPlaceholderValue($table, $field, $config, $row);
2384
2385 // Cleanup the string and support 'LLL:'
2386 $value = htmlspecialchars(trim($this->getLanguageService()->sL($value)));
2387 return empty($value) ? '' : ' placeholder="' . $value . '" ';
2388 }
2389
2390 /**
2391 * Determine and get the value for the placeholder for an input field.
2392 *
2393 * @param string $table
2394 * @param string $field
2395 * @param array $config
2396 * @param array $row
2397 * @return mixed
2398 */
2399 protected function getPlaceholderValue($table, $field, array $config, array $row) {
2400 $value = trim($config['placeholder']);
2401 if (!$value) {
2402 return '';
2403 }
2404 // Check if we have a reference to another field value from the current record
2405 if (substr($value, 0, 6) === '__row|') {
2406 /** @var FormDataTraverser $traverser */
2407 $traverseFields = GeneralUtility::trimExplode('|', substr($value, 6));
2408 $traverser = GeneralUtility::makeInstance(FormDataTraverser::class, $this);
2409 $value = $traverser->getTraversedFieldValue($traverseFields, $table, $row);
2410 }
2411
2412 return $value;
2413 }
2414
2415 /**
2416 * Insert additional style sheet link
2417 *
2418 * @param string $key Some key identifying the style sheet
2419 * @param string $href Uri to the style sheet file
2420 * @param string $title Value for the title attribute of the link element
2421 * @param string $relation Value for the rel attribute of the link element
2422 * @return void
2423 */
2424 public function addStyleSheet($key, $href, $title = '', $relation = 'stylesheet') {
2425 $this->getControllerDocumentTemplate()->addStyleSheet($key, $href, $title, $relation);
2426 }
2427
2428 /**
2429 * @return BackendUserAuthentication
2430 */
2431 protected function getBackendUserAuthentication() {
2432 return $GLOBALS['BE_USER'];
2433 }
2434
2435 /**
2436 * @return DocumentTemplate
2437 */
2438 protected function getControllerDocumentTemplate() {
2439 // $GLOBALS['SOBE'] might be any kind of PHP class (controller most of the times)
2440 // These class do not inherit from any common class, but they all seem to have a "doc" member
2441 return $GLOBALS['SOBE']->doc;
2442 }
2443
2444 /**
2445 * @return DatabaseConnection
2446 */
2447 protected function getDatabaseConnection() {
2448 return $GLOBALS['TYPO3_DB'];
2449 }
2450
2451 /**
2452 * @return LanguageService
2453 */
2454 protected function getLanguageService() {
2455 return $GLOBALS['LANG'];
2456 }
2457
2458 /**
2459 * @return DocumentTemplate
2460 */
2461 protected function getDocumentTemplate() {
2462 return $GLOBALS['TBE_TEMPLATE'];
2463 }
2464
2465
2466
2467
2468
2469
2470 /**
2471 * All properties and methods below are deprecated since TYPO3 CMS 7 and will be removed in TYPO3 CMS 8
2472 */
2473
2474
2475
2476 /**
2477 * @var array
2478 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2479 */
2480 public $printNeededJS = array();
2481
2482 /**
2483 * @var array
2484 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2485 */
2486 public $palFieldArr = array();
2487
2488 /**
2489 * @var bool
2490 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2491 */
2492 public $isPalettedoc = FALSE;
2493
2494 /**
2495 * @var int
2496 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2497 */
2498 public $paletteMargin = 1;
2499
2500 /**
2501 * @var string
2502 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2503 */
2504 public $defStyle = '';
2505
2506 /**
2507 * @var array
2508 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2509 */
2510 public $cachedTSconfig = array();
2511
2512 /**
2513 * @var array
2514 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2515 */
2516 public $cachedLanguageFlag = array();
2517
2518 /**
2519 * @var array
2520 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2521 */
2522 public $cachedTSconfig_fieldLevel = array();
2523
2524 /**
2525 * @var array
2526 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2527 */
2528 public $transformedRow = array();
2529
2530 /**
2531 * Set this to the 'backPath' pointing back to the typo3 admin directory
2532 * from the script where this form is displayed.
2533 *
2534 * @var string
2535 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2536 */
2537 public $backPath = '';
2538
2539 /**
2540 * If set, the RTE is disabled (from form display, eg. by checkbox in the bottom of the page!)
2541 *
2542 * @var bool
2543 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2544 */
2545 public $disableRTE = FALSE;
2546
2547 /**
2548 * If FALSE, then all CSH will be disabled
2549 *
2550 * @var bool
2551 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2552 */
2553 public $globalShowHelp = TRUE;
2554
2555 /**
2556 * If set to FALSE, palettes will NEVER be rendered.
2557 *
2558 * @var bool
2559 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2560 */
2561 public $doPrintPalette = TRUE;
2562
2563 /**
2564 * Enable click menu on reference icons.
2565 *
2566 * @var bool
2567 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2568 */
2569 public $enableClickMenu = FALSE;
2570
2571 /**
2572 * @var bool
2573 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2574 */
2575 public $enableTabMenu = FALSE;
2576
2577 /**
2578 * Form field width compensation: Factor of "size=12" to "style="width: 12*12px"
2579 * for form field widths of style-aware browsers
2580 *
2581 * @var float
2582 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2583 */
2584 public $form_rowsToStylewidth = 12;
2585
2586 /**
2587 * Value that gets added for style="width: ...px" for textareas compared to input fields.
2588 *
2589 * @var int
2590 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2591 */
2592 protected $form_additionalTextareaStyleWidth = 23;
2593
2594 /**
2595 * Form field width compensation: Compensation for large documents, doc-tab (editing)
2596 *
2597 * @var float
2598 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2599 */
2600 public $form_largeComp = 1.33;
2601
2602 /**
2603 * The number of chars expected per row when the height of a text area field is
2604 * automatically calculated based on the number of characters found in the field content.
2605 *
2606 * @var int
2607 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2608 */
2609 public $charsPerRow = 40;
2610
2611 /**
2612 * The maximum abstract value for textareas
2613 *
2614 * @var int
2615 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2616 */
2617 public $maxTextareaWidth = 48;
2618
2619 /**
2620 * The default abstract value for input and textarea elements
2621 *
2622 * @var int
2623 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2624 */
2625 public $defaultInputWidth = 30;
2626
2627 /**
2628 * The minimum abstract value for input and textarea elements
2629 *
2630 * @var int
2631 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2632 */
2633 public $minimumInputWidth = 10;
2634
2635 /**
2636 * The maximum abstract value for input and textarea elements
2637 *
2638 * @var int
2639 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2640 */
2641 public $maxInputWidth = 50;
2642
2643 /**
2644 * Default style for the selector boxes used for multiple items in "select" and "group" types.
2645 *
2646 * @var string
2647 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2648 */
2649 public $defaultMultipleSelectorStyle = '';
2650
2651 /**
2652 * The name attribute of the form
2653 *
2654 * @var string
2655 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2656 */
2657 public $formName = 'editform';
2658
2659 /**
2660 * Used to indicate the mode of CSH (Context Sensitive Help),
2661 * whether it should be icons-only ('icon') or not at all (blank).
2662 *
2663 * @var bool
2664 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2665 */
2666 public $edit_showFieldHelp = FALSE;
2667
2668 /**
2669 * @var bool
2670 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2671 */
2672 public $edit_docModuleUpload = FALSE;
2673
2674 /**
2675 * Loaded with info about the browser when class is instantiated
2676 *
2677 * @var array
2678 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2679 */
2680 public $clientInfo = array();
2681
2682 /**
2683 * TRUE, if RTE is possible for the current user (based on result from BE_USER->isRTE())
2684 *
2685 * @var bool
2686 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2687 */
2688 public $RTEenabled = FALSE;
2689
2690 /**
2691 * If $this->RTEenabled was FALSE, you can find the reasons listed in this array
2692 * which is filled with reasons why the RTE could not be loaded)
2693 *
2694 * @var string
2695 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2696 */
2697 public $RTEenabled_notReasons = '';
2698
2699 /**
2700 * Contains current color scheme
2701 *
2702 * @var array
2703 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2704 */
2705 public $colorScheme = array();
2706
2707 /**
2708 * Contains current class scheme
2709 *
2710 * @var array
2711 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2712 */
2713 public $classScheme = array();
2714
2715 /**
2716 * Contains the default color scheme
2717 *
2718 * @var array
2719 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2720 */
2721 public $defColorScheme = array();
2722
2723 /**
2724 * Contains the default class scheme
2725 *
2726 * @var array
2727 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2728 */
2729 public $defClassScheme = array();
2730
2731 /**
2732 * Contains field style values
2733 *
2734 * @var array|NULL
2735 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2736 */
2737 public $fieldStyle = NULL;
2738
2739 /**
2740 * Contains border style values
2741 *
2742 * @var array|NULL
2743 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2744 */
2745 public $borderStyle = NULL;
2746
2747 /**
2748 * An accumulation of messages from the class
2749 *
2750 * @var array
2751 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
2752 */
2753 public $commentMessages = array();
2754
2755 /**
2756 * Generation of TCEform elements of the type "input"
2757 * This will render a single-line input form field, possibly with various control/validation features
2758 *
2759 * @param string $table The table name of the record
2760 * @param string $field The field name which this element is supposed to edit
2761 * @param array $row The record data array where the value(s) for the field can be found
2762 * @param array $PA An array with additional configuration options.
2763 * @return string The HTML code for the TCEform field
2764 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\InputElement
2765 */
2766 public function getSingleField_typeInput($table, $field, $row, &$PA) {
2767 GeneralUtility::logDeprecatedFunction();
2768 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\InputElement::class, $this)
2769 ->render($table, $field, $row, $PA);
2770 }
2771
2772 /**
2773 * Generation of TCEform elements of the type "text"
2774 * This will render a <textarea> OR RTE area form field, possibly with various control/validation features
2775 *
2776 * @param string $table The table name of the record
2777 * @param string $field The field name which this element is supposed to edit
2778 * @param array $row The record data array where the value(s) for the field can be found
2779 * @param array $PA An array with additional configuration options.
2780 * @return string The HTML code for the TCEform field
2781 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\TextElement
2782 */
2783 public function getSingleField_typeText($table, $field, $row, &$PA) {
2784 GeneralUtility::logDeprecatedFunction();
2785 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\TextElement::class, $this)
2786 ->setGlobalOptions($this->getConfigurationOptionsForChildElements())
2787 ->render($table, $field, $row, $PA);
2788 }
2789
2790 /**
2791 * Generation of TCEform elements of the type "check"
2792 * This will render a check-box OR an array of checkboxes
2793 *
2794 * @param string $table The table name of the record
2795 * @param string $field The field name which this element is supposed to edit
2796 * @param array $row The record data array where the value(s) for the field can be found
2797 * @param array $PA An array with additional configuration options.
2798 * @return string The HTML code for the TCEform field
2799 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\CheckboxElement
2800 */
2801 public function getSingleField_typeCheck($table, $field, $row, &$PA) {
2802 GeneralUtility::logDeprecatedFunction();
2803 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\CheckboxElement::class, $this)
2804 ->setGlobalOptions($this->getConfigurationOptionsForChildElements())
2805 ->render($table, $field, $row, $PA);
2806 }
2807
2808 /**
2809 * Generation of TCEform elements of the type "radio"
2810 * This will render a series of radio buttons.
2811 *
2812 * @param string $table The table name of the record
2813 * @param string $field The field name which this element is supposed to edit
2814 * @param array $row The record data array where the value(s) for the field can be found
2815 * @param array $PA An array with additional configuration options.
2816 * @return string The HTML code for the TCEform field
2817 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\RadioElement
2818 */
2819 public function getSingleField_typeRadio($table, $field, $row, &$PA) {
2820 GeneralUtility::logDeprecatedFunction();
2821 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\RadioElement::class, $this)
2822 ->setGlobalOptions($this->getConfigurationOptionsForChildElements())
2823 ->render($table, $field, $row, $PA);
2824 }
2825
2826 /**
2827 * Generation of TCEform elements of the type "select"
2828 * This will render a selector box element, or possibly a special construction with two selector boxes.
2829 * That depends on configuration.
2830 *
2831 * @param string $table The table name of the record
2832 * @param string $field The field name which this element is supposed to edit
2833 * @param array $row The record data array where the value(s) for the field can be found
2834 * @param array $PA An array with additional configuration options.
2835 * @return string The HTML code for the TCEform field
2836 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\SelectElement
2837 */
2838 public function getSingleField_typeSelect($table, $field, $row, &$PA) {
2839 GeneralUtility::logDeprecatedFunction();
2840 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\SelectElement::class, $this)
2841 ->setGlobalOptions($this->getConfigurationOptionsForChildElements())
2842 ->render($table, $field, $row, $PA);
2843 }
2844
2845 /**
2846 * Generation of TCEform elements of the type "group"
2847 * This will render a selectorbox into which elements from either the file system or database can be inserted. Relations.
2848 *
2849 * @param string $table The table name of the record
2850 * @param string $field The field name which this element is supposed to edit
2851 * @param array $row The record data array where the value(s) for the field can be found
2852 * @param array $PA An array with additional configuration options.
2853 * @return string The HTML code for the TCEform field
2854 * @deprecated since 7.0 - will be removed two versions later; Use \TYPO3\CMS\Backend\Form\Element\GroupElement
2855 */
2856 public function getSingleField_typeGroup($table, $field, $row, &$PA) {
2857 GeneralUtility::logDeprecatedFunction();
2858 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\GroupElement::class, $this)
2859 ->setGlobalOptions($this->getConfigurationOptionsForChildElements())
2860 ->render($table, $field, $row, $PA);
2861 }
2862
2863 /**
2864 * Generation of TCEform elements of the type "none"
2865 * This will render a non-editable display of the content of the field.
2866 *
2867 * @param string $table The table name of the record
2868 * @param string $field The field name which this element is supposed to edit
2869 * @param array $row The record data array where the value(s) for the field can be found
2870 * @param array $PA An array with additional configuration options.
2871 * @return string The HTML code for the TCEform field
2872 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\NoneElement
2873 */
2874 public function getSingleField_typeNone($table, $field, $row, &$PA) {
2875 GeneralUtility::logDeprecatedFunction();
2876 return $item = GeneralUtility::makeInstance(NoneElement::class, $this)
2877 ->render($table, $field, $row, $PA);
2878 }
2879
2880 /**
2881 * HTML rendering of a value which is not editable.
2882 *
2883 * @param array $config Configuration for the display
2884 * @param string $itemValue The value to display
2885 * @return string The HTML code for the display
2886 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\NoneElement
2887 */
2888 public function getSingleField_typeNone_render($config, $itemValue) {
2889 GeneralUtility::logDeprecatedFunction();
2890 $noneElement = GeneralUtility::makeInstance(NoneElement::class, $this);
2891 $elementConfiguration = array(
2892 'fieldConf' => array(
2893 'config' => $config,
2894 ),
2895 'itemFormElValue' => $itemValue,
2896 );
2897 return $noneElement->render('', '', '', $elementConfiguration);
2898 }
2899
2900 /**
2901 * Handler for Flex Forms
2902 *
2903 * @param string $table The table name of the record
2904 * @param string $field The field name which this element is supposed to edit
2905 * @param array $row The record data array where the value(s) for the field can be found
2906 * @param array $PA An array with additional configuration options.
2907 * @return string The HTML code for the TCEform field
2908 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\FlexElement
2909 */
2910 public function getSingleField_typeFlex($table, $field, $row, &$PA) {
2911 GeneralUtility::logDeprecatedFunction();
2912 return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\FlexElement::class, $this)
2913 ->setGlobalOptions($this->getConfigurationOptionsForChildElements())
2914 ->render($table, $field, $row, $PA);
2915 }
2916
2917 /**