TYPO3 CMS  TYPO3_7-6
BackendUtility.php
Go to the documentation of this file.
1 <?php
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 
44 
54 {
61  protected static $tcaTableTypeConfigurationCache = [];
62 
63  /*******************************************
64  *
65  * SQL-related, selecting records, searching
66  *
67  *******************************************/
82  public static function deleteClause($table, $tableAlias = '')
83  {
84  if (!empty($GLOBALS['TCA'][$table]['ctrl']['delete'])) {
85  return ' AND ' . ($tableAlias ?: $table) . '.' . $GLOBALS['TCA'][$table]['ctrl']['delete'] . '=0';
86  } else {
87  return '';
88  }
89  }
90 
105  public static function getRecord($table, $uid, $fields = '*', $where = '', $useDeleteClause = true)
106  {
107  // Ensure we have a valid uid (not 0 and not NEWxxxx) and a valid TCA
108  if ((int)$uid && !empty($GLOBALS['TCA'][$table])) {
109  $where = 'uid=' . (int)$uid . ($useDeleteClause ? self::deleteClause($table) : '') . $where;
110  $row = static::getDatabaseConnection()->exec_SELECTgetSingleRow($fields, $table, $where);
111  if ($row) {
112  return $row;
113  }
114  }
115  return null;
116  }
117 
129  public static function getRecordWSOL($table, $uid, $fields = '*', $where = '', $useDeleteClause = true, $unsetMovePointers = false)
130  {
131  if ($fields !== '*') {
132  $internalFields = GeneralUtility::uniqueList($fields . ',uid,pid');
133  $row = self::getRecord($table, $uid, $internalFields, $where, $useDeleteClause);
134  self::workspaceOL($table, $row, -99, $unsetMovePointers);
135  if (is_array($row)) {
136  foreach ($row as $key => $_) {
137  if (!GeneralUtility::inList($fields, $key) && $key[0] !== '_') {
138  unset($row[$key]);
139  }
140  }
141  }
142  } else {
143  $row = self::getRecord($table, $uid, $fields, $where, $useDeleteClause);
144  self::workspaceOL($table, $row, -99, $unsetMovePointers);
145  }
146  return $row;
147  }
148 
161  public static function getRecordRaw($table, $where = '', $fields = '*')
162  {
163  $row = false;
164  $db = static::getDatabaseConnection();
165  if (false !== ($res = $db->exec_SELECTquery($fields, $table, $where, '', '', '1'))) {
166  $row = $db->sql_fetch_assoc($res);
167  $db->sql_free_result($res);
168  }
169  return $row;
170  }
171 
187  public static function getRecordsByField($theTable, $theField, $theValue, $whereClause = '', $groupBy = '', $orderBy = '', $limit = '', $useDeleteClause = true)
188  {
189  if (is_array($GLOBALS['TCA'][$theTable])) {
190  $db = static::getDatabaseConnection();
191  $res = $db->exec_SELECTquery(
192  '*',
193  $theTable,
194  $theField . '=' . $db->fullQuoteStr($theValue, $theTable) .
195  ($useDeleteClause ? self::deleteClause($theTable) . ' ' : '') .
196  self::versioningPlaceholderClause($theTable) . ' ' .
197  $whereClause,
198  $groupBy,
199  $orderBy,
200  $limit
201  );
202  $rows = [];
203  while ($row = $db->sql_fetch_assoc($res)) {
204  $rows[] = $row;
205  }
206  $db->sql_free_result($res);
207  if (!empty($rows)) {
208  return $rows;
209  }
210  }
211  return null;
212  }
213 
221  public static function splitTable_Uid($str)
222  {
223  list($uid, $table) = explode('_', strrev($str), 2);
224  return [strrev($table), strrev($uid)];
225  }
226 
236  public static function getSQLselectableList($in_list, $tablename, $default_tablename)
237  {
238  $list = [];
239  if ((string)trim($in_list) != '') {
240  $tempItemArray = explode(',', trim($in_list));
241  foreach ($tempItemArray as $key => $val) {
242  $val = strrev($val);
243  $parts = explode('_', $val, 2);
244  if ((string)trim($parts[0]) != '') {
245  $theID = (int)strrev($parts[0]);
246  $theTable = trim($parts[1]) ? strrev(trim($parts[1])) : $default_tablename;
247  if ($theTable == $tablename) {
248  $list[] = $theID;
249  }
250  }
251  }
252  }
253  return implode(',', $list);
254  }
255 
266  public static function BEenableFields($table, $inv = false)
267  {
268  $ctrl = $GLOBALS['TCA'][$table]['ctrl'];
269  $query = [];
270  $invQuery = [];
271  if (is_array($ctrl)) {
272  if (is_array($ctrl['enablecolumns'])) {
273  if ($ctrl['enablecolumns']['disabled']) {
274  $field = $table . '.' . $ctrl['enablecolumns']['disabled'];
275  $query[] = $field . '=0';
276  $invQuery[] = $field . '<>0';
277  }
278  if ($ctrl['enablecolumns']['starttime']) {
279  $field = $table . '.' . $ctrl['enablecolumns']['starttime'];
280  $query[] = '(' . $field . '<=' . $GLOBALS['SIM_ACCESS_TIME'] . ')';
281  $invQuery[] = '(' . $field . '<>0 AND ' . $field . '>' . $GLOBALS['SIM_ACCESS_TIME'] . ')';
282  }
283  if ($ctrl['enablecolumns']['endtime']) {
284  $field = $table . '.' . $ctrl['enablecolumns']['endtime'];
285  $query[] = '(' . $field . '=0 OR ' . $field . '>' . $GLOBALS['SIM_ACCESS_TIME'] . ')';
286  $invQuery[] = '(' . $field . '<>0 AND ' . $field . '<=' . $GLOBALS['SIM_ACCESS_TIME'] . ')';
287  }
288  }
289  }
290  $outQ = $inv ? '(' . implode(' OR ', $invQuery) . ')' : implode(' AND ', $query);
291  return $outQ ? ' AND ' . $outQ : '';
292  }
293 
303  public static function getRecordLocalization($table, $uid, $language, $andWhereClause = '')
304  {
305  $recordLocalization = false;
306 
307  // Check if translations are stored in other table
308  if (isset($GLOBALS['TCA'][$table]['ctrl']['transForeignTable'])) {
309  $table = $GLOBALS['TCA'][$table]['ctrl']['transForeignTable'];
310  }
311 
312  if (self::isTableLocalizable($table)) {
313  $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl'];
314  $recordLocalization = self::getRecordsByField($table, $tcaCtrl['transOrigPointerField'], $uid, 'AND ' . $tcaCtrl['languageField'] . '=' . (int)$language . ($andWhereClause ? ' ' . $andWhereClause : ''), '', '', '1');
315  }
316  return $recordLocalization;
317  }
318 
319  /*******************************************
320  *
321  * Page tree, TCA related
322  *
323  *******************************************/
334  public static function BEgetRootLine($uid, $clause = '', $workspaceOL = false)
335  {
336  static $BEgetRootLine_cache = [];
337  $output = [];
338  $pid = $uid;
339  $ident = $pid . '-' . $clause . '-' . $workspaceOL;
340  if (is_array($BEgetRootLine_cache[$ident])) {
341  $output = $BEgetRootLine_cache[$ident];
342  } else {
343  $loopCheck = 100;
344  $theRowArray = [];
345  while ($uid != 0 && $loopCheck) {
346  $loopCheck--;
347  $row = self::getPageForRootline($uid, $clause, $workspaceOL);
348  if (is_array($row)) {
349  $uid = $row['pid'];
350  $theRowArray[] = $row;
351  } else {
352  break;
353  }
354  }
355  if ($uid == 0) {
356  $theRowArray[] = ['uid' => 0, 'title' => ''];
357  }
358  $c = count($theRowArray);
359  foreach ($theRowArray as $val) {
360  $c--;
361  $output[$c] = [
362  'uid' => $val['uid'],
363  'pid' => $val['pid'],
364  'title' => $val['title'],
365  'doktype' => $val['doktype'],
366  'tsconfig_includes' => $val['tsconfig_includes'],
367  'TSconfig' => $val['TSconfig'],
368  'is_siteroot' => $val['is_siteroot'],
369  't3ver_oid' => $val['t3ver_oid'],
370  't3ver_wsid' => $val['t3ver_wsid'],
371  't3ver_state' => $val['t3ver_state'],
372  't3ver_stage' => $val['t3ver_stage'],
373  'backend_layout_next_level' => $val['backend_layout_next_level']
374  ];
375  if (isset($val['_ORIG_pid'])) {
376  $output[$c]['_ORIG_pid'] = $val['_ORIG_pid'];
377  }
378  }
379  $BEgetRootLine_cache[$ident] = $output;
380  }
381  return $output;
382  }
383 
393  protected static function getPageForRootline($uid, $clause, $workspaceOL)
394  {
395  static $getPageForRootline_cache = [];
396  $ident = $uid . '-' . $clause . '-' . $workspaceOL;
397  if (is_array($getPageForRootline_cache[$ident])) {
398  $row = $getPageForRootline_cache[$ident];
399  } else {
400  $db = static::getDatabaseConnection();
401  $res = $db->exec_SELECTquery('pid,uid,title,doktype,tsconfig_includes,TSconfig,is_siteroot,t3ver_oid,t3ver_wsid,t3ver_state,t3ver_stage,backend_layout_next_level', 'pages', 'uid=' . (int)$uid . ' ' . self::deleteClause('pages') . ' ' . $clause);
402  $row = $db->sql_fetch_assoc($res);
403  if ($row) {
404  $newLocation = false;
405  if ($workspaceOL) {
406  self::workspaceOL('pages', $row);
407  $newLocation = self::getMovePlaceholder('pages', $row['uid'], 'pid');
408  }
409  if (is_array($row)) {
410  if ($newLocation !== false) {
411  $row['pid'] = $newLocation['pid'];
412  } else {
413  self::fixVersioningPid('pages', $row);
414  }
415  $getPageForRootline_cache[$ident] = $row;
416  }
417  }
418  $db->sql_free_result($res);
419  }
420  return $row;
421  }
422 
430  public static function openPageTree($pid, $clearExpansion)
431  {
432  $beUser = static::getBackendUserAuthentication();
433  // Get current expansion data:
434  if ($clearExpansion) {
435  $expandedPages = [];
436  } else {
437  $expandedPages = unserialize($beUser->uc['browseTrees']['browsePages']);
438  }
439  // Get rootline:
440  $rL = self::BEgetRootLine($pid);
441  // First, find out what mount index to use (if more than one DB mount exists):
442  $mountIndex = 0;
443  $mountKeys = array_flip($beUser->returnWebmounts());
444  foreach ($rL as $rLDat) {
445  if (isset($mountKeys[$rLDat['uid']])) {
446  $mountIndex = $mountKeys[$rLDat['uid']];
447  break;
448  }
449  }
450  // Traverse rootline and open paths:
451  foreach ($rL as $rLDat) {
452  $expandedPages[$mountIndex][$rLDat['uid']] = 1;
453  }
454  // Write back:
455  $beUser->uc['browseTrees']['browsePages'] = serialize($expandedPages);
456  $beUser->writeUC();
457  }
458 
470  public static function getRecordPath($uid, $clause, $titleLimit, $fullTitleLimit = 0)
471  {
472  if (!$titleLimit) {
473  $titleLimit = 1000;
474  }
475  $output = $fullOutput = '/';
476  $clause = trim($clause);
477  if ($clause !== '' && substr($clause, 0, 3) !== 'AND') {
478  $clause = 'AND ' . $clause;
479  }
480  $data = self::BEgetRootLine($uid, $clause);
481  foreach ($data as $record) {
482  if ($record['uid'] === 0) {
483  continue;
484  }
485  $output = '/' . GeneralUtility::fixed_lgd_cs(strip_tags($record['title']), $titleLimit) . $output;
486  if ($fullTitleLimit) {
487  $fullOutput = '/' . GeneralUtility::fixed_lgd_cs(strip_tags($record['title']), $fullTitleLimit) . $fullOutput;
488  }
489  }
490  if ($fullTitleLimit) {
491  return [$output, $fullOutput];
492  } else {
493  return $output;
494  }
495  }
496 
504  public static function getExcludeFields()
505  {
507  $finalExcludeArray = [];
508 
509  // Fetch translations for table names
510  $tableToTranslation = [];
511  $lang = static::getLanguageService();
512  // All TCA keys
513  foreach ($GLOBALS['TCA'] as $table => $conf) {
514  $tableToTranslation[$table] = $lang->sl($conf['ctrl']['title']);
515  }
516  // Sort by translations
517  asort($tableToTranslation);
518  foreach ($tableToTranslation as $table => $translatedTable) {
519  $excludeArrayTable = [];
520 
521  // All field names configured and not restricted to admins
522  if (is_array($GLOBALS['TCA'][$table]['columns'])
523  && empty($GLOBALS['TCA'][$table]['ctrl']['adminOnly'])
524  && (empty($GLOBALS['TCA'][$table]['ctrl']['rootLevel']) || !empty($GLOBALS['TCA'][$table]['ctrl']['security']['ignoreRootLevelRestriction']))
525  ) {
526  foreach ($GLOBALS['TCA'][$table]['columns'] as $field => $_) {
527  if ($GLOBALS['TCA'][$table]['columns'][$field]['exclude']) {
528  // Get human readable names of fields
529  $translatedField = $lang->sl($GLOBALS['TCA'][$table]['columns'][$field]['label']);
530  // Add entry
531  $excludeArrayTable[] = [$translatedTable . ': ' . $translatedField, $table . ':' . $field];
532  }
533  }
534  }
535  // All FlexForm fields
536  $flexFormArray = static::getRegisteredFlexForms($table);
537  foreach ($flexFormArray as $tableField => $flexForms) {
538  // Prefix for field label, e.g. "Plugin Options:"
539  $labelPrefix = '';
540  if (!empty($GLOBALS['TCA'][$table]['columns'][$tableField]['label'])) {
541  $labelPrefix = $lang->sl($GLOBALS['TCA'][$table]['columns'][$tableField]['label']);
542  }
543  // Get all sheets and title
544  foreach ($flexForms as $extIdent => $extConf) {
545  $extTitle = $lang->sl($extConf['title']);
546  // Get all fields in sheet
547  foreach ($extConf['ds']['sheets'] as $sheetName => $sheet) {
548  if (empty($sheet['ROOT']['el']) || !is_array($sheet['ROOT']['el'])) {
549  continue;
550  }
551  foreach ($sheet['ROOT']['el'] as $fieldName => $field) {
552  // Use only fields that have exclude flag set
553  if (empty($field['TCEforms']['exclude'])) {
554  continue;
555  }
556  $fieldLabel = !empty($field['TCEforms']['label']) ? $lang->sl($field['TCEforms']['label']) : $fieldName;
557  $fieldIdent = $table . ':' . $tableField . ';' . $extIdent . ';' . $sheetName . ';' . $fieldName;
558  $excludeArrayTable[] = [trim($labelPrefix . ' ' . $extTitle, ': ') . ': ' . $fieldLabel, $fieldIdent];
559  }
560  }
561  }
562  }
563  // Sort fields by the translated value
564  if (!empty($excludeArrayTable)) {
565  usort($excludeArrayTable, function (array $array1, array $array2) {
566  $array1 = reset($array1);
567  $array2 = reset($array2);
568  if (is_string($array1) && is_string($array2)) {
569  return strcasecmp($array1, $array2);
570  }
571  return 0;
572  });
573  $finalExcludeArray = array_merge($finalExcludeArray, $excludeArrayTable);
574  }
575  }
576 
577  return $finalExcludeArray;
578  }
579 
587  public static function getExplicitAuthFieldValues()
588  {
590  // Initialize:
591  $lang = static::getLanguageService();
592  $adLabel = [
593  'ALLOW' => $lang->sl('LLL:EXT:lang/locallang_core.xlf:labels.allow'),
594  'DENY' => $lang->sl('LLL:EXT:lang/locallang_core.xlf:labels.deny')
595  ];
596  // All TCA keys:
597  $allowDenyOptions = [];
598  foreach ($GLOBALS['TCA'] as $table => $_) {
599  // All field names configured:
600  if (is_array($GLOBALS['TCA'][$table]['columns'])) {
601  foreach ($GLOBALS['TCA'][$table]['columns'] as $field => $_) {
602  $fCfg = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
603  if ($fCfg['type'] == 'select' && $fCfg['authMode']) {
604  // Check for items:
605  if (is_array($fCfg['items'])) {
606  // Get Human Readable names of fields and table:
607  $allowDenyOptions[$table . ':' . $field]['tableFieldLabel'] =
608  $lang->sl($GLOBALS['TCA'][$table]['ctrl']['title']) . ': '
609  . $lang->sl($GLOBALS['TCA'][$table]['columns'][$field]['label']);
610  // Check for items:
611  foreach ($fCfg['items'] as $iVal) {
612  // Values '' is not controlled by this setting.
613  if ((string)$iVal[1] !== '') {
614  // Find iMode
615  $iMode = '';
616  switch ((string)$fCfg['authMode']) {
617  case 'explicitAllow':
618  $iMode = 'ALLOW';
619  break;
620  case 'explicitDeny':
621  $iMode = 'DENY';
622  break;
623  case 'individual':
624  if ($iVal[4] === 'EXPL_ALLOW') {
625  $iMode = 'ALLOW';
626  } elseif ($iVal[4] === 'EXPL_DENY') {
627  $iMode = 'DENY';
628  }
629  break;
630  }
631  // Set iMode
632  if ($iMode) {
633  $allowDenyOptions[$table . ':' . $field]['items'][$iVal[1]] = [$iMode, $lang->sl($iVal[0]), $adLabel[$iMode]];
634  }
635  }
636  }
637  }
638  }
639  }
640  }
641  }
642  return $allowDenyOptions;
643  }
644 
655  public static function getSystemLanguages()
656  {
659  $translationConfigurationProvider = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider::class);
660  $languages = $translationConfigurationProvider->getSystemLanguages();
661  $sysLanguages = [];
662  foreach ($languages as $language) {
663  if ($language['uid'] !== -1) {
664  $sysLanguages[] = [
665  0 => htmlspecialchars($language['title']) . ' [' . $language['uid'] . ']',
666  1 => $language['uid'],
667  2 => $language['flagIcon']
668  ];
669  }
670  }
671  return $sysLanguages;
672  }
673 
681  public static function getOriginalTranslationTable($table)
682  {
683  if (!empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable'])) {
684  $table = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable'];
685  }
686 
687  return $table;
688  }
689 
696  public static function isTableLocalizable($table)
697  {
698  $isLocalizable = false;
699  if (isset($GLOBALS['TCA'][$table]['ctrl']) && is_array($GLOBALS['TCA'][$table]['ctrl'])) {
700  $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl'];
701  $isLocalizable = isset($tcaCtrl['languageField']) && $tcaCtrl['languageField'] && isset($tcaCtrl['transOrigPointerField']) && $tcaCtrl['transOrigPointerField'];
702  }
703  return $isLocalizable;
704  }
705 
715  public static function getInlineLocalizationMode($table, $fieldOrConfig)
716  {
717  $localizationMode = false;
718  $config = null;
719  if (is_array($fieldOrConfig) && !empty($fieldOrConfig)) {
720  $config = $fieldOrConfig;
721  } elseif (is_string($fieldOrConfig) && isset($GLOBALS['TCA'][$table]['columns'][$fieldOrConfig]['config'])) {
722  $config = $GLOBALS['TCA'][$table]['columns'][$fieldOrConfig]['config'];
723  }
724  if (is_array($config) && isset($config['type']) && $config['type'] === 'inline' && self::isTableLocalizable($table)) {
725  $localizationMode = isset($config['behaviour']['localizationMode']) && $config['behaviour']['localizationMode']
726  ? $config['behaviour']['localizationMode']
727  : 'select';
728  // The mode 'select' is not possible when child table is not localizable at all:
729  if ($localizationMode === 'select' && !self::isTableLocalizable($config['foreign_table'])) {
730  $localizationMode = false;
731  }
732  }
733  return $localizationMode;
734  }
735 
745  public static function readPageAccess($id, $perms_clause)
746  {
747  if ((string)$id !== '') {
748  $id = (int)$id;
749  if (!$id) {
750  if (static::getBackendUserAuthentication()->isAdmin()) {
751  $path = '/';
752  $pageinfo['_thePath'] = $path;
753  return $pageinfo;
754  }
755  } else {
756  $pageinfo = self::getRecord('pages', $id, '*', $perms_clause ? ' AND ' . $perms_clause : '');
757  if ($pageinfo['uid'] && static::getBackendUserAuthentication()->isInWebMount($id, $perms_clause)) {
758  self::workspaceOL('pages', $pageinfo);
759  if (is_array($pageinfo)) {
760  self::fixVersioningPid('pages', $pageinfo);
761  list($pageinfo['_thePath'], $pageinfo['_thePathFull']) = self::getRecordPath((int)$pageinfo['uid'], $perms_clause, 15, 1000);
762  return $pageinfo;
763  }
764  }
765  }
766  }
767  return false;
768  }
769 
778  public static function getTCAtypes($table, $rec, $useFieldNameAsKey = false)
779  {
780  if ($GLOBALS['TCA'][$table]) {
781  // Get type value:
782  $fieldValue = self::getTCAtypeValue($table, $rec);
783  $cacheIdentifier = $table . '-type-' . $fieldValue . '-fnk-' . $useFieldNameAsKey;
784 
785  // Fetch from first-level-cache if available
786  if (isset(self::$tcaTableTypeConfigurationCache[$cacheIdentifier])) {
787  return self::$tcaTableTypeConfigurationCache[$cacheIdentifier];
788  }
789 
790  // Get typesConf
791  $typesConf = $GLOBALS['TCA'][$table]['types'][$fieldValue];
792  // Get fields list and traverse it
793  $fieldList = explode(',', $typesConf['showitem']);
794 
795  // Add subtype fields e.g. for a valid RTE transformation
796  // The RTE runs the DB -> RTE transformation only, if the RTE field is part of the getTCAtypes array
797  if (isset($typesConf['subtype_value_field'])) {
798  $subType = $rec[$typesConf['subtype_value_field']];
799  if (isset($typesConf['subtypes_addlist'][$subType])) {
800  $subFields = GeneralUtility::trimExplode(',', $typesConf['subtypes_addlist'][$subType], true);
801  $fieldList = array_merge($fieldList, $subFields);
802  }
803  }
804 
805  // Add palette fields e.g. for a valid RTE transformation
806  $paletteFieldList = [];
807  foreach ($fieldList as $fieldData) {
808  list($pFieldName, $pAltTitle, $pPalette) = GeneralUtility::trimExplode(';', $fieldData);
809  if ($pPalette
810  && isset($GLOBALS['TCA'][$table]['palettes'][$pPalette])
811  && is_array($GLOBALS['TCA'][$table]['palettes'][$pPalette])
812  && isset($GLOBALS['TCA'][$table]['palettes'][$pPalette]['showitem'])
813  ) {
814  $paletteFields = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['palettes'][$pPalette]['showitem'], true);
815  foreach ($paletteFields as $paletteField) {
816  if ($paletteField !== '--linebreak--') {
817  $paletteFieldList[] = $paletteField;
818  }
819  }
820  }
821  }
822  $fieldList = array_merge($fieldList, $paletteFieldList);
823 
824  $altFieldList = [];
825  // Traverse fields in types config and parse the configuration into a nice array:
826  foreach ($fieldList as $k => $v) {
827  list($pFieldName, $pAltTitle, $pPalette) = GeneralUtility::trimExplode(';', $v);
828  $defaultExtras = '';
829  if (!empty($typesConf['columnsOverrides'][$pFieldName]['defaultExtras'])) {
830  // Use defaultExtras from columnsOverrides if given
831  $defaultExtras = $typesConf['columnsOverrides'][$pFieldName]['defaultExtras'];
832  } elseif (!empty($GLOBALS['TCA'][$table]['columns'][$pFieldName]['defaultExtras'])) {
833  // Use defaultExtras from columns if given
834  $defaultExtras = $GLOBALS['TCA'][$table]['columns'][$pFieldName]['defaultExtras'];
835  }
836  $specConfParts = self::getSpecConfParts($defaultExtras);
837  $fieldList[$k] = [
838  'field' => $pFieldName,
839  'title' => $pAltTitle,
840  'palette' => $pPalette,
841  'spec' => $specConfParts,
842  'origString' => $v
843  ];
844  if ($useFieldNameAsKey) {
845  $altFieldList[$fieldList[$k]['field']] = $fieldList[$k];
846  }
847  }
848  if ($useFieldNameAsKey) {
849  $fieldList = $altFieldList;
850  }
851 
852  // Add to first-level-cache
853  self::$tcaTableTypeConfigurationCache[$cacheIdentifier] = $fieldList;
854 
855  // Return array:
856  return $fieldList;
857  }
858  return null;
859  }
860 
878  public static function getTCAtypeValue($table, $row)
879  {
880  $typeNum = 0;
881  if ($GLOBALS['TCA'][$table]) {
882  $field = $GLOBALS['TCA'][$table]['ctrl']['type'];
883  if (strpos($field, ':') !== false) {
884  list($pointerField, $foreignTableTypeField) = explode(':', $field);
885  // Get field value from database if field is not in the $row array
886  if (!isset($row[$pointerField])) {
887  $localRow = self::getRecord($table, $row['uid'], $pointerField);
888  $foreignUid = $localRow[$pointerField];
889  } else {
890  $foreignUid = $row[$pointerField];
891  }
892  if ($foreignUid) {
893  $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$pointerField]['config'];
894  $relationType = $fieldConfig['type'];
895  if ($relationType === 'select') {
896  $foreignTable = $fieldConfig['foreign_table'];
897  } elseif ($relationType === 'group') {
898  $allowedTables = explode(',', $fieldConfig['allowed']);
899  $foreignTable = $allowedTables[0];
900  } else {
901  throw new \RuntimeException('TCA foreign field pointer fields are only allowed to be used with group or select field types.', 1325862240);
902  }
903  $foreignRow = self::getRecord($foreignTable, $foreignUid, $foreignTableTypeField);
904  if ($foreignRow[$foreignTableTypeField]) {
905  $typeNum = $foreignRow[$foreignTableTypeField];
906  }
907  }
908  } else {
909  $typeNum = $row[$field];
910  }
911  // If that value is an empty string, set it to "0" (zero)
912  if (empty($typeNum)) {
913  $typeNum = 0;
914  }
915  }
916  // If current typeNum doesn't exist, set it to 0 (or to 1 for historical reasons, if 0 doesn't exist)
917  if (!$GLOBALS['TCA'][$table]['types'][$typeNum]) {
918  $typeNum = $GLOBALS['TCA'][$table]['types']['0'] ? 0 : 1;
919  }
920  // Force to string. Necessary for eg '-1' to be recognized as a type value.
921  $typeNum = (string)$typeNum;
922  return $typeNum;
923  }
924 
935  public static function getSpecConfParts($defaultExtrasString, $_ = '')
936  {
937  if (!empty($_)) {
938  GeneralUtility::deprecationLog('Second parameter of BackendUtility::getSpecConfParts() is deprecated. Will be removed with TYPO3 CMS 8');
939  // Prepend old parameter, can be overwritten by casual defaultExtras string, then.
940  $defaultExtrasString = $_ . ':' . $defaultExtrasString;
941  }
942  $specConfParts = GeneralUtility::trimExplode(':', $defaultExtrasString, true);
943  $reg = [];
944  if (!empty($specConfParts)) {
945  foreach ($specConfParts as $k2 => $v2) {
946  unset($specConfParts[$k2]);
947  if (preg_match('/(.*)\\[(.*)\\]/', $v2, $reg)) {
948  $specConfParts[trim($reg[1])] = [
949  'parameters' => GeneralUtility::trimExplode('|', $reg[2], true)
950  ];
951  } else {
952  $specConfParts[trim($v2)] = 1;
953  }
954  }
955  } else {
956  $specConfParts = [];
957  }
958  return $specConfParts;
959  }
960 
968  public static function getSpecConfParametersFromArray($pArr)
969  {
970  $out = [];
971  if (is_array($pArr)) {
972  foreach ($pArr as $k => $v) {
973  $parts = explode('=', $v, 2);
974  if (count($parts) === 2) {
975  $out[trim($parts[0])] = trim($parts[1]);
976  } else {
977  $out[$k] = $v;
978  }
979  }
980  }
981  return $out;
982  }
983 
1012  public static function getFlexFormDS($conf, $row, $table, $fieldName = '', $WSOL = true, $newRecordPidValue = 0)
1013  {
1014  // Get pointer field etc from TCA-config:
1015  $ds_pointerField = $conf['ds_pointerField'];
1016  $ds_array = $conf['ds'];
1017  $ds_tableField = $conf['ds_tableField'];
1018  $ds_searchParentField = $conf['ds_pointerField_searchParent'];
1019  // If there is a data source array, that takes precedence
1020  if (is_array($ds_array)) {
1021  // If a pointer field is set, take the value from that field in the $row array and use as key.
1022  if ($ds_pointerField) {
1023  // Up to two pointer fields can be specified in a comma separated list.
1024  $pointerFields = GeneralUtility::trimExplode(',', $ds_pointerField);
1025  // If we have two pointer fields, the array keys should contain both field values separated by comma. The asterisk "*" catches all values. For backwards compatibility, it's also possible to specify only the value of the first defined ds_pointerField.
1026  if (count($pointerFields) === 2) {
1027  if ($ds_array[$row[$pointerFields[0]] . ',' . $row[$pointerFields[1]]]) {
1028  // Check if we have a DS for the combination of both pointer fields values
1029  $srcPointer = $row[$pointerFields[0]] . ',' . $row[$pointerFields[1]];
1030  } elseif ($ds_array[$row[$pointerFields[1]] . ',*']) {
1031  // Check if we have a DS for the value of the first pointer field suffixed with ",*"
1032  $srcPointer = $row[$pointerFields[1]] . ',*';
1033  } elseif ($ds_array['*,' . $row[$pointerFields[1]]]) {
1034  // Check if we have a DS for the value of the second pointer field prefixed with "*,"
1035  $srcPointer = '*,' . $row[$pointerFields[1]];
1036  } elseif ($ds_array[$row[$pointerFields[0]]]) {
1037  // Check if we have a DS for just the value of the first pointer field (mainly for backwards compatibility)
1038  $srcPointer = $row[$pointerFields[0]];
1039  } else {
1040  $srcPointer = null;
1041  }
1042  } else {
1043  $srcPointer = $row[$pointerFields[0]];
1044  }
1045  $srcPointer = $srcPointer !== null && isset($ds_array[$srcPointer]) ? $srcPointer : 'default';
1046  } else {
1047  $srcPointer = 'default';
1048  }
1049  // Get Data Source: Detect if it's a file reference and in that case read the file and parse as XML. Otherwise the value is expected to be XML.
1050  if (substr($ds_array[$srcPointer], 0, 5) == 'FILE:') {
1051  $file = GeneralUtility::getFileAbsFileName(substr($ds_array[$srcPointer], 5));
1052  if ($file && @is_file($file)) {
1053  $dataStructArray = GeneralUtility::xml2array(GeneralUtility::getUrl($file));
1054  } else {
1055  $dataStructArray = 'The file "' . substr($ds_array[$srcPointer], 5) . '" in ds-array key "' . $srcPointer . '" was not found ("' . $file . '")';
1056  }
1057  } else {
1058  $dataStructArray = GeneralUtility::xml2array($ds_array[$srcPointer]);
1059  }
1060  } elseif ($ds_pointerField) {
1061  // If pointer field AND possibly a table/field is set:
1062  // Value of field pointed to:
1063  $srcPointer = $row[$ds_pointerField];
1064  // Searching recursively back if 'ds_pointerField_searchParent' is defined (typ. a page rootline, or maybe a tree-table):
1065  if ($ds_searchParentField && !$srcPointer) {
1066  $rr = self::getRecord($table, $row['uid'], 'uid,' . $ds_searchParentField);
1067  // Get the "pid" field - we cannot know that it is in the input record! ###NOTE_A###
1068  if ($WSOL) {
1069  self::workspaceOL($table, $rr);
1070  self::fixVersioningPid($table, $rr, true);
1071  }
1072  $db = static::getDatabaseConnection();
1073  $uidAcc = [];
1074  // Used to avoid looping, if any should happen.
1075  $subFieldPointer = $conf['ds_pointerField_searchParent_subField'];
1076  while (!$srcPointer) {
1077  $res = $db->exec_SELECTquery('uid,' . $ds_pointerField . ',' . $ds_searchParentField . ($subFieldPointer ? ',' . $subFieldPointer : ''), $table, 'uid=' . (int)($newRecordPidValue ?: $rr[$ds_searchParentField]) . self::deleteClause($table));
1078  $newRecordPidValue = 0;
1079  $rr = $db->sql_fetch_assoc($res);
1080  $db->sql_free_result($res);
1081  // Break if no result from SQL db or if looping...
1082  if (!is_array($rr) || isset($uidAcc[$rr['uid']])) {
1083  break;
1084  }
1085  $uidAcc[$rr['uid']] = 1;
1086  if ($WSOL) {
1087  self::workspaceOL($table, $rr);
1088  self::fixVersioningPid($table, $rr, true);
1089  }
1090  $srcPointer = $subFieldPointer && $rr[$subFieldPointer] ? $rr[$subFieldPointer] : $rr[$ds_pointerField];
1091  }
1092  }
1093  // If there is a srcPointer value:
1094  if ($srcPointer) {
1095  if (MathUtility::canBeInterpretedAsInteger($srcPointer)) {
1096  // If integer, then its a record we will look up:
1097  list($tName, $fName) = explode(':', $ds_tableField, 2);
1098  if ($tName && $fName && is_array($GLOBALS['TCA'][$tName])) {
1099  $dataStructRec = self::getRecord($tName, $srcPointer);
1100  if ($WSOL) {
1101  self::workspaceOL($tName, $dataStructRec);
1102  }
1103  if (strpos($dataStructRec[$fName], '<') === false) {
1104  if (is_file(PATH_site . $dataStructRec[$fName])) {
1105  // The value is a pointer to a file
1106  $dataStructArray = GeneralUtility::xml2array(GeneralUtility::getUrl(PATH_site . $dataStructRec[$fName]));
1107  } else {
1108  $dataStructArray = sprintf('File \'%s\' was not found', $dataStructRec[$fName]);
1109  }
1110  } else {
1111  // No file pointer, handle as being XML (default behaviour)
1112  $dataStructArray = GeneralUtility::xml2array($dataStructRec[$fName]);
1113  }
1114  } else {
1115  $dataStructArray = 'No tablename (' . $tName . ') or fieldname (' . $fName . ') was found an valid!';
1116  }
1117  } else {
1118  // Otherwise expect it to be a file:
1119  $file = GeneralUtility::getFileAbsFileName($srcPointer);
1120  if ($file && @is_file($file)) {
1121  $dataStructArray = GeneralUtility::xml2array(GeneralUtility::getUrl($file));
1122  } else {
1123  // Error message.
1124  $dataStructArray = 'The file "' . $srcPointer . '" was not found ("' . $file . '")';
1125  }
1126  }
1127  } else {
1128  // Error message.
1129  $dataStructArray = 'No source value in fieldname "' . $ds_pointerField . '"';
1130  }
1131  } else {
1132  $dataStructArray = 'No proper configuration!';
1133  }
1134  // Hook for post-processing the Flexform DS. Introduces the possibility to configure Flexforms via TSConfig
1135  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['getFlexFormDSClass'])) {
1136  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['getFlexFormDSClass'] as $classRef) {
1137  $hookObj = GeneralUtility::getUserObj($classRef);
1138  if (method_exists($hookObj, 'getFlexFormDS_postProcessDS')) {
1139  $hookObj->getFlexFormDS_postProcessDS($dataStructArray, $conf, $row, $table, $fieldName);
1140  }
1141  }
1142  }
1143  return $dataStructArray;
1144  }
1145 
1154  public static function getRegisteredFlexForms($table = 'tt_content')
1155  {
1157  if (empty($table) || empty($GLOBALS['TCA'][$table]['columns'])) {
1158  return [];
1159  }
1160  $flexForms = [];
1161  foreach ($GLOBALS['TCA'][$table]['columns'] as $tableField => $fieldConf) {
1162  if (!empty($fieldConf['config']['type']) && !empty($fieldConf['config']['ds']) && $fieldConf['config']['type'] == 'flex') {
1163  $flexForms[$tableField] = [];
1164  unset($fieldConf['config']['ds']['default']);
1165  // Get pointer fields
1166  $pointerFields = !empty($fieldConf['config']['ds_pointerField']) ? $fieldConf['config']['ds_pointerField'] : 'list_type,CType';
1167  $pointerFields = GeneralUtility::trimExplode(',', $pointerFields);
1168  // Get FlexForms
1169  foreach ($fieldConf['config']['ds'] as $flexFormKey => $dataStruct) {
1170  // Get extension identifier (uses second value if it's not empty, "list" or "*", else first one)
1171  $identFields = GeneralUtility::trimExplode(',', $flexFormKey);
1172  $extIdent = $identFields[0];
1173  if (!empty($identFields[1]) && $identFields[1] != 'list' && $identFields[1] != '*') {
1174  $extIdent = $identFields[1];
1175  }
1176  // Load external file references
1177  if (!is_array($dataStruct)) {
1178  $file = GeneralUtility::getFileAbsFileName(str_ireplace('FILE:', '', $dataStruct));
1179  if ($file && @is_file($file)) {
1180  $dataStruct = GeneralUtility::getUrl($file);
1181  }
1182  $dataStruct = GeneralUtility::xml2array($dataStruct);
1183  if (!is_array($dataStruct)) {
1184  continue;
1185  }
1186  }
1187  // Get flexform content
1188  $dataStruct = GeneralUtility::resolveAllSheetsInDS($dataStruct);
1189  if (empty($dataStruct['sheets']) || !is_array($dataStruct['sheets'])) {
1190  continue;
1191  }
1192  // Use DS pointer to get extension title from TCA
1193  $title = $extIdent;
1194  $keyFields = GeneralUtility::trimExplode(',', $flexFormKey);
1195  foreach ($pointerFields as $pointerKey => $pointerName) {
1196  if (empty($keyFields[$pointerKey]) || $keyFields[$pointerKey] == '*' || $keyFields[$pointerKey] == 'list') {
1197  continue;
1198  }
1199  if (!empty($GLOBALS['TCA'][$table]['columns'][$pointerName]['config']['items'])) {
1200  $items = $GLOBALS['TCA'][$table]['columns'][$pointerName]['config']['items'];
1201  if (!is_array($items)) {
1202  continue;
1203  }
1204  foreach ($items as $itemConf) {
1205  if (!empty($itemConf[0]) && !empty($itemConf[1]) && $itemConf[1] == $keyFields[$pointerKey]) {
1206  $title = $itemConf[0];
1207  break 2;
1208  }
1209  }
1210  }
1211  }
1212  $flexForms[$tableField][$extIdent] = [
1213  'title' => $title,
1214  'ds' => $dataStruct
1215  ];
1216  }
1217  }
1218  }
1219  return $flexForms;
1220  }
1221 
1222  /*******************************************
1223  *
1224  * Caching related
1225  *
1226  *******************************************/
1238  public static function storeHash($hash, $data, $ident)
1239  {
1241  $cacheManager = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class);
1242  $cacheManager->getCache('cache_hash')->set($hash, $data, ['ident_' . $ident], 0);
1243  }
1244 
1254  public static function getHash($hash)
1255  {
1257  $cacheManager = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class);
1258  $cacheEntry = $cacheManager->getCache('cache_hash')->get($hash);
1259  $hashContent = null;
1260  if ($cacheEntry) {
1261  $hashContent = $cacheEntry;
1262  }
1263  return $hashContent;
1264  }
1265 
1266  /*******************************************
1267  *
1268  * TypoScript related
1269  *
1270  *******************************************/
1280  public static function getPagesTSconfig($id, $rootLine = null, $returnPartArray = false)
1281  {
1282  static $pagesTSconfig_cacheReference = [];
1283  static $combinedTSconfig_cache = [];
1284 
1285  $id = (int)$id;
1286  if ($returnPartArray === false
1287  && $rootLine === null
1288  && isset($pagesTSconfig_cacheReference[$id])
1289  ) {
1290  return $combinedTSconfig_cache[$pagesTSconfig_cacheReference[$id]];
1291  } else {
1292  $TSconfig = [];
1293  if (!is_array($rootLine)) {
1294  $useCacheForCurrentPageId = true;
1295  $rootLine = self::BEgetRootLine($id, '', true);
1296  } else {
1297  $useCacheForCurrentPageId = false;
1298  }
1299 
1300  // Order correctly
1301  ksort($rootLine);
1302  $TSdataArray = [];
1303  // Setting default configuration
1304  $TSdataArray['defaultPageTSconfig'] = $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPageTSconfig'];
1305  foreach ($rootLine as $k => $v) {
1306  if (trim($v['tsconfig_includes'])) {
1307  $includeTsConfigFileList = GeneralUtility::trimExplode(',', $v['tsconfig_includes'], true);
1308  // Traversing list
1309  foreach ($includeTsConfigFileList as $key => $includeTsConfigFile) {
1310  if (StringUtility::beginsWith($includeTsConfigFile, 'EXT:')) {
1311  list($includeTsConfigFileExtensionKey, $includeTsConfigFilename) = explode(
1312  '/',
1313  substr($includeTsConfigFile, 4),
1314  2
1315  );
1316  if (
1317  (string)$includeTsConfigFileExtensionKey !== ''
1318  && ExtensionManagementUtility::isLoaded($includeTsConfigFileExtensionKey)
1319  && (string)$includeTsConfigFilename !== ''
1320  ) {
1321  $includeTsConfigFileAndPath = ExtensionManagementUtility::extPath($includeTsConfigFileExtensionKey) .
1322  $includeTsConfigFilename;
1323  if (file_exists($includeTsConfigFileAndPath)) {
1324  $TSdataArray['uid_' . $v['uid'] . '_static_' . $key] = GeneralUtility::getUrl($includeTsConfigFileAndPath);
1325  }
1326  }
1327  }
1328  }
1329  }
1330  $TSdataArray['uid_' . $v['uid']] = $v['TSconfig'];
1331  }
1332  $TSdataArray = static::emitGetPagesTSconfigPreIncludeSignal($TSdataArray, $id, $rootLine, $returnPartArray);
1333  $TSdataArray = TypoScriptParser::checkIncludeLines_array($TSdataArray);
1334  if ($returnPartArray) {
1335  return $TSdataArray;
1336  }
1337  // Parsing the page TS-Config
1338  $pageTS = implode(LF . '[GLOBAL]' . LF, $TSdataArray);
1339  /* @var $parseObj \TYPO3\CMS\Backend\Configuration\TsConfigParser */
1340  $parseObj = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Configuration\TsConfigParser::class);
1341  $res = $parseObj->parseTSconfig($pageTS, 'PAGES', $id, $rootLine);
1342  if ($res) {
1343  $TSconfig = $res['TSconfig'];
1344  }
1345  $cacheHash = $res['hash'];
1346  // Get User TSconfig overlay
1347  $userTSconfig = static::getBackendUserAuthentication()->userTS['page.'];
1348  if (is_array($userTSconfig)) {
1349  ArrayUtility::mergeRecursiveWithOverrule($TSconfig, $userTSconfig);
1350  $cacheHash .= '_user' . $GLOBALS['BE_USER']->user['uid'];
1351  }
1352 
1353  if ($useCacheForCurrentPageId) {
1354  if (!isset($combinedTSconfig_cache[$cacheHash])) {
1355  $combinedTSconfig_cache[$cacheHash] = $TSconfig;
1356  }
1357  $pagesTSconfig_cacheReference[$id] = $cacheHash;
1358  }
1359  }
1360  return $TSconfig;
1361  }
1362 
1371  public static function implodeTSParams($p, $k = '')
1372  {
1374  $implodeParams = [];
1375  if (is_array($p)) {
1376  foreach ($p as $kb => $val) {
1377  if (is_array($val)) {
1378  $implodeParams = array_merge($implodeParams, self::implodeTSParams($val, $k . $kb));
1379  } else {
1380  $implodeParams[$k . $kb] = $val;
1381  }
1382  }
1383  }
1384  return $implodeParams;
1385  }
1386 
1387  /*******************************************
1388  *
1389  * Users / Groups related
1390  *
1391  *******************************************/
1400  public static function getUserNames($fields = 'username,usergroup,usergroup_cached_list,uid', $where = '')
1401  {
1402  return self::getRecordsSortedByTitle(
1403  GeneralUtility::trimExplode(',', $fields, true),
1404  'be_users',
1405  'username',
1406  'AND pid=0 ' . $where
1407  );
1408  }
1409 
1417  public static function getGroupNames($fields = 'title,uid', $where = '')
1418  {
1419  return self::getRecordsSortedByTitle(
1420  GeneralUtility::trimExplode(',', $fields, true),
1421  'be_groups',
1422  'title',
1423  'AND pid=0 ' . $where
1424  );
1425  }
1426 
1438  protected static function getRecordsSortedByTitle(array $fields, $table, $titleField, $where = '')
1439  {
1440  $fieldsIndex = array_flip($fields);
1441  // Make sure the titleField is amongst the fields when getting sorted
1442  $fieldsIndex[$titleField] = 1;
1443 
1444  $result = [];
1445  $db = static::getDatabaseConnection();
1446  $res = $db->exec_SELECTquery('*', $table, '1=1 ' . $where . self::deleteClause($table));
1447  while ($record = $db->sql_fetch_assoc($res)) {
1448  // store the uid, because it might be unset if it's not among the requested $fields
1449  $recordId = $record['uid'];
1450  $record[$titleField] = self::getRecordTitle($table, $record);
1451 
1452  // include only the requested fields in the result
1453  $result[$recordId] = array_intersect_key($record, $fieldsIndex);
1454  }
1455  $db->sql_free_result($res);
1456 
1457  // sort records by $sortField. This is not done in the query because the title might have been overwritten by
1458  // self::getRecordTitle();
1459  return ArrayUtility::sortArraysByKey($result, $titleField);
1460  }
1461 
1469  public static function getListGroupNames($fields = 'title, uid')
1470  {
1471  $beUser = static::getBackendUserAuthentication();
1472  $exQ = ' AND hide_in_lists=0';
1473  if (!$beUser->isAdmin()) {
1474  $exQ .= ' AND uid IN (' . ($beUser->user['usergroup_cached_list'] ?: 0) . ')';
1475  }
1476  return self::getGroupNames($fields, $exQ);
1477  }
1478 
1489  public static function blindUserNames($usernames, $groupArray, $excludeBlindedFlag = false)
1490  {
1491  if (is_array($usernames) && is_array($groupArray)) {
1492  foreach ($usernames as $uid => $row) {
1493  $userN = $uid;
1494  $set = 0;
1495  if ($row['uid'] != static::getBackendUserAuthentication()->user['uid']) {
1496  foreach ($groupArray as $v) {
1497  if ($v && GeneralUtility::inList($row['usergroup_cached_list'], $v)) {
1498  $userN = $row['username'];
1499  $set = 1;
1500  }
1501  }
1502  } else {
1503  $userN = $row['username'];
1504  $set = 1;
1505  }
1506  $usernames[$uid]['username'] = $userN;
1507  if ($excludeBlindedFlag && !$set) {
1508  unset($usernames[$uid]);
1509  }
1510  }
1511  }
1512  return $usernames;
1513  }
1514 
1523  public static function blindGroupNames($groups, $groupArray, $excludeBlindedFlag = false)
1524  {
1525  if (is_array($groups) && is_array($groupArray)) {
1526  foreach ($groups as $uid => $row) {
1527  $groupN = $uid;
1528  $set = 0;
1529  if (ArrayUtility::inArray($groupArray, $uid)) {
1530  $groupN = $row['title'];
1531  $set = 1;
1532  }
1533  $groups[$uid]['title'] = $groupN;
1534  if ($excludeBlindedFlag && !$set) {
1535  unset($groups[$uid]);
1536  }
1537  }
1538  }
1539  return $groups;
1540  }
1541 
1542  /*******************************************
1543  *
1544  * Output related
1545  *
1546  *******************************************/
1553  public static function daysUntil($tstamp)
1554  {
1555  $delta_t = $tstamp - $GLOBALS['EXEC_TIME'];
1556  return ceil($delta_t / (3600 * 24));
1557  }
1558 
1565  public static function date($tstamp)
1566  {
1567  return date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], (int)$tstamp);
1568  }
1569 
1576  public static function datetime($value)
1577  {
1578  return date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $value);
1579  }
1580 
1589  public static function time($value, $withSeconds = true)
1590  {
1591  $hh = floor($value / 3600);
1592  $min = floor(($value - $hh * 3600) / 60);
1593  $sec = $value - $hh * 3600 - $min * 60;
1594  $l = sprintf('%02d', $hh) . ':' . sprintf('%02d', $min);
1595  if ($withSeconds) {
1596  $l .= ':' . sprintf('%02d', $sec);
1597  }
1598  return $l;
1599  }
1600 
1608  public static function calcAge($seconds, $labels = ' min| hrs| days| yrs| min| hour| day| year')
1609  {
1610  $labelArr = explode('|', $labels);
1611  $absSeconds = abs($seconds);
1612  $sign = $seconds < 0 ? -1 : 1;
1613  if ($absSeconds < 3600) {
1614  $val = round($absSeconds / 60);
1615  $seconds = $sign * $val . ($val == 1 ? $labelArr[4] : $labelArr[0]);
1616  } elseif ($absSeconds < 24 * 3600) {
1617  $val = round($absSeconds / 3600);
1618  $seconds = $sign * $val . ($val == 1 ? $labelArr[5] : $labelArr[1]);
1619  } elseif ($absSeconds < 365 * 24 * 3600) {
1620  $val = round($absSeconds / (24 * 3600));
1621  $seconds = $sign * $val . ($val == 1 ? $labelArr[6] : $labelArr[2]);
1622  } else {
1623  $val = round($absSeconds / (365 * 24 * 3600));
1624  $seconds = $sign * $val . ($val == 1 ? $labelArr[7] : $labelArr[3]);
1625  }
1626  return $seconds;
1627  }
1628 
1638  public static function dateTimeAge($tstamp, $prefix = 1, $date = '')
1639  {
1640  if (!$tstamp) {
1641  return '';
1642  }
1643  $label = static::getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears');
1644  $age = ' (' . self::calcAge($prefix * ($GLOBALS['EXEC_TIME'] - $tstamp), $label) . ')';
1645  return ($date === 'date' ? self::date($tstamp) : self::datetime($tstamp)) . $age;
1646  }
1647 
1654  public static function titleAltAttrib($content)
1655  {
1656  $out = '';
1657  $out .= ' alt="' . htmlspecialchars($content) . '"';
1658  $out .= ' title="' . htmlspecialchars($content) . '"';
1659  return $out;
1660  }
1661 
1671  public static function resolveFileReferences($tableName, $fieldName, $element, $workspaceId = null)
1672  {
1673  if (empty($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config'])) {
1674  return null;
1675  }
1676  $configuration = $GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config'];
1677  if (empty($configuration['type']) || $configuration['type'] !== 'inline'
1678  || empty($configuration['foreign_table']) || $configuration['foreign_table'] !== 'sys_file_reference') {
1679  return null;
1680  }
1681 
1682  $fileReferences = [];
1684  $relationHandler = GeneralUtility::makeInstance(RelationHandler::class);
1685  if ($workspaceId !== null) {
1686  $relationHandler->setWorkspaceId($workspaceId);
1687  }
1688  $relationHandler->start($element[$fieldName], $configuration['foreign_table'], $configuration['MM'], $element['uid'], $tableName, $configuration);
1689  $relationHandler->processDeletePlaceholder();
1690  $referenceUids = $relationHandler->tableArray[$configuration['foreign_table']];
1691 
1692  foreach ($referenceUids as $referenceUid) {
1693  try {
1694  $fileReference = ResourceFactory::getInstance()->getFileReferenceObject($referenceUid, [], ($workspaceId === 0));
1695  $fileReferences[$fileReference->getUid()] = $fileReference;
1696  } catch (\TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException $e) {
1701  } catch (\InvalidArgumentException $e) {
1706  $logMessage = $e->getMessage() . ' (table: "' . $tableName . '", fieldName: "' . $fieldName . '", referenceUid: ' . $referenceUid . ')';
1707  GeneralUtility::sysLog($logMessage, 'core', GeneralUtility::SYSLOG_SEVERITY_ERROR);
1708  }
1709  }
1710 
1711  return $fileReferences;
1712  }
1713 
1731  public static function thumbCode($row, $table, $field, $backPath = '', $thumbScript = '', $uploaddir = null, $abs = 0, $tparams = '', $size = '', $linkInfoPopup = true)
1732  {
1733  // Check and parse the size parameter
1734  $size = trim($size);
1735  $sizeParts = [64, 64];
1736  if ($size) {
1737  $sizeParts = explode('x', $size . 'x' . $size);
1738  }
1739  $thumbData = '';
1740  $fileReferences = static::resolveFileReferences($table, $field, $row);
1741  // FAL references
1742  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
1743  if ($fileReferences !== null) {
1744  foreach ($fileReferences as $fileReferenceObject) {
1745  // Do not show previews of hidden references
1746  if ($fileReferenceObject->getProperty('hidden')) {
1747  continue;
1748  }
1749  $fileObject = $fileReferenceObject->getOriginalFile();
1750 
1751  if ($fileObject->isMissing()) {
1752  $thumbData .= '<span class="label label-danger">'
1753  . htmlspecialchars(static::getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:warning.file_missing'))
1754  . '</span>&nbsp;' . htmlspecialchars($fileObject->getName()) . '<br />';
1755  continue;
1756  }
1757 
1758  // Preview web image or media elements
1759  if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails'] && GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] . ',' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext'], $fileReferenceObject->getExtension())) {
1760  $processedImage = $fileObject->process(ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, [
1761  'width' => $sizeParts[0],
1762  'height' => $sizeParts[1] . 'c',
1763  'crop' => $fileReferenceObject->getProperty('crop')
1764  ]);
1765  $imageUrl = $processedImage->getPublicUrl(true);
1766  $imgTag = '<img src="' . $imageUrl . '" ' .
1767  'width="' . $processedImage->getProperty('width') . '" ' .
1768  'height="' . $processedImage->getProperty('height') . '" ' .
1769  'alt="' . htmlspecialchars($fileReferenceObject->getName()) . '" />';
1770  } else {
1771  // Icon
1772  $imgTag = '<span title="' . htmlspecialchars($fileObject->getName()) . '">' . $iconFactory->getIconForResource($fileObject, Icon::SIZE_SMALL)->render() . '</span>';
1773  }
1774  if ($linkInfoPopup) {
1775  $onClick = 'top.launchView(\'_FILE\',\'' . (int)$fileObject->getUid() . '\',' . GeneralUtility::quoteJSvalue($backPath) . '); return false;';
1776  $thumbData .= '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' . $imgTag . '</a> ';
1777  } else {
1778  $thumbData .= $imgTag;
1779  }
1780  }
1781  } else {
1782  // Find uploaddir automatically
1783  if (is_null($uploaddir)) {
1784  $uploaddir = $GLOBALS['TCA'][$table]['columns'][$field]['config']['uploadfolder'];
1785  }
1786  $uploaddir = rtrim($uploaddir, '/');
1787  // Traverse files:
1788  $thumbs = GeneralUtility::trimExplode(',', $row[$field], true);
1789  $thumbData = '';
1790  foreach ($thumbs as $theFile) {
1791  if ($theFile) {
1792  $fileName = trim($uploaddir . '/' . $theFile, '/');
1793  try {
1795  $fileObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($fileName);
1796  // Skip the resource if it's not of type AbstractFile. One case where this can happen if the
1797  // storage has been externally modified and the field value now points to a folder
1798  // instead of a file.
1799  if (!$fileObject instanceof AbstractFile) {
1800  continue;
1801  }
1802  if ($fileObject->isMissing()) {
1803  $thumbData .= '<span class="label label-danger">'
1804  . htmlspecialchars(static::getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:warning.file_missing'))
1805  . '</span>&nbsp;' . htmlspecialchars($fileObject->getName()) . '<br />';
1806  continue;
1807  }
1808  } catch (ResourceDoesNotExistException $exception) {
1809  $thumbData .= '<span class="label label-danger">'
1810  . htmlspecialchars(static::getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:warning.file_missing'))
1811  . '</span>&nbsp;' . htmlspecialchars($fileName) . '<br />';
1812  continue;
1813  }
1814 
1815  $fileExtension = $fileObject->getExtension();
1816  if ($fileExtension == 'ttf' || GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileExtension)) {
1817  $imageUrl = $fileObject->process(ProcessedFile::CONTEXT_IMAGEPREVIEW, [
1818  'width' => $sizeParts[0],
1819  'height' => $sizeParts[1]
1820  ])->getPublicUrl(true);
1821  $image = '<img src="' . htmlspecialchars($imageUrl) . '" hspace="2" border="0" title="' . htmlspecialchars($fileObject->getName()) . '"' . $tparams . ' alt="" />';
1822  if ($linkInfoPopup) {
1823  $onClick = 'top.launchView(\'_FILE\', ' . GeneralUtility::quoteJSvalue($fileName) . ',\'\',' . GeneralUtility::quoteJSvalue($backPath) . ');return false;';
1824  $thumbData .= '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' . $image . '</a> ';
1825  } else {
1826  $thumbData .= $image;
1827  }
1828  } else {
1829  // Gets the icon
1830  $fileIcon = '<span title="' . htmlspecialchars($fileObject->getName()) . '">' . $iconFactory->getIconForResource($fileObject, Icon::SIZE_SMALL)->render() . '</span>';
1831  if ($linkInfoPopup) {
1832  $onClick = 'top.launchView(\'_FILE\', ' . GeneralUtility::quoteJSvalue($fileName) . ',\'\',' . GeneralUtility::quoteJSvalue($backPath) . '); return false;';
1833  $thumbData .= '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' . $fileIcon . '</a> ';
1834  } else {
1835  $thumbData .= $fileIcon;
1836  }
1837  }
1838  }
1839  }
1840  }
1841  return $thumbData;
1842  }
1843 
1854  public static function getThumbNail($thumbScript, $theFile, $tparams = '', $size = '')
1855  {
1857  $size = trim($size);
1858  $check = basename($theFile) . ':' . filemtime($theFile) . ':' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
1859  $params = '&file=' . rawurlencode($theFile);
1860  $params .= $size ? '&size=' . $size : '';
1861  $params .= '&md5sum=' . md5($check);
1862  $url = $thumbScript . '?' . $params;
1863  $th = '<img src="' . htmlspecialchars($url) . '" title="' . trim(basename($theFile)) . '"' . ($tparams ? ' ' . $tparams : '') . ' alt="" />';
1864  return $th;
1865  }
1866 
1875  public static function titleAttribForPages($row, $perms_clause = '', $includeAttrib = true)
1876  {
1877  $lang = static::getLanguageService();
1878  $parts = [];
1879  $parts[] = 'id=' . $row['uid'];
1880  if ($row['alias']) {
1881  $parts[] = $lang->sL($GLOBALS['TCA']['pages']['columns']['alias']['label']) . ' ' . $row['alias'];
1882  }
1883  if ($row['pid'] < 0) {
1884  $parts[] = 'v#1.' . $row['t3ver_id'];
1885  }
1886  switch (VersionState::cast($row['t3ver_state'])) {
1888  $parts[] = 'PLH WSID#' . $row['t3ver_wsid'];
1889  break;
1891  $parts[] = 'Deleted element!';
1892  break;
1894  $parts[] = 'NEW LOCATION (PLH) WSID#' . $row['t3ver_wsid'];
1895  break;
1897  $parts[] = 'OLD LOCATION (PNT) WSID#' . $row['t3ver_wsid'];
1898  break;
1900  $parts[] = 'New element!';
1901  break;
1902  }
1903  if ($row['doktype'] == PageRepository::DOKTYPE_LINK) {
1904  $parts[] = $lang->sL($GLOBALS['TCA']['pages']['columns']['url']['label']) . ' ' . $row['url'];
1905  } elseif ($row['doktype'] == PageRepository::DOKTYPE_SHORTCUT) {
1906  if ($perms_clause) {
1907  $label = self::getRecordPath((int)$row['shortcut'], $perms_clause, 20);
1908  } else {
1909  $row['shortcut'] = (int)$row['shortcut'];
1910  $lRec = self::getRecordWSOL('pages', $row['shortcut'], 'title');
1911  $label = $lRec['title'] . ' (id=' . $row['shortcut'] . ')';
1912  }
1913  if ($row['shortcut_mode'] != PageRepository::SHORTCUT_MODE_NONE) {
1914  $label .= ', ' . $lang->sL($GLOBALS['TCA']['pages']['columns']['shortcut_mode']['label']) . ' ' . $lang->sL(self::getLabelFromItemlist('pages', 'shortcut_mode', $row['shortcut_mode']));
1915  }
1916  $parts[] = $lang->sL($GLOBALS['TCA']['pages']['columns']['shortcut']['label']) . ' ' . $label;
1917  } elseif ($row['doktype'] == PageRepository::DOKTYPE_MOUNTPOINT) {
1918  if ($perms_clause) {
1919  $label = self::getRecordPath((int)$row['mount_pid'], $perms_clause, 20);
1920  } else {
1921  $lRec = self::getRecordWSOL('pages', (int)$row['mount_pid'], 'title');
1922  $label = $lRec['title'] . ' (id=' . $row['mount_pid'] . ')';
1923  }
1924  $parts[] = $lang->sL($GLOBALS['TCA']['pages']['columns']['mount_pid']['label']) . ' ' . $label;
1925  if ($row['mount_pid_ol']) {
1926  $parts[] = $lang->sL($GLOBALS['TCA']['pages']['columns']['mount_pid_ol']['label']);
1927  }
1928  }
1929  if ($row['nav_hide']) {
1930  $parts[] = rtrim($lang->sL($GLOBALS['TCA']['pages']['columns']['nav_hide']['label']), ':');
1931  }
1932  if ($row['hidden']) {
1933  $parts[] = $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.hidden');
1934  }
1935  if ($row['starttime']) {
1936  $parts[] = $lang->sL($GLOBALS['TCA']['pages']['columns']['starttime']['label']) . ' ' . self::dateTimeAge($row['starttime'], -1, 'date');
1937  }
1938  if ($row['endtime']) {
1939  $parts[] = $lang->sL($GLOBALS['TCA']['pages']['columns']['endtime']['label']) . ' ' . self::dateTimeAge($row['endtime'], -1, 'date');
1940  }
1941  if ($row['fe_group']) {
1942  $fe_groups = [];
1943  foreach (GeneralUtility::intExplode(',', $row['fe_group']) as $fe_group) {
1944  if ($fe_group < 0) {
1945  $fe_groups[] = $lang->sL(self::getLabelFromItemlist('pages', 'fe_group', $fe_group));
1946  } else {
1947  $lRec = self::getRecordWSOL('fe_groups', $fe_group, 'title');
1948  $fe_groups[] = $lRec['title'];
1949  }
1950  }
1951  $label = implode(', ', $fe_groups);
1952  $parts[] = $lang->sL($GLOBALS['TCA']['pages']['columns']['fe_group']['label']) . ' ' . $label;
1953  }
1954  $out = htmlspecialchars(implode(' - ', $parts));
1955  return $includeAttrib ? 'title="' . $out . '"' : $out;
1956  }
1957 
1965  public static function getRecordToolTip(array $row, $table = 'pages')
1966  {
1967  $toolTipText = self::getRecordIconAltText($row, $table);
1968  $toolTipCode = 'data-toggle="tooltip" data-title=" ' . str_replace(' - ', '<br>', $toolTipText) . '" data-html="true" data-placement="right"';
1969  return $toolTipCode;
1970  }
1971 
1981  public static function getRecordIconAltText($row, $table = 'pages')
1982  {
1983  if ($table == 'pages') {
1984  $out = self::titleAttribForPages($row, '', 0);
1985  } else {
1986  $out = !empty(trim($GLOBALS['TCA'][$table]['ctrl']['descriptionColumn'])) ? $row[$GLOBALS['TCA'][$table]['ctrl']['descriptionColumn']] . ' ' : '';
1987  $ctrl = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns'];
1988  // Uid is added
1989  $out .= 'id=' . $row['uid'];
1990  if ($table == 'pages' && $row['alias']) {
1991  $out .= ' / ' . $row['alias'];
1992  }
1993  if (static::isTableWorkspaceEnabled($table) && $row['pid'] < 0) {
1994  $out .= ' - v#1.' . $row['t3ver_id'];
1995  }
1996  if (static::isTableWorkspaceEnabled($table)) {
1997  switch (VersionState::cast($row['t3ver_state'])) {
1999  $out .= ' - PLH WSID#' . $row['t3ver_wsid'];
2000  break;
2002  $out .= ' - Deleted element!';
2003  break;
2005  $out .= ' - NEW LOCATION (PLH) WSID#' . $row['t3ver_wsid'];
2006  break;
2008  $out .= ' - OLD LOCATION (PNT) WSID#' . $row['t3ver_wsid'];
2009  break;
2011  $out .= ' - New element!';
2012  break;
2013  }
2014  }
2015  // Hidden
2016  $lang = static::getLanguageService();
2017  if ($ctrl['disabled']) {
2018  $out .= $row[$ctrl['disabled']] ? ' - ' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.hidden') : '';
2019  }
2020  if ($ctrl['starttime']) {
2021  if ($row[$ctrl['starttime']] > $GLOBALS['EXEC_TIME']) {
2022  $out .= ' - ' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.starttime') . ':' . self::date($row[$ctrl['starttime']]) . ' (' . self::daysUntil($row[$ctrl['starttime']]) . ' ' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.days') . ')';
2023  }
2024  }
2025  if ($row[$ctrl['endtime']]) {
2026  $out .= ' - ' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.endtime') . ': ' . self::date($row[$ctrl['endtime']]) . ' (' . self::daysUntil($row[$ctrl['endtime']]) . ' ' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.days') . ')';
2027  }
2028  }
2029  return htmlspecialchars($out);
2030  }
2031 
2040  public static function getLabelFromItemlist($table, $col, $key)
2041  {
2042  // Check, if there is an "items" array:
2043  if (is_array($GLOBALS['TCA'][$table]) && is_array($GLOBALS['TCA'][$table]['columns'][$col]) && is_array($GLOBALS['TCA'][$table]['columns'][$col]['config']['items'])) {
2044  // Traverse the items-array...
2045  foreach ($GLOBALS['TCA'][$table]['columns'][$col]['config']['items'] as $v) {
2046  // ... and return the first found label where the value was equal to $key
2047  if ((string)$v[1] === (string)$key) {
2048  return $v[0];
2049  }
2050  }
2051  }
2052  return '';
2053  }
2054 
2064  public static function getLabelFromItemListMerged($pageId, $table, $column, $key)
2065  {
2066  $pageTsConfig = static::getPagesTSconfig($pageId);
2067  $label = '';
2068  if (is_array($pageTsConfig['TCEFORM.']) && is_array($pageTsConfig['TCEFORM.'][$table . '.']) && is_array($pageTsConfig['TCEFORM.'][$table . '.'][$column . '.'])) {
2069  if (is_array($pageTsConfig['TCEFORM.'][$table . '.'][$column . '.']['addItems.']) && isset($pageTsConfig['TCEFORM.'][$table . '.'][$column . '.']['addItems.'][$key])) {
2070  $label = $pageTsConfig['TCEFORM.'][$table . '.'][$column . '.']['addItems.'][$key];
2071  } elseif (is_array($pageTsConfig['TCEFORM.'][$table . '.'][$column . '.']['altLabels.']) && isset($pageTsConfig['TCEFORM.'][$table . '.'][$column . '.']['altLabels.'][$key])) {
2072  $label = $pageTsConfig['TCEFORM.'][$table . '.'][$column . '.']['altLabels.'][$key];
2073  }
2074  }
2075  if (empty($label)) {
2076  $tcaValue = self::getLabelFromItemlist($table, $column, $key);
2077  if (!empty($tcaValue)) {
2078  $label = $tcaValue;
2079  }
2080  }
2081  return $label;
2082  }
2083 
2094  public static function getLabelsFromItemsList($table, $column, $keyList, array $columnTsConfig = [])
2095  {
2096  // Check if there is an "items" array
2097  if (
2098  !isset($GLOBALS['TCA'][$table]['columns'][$column]['config']['items'])
2099  || !is_array($GLOBALS['TCA'][$table]['columns'][$column]['config']['items'])
2100  || $keyList === ''
2101  ) {
2102  return '';
2103  }
2104 
2105  $keys = GeneralUtility::trimExplode(',', $keyList, true);
2106  $labels = [];
2107  // Loop on all selected values
2108  foreach ($keys as $key) {
2109  $label = null;
2110  if ($columnTsConfig) {
2111  // Check if label has been defined or redefined via pageTsConfig
2112  if (isset($columnTsConfig['addItems.'][$key])) {
2113  $label = $columnTsConfig['addItems.'][$key];
2114  } elseif (isset($columnTsConfig['altLabels.'][$key])) {
2115  $label = $columnTsConfig['altLabels.'][$key];
2116  }
2117  }
2118  if ($label === null) {
2119  // Otherwise lookup the label in TCA items list
2120  foreach ($GLOBALS['TCA'][$table]['columns'][$column]['config']['items'] as $itemConfiguration) {
2121  list($currentLabel, $currentKey) = $itemConfiguration;
2122  if ((string)$key === (string)$currentKey) {
2123  $label = $currentLabel;
2124  break;
2125  }
2126  }
2127  }
2128  if ($label !== null) {
2129  $labels[] = static::getLanguageService()->sL($label);
2130  }
2131  }
2132  return implode(', ', $labels);
2133  }
2134 
2144  public static function getItemLabel($table, $col, $printAllWrap = '')
2145  {
2146  // Check if column exists
2147  if (is_array($GLOBALS['TCA'][$table]) && is_array($GLOBALS['TCA'][$table]['columns'][$col])) {
2148  return $GLOBALS['TCA'][$table]['columns'][$col]['label'];
2149  }
2150  if ($printAllWrap) {
2151  GeneralUtility::deprecationLog('The third parameter of getItemLabel() is deprecated with TYPO3 CMS 6.2 and will be removed two versions later.');
2152  $parts = explode('|', $printAllWrap);
2153  return $parts[0] . $col . $parts[1];
2154  }
2155 
2156  return null;
2157  }
2158 
2167  protected static function replaceL10nModeFields($table, array $row)
2168  {
2169  $originalUidField = isset($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'])
2170  ? $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']
2171  : '';
2172  if (empty($row[$originalUidField])) {
2173  return $row;
2174  }
2175 
2176  $originalTable = self::getOriginalTranslationTable($table);
2177  $originalRow = self::getRecord($originalTable, $row[$originalUidField]);
2178  foreach ($row as $field => $_) {
2179  $l10n_mode = isset($GLOBALS['TCA'][$originalTable]['columns'][$field]['l10n_mode'])
2180  ? $GLOBALS['TCA'][$originalTable]['columns'][$field]['l10n_mode']
2181  : '';
2182  if ($l10n_mode === 'exclude' || ($l10n_mode === 'mergeIfNotBlank' && trim($row[$field]) === '')) {
2183  $row[$field] = $originalRow[$field];
2184  }
2185  }
2186  return $row;
2187  }
2188 
2199  public static function getRecordTitle($table, $row, $prep = false, $forceResult = true)
2200  {
2201  $recordTitle = '';
2202  if (is_array($GLOBALS['TCA'][$table])) {
2203  // If configured, call userFunc
2204  if ($GLOBALS['TCA'][$table]['ctrl']['label_userFunc']) {
2205  $params['table'] = $table;
2206  $params['row'] = $row;
2207  $params['title'] = '';
2208  $params['options'] = isset($GLOBALS['TCA'][$table]['ctrl']['label_userFunc_options']) ? $GLOBALS['TCA'][$table]['ctrl']['label_userFunc_options'] : [];
2209 
2210  // Create NULL-reference
2211  $null = null;
2212  GeneralUtility::callUserFunction($GLOBALS['TCA'][$table]['ctrl']['label_userFunc'], $params, $null);
2213  $recordTitle = $params['title'];
2214  } else {
2215  if (is_array($row)) {
2216  $row = self::replaceL10nModeFields($table, $row);
2217  }
2218 
2219  // No userFunc: Build label
2220  $recordTitle = self::getProcessedValue($table, $GLOBALS['TCA'][$table]['ctrl']['label'], $row[$GLOBALS['TCA'][$table]['ctrl']['label']], 0, 0, false, $row['uid'], $forceResult);
2221  if ($GLOBALS['TCA'][$table]['ctrl']['label_alt'] && ($GLOBALS['TCA'][$table]['ctrl']['label_alt_force'] || (string)$recordTitle === '')) {
2222  $altFields = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['label_alt'], true);
2223  $tA = [];
2224  if (!empty($recordTitle)) {
2225  $tA[] = $recordTitle;
2226  }
2227  foreach ($altFields as $fN) {
2228  $recordTitle = trim(strip_tags($row[$fN]));
2229  if ((string)$recordTitle !== '') {
2230  $recordTitle = self::getProcessedValue($table, $fN, $recordTitle, 0, 0, false, $row['uid']);
2231  if (!$GLOBALS['TCA'][$table]['ctrl']['label_alt_force']) {
2232  break;
2233  }
2234  $tA[] = $recordTitle;
2235  }
2236  }
2237  if ($GLOBALS['TCA'][$table]['ctrl']['label_alt_force']) {
2238  $recordTitle = implode(', ', $tA);
2239  }
2240  }
2241  }
2242  // If the current result is empty, set it to '[No title]' (localized) and prepare for output if requested
2243  if ($prep || $forceResult) {
2244  if ($prep) {
2245  $recordTitle = self::getRecordTitlePrep($recordTitle);
2246  }
2247  if (trim($recordTitle) === '') {
2248  $recordTitle = self::getNoRecordTitle($prep);
2249  }
2250  }
2251  }
2252 
2253  return $recordTitle;
2254  }
2255 
2264  public static function getRecordTitlePrep($title, $titleLength = 0)
2265  {
2266  // If $titleLength is not a valid positive integer, use BE_USER->uc['titleLen']:
2267  if (!$titleLength || !MathUtility::canBeInterpretedAsInteger($titleLength) || $titleLength < 0) {
2268  $titleLength = static::getBackendUserAuthentication()->uc['titleLen'];
2269  }
2270  $titleOrig = htmlspecialchars($title);
2271  $title = htmlspecialchars(GeneralUtility::fixed_lgd_cs($title, $titleLength));
2272  // If title was cropped, offer a tooltip:
2273  if ($titleOrig != $title) {
2274  $title = '<span title="' . $titleOrig . '">' . $title . '</span>';
2275  }
2276  return $title;
2277  }
2278 
2285  public static function getNoRecordTitle($prep = false)
2286  {
2287  $noTitle = '[' . static::getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.no_title', true) . ']';
2288  if ($prep) {
2289  $noTitle = '<em>' . $noTitle . '</em>';
2290  }
2291  return $noTitle;
2292  }
2293 
2312  public static function getProcessedValue($table, $col, $value, $fixed_lgd_chars = 0, $defaultPassthrough = false, $noRecordLookup = false, $uid = 0, $forceResult = true, $pid = 0)
2313  {
2314  if ($col === 'uid') {
2315  // uid is not in TCA-array
2316  return $value;
2317  }
2318  // Check if table and field is configured
2319  if (!is_array($GLOBALS['TCA'][$table]) || !is_array($GLOBALS['TCA'][$table]['columns'][$col])) {
2320  return null;
2321  }
2322  // Depending on the fields configuration, make a meaningful output value.
2323  $theColConf = $GLOBALS['TCA'][$table]['columns'][$col]['config'];
2324  /*****************
2325  *HOOK: pre-processing the human readable output from a record
2326  ****************/
2327  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['preProcessValue'])) {
2328  // Create NULL-reference
2329  $null = null;
2330  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['preProcessValue'] as $_funcRef) {
2331  GeneralUtility::callUserFunction($_funcRef, $theColConf, $null);
2332  }
2333  }
2334  $l = '';
2335  $db = static::getDatabaseConnection();
2336  $lang = static::getLanguageService();
2337  switch ((string)$theColConf['type']) {
2338  case 'radio':
2339  $l = self::getLabelFromItemlist($table, $col, $value);
2340  $l = $lang->sL($l);
2341  break;
2342  case 'inline':
2343  case 'select':
2344  if ($theColConf['MM']) {
2345  if ($uid) {
2346  // Display the title of MM related records in lists
2347  if ($noRecordLookup) {
2348  $MMfield = $theColConf['foreign_table'] . '.uid';
2349  } else {
2350  $MMfields = [$theColConf['foreign_table'] . '.' . $GLOBALS['TCA'][$theColConf['foreign_table']]['ctrl']['label']];
2351  foreach (GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$theColConf['foreign_table']]['ctrl']['label_alt'], true) as $f) {
2352  $MMfields[] = $theColConf['foreign_table'] . '.' . $f;
2353  }
2354  $MMfield = implode(',', $MMfields);
2355  }
2357  $dbGroup = GeneralUtility::makeInstance(RelationHandler::class);
2358  $dbGroup->start($value, $theColConf['foreign_table'], $theColConf['MM'], $uid, $table, $theColConf);
2359  $selectUids = $dbGroup->tableArray[$theColConf['foreign_table']];
2360  if (is_array($selectUids) && !empty($selectUids)) {
2361  $MMres = $db->exec_SELECTquery('uid, ' . $MMfield, $theColConf['foreign_table'], 'uid IN (' . implode(',', $selectUids) . ')' . self::deleteClause($theColConf['foreign_table']));
2362  $mmlA = [];
2363  while ($MMrow = $db->sql_fetch_assoc($MMres)) {
2364  // Keep sorting of $selectUids
2365  $mmlA[array_search($MMrow['uid'], $selectUids)] = $noRecordLookup ?
2366  $MMrow['uid'] :
2367  static::getRecordTitle($theColConf['foreign_table'], $MMrow, false, $forceResult);
2368  }
2369  $db->sql_free_result($MMres);
2370  if (!empty($mmlA)) {
2371  ksort($mmlA);
2372  $l = implode('; ', $mmlA);
2373  } else {
2374  $l = 'N/A';
2375  }
2376  } else {
2377  $l = 'N/A';
2378  }
2379  } else {
2380  $l = 'N/A';
2381  }
2382  } else {
2383  $columnTsConfig = [];
2384  if ($pid) {
2385  $pageTsConfig = self::getPagesTSconfig($pid);
2386  if (isset($pageTsConfig['TCEFORM.'][$table . '.'][$col . '.']) && is_array($pageTsConfig['TCEFORM.'][$table . '.'][$col . '.'])) {
2387  $columnTsConfig = $pageTsConfig['TCEFORM.'][$table . '.'][$col . '.'];
2388  }
2389  }
2390  $l = self::getLabelsFromItemsList($table, $col, $value, $columnTsConfig);
2391  if ($theColConf['foreign_table'] && !$l && $GLOBALS['TCA'][$theColConf['foreign_table']]) {
2392  if ($noRecordLookup) {
2393  $l = $value;
2394  } else {
2395  $rParts = [];
2396  if ($uid && isset($theColConf['foreign_field']) && $theColConf['foreign_field'] !== '') {
2397  $whereClause = '';
2398  if (!empty($theColConf['foreign_table_field'])) {
2399  $whereClause .= ' AND ' . $theColConf['foreign_table_field'] . ' = ' . static::getDatabaseConnection()->fullQuoteStr($table, $theColConf['foreign_table']);
2400  }
2401  // Add additional where clause if foreign_match_fields are defined
2402  $foreignMatchFields = is_array($theColConf['foreign_match_fields']) ? $theColConf['foreign_match_fields'] : [];
2403  foreach ($foreignMatchFields as $matchField => $matchValue) {
2404  $whereClause .= ' AND ' . $matchField . '=' . static::getDatabaseConnection()->fullQuoteStr($matchValue, $theColConf['foreign_table']);
2405  }
2406  $records = self::getRecordsByField($theColConf['foreign_table'], $theColConf['foreign_field'], $uid, $whereClause);
2407  if (!empty($records)) {
2408  foreach ($records as $record) {
2409  $rParts[] = $record['uid'];
2410  }
2411  }
2412  }
2413  if (empty($rParts)) {
2414  $rParts = GeneralUtility::trimExplode(',', $value, true);
2415  }
2416  $lA = [];
2417  foreach ($rParts as $rVal) {
2418  $rVal = (int)$rVal;
2419  $r = self::getRecordWSOL($theColConf['foreign_table'], $rVal);
2420  if (is_array($r)) {
2421  $lA[] = $lang->sL($theColConf['foreign_table_prefix']) . self::getRecordTitle($theColConf['foreign_table'], $r, false, $forceResult);
2422  } else {
2423  $lA[] = $rVal ? '[' . $rVal . '!]' : '';
2424  }
2425  }
2426  $l = implode(', ', $lA);
2427  }
2428  }
2429  if (empty($l) && !empty($value)) {
2430  // Use plain database value when label is empty
2431  $l = $value;
2432  }
2433  }
2434  break;
2435  case 'group':
2436  // resolve the titles for DB records
2437  if ($theColConf['internal_type'] === 'db') {
2438  if ($theColConf['MM']) {
2439  if ($uid) {
2440  // Display the title of MM related records in lists
2441  if ($noRecordLookup) {
2442  $MMfield = $theColConf['foreign_table'] . '.uid';
2443  } else {
2444  $MMfields = [$theColConf['foreign_table'] . '.' . $GLOBALS['TCA'][$theColConf['foreign_table']]['ctrl']['label']];
2445  $altLabelFields = explode(',', $GLOBALS['TCA'][$theColConf['foreign_table']]['ctrl']['label_alt']);
2446  foreach ($altLabelFields as $f) {
2447  $f = trim($f);
2448  if ($f !== '') {
2449  $MMfields[] = $theColConf['foreign_table'] . '.' . $f;
2450  }
2451  }
2452  $MMfield = implode(',', $MMfields);
2453  }
2455  $dbGroup = GeneralUtility::makeInstance(RelationHandler::class);
2456  $dbGroup->start($value, $theColConf['foreign_table'], $theColConf['MM'], $uid, $table, $theColConf);
2457  $selectUids = $dbGroup->tableArray[$theColConf['foreign_table']];
2458  if (!empty($selectUids) && is_array($selectUids)) {
2459  $MMres = $db->exec_SELECTquery(
2460  'uid, ' . $MMfield,
2461  $theColConf['foreign_table'],
2462  'uid IN (' . implode(',', $selectUids) . ')' . static::deleteClause($theColConf['foreign_table'])
2463  );
2464  $mmlA = [];
2465  while ($MMrow = $db->sql_fetch_assoc($MMres)) {
2466  // Keep sorting of $selectUids
2467  $mmlA[array_search($MMrow['uid'], $selectUids)] = $noRecordLookup
2468  ? $MMrow['uid']
2469  : static::getRecordTitle($theColConf['foreign_table'], $MMrow, false, $forceResult);
2470  }
2471  $db->sql_free_result($MMres);
2472  if (!empty($mmlA)) {
2473  ksort($mmlA);
2474  $l = implode('; ', $mmlA);
2475  } else {
2476  $l = 'N/A';
2477  }
2478  } else {
2479  $l = 'N/A';
2480  }
2481  } else {
2482  $l = 'N/A';
2483  }
2484  } else {
2485  $finalValues = [];
2486  $relationTableName = $theColConf['allowed'];
2487  $explodedValues = GeneralUtility::trimExplode(',', $value, true);
2488 
2489  foreach ($explodedValues as $explodedValue) {
2490  if (MathUtility::canBeInterpretedAsInteger($explodedValue)) {
2491  $relationTableNameForField = $relationTableName;
2492  } else {
2493  list($relationTableNameForField, $explodedValue) = self::splitTable_Uid($explodedValue);
2494  }
2495 
2496  $relationRecord = static::getRecordWSOL($relationTableNameForField, $explodedValue);
2497  $finalValues[] = static::getRecordTitle($relationTableNameForField, $relationRecord);
2498  }
2499  $l = implode(', ', $finalValues);
2500  }
2501  } else {
2502  $l = implode(', ', GeneralUtility::trimExplode(',', $value, true));
2503  }
2504  break;
2505  case 'check':
2506  if (!is_array($theColConf['items']) || count($theColConf['items']) === 1) {
2507  $l = $value ? $lang->sL('LLL:EXT:lang/locallang_common.xlf:yes') : $lang->sL('LLL:EXT:lang/locallang_common.xlf:no');
2508  } else {
2509  $lA = [];
2510  foreach ($theColConf['items'] as $key => $val) {
2511  if ($value & pow(2, $key)) {
2512  $lA[] = $lang->sL($val[0]);
2513  }
2514  }
2515  $l = implode(', ', $lA);
2516  }
2517  break;
2518  case 'input':
2519  // Hide value 0 for dates, but show it for everything else
2520  if (isset($value)) {
2521  if (GeneralUtility::inList($theColConf['eval'], 'date')) {
2522  // Handle native date field
2523  if (isset($theColConf['dbType']) && $theColConf['dbType'] === 'date') {
2524  $dateTimeFormats = $db->getDateTimeFormats($table);
2525  $emptyValue = $dateTimeFormats['date']['empty'];
2526  $value = $value !== $emptyValue ? strtotime($value) : 0;
2527  }
2528  if (!empty($value)) {
2529  $ageSuffix = '';
2530  $dateColumnConfiguration = $GLOBALS['TCA'][$table]['columns'][$col]['config'];
2531  $ageDisplayKey = 'disableAgeDisplay';
2532 
2533  // generate age suffix as long as not explicitly suppressed
2534  if (!isset($dateColumnConfiguration[$ageDisplayKey])
2535  // non typesafe comparison on intention
2536  || $dateColumnConfiguration[$ageDisplayKey] == false) {
2537  $ageSuffix = ' (' . ($GLOBALS['EXEC_TIME'] - $value > 0 ? '-' : '') . self::calcAge(abs(($GLOBALS['EXEC_TIME'] - $value)), $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')) . ')';
2538  }
2539 
2540  $l = self::date($value) . $ageSuffix;
2541  }
2542  } elseif (GeneralUtility::inList($theColConf['eval'], 'time')) {
2543  if (!empty($value)) {
2544  $l = self::time($value, false);
2545  }
2546  } elseif (GeneralUtility::inList($theColConf['eval'], 'timesec')) {
2547  if (!empty($value)) {
2548  $l = self::time($value);
2549  }
2550  } elseif (GeneralUtility::inList($theColConf['eval'], 'datetime')) {
2551  // Handle native date/time field
2552  if (isset($theColConf['dbType']) && $theColConf['dbType'] === 'datetime') {
2553  $dateTimeFormats = $db->getDateTimeFormats($table);
2554  $emptyValue = $dateTimeFormats['datetime']['empty'];
2555  $value = $value !== $emptyValue ? strtotime($value) : 0;
2556  }
2557  if (!empty($value)) {
2558  $l = self::datetime($value);
2559  }
2560  } else {
2561  $l = $value;
2562  }
2563  }
2564  break;
2565  case 'flex':
2566  $l = strip_tags($value);
2567  break;
2568  default:
2569  if ($defaultPassthrough) {
2570  $l = $value;
2571  } elseif ($theColConf['MM']) {
2572  $l = 'N/A';
2573  } elseif ($value) {
2574  $l = GeneralUtility::fixed_lgd_cs(strip_tags($value), 200);
2575  }
2576  }
2577  // If this field is a password field, then hide the password by changing it to a random number of asterisk (*)
2578  if (stristr($theColConf['eval'], 'password')) {
2579  $l = '';
2580  $randomNumber = rand(5, 12);
2581  for ($i = 0; $i < $randomNumber; $i++) {
2582  $l .= '*';
2583  }
2584  }
2585  /*****************
2586  *HOOK: post-processing the human readable output from a record
2587  ****************/
2588  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['postProcessValue'])) {
2589  // Create NULL-reference
2590  $null = null;
2591  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['postProcessValue'] as $_funcRef) {
2592  $params = [
2593  'value' => $l,
2594  'colConf' => $theColConf
2595  ];
2596  $l = GeneralUtility::callUserFunction($_funcRef, $params, $null);
2597  }
2598  }
2599  if ($fixed_lgd_chars) {
2600  return GeneralUtility::fixed_lgd_cs($l, $fixed_lgd_chars);
2601  } else {
2602  return $l;
2603  }
2604  }
2605 
2619  public static function getProcessedValueExtra($table, $fN, $fV, $fixed_lgd_chars = 0, $uid = 0, $forceResult = true, $pid = 0)
2620  {
2621  $fVnew = self::getProcessedValue($table, $fN, $fV, $fixed_lgd_chars, 1, 0, $uid, $forceResult, $pid);
2622  if (!isset($fVnew)) {
2623  if (is_array($GLOBALS['TCA'][$table])) {
2624  if ($fN == $GLOBALS['TCA'][$table]['ctrl']['tstamp'] || $fN == $GLOBALS['TCA'][$table]['ctrl']['crdate']) {
2625  $fVnew = self::datetime($fV);
2626  } elseif ($fN == 'pid') {
2627  // Fetches the path with no regard to the users permissions to select pages.
2628  $fVnew = self::getRecordPath($fV, '1=1', 20);
2629  } else {
2630  $fVnew = $fV;
2631  }
2632  }
2633  }
2634  return $fVnew;
2635  }
2636 
2647  public static function getCommonSelectFields($table, $prefix = '', $fields = [])
2648  {
2649  $fields[] = $prefix . 'uid';
2650  if (isset($GLOBALS['TCA'][$table]['ctrl']['label']) && $GLOBALS['TCA'][$table]['ctrl']['label'] != '') {
2651  $fields[] = $prefix . $GLOBALS['TCA'][$table]['ctrl']['label'];
2652  }
2653  if ($GLOBALS['TCA'][$table]['ctrl']['label_alt']) {
2654  $secondFields = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['label_alt'], true);
2655  foreach ($secondFields as $fieldN) {
2656  $fields[] = $prefix . $fieldN;
2657  }
2658  }
2659  if (static::isTableWorkspaceEnabled($table)) {
2660  $fields[] = $prefix . 't3ver_id';
2661  $fields[] = $prefix . 't3ver_state';
2662  $fields[] = $prefix . 't3ver_wsid';
2663  $fields[] = $prefix . 't3ver_count';
2664  }
2665  if ($GLOBALS['TCA'][$table]['ctrl']['selicon_field']) {
2666  $fields[] = $prefix . $GLOBALS['TCA'][$table]['ctrl']['selicon_field'];
2667  }
2668  if ($GLOBALS['TCA'][$table]['ctrl']['typeicon_column']) {
2669  $fields[] = $prefix . $GLOBALS['TCA'][$table]['ctrl']['typeicon_column'];
2670  }
2671  if (is_array($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'])) {
2672  if ($GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']) {
2673  $fields[] = $prefix . $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
2674  }
2675  if ($GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['starttime']) {
2676  $fields[] = $prefix . $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['starttime'];
2677  }
2678  if ($GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['endtime']) {
2679  $fields[] = $prefix . $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['endtime'];
2680  }
2681  if ($GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['fe_group']) {
2682  $fields[] = $prefix . $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['fe_group'];
2683  }
2684  }
2685  return implode(',', array_unique($fields));
2686  }
2687 
2700  public static function makeConfigForm($configArray, $defaults, $dataPrefix)
2701  {
2702  $params = $defaults;
2703  $lines = [];
2704  if (is_array($configArray)) {
2705  foreach ($configArray as $fname => $config) {
2706  if (is_array($config)) {
2707  $lines[$fname] = '<strong>' . htmlspecialchars($config[1]) . '</strong><br />';
2708  $lines[$fname] .= $config[2] . '<br />';
2709  switch ($config[0]) {
2710  case 'string':
2711 
2712  case 'short':
2713  $formEl = '<input type="text" name="' . $dataPrefix . '[' . $fname . ']" value="' . $params[$fname] . '"' . static::getDocumentTemplate()->formWidth(($config[0] == 'short' ? 24 : 48)) . ' />';
2714  break;
2715  case 'check':
2716  $formEl = '<input type="hidden" name="' . $dataPrefix . '[' . $fname . ']" value="0" /><input type="checkbox" name="' . $dataPrefix . '[' . $fname . ']" value="1"' . ($params[$fname] ? ' checked="checked"' : '') . ' />';
2717  break;
2718  case 'comment':
2719  $formEl = '';
2720  break;
2721  case 'select':
2722  $opt = [];
2723  foreach ($config[3] as $k => $v) {
2724  $opt[] = '<option value="' . htmlspecialchars($k) . '"' . ($params[$fname] == $k ? ' selected="selected"' : '') . '>' . htmlspecialchars($v) . '</option>';
2725  }
2726  $formEl = '<select name="' . $dataPrefix . '[' . $fname . ']">' . implode('', $opt) . '</select>';
2727  break;
2728  default:
2729  $formEl = '<strong>Should not happen. Bug in config.</strong>';
2730  }
2731  $lines[$fname] .= $formEl;
2732  $lines[$fname] .= '<br /><br />';
2733  } else {
2734  $lines[$fname] = '<hr />';
2735  if ($config) {
2736  $lines[$fname] .= '<strong>' . strtoupper(htmlspecialchars($config)) . '</strong><br />';
2737  }
2738  if ($config) {
2739  $lines[$fname] .= '<br />';
2740  }
2741  }
2742  }
2743  }
2744  $out = implode('', $lines);
2745  $out .= '<input class="btn btn-default" type="submit" name="submit" value="Update configuration" />';
2746  return $out;
2747  }
2748 
2749  /*******************************************
2750  *
2751  * Backend Modules API functions
2752  *
2753  *******************************************/
2770  public static function helpTextIcon($table, $field, $_ = '', $force = false)
2771  {
2773  if (is_array($GLOBALS['TCA_DESCR'][$table]) && is_array($GLOBALS['TCA_DESCR'][$table]['columns'][$field])) {
2774  return self::wrapInHelp($table, $field);
2775  }
2776  return '';
2777  }
2778 
2786  public static function helpTextArray($table, $field)
2787  {
2788  if (!isset($GLOBALS['TCA_DESCR'][$table]['columns'])) {
2789  static::getLanguageService()->loadSingleTableDescription($table);
2790  }
2791  $output = [
2792  'description' => null,
2793  'title' => null,
2794  'moreInfo' => false
2795  ];
2796  if (is_array($GLOBALS['TCA_DESCR'][$table]) && is_array($GLOBALS['TCA_DESCR'][$table]['columns'][$field])) {
2797  $data = $GLOBALS['TCA_DESCR'][$table]['columns'][$field];
2798  // Add alternative title, if defined
2799  if ($data['alttitle']) {
2800  $output['title'] = $data['alttitle'];
2801  }
2802  // If we have more information to show and access to the cshmanual
2803  if (($data['image_descr'] || $data['seeAlso'] || $data['details'] || $data['syntax'])
2804  && static::getBackendUserAuthentication()->check('modules', 'help_CshmanualCshmanual')
2805  ) {
2806  $output['moreInfo'] = true;
2807  }
2808  // Add description
2809  if ($data['description']) {
2810  $output['description'] = $data['description'];
2811  }
2812  }
2813  return $output;
2814  }
2815 
2824  public static function helpText($table, $field)
2825  {
2826  $helpTextArray = self::helpTextArray($table, $field);
2827  $output = '';
2828  $arrow = '';
2829  // Put header before the rest of the text
2830  if ($helpTextArray['title'] !== null) {
2831  $output .= '<h2 class="t3-row-header">' . $helpTextArray['title'] . '</h2>';
2832  }
2833  // Add see also arrow if we have more info
2834  if ($helpTextArray['moreInfo']) {
2836  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
2837  $arrow = $iconFactory->getIcon('actions-view-go-forward', Icon::SIZE_SMALL)->render();
2838  }
2839  // Wrap description and arrow in p tag
2840  if ($helpTextArray['description'] !== null || $arrow) {
2841  $output .= '<p class="t3-help-short">' . nl2br(htmlspecialchars($helpTextArray['description'])) . $arrow . '</p>';
2842  }
2843  return $output;
2844  }
2845 
2858  public static function wrapInHelp($table, $field, $text = '', array $overloadHelpText = [])
2859  {
2860  if (!ExtensionManagementUtility::isLoaded('context_help')) {
2861  return $text;
2862  }
2863 
2864  // Initialize some variables
2865  $helpText = '';
2866  $abbrClassAdd = '';
2867  $wrappedText = $text;
2868  $hasHelpTextOverload = !empty($overloadHelpText);
2869  // Get the help text that should be shown on hover
2870  if (!$hasHelpTextOverload) {
2871  $helpText = self::helpText($table, $field);
2872  }
2873  // If there's a help text or some overload information, proceed with preparing an output
2874  // @todo: right now this is a hard dependency on csh manual, as the whole help system should be moved to
2875  // the extension. The core provides an API for adding help and rendering help, but the rendering
2876  // should be up to the extension itself
2877  if ((!empty($helpText) || $hasHelpTextOverload) && ExtensionManagementUtility::isLoaded('cshmanual')) {
2878  // If no text was given, just use the regular help icon
2879  if ($text == '') {
2881  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
2882  $text = $iconFactory->getIcon('actions-system-help-open', Icon::SIZE_SMALL)->render();
2883  $abbrClassAdd = '-icon';
2884  }
2885  $text = '<abbr class="t3-help-teaser' . $abbrClassAdd . '">' . $text . '</abbr>';
2886  $wrappedText = '<span class="t3-help-link" href="#" data-table="' . $table . '" data-field="' . $field . '"';
2887  // The overload array may provide a title and a description
2888  // If either one is defined, add them to the "data" attributes
2889  if ($hasHelpTextOverload) {
2890  if (isset($overloadHelpText['title'])) {
2891  $wrappedText .= ' data-title="' . htmlspecialchars($overloadHelpText['title']) . '"';
2892  }
2893  if (isset($overloadHelpText['description'])) {
2894  $wrappedText .= ' data-description="' . htmlspecialchars($overloadHelpText['description']) . '"';
2895  }
2896  }
2897  $wrappedText .= '>' . $text . '</span>';
2898  return $wrappedText;
2899  }
2900  return $text;
2901  }
2902 
2914  public static function cshItem($table, $field, $_ = '', $wrap = '')
2915  {
2916  static::getLanguageService()->loadSingleTableDescription($table);
2917  if (is_array($GLOBALS['TCA_DESCR'][$table])
2918  && is_array($GLOBALS['TCA_DESCR'][$table]['columns'][$field])) {
2919  // Creating short description
2920  $output = self::wrapInHelp($table, $field);
2921  if ($output && $wrap) {
2922  $wrParts = explode('|', $wrap);
2923  $output = $wrParts[0] . $output . $wrParts[1];
2924  }
2925  return $output;
2926  }
2927  return '';
2928  }
2929 
2940  public static function editOnClick($params, $_ = '', $requestUri = '')
2941  {
2942  if ($requestUri == -1) {
2943  $returnUrl = 'T3_THIS_LOCATION';
2944  } else {
2945  $returnUrl = GeneralUtility::quoteJSvalue(rawurlencode($requestUri ?: GeneralUtility::getIndpEnv('REQUEST_URI')));
2946  }
2947  return 'window.location.href=' . GeneralUtility::quoteJSvalue(self::getModuleUrl('record_edit') . $params . '&returnUrl=') . '+' . $returnUrl . '; return false;';
2948  }
2949 
2964  public static function viewOnClick($pageUid, $backPath = '', $rootLine = null, $anchorSection = '', $alternativeUrl = '', $additionalGetVars = '', $switchFocus = true)
2965  {
2966  $viewScript = '/index.php?id=';
2967  if ($alternativeUrl) {
2968  $viewScript = $alternativeUrl;
2969  }
2970 
2971  if (
2972  isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['viewOnClickClass'])
2973  && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['viewOnClickClass'])
2974  ) {
2975  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['viewOnClickClass'] as $funcRef) {
2976  $hookObj = GeneralUtility::getUserObj($funcRef);
2977  if (method_exists($hookObj, 'preProcess')) {
2978  $hookObj->preProcess($pageUid, $backPath, $rootLine, $anchorSection, $viewScript, $additionalGetVars, $switchFocus);
2979  }
2980  }
2981  }
2982 
2983  if ($alternativeUrl) {
2984  $previewUrl = $viewScript;
2985  } else {
2986  $previewUrl = self::createPreviewUrl($pageUid, $rootLine, $anchorSection, $additionalGetVars, $viewScript);
2987  }
2988 
2989  $onclickCode = 'var previewWin = window.open(' . GeneralUtility::quoteJSvalue($previewUrl) . ',\'newTYPO3frontendWindow\');' . ($switchFocus ? 'previewWin.focus();' : '');
2990  return $onclickCode;
2991  }
2992 
3019  public static function wrapClickMenuOnIcon(
3020  $content,
3021  $table,
3022  $uid = 0,
3023  $listFrame = true,
3024  $addParams = '',
3025  $enDisItems = '',
3026  $returnTagParameters = false
3027  ) {
3028  $tagParameters = [
3029  'class' => 't3-js-clickmenutrigger',
3030  'data-table' => $table,
3031  'data-uid' => (int)$uid !== 0 ? (int)$uid : '',
3032  'data-listframe' => $listFrame,
3033  'data-iteminfo' => str_replace('+', '%2B', $enDisItems),
3034  'data-parameters' => $addParams,
3035  ];
3036 
3037  if ($returnTagParameters) {
3038  return $tagParameters;
3039  }
3040  return '<a href="#" ' . GeneralUtility::implodeAttributes($tagParameters, true) . '>' . $content . '</a>';
3041  }
3042 
3050  public static function getLinkToDataHandlerAction($parameters, $redirectUrl = '')
3051  {
3052  $urlParameters = [
3053  'prErr' => 1,
3054  'uPT' => 1,
3055  'vC' => static::getBackendUserAuthentication()->veriCode()
3056  ];
3057  $url = self::getModuleUrl('tce_db', $urlParameters) . $parameters . '&redirect=';
3058  if ((int)$redirectUrl === -1) {
3059  $url = GeneralUtility::quoteJSvalue($url) . '+T3_THIS_LOCATION';
3060  } else {
3061  $url .= rawurlencode($redirectUrl ?: GeneralUtility::getIndpEnv('REQUEST_URI'));
3062  }
3063  return $url;
3064  }
3065 
3077  protected static function createPreviewUrl($pageUid, $rootLine, $anchorSection, $additionalGetVars, $viewScript)
3078  {
3079  // Look if a fixed preview language should be added:
3080  $beUser = static::getBackendUserAuthentication();
3081  $viewLanguageOrder = $beUser->getTSConfigVal('options.view.languageOrder');
3082 
3083  if ((string)$viewLanguageOrder !== '') {
3084  $suffix = '';
3085  // Find allowed languages (if none, all are allowed!)
3086  $allowedLanguages = null;
3087  if (!$beUser->user['admin'] && $beUser->groupData['allowed_languages'] !== '') {
3088  $allowedLanguages = array_flip(explode(',', $beUser->groupData['allowed_languages']));
3089  }
3090  // Traverse the view order, match first occurrence:
3091  $languageOrder = GeneralUtility::intExplode(',', $viewLanguageOrder);
3092  foreach ($languageOrder as $langUid) {
3093  if (is_array($allowedLanguages) && !empty($allowedLanguages)) {
3094  // Choose if set.
3095  if (isset($allowedLanguages[$langUid])) {
3096  $suffix = '&L=' . $langUid;
3097  break;
3098  }
3099  } else {
3100  // All allowed since no lang. are listed.
3101  $suffix = '&L=' . $langUid;
3102  break;
3103  }
3104  }
3105  // Add it
3106  $additionalGetVars .= $suffix;
3107  }
3108 
3109  // Check a mount point needs to be previewed
3110  $sys_page = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Page\PageRepository::class);
3111  $sys_page->init(false);
3112  $mountPointInfo = $sys_page->getMountPointInfo($pageUid);
3113 
3114  if ($mountPointInfo && $mountPointInfo['overlay']) {
3115  $pageUid = $mountPointInfo['mount_pid'];
3116  $additionalGetVars .= '&MP=' . $mountPointInfo['MPvar'];
3117  }
3118  $viewDomain = self::getViewDomain($pageUid, $rootLine);
3119 
3120  return $viewDomain . $viewScript . $pageUid . $additionalGetVars . $anchorSection;
3121  }
3122 
3131  public static function getViewDomain($pageId, $rootLine = null)
3132  {
3133  $domain = rtrim(GeneralUtility::getIndpEnv('TYPO3_SITE_URL'), '/');
3134  if (!is_array($rootLine)) {
3135  $rootLine = self::BEgetRootLine($pageId);
3136  }
3137  // Checks alternate domains
3138  if (!empty($rootLine)) {
3139  $urlParts = parse_url($domain);
3141  $sysPage = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Page\PageRepository::class);
3142  $page = (array)$sysPage->getPage($pageId);
3143  $protocol = 'http';
3144  if ($page['url_scheme'] == HttpUtility::SCHEME_HTTPS || $page['url_scheme'] == 0 && GeneralUtility::getIndpEnv('TYPO3_SSL')) {
3145  $protocol = 'https';
3146  }
3147  $previewDomainConfig = static::getBackendUserAuthentication()->getTSConfig('TCEMAIN.previewDomain', self::getPagesTSconfig($pageId));
3148  if ($previewDomainConfig['value']) {
3149  if (strpos($previewDomainConfig['value'], '://') !== false) {
3150  list($protocol, $domainName) = explode('://', $previewDomainConfig['value']);
3151  } else {
3152  $domainName = $previewDomainConfig['value'];
3153  }
3154  } else {
3155  $domainName = self::firstDomainRecord($rootLine);
3156  }
3157  if ($domainName) {
3158  $domain = $domainName;
3159  } else {
3160  $domainRecord = self::getDomainStartPage($urlParts['host'], $urlParts['path']);
3161  $domain = $domainRecord['domainName'];
3162  }
3163  if ($domain) {
3164  $domain = $protocol . '://' . $domain;
3165  } else {
3166  $domain = rtrim(GeneralUtility::getIndpEnv('TYPO3_SITE_URL'), '/');
3167  }
3168  // Append port number if lockSSLPort is not the standard port 443
3169  $portNumber = (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['lockSSLPort'];
3170  if ($portNumber > 0 && $portNumber !== 443 && $portNumber < 65536 && $protocol === 'https') {
3171  $domain .= ':' . strval($portNumber);
3172  }
3173  }
3174  return $domain;
3175  }
3176 
3185  public static function getModTSconfig($id, $TSref)
3186  {
3187  $beUser = static::getBackendUserAuthentication();
3188  $pageTS_modOptions = $beUser->getTSConfig($TSref, static::getPagesTSconfig($id));
3189  $BE_USER_modOptions = $beUser->getTSConfig($TSref);
3190  if (is_null($BE_USER_modOptions['value'])) {
3191  unset($BE_USER_modOptions['value']);
3192  }
3193  ArrayUtility::mergeRecursiveWithOverrule($pageTS_modOptions, $BE_USER_modOptions);
3194  return $pageTS_modOptions;
3195  }
3196 
3210  public static function getFuncMenu($mainParams, $elementName, $currentValue, $menuItems, $script = '', $addParams = '')
3211  {
3212  if (!is_array($menuItems) || count($menuItems) <= 1) {
3213  return '';
3214  }
3215  $scriptUrl = self::buildScriptUrl($mainParams, $addParams, $script);
3216  $options = [];
3217  foreach ($menuItems as $value => $label) {
3218  $options[] = '<option value="' . htmlspecialchars($value) . '"' . ((string)$currentValue === (string)$value ? ' selected="selected"' : '') . '>' . htmlspecialchars($label, ENT_COMPAT, 'UTF-8', false) . '</option>';
3219  }
3220  if (!empty($options)) {
3221  $onChange = 'jumpToUrl(' . GeneralUtility::quoteJSvalue($scriptUrl . '&' . $elementName . '=') . '+this.options[this.selectedIndex].value,this);';
3222  return '
3223 
3224  <!-- Function Menu of module -->
3225  <select name="' . $elementName . '" onchange="' . htmlspecialchars($onChange) . '">
3226  ' . implode('
3227  ', $options) . '
3228  </select>
3229  ';
3230  }
3231  return '';
3232  }
3233 
3248  public static function getDropdownMenu($mainParams, $elementName, $currentValue, $menuItems, $script = '', $addParams = '')
3249  {
3250  if (!is_array($menuItems) || count($menuItems) <= 1) {
3251  return '';
3252  }
3253  $scriptUrl = self::buildScriptUrl($mainParams, $addParams, $script);
3254  $options = [];
3255  foreach ($menuItems as $value => $label) {
3256  $options[] = '<option value="' . htmlspecialchars($value) . '"' . ((string)$currentValue === (string)$value ? ' selected="selected"' : '') . '>' . htmlspecialchars($label, ENT_COMPAT, 'UTF-8', false) . '</option>';
3257  }
3258  if (!empty($options)) {
3259  $onChange = 'jumpToUrl(' . GeneralUtility::quoteJSvalue($scriptUrl . '&' . $elementName . '=') . '+this.options[this.selectedIndex].value,this);';
3260  return '
3261  <div class="form-group">
3262  <!-- Function Menu of module -->
3263  <select class="form-control input-sm" name="' . htmlspecialchars($elementName) . '" onchange="' . htmlspecialchars($onChange) . '">
3264  ' . implode(LF, $options) . '
3265  </select>
3266  </div>
3267  ';
3268  }
3269  return '';
3270  }
3271 
3285  public static function getFuncCheck($mainParams, $elementName, $currentValue, $script = '', $addParams = '', $tagParams = '')
3286  {
3287  $scriptUrl = self::buildScriptUrl($mainParams, $addParams, $script);
3288  $onClick = 'jumpToUrl(' . GeneralUtility::quoteJSvalue($scriptUrl . '&' . $elementName . '=') . '+(this.checked?1:0),this);';
3289 
3290  return
3291  '<input' .
3292  ' type="checkbox"' .
3293  ' class="checkbox"' .
3294  ' name="' . $elementName . '"' .
3295  ($currentValue ? ' checked="checked"' : '') .
3296  ' onclick="' . htmlspecialchars($onClick) . '"' .
3297  ($tagParams ? ' ' . $tagParams : '') .
3298  ' value="1"' .
3299  ' />';
3300  }
3301 
3315  public static function getFuncInput($mainParams, $elementName, $currentValue, $size = 10, $script = '', $addParams = '')
3316  {
3317  $scriptUrl = self::buildScriptUrl($mainParams, $addParams, $script);
3318  $onChange = 'jumpToUrl(' . GeneralUtility::quoteJSvalue($scriptUrl . '&' . $elementName . '=') . '+escape(this.value),this);';
3319  return '<input type="text"' . static::getDocumentTemplate()->formWidth($size) . ' name="' . $elementName . '" value="' . htmlspecialchars($currentValue) . '" onchange="' . htmlspecialchars($onChange) . '" />';
3320  }
3321 
3330  protected static function buildScriptUrl($mainParams, $addParams, $script = '')
3331  {
3332  if (!is_array($mainParams)) {
3333  $mainParams = ['id' => $mainParams];
3334  }
3335  if (!$script) {
3336  $script = basename(PATH_thisScript);
3337  }
3338 
3339  if (GeneralUtility::_GP('route')) {
3340  $router = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\Router::class);
3341  $route = $router->match(GeneralUtility::_GP('route'));
3342  $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
3343  $scriptUrl = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier'));
3344  $scriptUrl .= $addParams;
3345  } elseif ($script === 'index.php' && GeneralUtility::_GET('M')) {
3346  $scriptUrl = self::getModuleUrl(GeneralUtility::_GET('M'), $mainParams) . $addParams;
3347  } else {
3348  $scriptUrl = $script . '?' . GeneralUtility::implodeArrayForUrl('', $mainParams) . $addParams;
3349  }
3350 
3351  return $scriptUrl;
3352  }
3353 
3363  public static function unsetMenuItems($modTSconfig, $itemArray, $TSref)
3364  {
3365  // Getting TS-config options for this module for the Backend User:
3366  $conf = static::getBackendUserAuthentication()->getTSConfig($TSref, $modTSconfig);
3367  if (is_array($conf['properties'])) {
3368  foreach ($conf['properties'] as $key => $val) {
3369  if (!$val) {
3370  unset($itemArray[$key]);
3371  }
3372  }
3373  }
3374  return $itemArray;
3375  }
3376 
3386  public static function setUpdateSignal($set = '', $params = '')
3387  {
3388  $beUser = static::getBackendUserAuthentication();
3389  $modData = $beUser->getModuleData(\TYPO3\CMS\Backend\Utility\BackendUtility::class . '::getUpdateSignal', 'ses');
3390  if ($set) {
3391  $modData[$set] = [
3392  'set' => $set,
3393  'parameter' => $params
3394  ];
3395  } else {
3396  // clear the module data
3397  $modData = [];
3398  }
3399  $beUser->pushModuleData(\TYPO3\CMS\Backend\Utility\BackendUtility::class . '::getUpdateSignal', $modData);
3400  }
3401 
3410  public static function getUpdateSignalCode()
3411  {
3412  $signals = [];
3413  $modData = static::getBackendUserAuthentication()->getModuleData(\TYPO3\CMS\Backend\Utility\BackendUtility::class . '::getUpdateSignal', 'ses');
3414  if (empty($modData)) {
3415  return '';
3416  }
3417  // Hook: Allows to let TYPO3 execute your JS code
3418  if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['updateSignalHook'])) {
3419  $updateSignals = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['updateSignalHook'];
3420  } else {
3421  $updateSignals = [];
3422  }
3423  // Loop through all setUpdateSignals and get the JS code
3424  foreach ($modData as $set => $val) {
3425  if (isset($updateSignals[$set])) {
3426  $params = ['set' => $set, 'parameter' => $val['parameter'], 'JScode' => ''];
3427  $ref = null;
3428  GeneralUtility::callUserFunction($updateSignals[$set], $params, $ref);
3429  $signals[] = $params['JScode'];
3430  } else {
3431  switch ($set) {
3432  case 'updatePageTree':
3433  $signals[] = '
3434  if (top && top.TYPO3.Backend.NavigationContainer.PageTree) {
3435  top.TYPO3.Backend.NavigationContainer.PageTree.refreshTree();
3436  }
3437  ';
3438  break;
3439  case 'updateFolderTree':
3440  $signals[] = '
3441  if (top && top.TYPO3.Backend.NavigationIframe) {
3442  top.TYPO3.Backend.NavigationIframe.refresh();
3443  }';
3444  break;
3445  case 'updateModuleMenu':
3446  $signals[] = '
3447  if (top && top.TYPO3.ModuleMenu.App) {
3448  top.TYPO3.ModuleMenu.App.refreshMenu();
3449  }';
3450  }
3451  }
3452  }
3453  $content = implode(LF, $signals);
3454  // For backwards compatibility, should be replaced
3455  self::setUpdateSignal();
3456  return $content;
3457  }
3458 
3473  public static function getModuleData($MOD_MENU, $CHANGED_SETTINGS, $modName, $type = '', $dontValidateList = '', $setDefaultList = '')
3474  {
3475  if ($modName && is_string($modName)) {
3476  // Getting stored user-data from this module:
3477  $beUser = static::getBackendUserAuthentication();
3478  $settings = $beUser->getModuleData($modName, $type);
3479  $changed = 0;
3480  if (!is_array($settings)) {
3481  $changed = 1;
3482  $settings = [];
3483  }
3484  if (is_array($MOD_MENU)) {
3485  foreach ($MOD_MENU as $key => $var) {
3486  // If a global var is set before entering here. eg if submitted, then it's substituting the current value the array.
3487  if (is_array($CHANGED_SETTINGS) && isset($CHANGED_SETTINGS[$key])) {
3488  if (is_array($CHANGED_SETTINGS[$key])) {
3489  $serializedSettings = serialize($CHANGED_SETTINGS[$key]);
3490  if ((string)$settings[$key] !== $serializedSettings) {
3491  $settings[$key] = $serializedSettings;
3492  $changed = 1;
3493  }
3494  } else {
3495  if ((string)$settings[$key] !== (string)$CHANGED_SETTINGS[$key]) {
3496  $settings[$key] = $CHANGED_SETTINGS[$key];
3497  $changed = 1;
3498  }
3499  }
3500  }
3501  // If the $var is an array, which denotes the existence of a menu, we check if the value is permitted
3502  if (is_array($var) && (!$dontValidateList || !GeneralUtility::inList($dontValidateList, $key))) {
3503  // If the setting is an array or not present in the menu-array, MOD_MENU, then the default value is inserted.
3504  if (is_array($settings[$key]) || !isset($MOD_MENU[$key][$settings[$key]])) {
3505  $settings[$key] = (string)key($var);
3506  $changed = 1;
3507  }
3508  }
3509  // Sets default values (only strings/checkboxes, not menus)
3510  if ($setDefaultList && !is_array($var)) {
3511  if (GeneralUtility::inList($setDefaultList, $key) && !isset($settings[$key])) {
3512  $settings[$key] = (string)$var;
3513  }
3514  }
3515  }
3516  } else {
3517  die('No menu!');
3518  }
3519  if ($changed) {
3520  $beUser->pushModuleData($modName, $settings);
3521  }
3522  return $settings;
3523  } else {
3524  die('Wrong module name: "' . $modName . '"');
3525  }
3526  }
3527 
3537  public static function getModuleUrl($moduleName, $urlParameters = [], $backPathOverride = false, $returnAbsoluteUrl = false)
3538  {
3540  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
3541  try {
3542  $uri = $uriBuilder->buildUriFromRoute($moduleName, $urlParameters, $returnAbsoluteUrl ? UriBuilder::ABSOLUTE_URL : UriBuilder::ABSOLUTE_PATH);
3543  } catch (\TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException $e) {
3544  // no route registered, use the fallback logic to check for a module
3545  $uri = $uriBuilder->buildUriFromModule($moduleName, $urlParameters, $returnAbsoluteUrl ? UriBuilder::ABSOLUTE_URL : UriBuilder::ABSOLUTE_PATH);
3546  }
3547  return (string)$uri;
3548  }
3549 
3563  public static function getAjaxUrl($ajaxIdentifier, array $urlParameters = [], $backPathOverride = false, $returnAbsoluteUrl = false)
3564  {
3566  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
3567  try {
3568  $routeIdentifier = 'ajax_' . $ajaxIdentifier;
3569  $uri = $uriBuilder->buildUriFromRoute($routeIdentifier, $urlParameters, $returnAbsoluteUrl ? UriBuilder::ABSOLUTE_URL : UriBuilder::ABSOLUTE_PATH);
3570  } catch (\TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException $e) {
3571  // no route registered, use the fallback logic to check for a module
3572  $uri = $uriBuilder->buildUriFromAjaxId($ajaxIdentifier, $urlParameters, $returnAbsoluteUrl ? UriBuilder::ABSOLUTE_URL : UriBuilder::ABSOLUTE_PATH);
3573  }
3574  return (string)$uri;
3575  }
3576 
3585  public static function getListViewLink($urlParameters = [], $linkTitle = '', $linkText = '')
3586  {
3588  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
3589  return '<a href="' . htmlspecialchars(self::getModuleUrl('web_list', $urlParameters)) . '" title="' . htmlspecialchars($linkTitle) . '">' . $iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL)->render() . htmlspecialchars($linkText) . '</a>';
3590  }
3591 
3601  public static function getUrlToken($formName = 'securityToken', $tokenName = 'formToken')
3602  {
3604  $formProtection = FormProtectionFactory::get();
3605  return '&' . $tokenName . '=' . $formProtection->generateToken($formName);
3606  }
3607 
3608  /*******************************************
3609  *
3610  * Core
3611  *
3612  *******************************************/
3623  public static function lockRecords($table = '', $uid = 0, $pid = 0)
3624  {
3625  $beUser = static::getBackendUserAuthentication();
3626  if (isset($beUser->user['uid'])) {
3627  $user_id = (int)$beUser->user['uid'];
3628  if ($table && $uid) {
3629  $fields_values = [
3630  'userid' => $user_id,
3631  'feuserid' => 0,
3632  'tstamp' => $GLOBALS['EXEC_TIME'],
3633  'record_table' => $table,
3634  'record_uid' => $uid,
3635  'username' => $beUser->user['username'],
3636  'record_pid' => $pid
3637  ];
3638  static::getDatabaseConnection()->exec_INSERTquery('sys_lockedrecords', $fields_values);
3639  } else {
3640  static::getDatabaseConnection()->exec_DELETEquery('sys_lockedrecords', 'userid=' . (int)$user_id);
3641  }
3642  }
3643  }
3644 
3657  public static function isRecordLocked($table, $uid)
3658  {
3659  if (!is_array($GLOBALS['LOCKED_RECORDS'])) {
3660  $GLOBALS['LOCKED_RECORDS'] = [];
3661  $db = static::getDatabaseConnection();
3662  $res = $db->exec_SELECTquery(
3663  '*',
3664  'sys_lockedrecords',
3665  'sys_lockedrecords.userid<>' . (int)static::getBackendUserAuthentication()->user['uid']
3666  . ' AND sys_lockedrecords.tstamp > ' . ($GLOBALS['EXEC_TIME'] - 2 * 3600)
3667  );
3668  while ($row = $db->sql_fetch_assoc($res)) {
3669  // Get the type of the user that locked this record:
3670  if ($row['userid']) {
3671  $userTypeLabel = 'beUser';
3672  } elseif ($row['feuserid']) {
3673  $userTypeLabel = 'feUser';
3674  } else {
3675  $userTypeLabel = 'user';
3676  }
3677  $lang = static::getLanguageService();
3678  $userType = $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.' . $userTypeLabel);
3679  // Get the username (if available):
3680  if ($row['username']) {
3681  $userName = $row['username'];
3682  } else {
3683  $userName = $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.unknownUser');
3684  }
3685  $GLOBALS['LOCKED_RECORDS'][$row['record_table'] . ':' . $row['record_uid']] = $row;
3686  $GLOBALS['LOCKED_RECORDS'][$row['record_table'] . ':' . $row['record_uid']]['msg'] = sprintf(
3687  $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.lockedRecordUser'),
3688  $userType,
3689  $userName,
3690  self::calcAge($GLOBALS['EXEC_TIME'] - $row['tstamp'], $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears'))
3691  );
3692  if ($row['record_pid'] && !isset($GLOBALS['LOCKED_RECORDS'][$row['record_table'] . ':' . $row['record_pid']])) {
3693  $GLOBALS['LOCKED_RECORDS']['pages:' . $row['record_pid']]['msg'] = sprintf(
3694  $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.lockedRecordUser_content'),
3695  $userType,
3696  $userName,
3697  self::calcAge($GLOBALS['EXEC_TIME'] - $row['tstamp'], $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears'))
3698  );
3699  }
3700  }
3701  $db->sql_free_result($res);
3702  }
3703  return $GLOBALS['LOCKED_RECORDS'][$table . ':' . $uid];
3704  }
3705 
3716  public static function exec_foreign_table_where_query($fieldConfig, $field = '', $TSconfig = [])
3717  {
3719  $foreign_table = $fieldConfig['config']['foreign_table'];
3720  $rootLevel = $GLOBALS['TCA'][$foreign_table]['ctrl']['rootLevel'];
3721  $fTWHERE = $fieldConfig['config']['foreign_table_where'];
3722  $fTWHERE = static::replaceMarkersInWhereClause($fTWHERE, $foreign_table, $field, $TSconfig);
3723  $db = static::getDatabaseConnection();
3724  $wgolParts = $db->splitGroupOrderLimit($fTWHERE);
3725  // rootLevel = -1 means that elements can be on the rootlevel OR on any page (pid!=-1)
3726  // rootLevel = 0 means that elements are not allowed on root level
3727  // rootLevel = 1 means that elements are only on the root level (pid=0)
3728  if ($rootLevel == 1 || $rootLevel == -1) {
3729  $pidWhere = $foreign_table . '.pid' . (($rootLevel == -1) ? '<>-1' : '=0');
3730  $queryParts = [
3731  'SELECT' => self::getCommonSelectFields($foreign_table, $foreign_table . '.'),
3732  'FROM' => $foreign_table,
3733  'WHERE' => $pidWhere . ' ' . self::deleteClause($foreign_table) . ' ' . $wgolParts['WHERE'],
3734  'GROUPBY' => $wgolParts['GROUPBY'],
3735  'ORDERBY' => $wgolParts['ORDERBY'],
3736  'LIMIT' => $wgolParts['LIMIT']
3737  ];
3738  } else {
3739  $pageClause = static::getBackendUserAuthentication()->getPagePermsClause(1);
3740  if ($foreign_table != 'pages') {
3741  $queryParts = [
3742  'SELECT' => self::getCommonSelectFields($foreign_table, $foreign_table . '.'),
3743  'FROM' => $foreign_table . ', pages',
3744  'WHERE' => 'pages.uid=' . $foreign_table . '.pid
3745  AND pages.deleted=0 ' . self::deleteClause($foreign_table) . ' AND ' . $pageClause . ' ' . $wgolParts['WHERE'],
3746  'GROUPBY' => $wgolParts['GROUPBY'],
3747  'ORDERBY' => $wgolParts['ORDERBY'],
3748  'LIMIT' => $wgolParts['LIMIT']
3749  ];
3750  } else {
3751  $queryParts = [
3752  'SELECT' => self::getCommonSelectFields($foreign_table, $foreign_table . '.'),
3753  'FROM' => 'pages',
3754  'WHERE' => 'pages.deleted=0
3755  AND ' . $pageClause . ' ' . $wgolParts['WHERE'],
3756  'GROUPBY' => $wgolParts['GROUPBY'],
3757  'ORDERBY' => $wgolParts['ORDERBY'],
3758  'LIMIT' => $wgolParts['LIMIT']
3759  ];
3760  }
3761  }
3762  return $db->exec_SELECT_queryArray($queryParts);
3763  }
3764 
3784  public static function replaceMarkersInWhereClause($whereClause, $table, $field = '', $tsConfig = [])
3785  {
3787  $db = static::getDatabaseConnection();
3788  if (strstr($whereClause, '###REC_FIELD_')) {
3789  $whereClauseParts = explode('###REC_FIELD_', $whereClause);
3790  foreach ($whereClauseParts as $key => $value) {
3791  if ($key) {
3792  $whereClauseSubarts = explode('###', $value, 2);
3793  if (substr($whereClauseParts[0], -1) === '\'' && $whereClauseSubarts[1][0] === '\'') {
3794  $whereClauseParts[$key] = $db->quoteStr($tsConfig['_THIS_ROW'][$whereClauseSubarts[0]], $table) . $whereClauseSubarts[1];
3795  } else {
3796  $whereClauseParts[$key] = $db->fullQuoteStr($tsConfig['_THIS_ROW'][$whereClauseSubarts[0]], $table) . $whereClauseSubarts[1];
3797  }
3798  }
3799  }
3800  $whereClause = implode('', $whereClauseParts);
3801  }
3802  return str_replace(
3803  [
3804  '###CURRENT_PID###',
3805  '###THIS_UID###',
3806  '###STORAGE_PID###',
3807  '###SITEROOT###',
3808  '###PAGE_TSCONFIG_ID###',
3809  '###PAGE_TSCONFIG_IDLIST###',
3810  '###PAGE_TSCONFIG_STR###'
3811  ],
3812  [
3813  (int)$tsConfig['_CURRENT_PID'],
3814  (int)$tsConfig['_THIS_UID'],
3815  (int)$tsConfig['_STORAGE_PID'],
3816  (int)$tsConfig['_SITEROOT'],
3817  (int)$tsConfig[$field]['PAGE_TSCONFIG_ID'],
3818  $db->cleanIntList($tsConfig[$field]['PAGE_TSCONFIG_IDLIST']),
3819  $db->quoteStr($tsConfig[$field]['PAGE_TSCONFIG_STR'], $table)
3820  ],
3821  $whereClause
3822  );
3823  }
3824 
3833  public static function getTCEFORM_TSconfig($table, $row)
3834  {
3835  self::fixVersioningPid($table, $row);
3836  $res = [];
3837  $typeVal = self::getTCAtypeValue($table, $row);
3838  // Get main config for the table
3839  list($TScID, $cPid) = self::getTSCpid($table, $row['uid'], $row['pid']);
3840  if ($TScID >= 0) {
3841  $tempConf = static::getBackendUserAuthentication()->getTSConfig('TCEFORM.' . $table, self::getPagesTSconfig($TScID));
3842  if (is_array($tempConf['properties'])) {
3843  foreach ($tempConf['properties'] as $key => $val) {
3844  if (is_array($val)) {
3845  $fieldN = substr($key, 0, -1);
3846  $res[$fieldN] = $val;
3847  unset($res[$fieldN]['types.']);
3848  if ((string)$typeVal !== '' && is_array($val['types.'][$typeVal . '.'])) {
3849  ArrayUtility::mergeRecursiveWithOverrule($res[$fieldN], $val['types.'][$typeVal . '.']);
3850  }
3851  }
3852  }
3853  }
3854  }
3855  $res['_CURRENT_PID'] = $cPid;
3856  $res['_THIS_UID'] = $row['uid'];
3857  // So the row will be passed to foreign_table_where_query()
3858  $res['_THIS_ROW'] = $row;
3859  $rootLine = self::BEgetRootLine($TScID, '', true);
3860  foreach ($rootLine as $rC) {
3861  if (!$res['_STORAGE_PID']) {
3862  $res['_STORAGE_PID'] = (int)$rC['storage_pid'];
3863  }
3864  if (!$res['_SITEROOT']) {
3865  $res['_SITEROOT'] = $rC['is_siteroot'] ? (int)$rC['uid'] : 0;
3866  }
3867  }
3868  return $res;
3869  }
3870 
3884  public static function getTSconfig_pidValue($table, $uid, $pid)
3885  {
3886  // If pid is an integer this takes precedence in our lookup.
3888  $thePidValue = (int)$pid;
3889  // If ref to another record, look that record up.
3890  if ($thePidValue < 0) {
3891  $pidRec = self::getRecord($table, abs($thePidValue), 'pid');
3892  $thePidValue = is_array($pidRec) ? $pidRec['pid'] : -2;
3893  }
3894  } else {
3895  // Try to fetch the record pid from uid. If the uid is 'NEW...' then this will of course return nothing
3896  $rr = self::getRecord($table, $uid);
3897  $thePidValue = null;
3898  if (is_array($rr)) {
3899  // First check if the pid is -1 which means it is a workspaced element. Get the "real" record:
3900  if ($rr['pid'] == '-1') {
3901  $rr = self::getRecord($table, $rr['t3ver_oid'], 'pid');
3902  if (is_array($rr)) {
3903  $thePidValue = $rr['pid'];
3904  }
3905  } else {
3906  // Returning the "pid" of the record
3907  $thePidValue = $rr['pid'];
3908  }
3909  }
3910  if (!$thePidValue) {
3911  // Returns -1 if the record with this pid was not found.
3912  $thePidValue = -1;
3913  }
3914  }
3915  return $thePidValue;
3916  }
3917 
3927  public static function getPidForModTSconfig($table, $uid, $pid)
3928  {
3929  return $table === 'pages' && MathUtility::canBeInterpretedAsInteger($uid) ? $uid : $pid;
3930  }
3931 
3944  public static function getTSCpidCached($table, $uid, $pid)
3945  {
3946  // A local first level cache
3947  static $firstLevelCache;
3948 
3949  if (!is_array($firstLevelCache)) {
3950  $firstLevelCache = [];
3951  }
3952 
3953  $key = $table . ':' . $uid . ':' . $pid;
3954  if (!isset($firstLevelCache[$key])) {
3955  $firstLevelCache[$key] = static::getTSCpid($table, $uid, $pid);
3956  }
3957  return $firstLevelCache[$key];
3958  }
3959 
3971  public static function getTSCpid($table, $uid, $pid)
3972  {
3973  // If pid is negative (referring to another record) the pid of the other record is fetched and returned.
3974  $cPid = self::getTSconfig_pidValue($table, $uid, $pid);
3975  // $TScID is the id of $table = pages, else it's the pid of the record.
3976  $TScID = self::getPidForModTSconfig($table, $uid, $cPid);
3977  return [$TScID, $cPid];
3978  }
3979 
3986  public static function firstDomainRecord($rootLine)
3987  {
3988  foreach ($rootLine as $row) {
3989  $dRec = self::getRecordsByField('sys_domain', 'pid', $row['uid'], ' AND redirectTo=\'\' AND hidden=0', '', 'sorting');
3990  if (is_array($dRec)) {
3991  $dRecord = reset($dRec);
3992  return rtrim($dRecord['domainName'], '/');
3993  }
3994  }
3995  return null;
3996  }
3997 
4005  public static function getDomainStartPage($domain, $path = '')
4006  {
4007  $domain = explode(':', $domain);
4008  $domain = strtolower(preg_replace('/\\.$/', '', $domain[0]));
4009  // Path is calculated.
4010  $path = trim(preg_replace('/\\/[^\\/]*$/', '', $path));
4011  // Stuff
4012  $domain .= $path;
4013  $db = static::getDatabaseConnection();
4014  $res = $db->exec_SELECTquery('sys_domain.*', 'pages,sys_domain', '
4015  pages.uid=sys_domain.pid
4016  AND sys_domain.hidden=0
4017  AND (sys_domain.domainName=' . $db->fullQuoteStr($domain, 'sys_domain') . ' OR sys_domain.domainName='
4018  . $db->fullQuoteStr(($domain . '/'), 'sys_domain') . ')' . self::deleteClause('pages'), '', '', '1');
4019  $result = $db->sql_fetch_assoc($res);
4020  $db->sql_free_result($res);
4021  return $result;
4022  }
4023 
4035  public static function RTEsetup($RTEprop, $table, $field, $type = '')
4036  {
4037  $thisConfig = is_array($RTEprop['default.']) ? $RTEprop['default.'] : [];
4038  $thisFieldConf = $RTEprop['config.'][$table . '.'][$field . '.'];
4039  if (is_array($thisFieldConf)) {
4040  unset($thisFieldConf['types.']);
4041  ArrayUtility::mergeRecursiveWithOverrule($thisConfig, $thisFieldConf);
4042  }
4043  if ($type && is_array($RTEprop['config.'][$table . '.'][$field . '.']['types.'][$type . '.'])) {
4044  ArrayUtility::mergeRecursiveWithOverrule($thisConfig, $RTEprop['config.'][$table . '.'][$field . '.']['types.'][$type . '.']);
4045  }
4046  return $thisConfig;
4047  }
4048 
4056  public static function RTEgetObj()
4057  {
4059  // If no RTE object has been set previously, try to create it:
4060  if (!isset($GLOBALS['T3_VAR']['RTEobj'])) {
4061  // Set the object string to blank by default:
4062  $GLOBALS['T3_VAR']['RTEobj'] = [];
4063  // Traverse registered RTEs:
4064  if (is_array($GLOBALS['TYPO3_CONF_VARS']['BE']['RTE_reg'])) {
4065  foreach ($GLOBALS['TYPO3_CONF_VARS']['BE']['RTE_reg'] as $rteObjCfg) {
4066  $rteObj = GeneralUtility::getUserObj($rteObjCfg['objRef']);
4067  if (is_object($rteObj)) {
4068  if ($rteObj->isAvailable()) {
4069  $GLOBALS['T3_VAR']['RTEobj'] = $rteObj;
4070  break;
4071  } else {
4072  $GLOBALS['T3_VAR']['RTEobj'] = array_merge($GLOBALS['T3_VAR']['RTEobj'], $rteObj->errorLog);
4073  }
4074  }
4075  }
4076  }
4077  if (empty($GLOBALS['T3_VAR']['RTEobj'])) {
4078  $GLOBALS['T3_VAR']['RTEobj'][] = 'No RTEs configured at all';
4079  }
4080  }
4081  // Return RTE object (if any!)
4082  return $GLOBALS['T3_VAR']['RTEobj'];
4083  }
4084 
4092  public static function &softRefParserObj($spKey)
4093  {
4094  // If no softRef parser object has been set previously, try to create it:
4095  if (!isset($GLOBALS['T3_VAR']['softRefParser'][$spKey])) {
4096  // Set the object string to blank by default:
4097  $GLOBALS['T3_VAR']['softRefParser'][$spKey] = '';
4098  // Now, try to create parser object:
4099  $objRef = null;
4100  if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser'][$spKey])) {
4101  $objRef = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser'][$spKey];
4102  } elseif (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'][$spKey])) {
4103  GeneralUtility::deprecationLog('The hook softRefParser_GL (used with parser key "'
4104  . $spKey . '") is deprecated since TYPO3 CMS 7 and will be removed in TYPO3 CMS 8');
4105  $objRef = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'][$spKey];
4106  }
4107  if ($objRef) {
4108  $softRefParserObj = GeneralUtility::getUserObj($objRef);
4109  if (is_object($softRefParserObj)) {
4110  $GLOBALS['T3_VAR']['softRefParser'][$spKey] = $softRefParserObj;
4111  }
4112  }
4113  }
4114  // Return RTE object (if any!)
4115  return $GLOBALS['T3_VAR']['softRefParser'][$spKey];
4116  }
4117 
4123  protected static function getRuntimeCache()
4124  {
4125  return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_runtime');
4126  }
4127 
4134  public static function explodeSoftRefParserList($parserList)
4135  {
4136  // Return immediately if list is blank:
4137  if ((string)$parserList === '') {
4138  return false;
4139  }
4140 
4141  $runtimeCache = self::getRuntimeCache();
4142  $cacheId = 'backend-softRefList-' . md5($parserList);
4143  $parserListCache = $runtimeCache->get($cacheId);
4144  if ($parserListCache !== false) {
4145  return $parserListCache;
4146  }
4147 
4148  // Looking for global parsers:
4149  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL']) && !empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'])) {
4150  GeneralUtility::deprecationLog('The hook softRefParser_GL is deprecated since TYPO3 CMS 7 and will be removed in TYPO3 CMS 8');
4151  $parserList = implode(',', array_keys($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'])) . ',' . $parserList;
4152  }
4153 
4154  // Otherwise parse the list:
4155  $keyList = GeneralUtility::trimExplode(',', $parserList, true);
4156  $output = [];
4157  foreach ($keyList as $val) {
4158  $reg = [];
4159  if (preg_match('/^([[:alnum:]_-]+)\\[(.*)\\]$/', $val, $reg)) {
4160  $output[$reg[1]] = GeneralUtility::trimExplode(';', $reg[2], true);
4161  } else {
4162  $output[$val] = '';
4163  }
4164  }
4165  $runtimeCache->set($cacheId, $output);
4166  return $output;
4167  }
4168 
4175  public static function isModuleSetInTBE_MODULES($modName)
4176  {
4177  $loaded = [];
4178  foreach ($GLOBALS['TBE_MODULES'] as $mkey => $list) {
4179  $loaded[$mkey] = 1;
4180  if (!is_array($list) && trim($list)) {
4181  $subList = GeneralUtility::trimExplode(',', $list, true);
4182  foreach ($subList as $skey) {
4183  $loaded[$mkey . '_' . $skey] = 1;
4184  }
4185  }
4186  }
4187  return $modName && isset($loaded[$modName]);
4188  }
4189 
4199  public static function referenceCount($table, $ref, $msg = '', $count = null)
4200  {
4201  if ($count === null) {
4202  $db = static::getDatabaseConnection();
4203  // Look up the path:
4204  if ($table == '_FILE') {
4205  if (GeneralUtility::isFirstPartOfStr($ref, PATH_site)) {
4206  $ref = PathUtility::stripPathSitePrefix($ref);
4207  $condition = 'ref_string=' . $db->fullQuoteStr($ref, 'sys_refindex');
4208  } else {
4209  return '';
4210  }
4211  } else {
4212  $condition = 'ref_uid=' . (int)$ref;
4213  if ($table === 'sys_file') {
4214  $condition .= ' AND tablename != ' . $db->fullQuoteStr('sys_file_metadata', $table);
4215  }
4216  }
4217  $count = $db->exec_SELECTcountRows('*', 'sys_refindex', 'ref_table=' . $db->fullQuoteStr($table, 'sys_refindex') . ' AND ' . $condition . ' AND deleted=0');
4218  }
4219  return $count ? ($msg ? sprintf($msg, $count) : $count) : '';
4220  }
4221 
4230  public static function translationCount($table, $ref, $msg = '')
4231  {
4232  $count = null;
4233  if (empty($GLOBALS['TCA'][$table]['ctrl']['transForeignTable']) && $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] && !$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']) {
4234  $where = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . '=' . (int)$ref . ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '<>0';
4235  if (!empty($GLOBALS['TCA'][$table]['ctrl']['delete'])) {
4236  $where .= ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['delete'] . '=0';
4237  }
4238  $count = static::getDatabaseConnection()->exec_SELECTcountRows('*', $table, $where);
4239  }
4240  return $count ? ($msg ? sprintf($msg, $count) : $count) : '';
4241  }
4242 
4243  /*******************************************
4244  *
4245  * Workspaces / Versioning
4246  *
4247  *******************************************/
4259  public static function selectVersionsOfRecord($table, $uid, $fields = '*', $workspace = 0, $includeDeletedRecords = false, $row = null)
4260  {
4261  $realPid = 0;
4262  $outputRows = [];
4263  if ($GLOBALS['TCA'][$table] && static::isTableWorkspaceEnabled($table)) {
4264  if (is_array($row) && !$includeDeletedRecords) {
4265  $row['_CURRENT_VERSION'] = true;
4266  $realPid = $row['pid'];
4267  $outputRows[] = $row;
4268  } else {
4269  // Select UID version:
4270  $row = self::getRecord($table, $uid, $fields, '', !$includeDeletedRecords);
4271  // Add rows to output array:
4272  if ($row) {
4273  $row['_CURRENT_VERSION'] = true;
4274  $realPid = $row['pid'];
4275  $outputRows[] = $row;
4276  }
4277  }
4278  $workspaceSqlPart = '';
4279  if ($workspace === 0) {
4280  // Only in Live WS
4281  $workspaceSqlPart = ' AND t3ver_wsid=0';
4282  } elseif ($workspace !== null) {
4283  // In Live WS and Workspace with given ID
4284  $workspaceSqlPart = ' AND t3ver_wsid IN (0,' . (int)$workspace . ')';
4285  }
4286  // Select all offline versions of record:
4287  $rows = static::getDatabaseConnection()->exec_SELECTgetRows(
4288  $fields,
4289  $table,
4290  'pid=-1 AND uid<>' . (int)$uid . ' AND t3ver_oid=' . (int)$uid
4291  . $workspaceSqlPart
4292  . ($includeDeletedRecords ? '' : self::deleteClause($table)),
4293  '',
4294  't3ver_id DESC'
4295  );
4296  // Add rows to output array:
4297  if (is_array($rows)) {
4298  $outputRows = array_merge($outputRows, $rows);
4299  }
4300  // Set real-pid:
4301  foreach ($outputRows as $idx => $oRow) {
4302  $outputRows[$idx]['_REAL_PID'] = $realPid;
4303  }
4304  return $outputRows;
4305  }
4306  return null;
4307  }
4308 
4327  public static function fixVersioningPid($table, &$rr, $ignoreWorkspaceMatch = false)
4328  {
4329  if (!ExtensionManagementUtility::isLoaded('version')) {
4330  return;
4331  }
4332  // Check that the input record is an offline version from a table that supports versioning:
4333  if (is_array($rr) && $rr['pid'] == -1 && static::isTableWorkspaceEnabled($table)) {
4334  // Check values for t3ver_oid and t3ver_wsid:
4335  if (isset($rr['t3ver_oid']) && isset($rr['t3ver_wsid'])) {
4336  // If "t3ver_oid" is already a field, just set this:
4337  $oid = $rr['t3ver_oid'];
4338  $wsid = $rr['t3ver_wsid'];
4339  } else {
4340  $oid = 0;
4341  $wsid = 0;
4342  // Otherwise we have to expect "uid" to be in the record and look up based on this:
4343  $newPidRec = self::getRecord($table, $rr['uid'], 't3ver_oid,t3ver_wsid');
4344  if (is_array($newPidRec)) {
4345  $oid = $newPidRec['t3ver_oid'];
4346  $wsid = $newPidRec['t3ver_wsid'];
4347  }
4348  }
4349  // If ID of current online version is found, look up the PID value of that:
4350  if ($oid && ($ignoreWorkspaceMatch || (int)$wsid === (int)static::getBackendUserAuthentication()->workspace)) {
4351  $oidRec = self::getRecord($table, $oid, 'pid');
4352  if (is_array($oidRec)) {
4353  $rr['_ORIG_pid'] = $rr['pid'];
4354  $rr['pid'] = $oidRec['pid'];
4355  }
4356  // Use target PID in case of move pointer
4357  if (
4358  !isset($rr['t3ver_state'])
4359  || VersionState::cast($rr['t3ver_state'])->equals(VersionState::MOVE_POINTER)
4360  ) {
4361  $movePlaceholder = self::getMovePlaceholder($table, $oid, 'pid');
4362  if ($movePlaceholder) {
4363  $rr['_ORIG_pid'] = $rr['pid'];
4364  $rr['pid'] = $movePlaceholder['pid'];
4365  }
4366  }
4367  }
4368  }
4369  }
4370 
4388  public static function workspaceOL($table, &$row, $wsid = -99, $unsetMovePointers = false)
4389  {
4390  if (!ExtensionManagementUtility::isLoaded('version')) {
4391  return;
4392  }
4393  // If this is FALSE the placeholder is shown raw in the backend.
4394  // I don't know if this move can be useful for users to toggle. Technically it can help debugging.
4395  $previewMovePlaceholders = true;
4396  // Initialize workspace ID
4397  if ($wsid == -99) {
4398  $wsid = static::getBackendUserAuthentication()->workspace;
4399  }
4400  // Check if workspace is different from zero and record is set:
4401  if ($wsid !== 0 && is_array($row)) {
4402  // Check if input record is a move-placeholder and if so, find the pointed-to live record:
4403  $movePldSwap = null;
4404  $orig_uid = 0;
4405  $orig_pid = 0;
4406  if ($previewMovePlaceholders) {
4407  $orig_uid = $row['uid'];
4408  $orig_pid = $row['pid'];
4409  $movePldSwap = self::movePlhOL($table, $row);
4410  }
4411  $wsAlt = self::getWorkspaceVersionOfRecord($wsid, $table, $row['uid'], implode(',', array_keys($row)));
4412  // If version was found, swap the default record with that one.
4413  if (is_array($wsAlt)) {
4414  // Check if this is in move-state:
4415  if ($previewMovePlaceholders && !$movePldSwap && static::isTableWorkspaceEnabled($table) && $unsetMovePointers) {
4416  // Only for WS ver 2... (moving)
4417  // If t3ver_state is not found, then find it... (but we like best if it is here...)
4418  if (!isset($wsAlt['t3ver_state'])) {
4419  $stateRec = self::getRecord($table, $wsAlt['uid'], 't3ver_state');
4420  $versionState = VersionState::cast($stateRec['t3ver_state']);
4421  } else {
4422  $versionState = VersionState::cast($wsAlt['t3ver_state']);
4423  }
4424  if ($versionState->equals(VersionState::MOVE_POINTER)) {
4425  // @todo Same problem as frontend in versionOL(). See TODO point there.
4426  $row = false;
4427  return;
4428  }
4429  }
4430  // Always correct PID from -1 to what it should be
4431  if (isset($wsAlt['pid'])) {
4432  // Keep the old (-1) - indicates it was a version.
4433  $wsAlt['_ORIG_pid'] = $wsAlt['pid'];
4434  // Set in the online versions PID.
4435  $wsAlt['pid'] = $row['pid'];
4436  }
4437  // For versions of single elements or page+content, swap UID and PID
4438  $wsAlt['_ORIG_uid'] = $wsAlt['uid'];
4439  $wsAlt['uid'] = $row['uid'];
4440  // Backend css class:
4441  $wsAlt['_CSSCLASS'] = 'ver-element';
4442  // Changing input record to the workspace version alternative:
4443  $row = $wsAlt;
4444  }
4445  // If the original record was a move placeholder, the uid and pid of that is preserved here:
4446  if ($movePldSwap) {
4447  $row['_MOVE_PLH'] = true;
4448  $row['_MOVE_PLH_uid'] = $orig_uid;
4449  $row['_MOVE_PLH_pid'] = $orig_pid;
4450  // For display; To make the icon right for the placeholder vs. the original
4451  $row['t3ver_state'] = (string)new VersionState(VersionState::MOVE_PLACEHOLDER);
4452  }
4453  }
4454  }
4455 
4465  public static function movePlhOL($table, &$row)
4466  {
4467  if (static::isTableWorkspaceEnabled($table)) {
4468  // If t3ver_move_id or t3ver_state is not found, then find it... (but we like best if it is here...)
4469  if (!isset($row['t3ver_move_id']) || !isset($row['t3ver_state'])) {
4470  $moveIDRec = self::getRecord($table, $row['uid'], 't3ver_move_id, t3ver_state');
4471  $moveID = $moveIDRec['t3ver_move_id'];
4472  $versionState = VersionState::cast($moveIDRec['t3ver_state']);
4473  } else {
4474  $moveID = $row['t3ver_move_id'];
4475  $versionState = VersionState::cast($row['t3ver_state']);
4476  }
4477  // Find pointed-to record.
4478  if ($versionState->equals(VersionState::MOVE_PLACEHOLDER) && $moveID) {
4479  if ($origRow = self::getRecord($table, $moveID, implode(',', array_keys($row)))) {
4480  $row = $origRow;
4481  return true;
4482  }
4483  }
4484  }
4485  return false;
4486  }
4487 
4497  public static function getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields = '*')
4498  {
4499  if (ExtensionManagementUtility::isLoaded('version')) {
4500  if ($workspace !== 0 && $GLOBALS['TCA'][$table] && self::isTableWorkspaceEnabled($table)) {
4501  // Select workspace version of record:
4502  $row = static::getDatabaseConnection()->exec_SELECTgetSingleRow($fields, $table, 'pid=-1 AND ' . 't3ver_oid=' . (int)$uid . ' AND ' . 't3ver_wsid=' . (int)$workspace . self::deleteClause($table));
4503  if (is_array($row)) {
4504  return $row;
4505  }
4506  }
4507  }
4508  return false;
4509  }
4510 
4519  public static function getLiveVersionOfRecord($table, $uid, $fields = '*')
4520  {
4521  $liveVersionId = self::getLiveVersionIdOfRecord($table, $uid);
4522  if (is_null($liveVersionId) === false) {
4523  return self::getRecord($table, $liveVersionId, $fields);
4524  }
4525  return null;
4526  }
4527 
4535  public static function getLiveVersionIdOfRecord($table, $uid)
4536  {
4537  if (!ExtensionManagementUtility::isLoaded('version')) {
4538  return null;
4539  }
4540  $liveVersionId = null;
4541  if (self::isTableWorkspaceEnabled($table)) {
4542  $currentRecord = self::getRecord($table, $uid, 'pid,t3ver_oid');
4543  if (is_array($currentRecord) && $currentRecord['pid'] == -1) {
4544  $liveVersionId = $currentRecord['t3ver_oid'];
4545  }
4546  }
4547  return $liveVersionId;
4548  }
4549 
4557  public static function versioningPlaceholderClause($table)
4558  {
4559  if (static::isTableWorkspaceEnabled($table)) {
4560  $currentWorkspace = (int)static::getBackendUserAuthentication()->workspace;
4561  return ' AND (' . $table . '.t3ver_state <= ' . new VersionState(VersionState::DEFAULT_STATE) . ' OR ' . $table . '.t3ver_wsid = ' . $currentWorkspace . ')';
4562  }
4563  return '';
4564  }
4565 
4573  public static function getWorkspaceWhereClause($table, $workspaceId = null)
4574  {
4575  $whereClause = '';
4576  if (self::isTableWorkspaceEnabled($table)) {
4577  if (is_null($workspaceId)) {
4578  $workspaceId = static::getBackendUserAuthentication()->workspace;
4579  }
4580  $workspaceId = (int)$workspaceId;
4581  $pidOperator = $workspaceId === 0 ? '!=' : '=';
4582  $whereClause = ' AND ' . $table . '.t3ver_wsid=' . $workspaceId . ' AND ' . $table . '.pid' . $pidOperator . '-1';
4583  }
4584  return $whereClause;
4585  }
4586 
4595  public static function countVersionsOfRecordsOnPage($workspace, $pageId)
4596  {
4598  if ((int)$workspace === 0) {
4599  return [];
4600  }
4601  $output = [];
4602  foreach ($GLOBALS['TCA'] as $tableName => $cfg) {
4603  if ($tableName != 'pages' && $cfg['ctrl']['versioningWS']) {
4604  $movePointer = new VersionState(VersionState::MOVE_POINTER);
4605  $joinStatement = '(A.t3ver_oid=B.uid AND A.t3ver_state<>' . $movePointer
4606  . ' OR A.t3ver_oid=B.t3ver_move_id AND A.t3ver_state=' . $movePointer . ')';
4607 
4608  // Select all records from this table in the database from the workspace
4609  // This joins the online version with the offline version as tables A and B
4610  $output[$tableName] = static::getDatabaseConnection()->exec_SELECTgetRows(
4611  'B.uid as live_uid, A.uid as offline_uid',
4612  $tableName . ' A,' . $tableName . ' B',
4613  'A.pid=-1' . ' AND B.pid=' . (int)$pageId
4614  . ' AND A.t3ver_wsid=' . (int)$workspace . ' AND ' . $joinStatement
4615  . self::deleteClause($tableName, 'A') . self::deleteClause($tableName, 'B')
4616  );
4617  if (!is_array($output[$tableName]) || empty($output[$tableName])) {
4618  unset($output[$tableName]);
4619  }
4620  }
4621  }
4622  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['countVersionsOfRecordsOnPage'])) {
4623  $reference = null;
4624  $parameters = [
4625  'workspace' => 'workspace',
4626  'pageId' => $pageId,
4627  'versions' => &$output,
4628  ];
4629  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['countVersionsOfRecordsOnPage'] as $hookFunction) {
4630  GeneralUtility::callUserFunction($hookFunction, $parameters, $reference);
4631  }
4632  }
4633  return $output;
4634  }
4635 
4643  public static function wsMapId($table, $uid)
4644  {
4645  $wsRec = self::getWorkspaceVersionOfRecord(static::getBackendUserAuthentication()->workspace, $table, $uid, 'uid');
4646  return is_array($wsRec) ? $wsRec['uid'] : $uid;
4647  }
4648 
4658  public static function getMovePlaceholder($table, $uid, $fields = '*', $workspace = null)
4659  {
4660  if ($workspace === null) {
4661  $workspace = static::getBackendUserAuthentication()->workspace;
4662  }
4663  if ((int)$workspace !== 0 && $GLOBALS['TCA'][$table] && static::isTableWorkspaceEnabled($table)) {
4664  // Select workspace version of record:
4665  $row = static::getDatabaseConnection()->exec_SELECTgetSingleRow(
4666  $fields,
4667  $table,
4668  'pid<>-1 AND t3ver_state=' . new VersionState(VersionState::MOVE_PLACEHOLDER) . ' AND t3ver_move_id='
4669  . (int)$uid . ' AND t3ver_wsid=' . (int)$workspace . self::deleteClause($table)
4670  );
4671  if (is_array($row)) {
4672  return $row;
4673  }
4674  }
4675  return false;
4676  }
4677 
4678  /*******************************************
4679  *
4680  * Miscellaneous
4681  *
4682  *******************************************/
4693  public static function TYPO3_copyRightNotice()
4694  {
4695  // Copyright Notice
4696  $loginCopyrightWarrantyProvider = strip_tags(trim($GLOBALS['TYPO3_CONF_VARS']['SYS']['loginCopyrightWarrantyProvider']));
4697  $loginCopyrightWarrantyURL = strip_tags(trim($GLOBALS['TYPO3_CONF_VARS']['SYS']['loginCopyrightWarrantyURL']));
4698 
4699  $lang = static::getLanguageService();
4700 
4701  if (strlen($loginCopyrightWarrantyProvider) >= 2 && strlen($loginCopyrightWarrantyURL) >= 10) {
4702  $warrantyNote = sprintf($lang->sL('LLL:EXT:lang/locallang_login.xlf:warranty.by'), htmlspecialchars($loginCopyrightWarrantyProvider), '<a href="' . htmlspecialchars($loginCopyrightWarrantyURL) . '" target="_blank">', '</a>');
4703  } else {
4704  $warrantyNote = sprintf($lang->sL('LLL:EXT:lang/locallang_login.xlf:no.warranty'), '<a href="' . TYPO3_URL_LICENSE . '" target="_blank">', '</a>');
4705  }
4706  $cNotice = '<a href="' . TYPO3_URL_GENERAL . '" target="_blank">' .
4707  $lang->sL('LLL:EXT:lang/locallang_login.xlf:typo3.cms') . '</a>. ' .
4708  $lang->sL('LLL:EXT:lang/locallang_login.xlf:copyright') . ' &copy; ' . htmlspecialchars(TYPO3_copyright_year) . ' Kasper Sk&aring;rh&oslash;j. ' .
4709  $lang->sL('LLL:EXT:lang/locallang_login.xlf:extension.copyright') . ' ' .
4710  sprintf($lang->sL('LLL:EXT:lang/locallang_login.xlf:details.link'), ('<a href="' . TYPO3_URL_GENERAL . '" target="_blank">' . TYPO3_URL_GENERAL . '</a>')) . ' ' .
4711  strip_tags($warrantyNote, '<a>') . ' ' .
4712  sprintf($lang->sL('LLL:EXT:lang/locallang_login.xlf:free.software'), ('<a href="' . TYPO3_URL_LICENSE . '" target="_blank">'), '</a> ') .
4713  $lang->sL('LLL:EXT:lang/locallang_login.xlf:keep.notice');
4714  return $cNotice;
4715  }
4716 
4724  public static function getPathType_web_nonweb($path)
4725  {
4727  return GeneralUtility::isFirstPartOfStr($path, GeneralUtility::getIndpEnv('TYPO3_DOCUMENT_ROOT')) ? 'web' : '';
4728  }
4729 
4737  public static function ADMCMD_previewCmds($pageInfo)
4738  {
4739  $simUser = '';
4740  $simTime = '';
4741  if ($pageInfo['fe_group'] > 0) {
4742  $simUser = '&ADMCMD_simUser=' . $pageInfo['fe_group'];
4743  } elseif ((int)$pageInfo['fe_group'] === -2) {
4744  // -2 means "show at any login". We simulate first available fe_group.
4746  $sysPage = GeneralUtility::makeInstance(PageRepository::class);
4747  $activeFeGroupRow = self::getRecordRaw('fe_groups', '1=1' . $sysPage->enableFields('fe_groups'), 'uid');
4748  if (!empty($activeFeGroupRow)) {
4749  $simUser = '&ADMCMD_simUser=' . $activeFeGroupRow['uid'];
4750  }
4751  }
4752  if ($pageInfo['starttime'] > $GLOBALS['EXEC_TIME']) {
4753  $simTime = '&ADMCMD_simTime=' . $pageInfo['starttime'];
4754  }
4755  if ($pageInfo['endtime'] < $GLOBALS['EXEC_TIME'] && $pageInfo['endtime'] != 0) {
4756  $simTime = '&ADMCMD_simTime=' . ($pageInfo['endtime'] - 1);
4757  }
4758  return $simUser . $simTime;
4759  }
4760 
4769  public static function processParams($params)
4770  {
4771  $paramArr = [];
4772  $lines = explode(LF, $params);
4773  foreach ($lines as $val) {
4774  $val = trim($val);
4775  if ($val) {
4776  $pair = explode('=', $val, 2);
4777  $paramArr[trim($pair[0])] = trim($pair[1]);
4778  }
4779  }
4780  return $paramArr;
4781  }
4782 
4789  public static function getBackendScript($interface = '')
4790  {
4791  if (!$interface) {
4792  $interface = static::getBackendUserAuthentication()->uc['interfaceSetup'];
4793  }
4794  switch ($interface) {
4795  case 'frontend':
4796  $script = '../.';
4797  break;
4798  case 'backend':
4799  default:
4800  $script = self::getModuleUrl('main');
4801  }
4802  return $script;
4803  }
4804 
4811  public static function isTableWorkspaceEnabled($table)
4812  {
4813  return !empty($GLOBALS['TCA'][$table]['ctrl']['versioningWS']);
4814  }
4815 
4825  public static function isTableMovePlaceholderAware($table)
4826  {
4827  return self::isTableWorkspaceEnabled($table);
4828  }
4829 
4837  public static function getTcaFieldConfiguration($table, $field)
4838  {
4839  $configuration = [];
4840  if (isset($GLOBALS['TCA'][$table]['columns'][$field]['config'])) {
4841  $configuration = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
4842  }
4843  return $configuration;
4844  }
4845 
4854  public static function isWebMountRestrictionIgnored($table)
4855  {
4856  return !empty($GLOBALS['TCA'][$table]['ctrl']['security']['ignoreWebMountRestriction']);
4857  }
4858 
4867  public static function isRootLevelRestrictionIgnored($table)
4868  {
4869  return !empty($GLOBALS['TCA'][$table]['ctrl']['security']['ignoreRootLevelRestriction']);
4870  }
4871 
4879  public static function shortcutExists($url)
4880  {
4881  $statement = self::getDatabaseConnection()->prepare_SELECTquery(
4882  'uid',
4883  'sys_be_shortcuts',
4884  'userid = :userid AND url = :url'
4885  );
4886 
4887  $statement->bindValues([
4888  ':userid' => self::getBackendUserAuthentication()->user['uid'],
4889  ':url' => $url
4890  ]
4891  );
4892 
4893  $statement->execute();
4894  $rows = $statement->fetch(PreparedStatement::FETCH_ASSOC);
4895  $statement->free();
4896 
4897  return !empty($rows);
4898  }
4899 
4905  protected static function getSignalSlotDispatcher()
4906  {
4907  return GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
4908  }
4909 
4919  protected static function emitGetPagesTSconfigPreIncludeSignal(array $TSdataArray, $id, array $rootLine, $returnPartArray)
4920  {
4921  $signalArguments = static::getSignalSlotDispatcher()->dispatch(__CLASS__, 'getPagesTSconfigPreInclude', [$TSdataArray, $id, $rootLine, $returnPartArray]);
4922  return $signalArguments[0];
4923  }
4924 
4928  protected static function getDatabaseConnection()
4929  {
4930  return $GLOBALS['TYPO3_DB'];
4931  }
4932 
4936  protected static function getLanguageService()
4937  {
4938  return $GLOBALS['LANG'];
4939  }
4940 
4944  protected static function getBackendUserAuthentication()
4945  {
4946  return $GLOBALS['BE_USER'];
4947  }
4948 
4952  protected static function getDocumentTemplate()
4953  {
4954  return $GLOBALS['TBE_TEMPLATE'];
4955  }
4956 }
static translationCount($table, $ref, $msg='')
static getTSconfig_pidValue($table, $uid, $pid)
static getPagesTSconfig($id, $rootLine=null, $returnPartArray=false)
static getFuncCheck($mainParams, $elementName, $currentValue, $script='', $addParams='', $tagParams='')
static getWorkspaceWhereClause($table, $workspaceId=null)
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
if(!defined("DB_ERROR")) define("DB_ERROR"
static readPageAccess($id, $perms_clause)
static getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields=' *')
static createPreviewUrl($pageUid, $rootLine, $anchorSection, $additionalGetVars, $viewScript)
static implodeAttributes(array $arr, $xhtmlSafe=false, $dontOmitBlankAttribs=false)
static editOnClick($params, $_='', $requestUri='')
static getItemLabel($table, $col, $printAllWrap='')
static countVersionsOfRecordsOnPage($workspace, $pageId)
static getProcessedValueExtra($table, $fN, $fV, $fixed_lgd_chars=0, $uid=0, $forceResult=true, $pid=0)
static isFirstPartOfStr($str, $partStr)
static getRecordsByField($theTable, $theField, $theValue, $whereClause='', $groupBy='', $orderBy='', $limit='', $useDeleteClause=true)
static resolveAllSheetsInDS(array $dataStructArray)
static openPageTree($pid, $clearExpansion)
static blindUserNames($usernames, $groupArray, $excludeBlindedFlag=false)
static BEenableFields($table, $inv=false)
static getRecordsSortedByTitle(array $fields, $table, $titleField, $where='')
static getRecordToolTip(array $row, $table='pages')
static getCommonSelectFields($table, $prefix='', $fields=[])
static getFuncInput($mainParams, $elementName, $currentValue, $size=10, $script='', $addParams='')
static BEgetRootLine($uid, $clause='', $workspaceOL=false)
static getTCAtypes($table, $rec, $useFieldNameAsKey=false)
static replaceMarkersInWhereClause($whereClause, $table, $field='', $tsConfig=[])
static getGroupNames($fields='title, uid', $where='')
static lockRecords($table='', $uid=0, $pid=0)
static getFlexFormDS($conf, $row, $table, $fieldName='', $WSOL=true, $newRecordPidValue=0)
static getUrlToken($formName='securityToken', $tokenName='formToken')
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static workspaceOL($table, &$row, $wsid=-99, $unsetMovePointers=false)
static callUserFunction($funcName, &$params, &$ref, $checkPrefix='', $errorMode=0)
static calcAge($seconds, $labels=' min|hrs|days|yrs|min|hour|day|year')
static time($value, $withSeconds=true)
static inArray(array $in_array, $item)
static getInlineLocalizationMode($table, $fieldOrConfig)
static fixVersioningPid($table, &$rr, $ignoreWorkspaceMatch=false)
static exec_foreign_table_where_query($fieldConfig, $field='', $TSconfig=[])
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=false, $rawurlencodeParamName=false)
static getDomainStartPage($domain, $path='')
static getRegisteredFlexForms($table='tt_content')
static getModuleData($MOD_MENU, $CHANGED_SETTINGS, $modName, $type='', $dontValidateList='', $setDefaultList='')
static emitGetPagesTSconfigPreIncludeSignal(array $TSdataArray, $id, array $rootLine, $returnPartArray)
static blindGroupNames($groups, $groupArray, $excludeBlindedFlag=false)
static getUserNames($fields='username, usergroup, usergroup_cached_list, uid', $where='')
static getRecordLocalization($table, $uid, $language, $andWhereClause='')
static makeConfigForm($configArray, $defaults, $dataPrefix)
static setUpdateSignal($set='', $params='')
static referenceCount($table, $ref, $msg='', $count=null)
static cshItem($table, $field, $_='', $wrap='')
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
static getRecordRaw($table, $where='', $fields=' *')
static getTcaFieldConfiguration($table, $field)
static getTSCpidCached($table, $uid, $pid)
static RTEsetup($RTEprop, $table, $field, $type='')
static getFuncMenu($mainParams, $elementName, $currentValue, $menuItems, $script='', $addParams='')
static unsetMenuItems($modTSconfig, $itemArray, $TSref)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
static getUrl($url, $includeHeader=0, $requestHeaders=false, &$report=null)
static getSQLselectableList($in_list, $tablename, $default_tablename)
static xml2array($string, $NSprefix='', $reportDocTag=false)
static viewOnClick($pageUid, $backPath='', $rootLine=null, $anchorSection='', $alternativeUrl='', $additionalGetVars='', $switchFocus=true)
static getRecordIconAltText($row, $table='pages')
static fixed_lgd_cs($string, $chars, $appendString='...')
$uid
Definition: server.php:38
static getPageForRootline($uid, $clause, $workspaceOL)
static getListGroupNames($fields='title, uid')
static getRecordPath($uid, $clause, $titleLimit, $fullTitleLimit=0)
static getRecordTitlePrep($title, $titleLength=0)
static getFileAbsFileName($filename, $onlyRelative=true, $relToTYPO3_mainDir=false)
static getLabelFromItemListMerged($pageId, $table, $column, $key)
static getPidForModTSconfig($table, $uid, $pid)
static helpTextIcon($table, $field, $_='', $force=false)
static buildScriptUrl($mainParams, $addParams, $script='')
static getLiveVersionOfRecord($table, $uid, $fields=' *')
static getMovePlaceholder($table, $uid, $fields=' *', $workspace=null)
static beginsWith($haystack, $needle)
static titleAttribForPages($row, $perms_clause='', $includeAttrib=true)
static wrapClickMenuOnIcon( $content, $table, $uid=0, $listFrame=true, $addParams='', $enDisItems='', $returnTagParameters=false)
static getSpecConfParts($defaultExtrasString, $_='')
static getRecord($table, $uid, $fields=' *', $where='', $useDeleteClause=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static selectVersionsOfRecord($table, $uid, $fields=' *', $workspace=0, $includeDeletedRecords=false, $row=null)
static getRecordWSOL($table, $uid, $fields=' *', $where='', $useDeleteClause=true, $unsetMovePointers=false)
static getLinkToDataHandlerAction($parameters, $redirectUrl='')
static dateTimeAge($tstamp, $prefix=1, $date='')
$extConf
static sortArraysByKey(array $arrays, $key, $ascending=true)
static deleteClause($table, $tableAlias='')
static replaceL10nModeFields($table, array $row)
static getLabelFromItemlist($table, $col, $key)
static uniqueList($in_list, $secondParameter=null)
static getDropdownMenu($mainParams, $elementName, $currentValue, $menuItems, $script='', $addParams='')
static getThumbNail($thumbScript, $theFile, $tparams='', $size='')
static getLabelsFromItemsList($table, $column, $keyList, array $columnTsConfig=[])