‪TYPO3CMS  ‪main
TcaInputPlaceholders.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
25 
32 {
40  public function ‪addData(array $result)
41  {
42  foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
43  // Placeholders are only valid for input-like and text-like fields.
44  if (!isset($fieldConfig['config']['placeholder'], $fieldConfig['config']['type'])
45  || (
46  $fieldConfig['config']['type'] !== 'input'
47  && $fieldConfig['config']['type'] !== 'text'
48  && $fieldConfig['config']['type'] !== 'number'
49  && $fieldConfig['config']['type'] !== 'email'
50  && $fieldConfig['config']['type'] !== 'link'
51  && $fieldConfig['config']['type'] !== 'password'
52  && $fieldConfig['config']['type'] !== 'datetime'
53  && $fieldConfig['config']['type'] !== 'color'
54  && $fieldConfig['config']['type'] !== 'json'
55  )
56  ) {
57  continue;
58  }
59 
60  // Resolve __row|field type placeholders
61  if (str_starts_with((string)$fieldConfig['config']['placeholder'], '__row|')) {
62  // split field names into array and remove the __row indicator
63  $fieldNameArray = array_slice(
64  ‪GeneralUtility::trimExplode('|', $fieldConfig['config']['placeholder'], true),
65  1
66  );
67  $result['processedTca']['columns'][$fieldName]['config']['placeholder'] = $this->‪getPlaceholderValue($fieldNameArray, $result);
68  } elseif (!empty($fieldConfig['config']['placeholder'])) {
69  // Resolve placeholders from language files
70  $result['processedTca']['columns'][$fieldName]['config']['placeholder'] = $this->‪getLanguageService()->sL($fieldConfig['config']['placeholder']);
71  }
72 
73  // Remove empty placeholders
74  if (empty($result['processedTca']['columns'][$fieldName]['config']['placeholder'])) {
75  unset($result['processedTca']['columns'][$fieldName]['config']['placeholder']);
76  }
77  }
78 
79  return $result;
80  }
81 
92  protected function ‪getPlaceholderValue($fieldNameArray, $result, $recursionLevel = 0)
93  {
94  if ($recursionLevel > 99) {
95  // This should not happen, treat as misconfiguration
96  return '';
97  }
98 
99  $fieldName = array_shift($fieldNameArray);
100 
101  // Skip if a defined field was actually not present in the database row
102  // Using array_key_exists here, since NULL values are valid as well.
103  if (!array_key_exists($fieldName, $result['databaseRow'])) {
104  return '';
105  }
106 
107  $value = $result['databaseRow'][$fieldName];
108 
109  if (!isset($result['processedTca']['columns'][$fieldName]['config'])
110  || !is_array($result['processedTca']['columns'][$fieldName]['config'])
111  ) {
112  return (string)$value;
113  }
114 
115  $fieldConfig = $result['processedTca']['columns'][$fieldName]['config'];
116 
117  switch ($fieldConfig['type']) {
118  case 'select':
119  case 'category':
120  // The FormDataProviders already resolved the select items to an array of uids,
121  // filter out empty values that occur when no related record has been selected.
122  $possibleUids = array_filter($value);
123  $foreignTableName = $fieldConfig['foreign_table'] ?? '';
124  break;
125  case 'group':
126  $possibleUids = $this->‪getRelatedGroupFieldUids($fieldConfig, $value);
127  $foreignTableName = $this->‪getAllowedTableForGroupField($fieldConfig);
128  break;
129  case 'inline':
130  case 'file':
131  $possibleUids = array_filter(‪GeneralUtility::trimExplode(',', $value, true));
132  $foreignTableName = $fieldConfig['foreign_table'];
133  break;
134  default:
135  $possibleUids = [];
136  $foreignTableName = '';
137  }
138 
139  if (!empty($possibleUids) && !empty($fieldNameArray)) {
140  if (count($possibleUids) > 1
141  && !empty(‪$GLOBALS['TCA'][$foreignTableName]['ctrl']['languageField'])
142  && isset($result['currentSysLanguage'])
143  ) {
144  $possibleUids = $this->‪getPossibleUidsByCurrentSysLanguage($possibleUids, $foreignTableName, $result['currentSysLanguage']);
145  }
146  $relatedFormData = $this->‪getRelatedFormData($result, $foreignTableName, $possibleUids[0], $fieldNameArray[0]);
147  if (!empty(‪$GLOBALS['TCA'][$result['tableName']]['ctrl']['languageField'])
148  && isset($result['databaseRow'][‪$GLOBALS['TCA'][$result['tableName']]['ctrl']['languageField']])
149  ) {
150  $relatedFormData['currentSysLanguage'] = $result['databaseRow'][‪$GLOBALS['TCA'][$result['tableName']]['ctrl']['languageField']];
151  }
152  $value = $this->‪getPlaceholderValue($fieldNameArray, $relatedFormData, $recursionLevel + 1);
153  }
154 
155  if ($recursionLevel === 0 && is_array($value)) {
156  $value = implode(', ', $value);
157  }
158  return (string)$value;
159  }
160 
169  protected function ‪getRelatedFormData(array $result, $tableName, ‪$uid, $columnToProcess)
170  {
171  $fakeDataInput = [
172  'request' => $result['request'],
173  'command' => 'edit',
174  'vanillaUid' => (int)‪$uid,
175  'tableName' => $tableName,
176  'inlineCompileExistingChildren' => false,
177  'columnsToProcess' => [$columnToProcess],
178  ];
179  $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class);
180  $compilerResult = $formDataCompiler->compile($fakeDataInput, GeneralUtility::makeInstance(TcaInputPlaceholderRecord::class));
181  return $compilerResult;
182  }
183 
193  protected function ‪getRelatedGroupFieldUids(array $fieldConfig, $value): array
194  {
195  $relatedUids = [];
196  $allowedTable = $this->‪getAllowedTableForGroupField($fieldConfig);
197 
198  // Skip if it's not a resolvable foreign table
199  if (!$allowedTable) {
200  return [];
201  }
202 
203  // Related group values have been prepared by TcaGroup data provider, an array is expected here
204  foreach ($value as $singleValue) {
205  $relatedUids[] = $singleValue['uid'];
206  }
207 
208  return $relatedUids;
209  }
210 
219  protected function ‪getAllowedTableForGroupField(array $fieldConfig)
220  {
221  $allowedTable = false;
222 
223  $allowedTables = ‪GeneralUtility::trimExplode(',', $fieldConfig['allowed'], true);
224  if (count($allowedTables) === 1) {
225  $allowedTable = $allowedTables[0];
226  }
227 
228  return $allowedTable;
229  }
230 
243  protected function ‪getPossibleUidsByCurrentSysLanguage(array $possibleUids, $foreignTableName, $currentLanguage)
244  {
245  $languageField = ‪$GLOBALS['TCA'][$foreignTableName]['ctrl']['languageField'];
246  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($foreignTableName);
247  $possibleRecords = $queryBuilder->select('uid', $languageField)
248  ->from($foreignTableName)
249  ->where(
250  $queryBuilder->expr()->in(
251  'uid',
252  $queryBuilder->createNamedParameter($possibleUids, ‪Connection::PARAM_INT_ARRAY)
253  ),
254  $queryBuilder->expr()->in(
255  $languageField,
256  $queryBuilder->createNamedParameter([$currentLanguage, 0], ‪Connection::PARAM_INT_ARRAY)
257  )
258  )
259  ->groupBy($languageField, 'uid')
260  ->executeQuery()
261  ->fetchAllAssociative();
262 
263  if (!empty($possibleRecords)) {
264  // Either only one record or first record matches language
265  if (count($possibleRecords) === 1
266  || (int)$possibleRecords[0][$languageField] === (int)$currentLanguage
267  ) {
268  return [$possibleRecords[0]['uid']];
269  }
270 
271  // Language of second record matches language
272  return [$possibleRecords[1]['uid']];
273  }
274 
275  return $possibleUids;
276  }
277 
279  {
280  return ‪$GLOBALS['LANG'];
281  }
282 }
‪TYPO3\CMS\Backend\Form\FormDataGroup\TcaInputPlaceholderRecord
Definition: TcaInputPlaceholderRecord.php:25
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders\getLanguageService
‪getLanguageService()
Definition: TcaInputPlaceholders.php:278
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders\getAllowedTableForGroupField
‪bool string getAllowedTableForGroupField(array $fieldConfig)
Definition: TcaInputPlaceholders.php:219
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders
Definition: TcaInputPlaceholders.php:32
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders\getRelatedFormData
‪array getRelatedFormData(array $result, $tableName, $uid, $columnToProcess)
Definition: TcaInputPlaceholders.php:169
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders\addData
‪array addData(array $result)
Definition: TcaInputPlaceholders.php:40
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders\getPlaceholderValue
‪string getPlaceholderValue($fieldNameArray, $result, $recursionLevel=0)
Definition: TcaInputPlaceholders.php:92
‪TYPO3\CMS\Backend\Form\FormDataProvider
Definition: AbstractDatabaseRecordProvider.php:16
‪TYPO3\CMS\Backend\Form\FormDataProviderInterface
Definition: FormDataProviderInterface.php:23
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:41
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders\getRelatedGroupFieldUids
‪getRelatedGroupFieldUids(array $fieldConfig, $value)
Definition: TcaInputPlaceholders.php:193
‪TYPO3\CMS\Webhooks\Message\$uid
‪identifier readonly int $uid
Definition: PageModificationMessage.php:35
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders\getPossibleUidsByCurrentSysLanguage
‪array getPossibleUidsByCurrentSysLanguage(array $possibleUids, $foreignTableName, $currentLanguage)
Definition: TcaInputPlaceholders.php:243
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Backend\Form\FormDataCompiler
Definition: FormDataCompiler.php:26
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT_ARRAY
‪const PARAM_INT_ARRAY
Definition: Connection.php:72
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode(string $delim, string $string, bool $removeEmptyValues=false, int $limit=0)
Definition: GeneralUtility.php:822