TYPO3  7.6
TcaInlineConfiguration.php
Go to the documentation of this file.
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 
20 
25 {
33  public function addData(array $result)
34  {
35  foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
36  if (empty($fieldConfig['config']['type']) || $fieldConfig['config']['type'] !== 'inline') {
37  continue;
38  }
39 
40  // Throw if an inline field without foreign_table is set
41  if (!isset($fieldConfig['config']['foreign_table'])) {
42  throw new \UnexpectedValueException(
43  'Inline field ' . $fieldName . ' of table ' . $result['tableName'] . ' must have a foreign_table config',
44  1443793404
45  );
46  }
47 
48  $result = $this->initializeMinMaxItems($result, $fieldName);
49  $result = $this->initializeLocalizationMode($result, $fieldName);
50  $result = $this->initializeAppearance($result, $fieldName);
51  $result = $this->addInlineSelectorAndUniqueConfiguration($result, $fieldName);
52  }
53  return $result;
54  }
55 
64  protected function initializeMinMaxItems(array $result, $fieldName)
65  {
66  $config = $result['processedTca']['columns'][$fieldName]['config'];
67 
68  $minItems = 0;
69  if (isset($config['minitems'])) {
70  $minItems = MathUtility::forceIntegerInRange($config['minitems'], 0);
71  }
72  $result['processedTca']['columns'][$fieldName]['config']['minitems'] = $minItems;
73 
74  $maxItems = 100000;
75  if (isset($config['maxitems'])) {
76  $maxItems = MathUtility::forceIntegerInRange($config['maxitems'], 1);
77  }
78  $result['processedTca']['columns'][$fieldName]['config']['maxitems'] = $maxItems;
79 
80  return $result;
81  }
82 
91  protected function initializeAppearance(array $result, $fieldName)
92  {
93  $config = $result['processedTca']['columns'][$fieldName]['config'];
94  if (!isset($config['appearance']) || !is_array($config['appearance'])) {
95  // Init appearance if not set
96  $config['appearance'] = [];
97  }
98  // Set the position/appearance of the "Create new record" link
99  if (isset($config['foreign_selector']) && $config['foreign_selector']
100  && (!isset($config['appearance']['useCombination']) || !$config['appearance']['useCombination'])
101  ) {
102  $config['appearance']['levelLinksPosition'] = 'none';
103  } elseif (!isset($config['appearance']['levelLinksPosition'])
104  || !in_array($config['appearance']['levelLinksPosition'], array('top', 'bottom', 'both', 'none'), true)
105  ) {
106  $config['appearance']['levelLinksPosition'] = 'top';
107  }
108  $config['appearance']['showPossibleLocalizationRecords']
109  = isset($config['appearance']['showPossibleLocalizationRecords']) && $config['appearance']['showPossibleLocalizationRecords'];
110  $config['appearance']['showRemovedLocalizationRecords']
111  = isset($config['appearance']['showRemovedLocalizationRecords']) && $config['appearance']['showRemovedLocalizationRecords'];
112  // Defines which controls should be shown in header of each record
113  $enabledControls = [
114  'info' => true,
115  'new' => true,
116  'dragdrop' => true,
117  'sort' => true,
118  'hide' => true,
119  'delete' => true,
120  'localize' => true
121  ];
122  if (isset($config['appearance']['enabledControls']) && is_array($config['appearance']['enabledControls'])) {
123  $config['appearance']['enabledControls'] = array_merge($enabledControls, $config['appearance']['enabledControls']);
124  } else {
125  $config['appearance']['enabledControls'] = $enabledControls;
126  }
127  $result['processedTca']['columns'][$fieldName]['config'] = $config;
128 
129  return $result;
130  }
131 
143  protected function initializeLocalizationMode(array $result, $fieldName)
144  {
145  if ($result['defaultLanguageRow'] === null) {
146  // Currently handled parent is a localized row if a former provider added the "default" row
147  // If handled record is not localized, set localizationMode to 'none' and return
148  $result['processedTca']['columns'][$fieldName]['config']['behaviour']['localizationMode'] = 'none';
149  return $result;
150  }
151 
152  $childTableName = $result['processedTca']['columns'][$fieldName]['config']['foreign_table'];
153  $parentConfig = $result['processedTca']['columns'][$fieldName]['config'];
154 
155  $isChildTableLocalizable = false;
156  if (isset($GLOBALS['TCA'][$childTableName]['ctrl']) && is_array($GLOBALS['TCA'][$childTableName]['ctrl'])
157  && isset($GLOBALS['TCA'][$childTableName]['ctrl']['languageField'])
158  && $GLOBALS['TCA'][$childTableName]['ctrl']['languageField']
159  && isset($GLOBALS['TCA'][$childTableName]['ctrl']['transOrigPointerField'])
160  && $GLOBALS['TCA'][$childTableName]['ctrl']['transOrigPointerField']
161  ) {
162  $isChildTableLocalizable = true;
163  }
164 
165  $mode = null;
166 
167  if (isset($parentConfig['behaviour']['localizationMode'])) {
168  // Use explicit set mode, but validate before use
169  // Use mode if set, but throw if not set to either 'select' or 'keep'
170  if ($parentConfig['behaviour']['localizationMode'] !== 'keep' && $parentConfig['behaviour']['localizationMode'] !== 'select') {
171  throw new \UnexpectedValueException(
172  'localizationMode of table ' . $result['tableName'] . ' field ' . $fieldName . ' is not valid, set to either \'keep\' or \'select\'',
173  1443829370
174  );
175  }
176  // Throw if is set to select, but child can not be localized
177  if ($parentConfig['behaviour']['localizationMode'] === 'select' && !$isChildTableLocalizable) {
178  throw new \UnexpectedValueException(
179  'Wrong configuration: localizationMode of table ' . $result['tableName'] . ' field ' . $fieldName . ' is set to \'select\', but table is not localizable.',
180  1443944274
181  );
182  }
183  $mode = $parentConfig['behaviour']['localizationMode'];
184  } else {
185  // Not set explicitly -> use "none"
186  $mode = 'none';
187  if ($isChildTableLocalizable) {
188  // Except if child is localizable, then use "select"
189  $mode = 'select';
190  }
191  }
192 
193  $result['processedTca']['columns'][$fieldName]['config']['behaviour']['localizationMode'] = $mode;
194  return $result;
195  }
196 
211  protected function addInlineSelectorAndUniqueConfiguration(array $result, $fieldName)
212  {
213  $config = $result['processedTca']['columns'][$fieldName]['config'];
214 
215  // Early return if neither foreign_unique nor foreign_selector are set
216  if (!isset($config['foreign_unique']) && !isset($config['foreign_selector'])) {
217  return $result;
218  }
219 
220  // If both are set, they must point to the same field
221  if (isset($config['foreign_unique']) && isset($config['foreign_selector'])
222  && $config['foreign_unique'] !== $config['foreign_selector']
223  ) {
224  throw new \UnexpectedValueException(
225  'Table ' . $result['tableName'] . ' field ' . $fieldName . ': If both foreign_unique and'
226  . ' foreign_selector are set, they must point to the same field',
227  1444995464
228  );
229  }
230 
231  if (isset($config['foreign_unique'])) {
232  $fieldNameInChildConfiguration = $config['foreign_unique'];
233  } else {
234  $fieldNameInChildConfiguration = $config['foreign_selector'];
235  }
236 
237  // Throw if field name in globals does not exist or is not of type select or group
238  if (!isset($GLOBALS['TCA'][$config['foreign_table']]['columns'][$fieldNameInChildConfiguration]['config']['type'])
239  || ($GLOBALS['TCA'][$config['foreign_table']]['columns'][$fieldNameInChildConfiguration]['config']['type'] !== 'select'
240  && $GLOBALS['TCA'][$config['foreign_table']]['columns'][$fieldNameInChildConfiguration]['config']['type'] !== 'group')
241  ) {
242  throw new \UnexpectedValueException(
243  'Table ' . $result['tableName'] . ' field ' . $fieldName . ' points in foreign_selector or foreign_unique'
244  . ' to field ' . $fieldNameInChildConfiguration . ' of table ' . $config['foreign_table'] . ', but this field'
245  . ' is either not defined or is not of type select or group',
246  1444996537
247  );
248  }
249 
250  $selectorOrUniqueConfiguration = [
251  'config' => $GLOBALS['TCA'][$config['foreign_table']]['columns'][$fieldNameInChildConfiguration]['config'],
252  ];
253 
254  // Throw if field is type group, but not internal_type db
255  if ($selectorOrUniqueConfiguration['config']['type'] === 'group'
256  && (!isset($selectorOrUniqueConfiguration['config']['internal_type']) || $selectorOrUniqueConfiguration['config']['internal_type'] !== 'db')) {
257  throw new \UnexpectedValueException(
258  'Table ' . $result['tableName'] . ' field ' . $fieldName . ' points in foreign_selector or foreign_unique'
259  . ' to field ' . $fieldNameInChildConfiguration . ' of table ' . $config['foreign_table'] . '. This field'
260  . ' is of type group and must be of internal_type db, which is not the case',
261  1444999130
262  );
263  }
264 
265  // Merge foreign_selector_fieldTcaOverride if given
266  if (isset($config['foreign_selector'])
267  && isset($config['foreign_selector_fieldTcaOverride']['config'])
268  && is_array($config['foreign_selector_fieldTcaOverride']['config'])
269  ) {
270  ArrayUtility::mergeRecursiveWithOverrule($selectorOrUniqueConfiguration['config'], $config['foreign_selector_fieldTcaOverride']['config']);
271  }
272 
273  // Add field name to config for easy access later
274  $selectorOrUniqueConfiguration['fieldName'] = $fieldNameInChildConfiguration;
275 
276  // Add remote table name for easy access later
277  if ($selectorOrUniqueConfiguration['config']['type'] === 'select') {
278  if (!isset($selectorOrUniqueConfiguration['config']['foreign_table'])) {
279  throw new \UnexpectedValueException(
280  'Table ' . $result['tableName'] . ' field ' . $fieldName . ' points in foreign_selector or foreign_unique'
281  . ' to field ' . $fieldNameInChildConfiguration . ' of table ' . $config['foreign_table'] . '. This field'
282  . ' is of type select and must define foreign_table',
283  1445078627
284  );
285  }
286  $foreignTable = $selectorOrUniqueConfiguration['config']['foreign_table'];
287  } else {
288  if (!isset($selectorOrUniqueConfiguration['config']['allowed'])) {
289  throw new \UnexpectedValueException(
290  'Table ' . $result['tableName'] . ' field ' . $fieldName . ' points in foreign_selector or foreign_unique'
291  . ' to field ' . $fieldNameInChildConfiguration . ' of table ' . $config['foreign_table'] . '. This field'
292  . ' is of type select and must define allowed',
293  1445078628
294  );
295  }
296  $foreignTable = $selectorOrUniqueConfiguration['config']['allowed'];
297  }
298  $selectorOrUniqueConfiguration['foreignTable'] = $foreignTable;
299 
300  // If this is a foreign_selector field, mark it as such for data fetching later
301  $selectorOrUniqueConfiguration['isSelector'] = false;
302  if (isset($config['foreign_selector'])) {
303  $selectorOrUniqueConfiguration['isSelector'] = true;
304  }
305 
306  // If this is a foreign_unique field, mark it a such for unique data fetching later
307  $selectorOrUniqueConfiguration['isUnique'] = false;
308  if (isset($config['foreign_unique'])) {
309  $selectorOrUniqueConfiguration['isUnique'] = true;
310  }
311 
312  // Add field configuration to inline configuration
313  $result['processedTca']['columns'][$fieldName]['config']['selectorOrUniqueConfiguration'] = $selectorOrUniqueConfiguration;
314 
315  return $result;
316  }
317 }