‪TYPO3CMS  11.5
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 {
41  public function ‪addData(array $result)
42  {
43  foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
44  // Placeholders are only valid for input and text type fields
45  if (
46  (!in_array($fieldConfig['config']['type'] ?? false, ['input', 'text']))
47  || !isset($fieldConfig['config']['placeholder'])
48  ) {
49  continue;
50  }
51 
52  // Resolve __row|field type placeholders
53  if (strpos($fieldConfig['config']['placeholder'], '__row|') === 0) {
54  // split field names into array and remove the __row indicator
55  $fieldNameArray = array_slice(
56  ‪GeneralUtility::trimExplode('|', $fieldConfig['config']['placeholder'], true),
57  1
58  );
59  $result['processedTca']['columns'][$fieldName]['config']['placeholder'] = $this->‪getPlaceholderValue($fieldNameArray, $result);
60  }
61 
62  // Resolve placeholders from language files
63  if (strpos($fieldConfig['config']['placeholder'], 'LLL:') === 0) {
64  $result['processedTca']['columns'][$fieldName]['config']['placeholder'] = $this->‪getLanguageService()->‪sL($fieldConfig['config']['placeholder']);
65  }
66 
67  // Remove empty placeholders
68  if (empty($result['processedTca']['columns'][$fieldName]['config']['placeholder'])) {
69  unset($result['processedTca']['columns'][$fieldName]['config']['placeholder']);
70  }
71  }
72 
73  return $result;
74  }
75 
86  protected function ‪getPlaceholderValue($fieldNameArray, $result, $recursionLevel = 0)
87  {
88  if ($recursionLevel > 99) {
89  // This should not happen, treat as misconfiguration
90  return '';
91  }
92 
93  $fieldName = array_shift($fieldNameArray);
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  if (!isset($result['processedTca']['columns'][$fieldName]['config'])
104  || !is_array($result['processedTca']['columns'][$fieldName]['config'])
105  ) {
106  return (string)$value;
107  }
108 
109  $fieldConfig = $result['processedTca']['columns'][$fieldName]['config'];
110 
111  switch ($fieldConfig['type']) {
112  case 'select':
113  case 'category':
114  // The FormDataProviders already resolved the select items to an array of uids,
115  // filter out empty values that occur when no related record has been selected.
116  $possibleUids = array_filter($value);
117  $foreignTableName = $fieldConfig['foreign_table'];
118  break;
119  case 'group':
120  $possibleUids = $this->‪getRelatedGroupFieldUids($fieldConfig, $value);
121  $foreignTableName = $this->‪getAllowedTableForGroupField($fieldConfig);
122  break;
123  case 'inline':
124  $possibleUids = array_filter(‪GeneralUtility::trimExplode(',', $value, true));
125  $foreignTableName = $fieldConfig['foreign_table'];
126  break;
127  default:
128  $possibleUids = [];
129  $foreignTableName = '';
130  }
131 
132  if (!empty($possibleUids) && !empty($fieldNameArray)) {
133  if (count($possibleUids) > 1
134  && !empty(‪$GLOBALS['TCA'][$foreignTableName]['ctrl']['languageField'])
135  && isset($result['currentSysLanguage'])
136  ) {
137  $possibleUids = $this->‪getPossibleUidsByCurrentSysLanguage($possibleUids, $foreignTableName, $result['currentSysLanguage']);
138  }
139  $relatedFormData = $this->‪getRelatedFormData($foreignTableName, $possibleUids[0], $fieldNameArray[0]);
140  if (!empty(‪$GLOBALS['TCA'][$result['tableName']]['ctrl']['languageField'])
141  && isset($result['databaseRow'][‪$GLOBALS['TCA'][$result['tableName']]['ctrl']['languageField']])
142  ) {
143  $relatedFormData['currentSysLanguage'] = $result['databaseRow'][‪$GLOBALS['TCA'][$result['tableName']]['ctrl']['languageField']];
144  }
145  $value = $this->‪getPlaceholderValue($fieldNameArray, $relatedFormData, $recursionLevel + 1);
146  }
147 
148  if ($recursionLevel === 0 && is_array($value)) {
149  $value = implode(', ', $value);
150  }
151  return (string)$value;
152  }
153 
162  protected function ‪getRelatedFormData($tableName, $uid, $columnToProcess)
163  {
164  $fakeDataInput = [
165  'command' => 'edit',
166  'vanillaUid' => (int)$uid,
167  'tableName' => $tableName,
168  'inlineCompileExistingChildren' => false,
169  'columnsToProcess' => [$columnToProcess],
170  ];
171  $formDataGroup = GeneralUtility::makeInstance(TcaInputPlaceholderRecord::class);
172  $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
173  $compilerResult = $formDataCompiler->compile($fakeDataInput);
174  return $compilerResult;
175  }
176 
187  protected function ‪getRelatedGroupFieldUids(array $fieldConfig, $value): array
188  {
189  $relatedUids = [];
190  $allowedTable = $this->‪getAllowedTableForGroupField($fieldConfig);
191 
192  // Skip if it's not a resolvable foreign table
193  if (!$allowedTable) {
194  return [];
195  }
196 
197  // Related group values have been prepared by TcaGroup data provider, an array is expected here
198  foreach ($value as $singleValue) {
199  $relatedUids[] = $singleValue['uid'];
200  }
201 
202  return $relatedUids;
203  }
204 
213  protected function ‪getAllowedTableForGroupField(array $fieldConfig)
214  {
215  $allowedTable = false;
216 
217  $allowedTables = ‪GeneralUtility::trimExplode(',', $fieldConfig['allowed'], true);
218  if (count($allowedTables) === 1) {
219  $allowedTable = $allowedTables[0];
220  }
221 
222  return $allowedTable;
223  }
224 
237  protected function ‪getPossibleUidsByCurrentSysLanguage(array $possibleUids, $foreignTableName, $currentLanguage)
238  {
239  $languageField = ‪$GLOBALS['TCA'][$foreignTableName]['ctrl']['languageField'];
240  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($foreignTableName);
241  $possibleRecords = $queryBuilder->select('uid', $languageField)
242  ->from($foreignTableName)
243  ->where(
244  $queryBuilder->expr()->in(
245  'uid',
246  $queryBuilder->createNamedParameter($possibleUids, Connection::PARAM_INT_ARRAY)
247  ),
248  $queryBuilder->expr()->in(
249  $languageField,
250  $queryBuilder->createNamedParameter([$currentLanguage, 0], Connection::PARAM_INT_ARRAY)
251  )
252  )
253  ->groupBy($languageField, 'uid')
254  ->executeQuery()
255  ->fetchAllAssociative();
256 
257  if (!empty($possibleRecords)) {
258  // Either only one record or first record matches language
259  if (count($possibleRecords) === 1
260  || (int)$possibleRecords[0][$languageField] === (int)$currentLanguage
261  ) {
262  return [$possibleRecords[0]['uid']];
263  }
264 
265  // Language of second record matches language
266  return [$possibleRecords[1]['uid']];
267  }
268 
269  return $possibleUids;
270  }
271 
275  protected function ‪getLanguageService()
276  {
277  return ‪$GLOBALS['LANG'];
278  }
279 }
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:999
‪TYPO3\CMS\Backend\Form\FormDataGroup\TcaInputPlaceholderRecord
Definition: TcaInputPlaceholderRecord.php:25
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders\getAllowedTableForGroupField
‪bool string getAllowedTableForGroupField(array $fieldConfig)
Definition: TcaInputPlaceholders.php:213
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders
Definition: TcaInputPlaceholders.php:32
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders\getLanguageService
‪LanguageService getLanguageService()
Definition: TcaInputPlaceholders.php:275
‪TYPO3\CMS\Core\Localization\LanguageService\sL
‪string sL($input)
Definition: LanguageService.php:161
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders\getRelatedFormData
‪array getRelatedFormData($tableName, $uid, $columnToProcess)
Definition: TcaInputPlaceholders.php:162
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders\addData
‪array addData(array $result)
Definition: TcaInputPlaceholders.php:41
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders\getPlaceholderValue
‪string getPlaceholderValue($fieldNameArray, $result, $recursionLevel=0)
Definition: TcaInputPlaceholders.php:86
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders\getRelatedGroupFieldUids
‪array getRelatedGroupFieldUids(array $fieldConfig, $value)
Definition: TcaInputPlaceholders.php:187
‪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:38
‪$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:237
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Backend\Form\FormDataCompiler
Definition: FormDataCompiler.php:25