TYPO3 CMS  TYPO3_8-7
TcaInputPlaceholders.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 
24 
31 {
40  public function addData(array $result)
41  {
42  foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
43  // Placeholders are only valid for input and text type fields
44  if (
45  ($fieldConfig['config']['type'] !== 'input' && $fieldConfig['config']['type'] !== 'text')
46  || !isset($fieldConfig['config']['placeholder'])
47  ) {
48  continue;
49  }
50 
51  // Resolve __row|field type placeholders
52  if (strpos($fieldConfig['config']['placeholder'], '__row|') === 0) {
53  // split field names into array and remove the __row indicator
54  $fieldNameArray = array_slice(
55  GeneralUtility::trimExplode('|', $fieldConfig['config']['placeholder'], true),
56  1
57  );
58  $result['processedTca']['columns'][$fieldName]['config']['placeholder'] = $this->getPlaceholderValue($fieldNameArray, $result);
59  }
60 
61  // Resolve placeholders from language files
62  if (strpos($fieldConfig['config']['placeholder'], 'LLL:') === 0) {
63  $result['processedTca']['columns'][$fieldName]['config']['placeholder'] = $this->getLanguageService()->sL($fieldConfig['config']['placeholder']);
64  }
65 
66  // Remove empty placeholders
67  if (empty($result['processedTca']['columns'][$fieldName]['config']['placeholder'])) {
68  unset($result['processedTca']['columns'][$fieldName]['config']['placeholder']);
69  }
70  }
71 
72  return $result;
73  }
74 
85  protected function getPlaceholderValue($fieldNameArray, $result, $recursionLevel = 0)
86  {
87  if ($recursionLevel > 99) {
88  // This should not happen, treat as misconfiguration
89  return '';
90  }
91 
92  $fieldName = array_shift($fieldNameArray);
93  $fieldConfig = $result['processedTca']['columns'][$fieldName]['config'];
94 
95  // Skip if a defined field was actually not present in the database row
96  // Using array_key_exists here, since NULL values are valid as well.
97  if (!array_key_exists($fieldName, $result['databaseRow'])) {
98  return '';
99  }
100 
101  $value = $result['databaseRow'][$fieldName];
102 
103  switch ($fieldConfig['type']) {
104  case 'select':
105  // The FormDataProviders already resolved the select items to an array of uids,
106  // filter out empty values that occur when no related record has been selected.
107  $possibleUids = array_filter($value);
108  $foreignTableName = $fieldConfig['foreign_table'];
109  break;
110  case 'group':
111  $possibleUids = $this->getRelatedGroupFieldUids($fieldConfig, $value);
112  $foreignTableName = $this->getAllowedTableForGroupField($fieldConfig);
113  break;
114  case 'inline':
115  $possibleUids = array_filter(GeneralUtility::trimExplode(',', $value, true));
116  $foreignTableName = $fieldConfig['foreign_table'];
117  break;
118  default:
119  $possibleUids = [];
120  $foreignTableName = '';
121  }
122 
123  if (!empty($possibleUids) && !empty($fieldNameArray)) {
124  if (count($possibleUids) > 1
125  && !empty($GLOBALS['TCA'][$foreignTableName]['ctrl']['languageField'])
126  && isset($result['currentSysLanguage'])
127  ) {
128  $possibleUids = $this->getPossibleUidsByCurrentSysLanguage($possibleUids, $foreignTableName, $result['currentSysLanguage']);
129  }
130  $relatedFormData = $this->getRelatedFormData($foreignTableName, $possibleUids[0], $fieldNameArray[0]);
131  if (!empty($GLOBALS['TCA'][$result['tableName']]['ctrl']['languageField'])
132  && (isset($result['databaseRow'][$GLOBALS['TCA'][$result['tableName']]['ctrl']['languageField']]))
133  ) {
134  $relatedFormData['currentSysLanguage'] = $result['databaseRow'][$GLOBALS['TCA'][$result['tableName']]['ctrl']['languageField']][0];
135  }
136  $value = $this->getPlaceholderValue($fieldNameArray, $relatedFormData, $recursionLevel + 1);
137  }
138 
139  if ($recursionLevel === 0 && is_array($value)) {
140  $value = implode(', ', $value);
141  }
142  return (string)$value;
143  }
144 
153  protected function getRelatedFormData($tableName, $uid, $columnToProcess)
154  {
155  $fakeDataInput = [
156  'command' => 'edit',
157  'vanillaUid' => (int)$uid,
158  'tableName' => $tableName,
159  'inlineCompileExistingChildren' => false,
160  'columnsToProcess' => [$columnToProcess],
161  ];
163  $formDataGroup = GeneralUtility::makeInstance(TcaInputPlaceholderRecord::class);
165  $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
166  $compilerResult = $formDataCompiler->compile($fakeDataInput);
167  return $compilerResult;
168  }
169 
180  protected function getRelatedGroupFieldUids(array $fieldConfig, $value)
181  {
182  $relatedUids = [];
183  $allowedTable = $this->getAllowedTableForGroupField($fieldConfig);
184 
185  // Skip if it's not a database relation with a resolvable foreign table
186  if (($fieldConfig['internal_type'] !== 'db') || ($allowedTable === false)) {
187  return $relatedUids;
188  }
189 
190  // Related group values have been prepared by TcaGroup data provider, an array is expected here
191  foreach ($value as $singleValue) {
192  $relatedUids[] = $singleValue['uid'];
193  }
194 
195  return $relatedUids;
196  }
197 
206  protected function getAllowedTableForGroupField(array $fieldConfig)
207  {
208  $allowedTable = false;
209 
210  $allowedTables = GeneralUtility::trimExplode(',', $fieldConfig['allowed'], true);
211  if (count($allowedTables) === 1) {
212  $allowedTable = $allowedTables[0];
213  }
214 
215  return $allowedTable;
216  }
217 
230  protected function getPossibleUidsByCurrentSysLanguage(array $possibleUids, $foreignTableName, $currentLanguage)
231  {
232  $languageField = $GLOBALS['TCA'][$foreignTableName]['ctrl']['languageField'];
233  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($foreignTableName);
234  $possibleRecords = $queryBuilder->select('uid', $languageField)
235  ->from($foreignTableName)
236  ->where(
237  $queryBuilder->expr()->in(
238  'uid',
239  $queryBuilder->createNamedParameter($possibleUids, Connection::PARAM_INT_ARRAY)
240  ),
241  $queryBuilder->expr()->in(
242  $languageField,
243  $queryBuilder->createNamedParameter([$currentLanguage, 0], Connection::PARAM_INT_ARRAY)
244  )
245  )
246  ->groupBy($languageField, 'uid')
247  ->execute()
248  ->fetchAll();
249 
250  if (!empty($possibleRecords)) {
251  // Either only one record or first record matches language
252  if (count($possibleRecords) === 1
253  || (int)$possibleRecords[0][$languageField] === (int)$currentLanguage
254  ) {
255  return [$possibleRecords[0]['uid']];
256  }
257 
258  // Language of second record matches language
259  return [$possibleRecords[1]['uid']];
260  }
261 
262  return $possibleUids;
263  }
264 
268  protected function getLanguageService()
269  {
270  return $GLOBALS['LANG'];
271  }
272 }
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static makeInstance($className,... $constructorArguments)
getPossibleUidsByCurrentSysLanguage(array $possibleUids, $foreignTableName, $currentLanguage)
getPlaceholderValue($fieldNameArray, $result, $recursionLevel=0)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']