3a1c165456dd579752a0662d55b311d3bc23068d
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / FormDataProvider / TcaRecordTitle.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form\FormDataProvider;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Core\Database\DatabaseConnection;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Lang\LanguageService;
22
23 /**
24 * Determine the title of a record and write it to $result['recordTitle'].
25 *
26 * TCA ctrl fields like label and label_alt are evaluated and their
27 * current values from databaseRow used to create the title.
28 */
29 class TcaRecordTitle implements FormDataProviderInterface
30 {
31 /**
32 * Enrich the processed record information with the resolved title
33 *
34 * @param array $result Incoming result array
35 * @return array Modified array
36 */
37 public function addData(array $result)
38 {
39 if (!isset($result['processedTca']['ctrl']['label'])) {
40 throw new \UnexpectedValueException(
41 'TCA of table ' . $result['tableName'] . ' misses required [\'ctrl\'][\'label\'] definition.',
42 1443706103
43 );
44 }
45
46 if (isset($result['processedTca']['ctrl']['label_userFunc'])) {
47 // userFunc takes precedence over everything
48 $parameters = [
49 'table' => $result['tableName'],
50 'row' => $result['databaseRow'],
51 'title' => '',
52 'options' => isset($result['processedTca']['ctrl']['label_userFunc_options'])
53 ? $result['processedTca']['ctrl']['label_userFunc_options']
54 : [],
55 ];
56 $null = null;
57 GeneralUtility::callUserFunction($result['processedTca']['ctrl']['label_userFunc'], $parameters, $null);
58 $result['recordTitle'] = $parameters['title'];
59 } else {
60 $result = $this->getRecordTitleByLabelProperties($result);
61 }
62
63 return $result;
64 }
65
66 /**
67 * Build the record title from label, label_alt and label_alt_force properties
68 *
69 * @param array $result Incoming result array
70 * @return array Modified result array
71 */
72 protected function getRecordTitleByLabelProperties(array $result)
73 {
74 $titles = [];
75 $titleByLabel = $this->getRecordTitleForField($result['processedTca']['ctrl']['label'], $result);
76 if (!empty($titleByLabel)) {
77 $titles[] = $titleByLabel;
78 }
79
80 $labelAltForce = isset($result['processedTca']['ctrl']['label_alt_force'])
81 ? (bool)$result['processedTca']['ctrl']['label_alt_force']
82 : false;
83 if (!empty($result['processedTca']['ctrl']['label_alt']) && ($labelAltForce || empty($titleByLabel))) {
84 // Dive into label_alt evaluation if label_alt_force is set or if label did not came up with a title yet
85 $labelAltFields = GeneralUtility::trimExplode(',', $result['processedTca']['ctrl']['label_alt'], true);
86 foreach ($labelAltFields as $fieldName) {
87 $titleByLabelAlt = $this->getRecordTitleForField($fieldName, $result);
88 if (!empty($titleByLabelAlt)) {
89 $titles[] = $titleByLabelAlt;
90 }
91 if (!$labelAltForce && !empty($titleByLabelAlt)) {
92 // label_alt_force creates a comma separated list of multiple fields.
93 // If not set, one found field with content is enough
94 break;
95 }
96 }
97 }
98
99 $result['recordTitle'] = implode(', ', $titles);
100 return $result;
101 }
102
103 /**
104 * Record title of a single field
105 *
106 * @param string $fieldName Field to handle
107 * @param array $result Incoming result array
108 * @return string
109 */
110 protected function getRecordTitleForField($fieldName, $result)
111 {
112 if ($fieldName === 'uid') {
113 // uid return field content directly since it usually has not TCA definition
114 return $result['databaseRow']['uid'];
115 }
116
117 if (!isset($result['processedTca']['columns'][$fieldName]['config']['type'])
118 || !is_string($result['processedTca']['columns'][$fieldName]['config']['type'])
119 ) {
120 return '';
121 }
122
123 $recordTitle = '';
124 $rawValue = null;
125 if (array_key_exists($fieldName, $result['databaseRow'])) {
126 $rawValue = $result['databaseRow'][$fieldName];
127 }
128 $fieldConfig = $result['processedTca']['columns'][$fieldName]['config'];
129 switch ($fieldConfig['type']) {
130 case 'radio':
131 $recordTitle = $this->getRecordTitleForRadioType($rawValue, $fieldConfig);
132 break;
133 case 'inline':
134 // intentional fall-through
135 case 'select':
136 $recordTitle = $this->getRecordTitleForSelectType($rawValue, $fieldConfig);
137 break;
138 case 'group':
139 $recordTitle = $this->getRecordTitleForGroupType($rawValue, $fieldConfig);
140 break;
141 case 'check':
142 $recordTitle = $this->getRecordTitleForCheckboxType($rawValue, $fieldConfig);
143 break;
144 case 'input':
145 $recordTitle = $this->getRecordTitleForInputType($rawValue, $fieldConfig);
146 break;
147 case 'text':
148 $recordTitle = $this->getRecordTitleForTextType($rawValue);
149 case 'flex':
150 // TODO: Check if and how a label could be generated from flex field data
151 default:
152
153 }
154
155 return $recordTitle;
156 }
157
158 /**
159 * Return the record title for radio fields
160 *
161 * @param mixed $value Current database value of this field
162 * @param array $fieldConfig TCA field configuration
163 * @return string
164 */
165 protected function getRecordTitleForRadioType($value, $fieldConfig)
166 {
167 if (!isset($fieldConfig['items']) || !is_array($fieldConfig['items'])) {
168 return '';
169 }
170 foreach ($fieldConfig['items'] as $item) {
171 list($itemLabel, $itemValue) = $item;
172 if ((string)$value === (string)$itemValue) {
173 return $itemLabel;
174 }
175 }
176 return '';
177 }
178
179 /**
180 * Return the record title for database records
181 *
182 * @param mixed $value Current database value of this field
183 * @param array $fieldConfig TCA field configuration
184 * @return string
185 */
186 protected function getRecordTitleForSelectType($value, $fieldConfig)
187 {
188 if (!is_array($value)) {
189 return '';
190 }
191 $labelParts = [];
192 foreach ($value as $itemValue) {
193 $itemKey = array_search($itemValue, array_column($fieldConfig['items'], 1));
194 if ($itemKey !== false) {
195 $labelParts[] = $fieldConfig['items'][$itemKey][0];
196 }
197 }
198 $title = implode(', ', $labelParts);
199 if (empty($title) && !empty($value)) {
200 $title = implode(', ', $value);
201 }
202 return $title;
203 }
204
205 /**
206 * Return the record title for database records
207 *
208 * @param mixed $value Current database value of this field
209 * @param array $fieldConfig TCA field configuration
210 * @return string
211 */
212 protected function getRecordTitleForGroupType($value, $fieldConfig)
213 {
214 if ($fieldConfig['internal_type'] !== 'db') {
215 return implode(', ', GeneralUtility::trimExplode(',', $value, true));
216 }
217 $labelParts = array_map(
218 function ($rawLabelItem) {
219 return array_pop(GeneralUtility::trimExplode('|', $rawLabelItem, true, 2));
220 },
221 GeneralUtility::trimExplode(',', $value, true)
222 );
223 if (!empty($labelParts)) {
224 sort($labelParts);
225 return implode(', ', $labelParts);
226 }
227 return '';
228 }
229
230 /**
231 * Returns the record title for checkbox fields
232 *
233 * @param mixed $value Current database value of this field
234 * @param array $fieldConfig TCA field configuration
235 * @return string
236 */
237 protected function getRecordTitleForCheckboxType($value, $fieldConfig)
238 {
239 $languageService = $this->getLanguageService();
240 if (empty($fieldConfig['items']) || !is_array($fieldConfig['items'])) {
241 $title = (bool)$value
242 ? $languageService->sL('LLL:EXT:lang/locallang_common.xlf:yes')
243 : $languageService->sL('LLL:EXT:lang/locallang_common.xlf:no');
244 } else {
245 $labelParts = [];
246 foreach ($fieldConfig['items'] as $key => $val) {
247 if ($value & pow(2, $key)) {
248 $labelParts[] = $val[0];
249 }
250 }
251 $title = implode(', ', $labelParts);
252 }
253 return $title;
254 }
255
256 /**
257 * Returns the record title for input fields
258 *
259 * @param mixed $value Current database value of this field
260 * @param array $fieldConfig TCA field configuration
261 * @return string
262 */
263 protected function getRecordTitleForInputType($value, $fieldConfig)
264 {
265 if (!isset($value)) {
266 return '';
267 }
268 $title = $value;
269 if (GeneralUtility::inList($fieldConfig['eval'], 'date')) {
270 if (isset($fieldConfig['dbType']) && $fieldConfig['dbType'] === 'date') {
271 $value = $value === '0000-00-00' ? 0 : (int)strtotime($value);
272 } else {
273 $value = (int)$value;
274 }
275 if (!empty($value)) {
276 $ageSuffix = '';
277 // Generate age suffix as long as not explicitly suppressed
278 if (!isset($fieldConfig['disableAgeDisplay']) || (bool)$fieldConfig['disableAgeDisplay'] === false) {
279 $ageDelta = $GLOBALS['EXEC_TIME'] - $value;
280 $calculatedAge = BackendUtility::calcAge(
281 abs($ageDelta),
282 $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')
283 );
284 $ageSuffix = ' (' . ($ageDelta > 0 ? '-' : '') . $calculatedAge . ')';
285 }
286 $title = BackendUtility::date($value) . $ageSuffix;
287 }
288 } elseif (GeneralUtility::inList($fieldConfig['eval'], 'time')) {
289 if (!empty($value)) {
290 $title = BackendUtility::time((int)$value, false);
291 }
292 } elseif (GeneralUtility::inList($fieldConfig['eval'], 'timesec')) {
293 if (!empty($value)) {
294 $title = BackendUtility::time((int)$value);
295 }
296 } elseif (GeneralUtility::inList($fieldConfig['eval'], 'datetime')) {
297 // Handle native date/time field
298 if (isset($fieldConfig['dbType']) && $fieldConfig['dbType'] === 'datetime') {
299 $value = $value === '0000-00-00 00:00:00' ? 0 : (int)strtotime($value);
300 } else {
301 $value = (int)$value;
302 }
303 if (!empty($value)) {
304 $title = BackendUtility::datetime($value);
305 }
306 }
307 return $title;
308 }
309
310 /**
311 * Returns the record title for text fields
312 *
313 * @param mixed $value Current database value of this field
314 * @return string
315 */
316 protected function getRecordTitleForTextType($value)
317 {
318 return trim(strip_tags($value));
319 }
320
321 /**
322 * @return DatabaseConnection
323 */
324 protected function getDatabaseConnection()
325 {
326 return $GLOBALS['TYPO3_DB'];
327 }
328
329 /**
330 * @return LanguageService
331 */
332 protected function getLanguageService()
333 {
334 return $GLOBALS['LANG'];
335 }
336 }