2 namespace TYPO3\CMS\Backend\Form\FormDataProvider
;
5 * This file is part of the TYPO3 CMS project.
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.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
17 use TYPO3\CMS\Backend\Form\FormDataCompiler
;
18 use TYPO3\CMS\Backend\Form\FormDataGroup\TcaInputPlaceholderRecord
;
19 use TYPO3\CMS\Backend\Form\FormDataProviderInterface
;
20 use TYPO3\CMS\Backend\Utility\BackendUtility
;
21 use TYPO3\CMS\Core\Utility\GeneralUtility
;
22 use TYPO3\CMS\Core\Utility\StringUtility
;
25 * Resolve placeholders for fields of type input or text. The placeholder value
26 * in the processedTca section of the result will be replaced with the resolved
29 class TcaInputPlaceholders
extends AbstractItemProvider
implements FormDataProviderInterface
{
32 * Resolve placeholders for input/text fields. Placeholders that are simple
33 * strings will be returned unmodified. Placeholders beginning with __row are
34 * being resolved, possibly traversing multiple tables.
36 * @param array $result
39 public function addData(array $result) {
40 foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
41 // Placeholders are only valid for input and text type fields
43 ($fieldConfig['config']['type'] !== 'input' && $fieldConfig['config']['type'] !== 'text')
44 ||
!isset($fieldConfig['config']['placeholder'])
49 // Resolve __row|field type placeholders
50 if (StringUtility
::beginsWith($fieldConfig['config']['placeholder'], '__row|')) {
51 // split field names into array and remove the __row indicator
52 $fieldNameArray = array_slice(
53 GeneralUtility
::trimExplode('|', $fieldConfig['config']['placeholder'], TRUE
),
56 $result['processedTca']['columns'][$fieldName]['config']['placeholder'] = $this->getPlaceholderValue($fieldNameArray, $result);
59 // Remove empty placeholders
60 if (empty($fieldConfig['config']['placeholder'])) {
61 unset($result['processedTca']['columns'][$fieldName]['config']['placeholder']);
69 * Recursively resolve the placeholder value. A placeholder string with a
70 * syntax of __row|field1|field2|field3 will be recursively resolved to a
73 * @param array $fieldNameArray
74 * @param array $result
75 * @param int $recursionLevel
78 protected function getPlaceholderValue($fieldNameArray, $result, $recursionLevel = 0) {
79 if ($recursionLevel > 99) {
80 // This should not happen, treat as misconfiguration
84 $fieldName = array_shift($fieldNameArray);
85 $fieldConfig = $result['processedTca']['columns'][$fieldName]['config'];
87 // Skip if a defined field was actually not present in the database row
88 // Using array_key_exists here, since NULL values are valid as well.
89 if (!array_key_exists($fieldName, $result['databaseRow'])) {
93 $value = $result['databaseRow'][$fieldName];
95 switch($fieldConfig['type']) {
97 // The FormDataProviders already resolved the select items to an array of uids
98 $possibleUids = $value;
99 $foreignTableName = $fieldConfig['foreign_table'];
102 $possibleUids = $this->getRelatedGroupFieldUids($fieldConfig, $value);
103 $foreignTableName = $this->getAllowedTableForGroupField($fieldConfig);
106 $possibleUids = array_filter(GeneralUtility
::trimExplode(',', $value, TRUE
));
107 $foreignTableName = $fieldConfig['foreign_table'];
111 $foreignTableName = '';
114 if (!empty($possibleUids) && !empty($fieldNameArray)) {
115 $relatedFormData = $this->getRelatedFormData($foreignTableName, $possibleUids[0]);
116 $value = $this->getPlaceholderValue($fieldNameArray, $relatedFormData, $recursionLevel +
1);
119 // @todo: This might not be the best solution. The database row
120 // @todo: can include array type values. Final resolution would
121 // @todo: need to take the recursion into account.
122 return (string)$value;
126 * Compile a formdata result set based on the tablename and record uid.
128 * @param string $tableName Name of the table for which to compile formdata
129 * @param int $uid UID of the record for which to compile the formdata
130 * @return array The compiled formdata
132 protected function getRelatedFormData($tableName, $uid) {
135 'vanillaUid' => (int)$uid,
136 'tableName' => $tableName,
138 /** @var TcaInputPlaceholderRecord $formDataGroup */
139 $formDataGroup = GeneralUtility
::makeInstance(TcaInputPlaceholderRecord
::class);
140 /** @var FormDataCompiler $formDataCompiler */
141 $formDataCompiler = GeneralUtility
::makeInstance(FormDataCompiler
::class, $formDataGroup);
142 $compilerResult = $formDataCompiler->compile($fakeDataInput);
143 return $compilerResult;
147 * Return uids of related records for group type fields. Uids consisting of
148 * multiple parts like [table]_[uid]|[title] will be reduced to integers and
149 * validated against the allowed table. Uids without a table prefix are
150 * accepted in any case.
152 * @param array $fieldConfig TCA "config" section for the group type field.
153 * @param string $value A comma separated list of records
156 protected function getRelatedGroupFieldUids(array $fieldConfig, $value) {
158 $allowedTable = $this->getAllowedTableForGroupField($fieldConfig);
160 // Skip if it's not a database relation with a resolvable foreign table
161 if (($fieldConfig['internal_type'] !== 'db') ||
($allowedTable === FALSE
)) {
165 $values = GeneralUtility
::trimExplode(',', $value, TRUE
);
166 foreach ($values as $groupValue) {
167 list($foreignIdentifier, $_) = GeneralUtility
::trimExplode('|', $groupValue);
168 list($recordForeignTable, $foreignUid) = BackendUtility
::splitTable_Uid($foreignIdentifier);
169 // skip records that do not match the allowed table
170 if (!empty($recordForeignTable) && ($recordForeignTable !== $allowedTable)) {
173 $relatedUids[] = $foreignUid;
180 * Will read the "allowed" value from the given field configuration
181 * and returns FALSE if none or more than one has been defined.
182 * Otherwise the name of the allowed table will be returned.
184 * @param array $fieldConfig TCA "config" section for the group type field.
185 * @return bool|string
187 protected function getAllowedTableForGroupField(array $fieldConfig) {
188 $allowedTable = FALSE
;
190 $allowedTables = GeneralUtility
::trimExplode(',', $fieldConfig['allowed'], TRUE
);
191 if (count($allowedTables) === 1) {
192 $allowedTable = $allowedTables[0];
195 return $allowedTable;