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