‪TYPO3CMS  10.4
SiteTcaInline.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
31 
38 {
45  public function ‪addData(array $result): array
46  {
47  $result = $this->‪addInlineFirstPid($result);
48  foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
49  if (!$this->‪isInlineField($fieldConfig)) {
50  continue;
51  }
52  $childTableName = $fieldConfig['config']['foreign_table'] ?? '';
53  if (!in_array($childTableName, ['site_errorhandling', 'site_language', 'site_route', 'site_base_variant'], true)) {
54  throw new \RuntimeException('Inline relation to other tables not implemented', 1522494737);
55  }
56  $result['processedTca']['columns'][$fieldName]['children'] = [];
57  $result = $this->‪resolveSiteRelatedChildren($result, $fieldName);
58  $result = $this->‪addForeignSelectorAndUniquePossibleRecords($result, $fieldName);
59  }
60 
61  return $result;
62  }
63 
70  protected function ‪isInlineField(array $fieldConfig): bool
71  {
72  return !empty($fieldConfig['config']['type']) && $fieldConfig['config']['type'] === 'inline';
73  }
74 
83  protected function ‪addInlineFirstPid(array $result): array
84  {
85  if ($result['inlineFirstPid'] === null) {
86  $table = $result['tableName'];
87  $row = $result['databaseRow'];
88  // If the parent is a page, use the uid(!) of the (new?) page as pid for the child records:
89  if ($table === 'pages') {
90  $liveVersionId = ‪BackendUtility::getLiveVersionIdOfRecord('pages', $row['uid']);
91  $pid = $liveVersionId ?? $row['uid'];
92  } elseif (($row['pid'] ?? 0) < 0) {
93  $prevRec = ‪BackendUtility::getRecord($table, (int)abs($row['pid']));
94  $pid = $prevRec['pid'];
95  } else {
96  $pid = $row['pid'] ?? 0;
97  }
99  $pageRecord = ‪BackendUtility::getRecord('pages', (int)$pid);
100  if ((int)$pageRecord[‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']] > 0) {
101  $pid = (int)$pageRecord[‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']];
102  }
103  } elseif (strpos($pid, 'NEW') !== 0) {
104  throw new \RuntimeException(
105  'inlineFirstPid should either be an integer or a "NEW..." string',
106  1521220141
107  );
108  }
109  $result['inlineFirstPid'] = $pid;
110  }
111  return $result;
112  }
113 
122  protected function ‪resolveSiteRelatedChildren(array $result, string $fieldName): array
123  {
124  $connectedUids = [];
125  if ($result['command'] === 'edit') {
126  $siteConfigurationForPageUid = (int)$result['databaseRow']['rootPageId'][0];
127  $siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
128  try {
129  $site = $siteFinder->getSiteByRootPageId($siteConfigurationForPageUid);
130  } catch (‪SiteNotFoundException $e) {
131  $site = null;
132  }
133  $siteConfiguration = $site ? $site->getConfiguration() : [];
134  if (is_array($siteConfiguration[$fieldName])) {
135  $connectedUids = array_keys($siteConfiguration[$fieldName]);
136  }
137  }
138 
139  // If we are dealing with site_language, we *always* force a relation to sys_language "0"
140  $foreignTable = $result['processedTca']['columns'][$fieldName]['config']['foreign_table'];
141  if ($foreignTable === 'site_language' && $result['command'] === 'new') {
142  // If new, just add a new default child
143  $child = $this->‪compileDefaultSysSiteLanguageChild($result, $fieldName);
144  $connectedUids[] = $child['databaseRow']['uid'];
145  $result['processedTca']['columns'][$fieldName]['children'][] = $child;
146  }
147 
148  $result['databaseRow'][$fieldName] = implode(',', $connectedUids);
149  if ($result['inlineCompileExistingChildren']) {
150  foreach ($connectedUids as $uid) {
151  if (strpos((string)$uid, 'NEW') !== 0) {
152  $compiledChild = $this->‪compileChild($result, $fieldName, $uid);
153  $result['processedTca']['columns'][$fieldName]['children'][] = $compiledChild;
154  }
155  }
156  }
157 
158  // If we are dealing with site_language, we *always* force a relation to sys_language "0"
159  if ($foreignTable === 'site_language' && $result['command'] === 'edit') {
160  // If edit, find out if a child using sys_language "0" exists, else add it on top
161  $defaultSysSiteLanguageChildFound = false;
162  foreach ($result['processedTca']['columns'][$fieldName]['children'] as $child) {
163  if (isset($child['databaseRow']['languageId']) && (int)$child['databaseRow']['languageId'][0] == 0) {
164  $defaultSysSiteLanguageChildFound = true;
165  }
166  }
167  if (!$defaultSysSiteLanguageChildFound) {
168  // Compile and add child as first child
169  $child = $this->‪compileDefaultSysSiteLanguageChild($result, $fieldName);
170  $result['databaseRow'][$fieldName] = $child['databaseRow']['uid'] . ',' . $result['databaseRow'][$fieldName];
171  array_unshift($result['processedTca']['columns'][$fieldName]['children'], $child);
172  }
173  }
174 
175  return $result;
176  }
177 
187  protected function ‪addForeignSelectorAndUniquePossibleRecords(array $result, string $fieldName): array
188  {
189  if (!is_array($result['processedTca']['columns'][$fieldName]['config']['selectorOrUniqueConfiguration'])) {
190  return $result;
191  }
192 
193  $selectorOrUniqueConfiguration = $result['processedTca']['columns'][$fieldName]['config']['selectorOrUniqueConfiguration'];
194  $foreignFieldName = $selectorOrUniqueConfiguration['fieldName'];
195  $selectorOrUniquePossibleRecords = [];
196 
197  if ($selectorOrUniqueConfiguration['config']['type'] === 'select') {
198  // Compile child table data for this field only
199  $selectDataInput = [
200  'tableName' => $result['processedTca']['columns'][$fieldName]['config']['foreign_table'],
201  'command' => 'new',
202  // Since there is no existing record that may have a type, it does not make sense to
203  // do extra handling of pageTsConfig merged here. Just provide "parent" pageTS as is
204  'pageTsConfig' => $result['pageTsConfig'],
205  'userTsConfig' => $result['userTsConfig'],
206  'databaseRow' => $result['databaseRow'],
207  'processedTca' => [
208  'ctrl' => [],
209  'columns' => [
210  $foreignFieldName => [
211  'config' => $selectorOrUniqueConfiguration['config'],
212  ],
213  ],
214  ],
215  'inlineExpandCollapseStateArray' => $result['inlineExpandCollapseStateArray'],
216  ];
217  $formDataGroup = GeneralUtility::makeInstance(OnTheFly::class);
218  $formDataGroup->setProviderList([TcaSelectItems::class]);
219  $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
220  $compilerResult = $formDataCompiler->compile($selectDataInput);
221  $selectorOrUniquePossibleRecords = $compilerResult['processedTca']['columns'][$foreignFieldName]['config']['items'];
222  }
223 
224  $result['processedTca']['columns'][$fieldName]['config']['selectorOrUniquePossibleRecords'] = $selectorOrUniquePossibleRecords;
225 
226  return $result;
227  }
228 
237  protected function ‪compileChild(array $result, string $parentFieldName, int $childUid): array
238  {
239  $parentConfig = $result['processedTca']['columns'][$parentFieldName]['config'];
240  $childTableName = $parentConfig['foreign_table'];
241 
242  $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
243  $inlineStackProcessor->initializeByGivenStructure($result['inlineStructure']);
244  $inlineTopMostParent = $inlineStackProcessor->getStructureLevel(0);
245 
246  $formDataGroup = GeneralUtility::makeInstance(SiteConfigurationDataGroup::class);
247  $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
248  $formDataCompilerInput = [
249  'command' => 'edit',
250  'tableName' => $childTableName,
251  'vanillaUid' => $childUid,
252  // Give incoming returnUrl down to children so they generate a returnUrl back to
253  // the originally opening record, also see "originalReturnUrl" in inline container
254  // and FormInlineAjaxController
255  'returnUrl' => $result['returnUrl'],
256  'isInlineChild' => true,
257  'inlineStructure' => $result['inlineStructure'],
258  'inlineExpandCollapseStateArray' => $result['inlineExpandCollapseStateArray'],
259  'inlineFirstPid' => $result['inlineFirstPid'],
260  'inlineParentConfig' => $parentConfig,
261 
262  // values of the current parent element
263  // it is always a string either an id or new...
264  'inlineParentUid' => $result['databaseRow']['uid'],
265  'inlineParentTableName' => $result['tableName'],
266  'inlineParentFieldName' => $parentFieldName,
267 
268  // values of the top most parent element set on first level and not overridden on following levels
269  'inlineTopMostParentUid' => $result['inlineTopMostParentUid'] ?: $inlineTopMostParent['uid'],
270  'inlineTopMostParentTableName' => $result['inlineTopMostParentTableName'] ?: $inlineTopMostParent['table'],
271  'inlineTopMostParentFieldName' => $result['inlineTopMostParentFieldName'] ?: $inlineTopMostParent['field'],
272  ];
273 
274  if ($parentConfig['foreign_selector'] && ($parentConfig['appearance']['useCombination'] ?? false)) {
275  throw new \RuntimeException('useCombination not implemented in sites module', 1522493097);
276  }
277  return $formDataCompiler->compile($formDataCompilerInput);
278  }
279 
287  protected function ‪compileDefaultSysSiteLanguageChild(array $result, string $parentFieldName): array
288  {
289  $parentConfig = $result['processedTca']['columns'][$parentFieldName]['config'];
290  $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
291  $inlineStackProcessor->initializeByGivenStructure($result['inlineStructure']);
292  $inlineTopMostParent = $inlineStackProcessor->getStructureLevel(0);
293  $formDataGroup = GeneralUtility::makeInstance(SiteConfigurationDataGroup::class);
294  $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
295  $formDataCompilerInput = [
296  'command' => 'new',
297  'tableName' => 'site_language',
298  'vanillaUid' => $result['inlineFirstPid'],
299  'returnUrl' => $result['returnUrl'],
300  'isInlineChild' => true,
301  'inlineStructure' => [],
302  'inlineExpandCollapseStateArray' => $result['inlineExpandCollapseStateArray'],
303  'inlineFirstPid' => $result['inlineFirstPid'],
304  'inlineParentConfig' => $parentConfig,
305  'inlineParentUid' => $result['databaseRow']['uid'],
306  'inlineParentTableName' => $result['tableName'],
307  'inlineParentFieldName' => $parentFieldName,
308  'inlineTopMostParentUid' => $result['inlineTopMostParentUid'] ?: $inlineTopMostParent['uid'],
309  'inlineTopMostParentTableName' => $result['inlineTopMostParentTableName'] ?: $inlineTopMostParent['table'],
310  'inlineTopMostParentFieldName' => $result['inlineTopMostParentFieldName'] ?: $inlineTopMostParent['field'],
311  // The sys_language uid 0
312  'inlineChildChildUid' => 0,
313  ];
314  return $formDataCompiler->compile($formDataCompilerInput);
315  }
316 
321  {
322  return ‪$GLOBALS['BE_USER'];
323  }
324 }
‪TYPO3\CMS\Backend\Form\FormDataProvider\SiteTcaInline\addInlineFirstPid
‪array addInlineFirstPid(array $result)
Definition: SiteTcaInline.php:83
‪TYPO3\CMS\Backend\Form\FormDataGroup\OnTheFly
Definition: OnTheFly.php:27
‪TYPO3\CMS\Backend\Form\FormDataProvider\SiteTcaInline\addData
‪array addData(array $result)
Definition: SiteTcaInline.php:45
‪TYPO3\CMS\Backend\Form\FormDataProvider\SiteTcaInline\compileDefaultSysSiteLanguageChild
‪array compileDefaultSysSiteLanguageChild(array $result, string $parentFieldName)
Definition: SiteTcaInline.php:287
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:74
‪TYPO3\CMS\Backend\Form\FormDataProvider\AbstractDatabaseRecordProvider
Definition: AbstractDatabaseRecordProvider.php:29
‪TYPO3\CMS\Backend\Form\FormDataProvider\SiteTcaInline\isInlineField
‪bool isInlineField(array $fieldConfig)
Definition: SiteTcaInline.php:70
‪TYPO3\CMS\Backend\Form\FormDataProvider\SiteTcaInline\getBackendUser
‪BackendUserAuthentication getBackendUser()
Definition: SiteTcaInline.php:320
‪TYPO3\CMS\Core\Exception\SiteNotFoundException
Definition: SiteNotFoundException.php:26
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Backend\Utility\BackendUtility\getLiveVersionIdOfRecord
‪static int null getLiveVersionIdOfRecord($table, $uid)
Definition: BackendUtility.php:3765
‪TYPO3\CMS\Backend\Form\FormDataProvider\SiteTcaInline\compileChild
‪array compileChild(array $result, string $parentFieldName, int $childUid)
Definition: SiteTcaInline.php:237
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Backend\Form\FormDataProvider\SiteTcaInline
Definition: SiteTcaInline.php:38
‪TYPO3\CMS\Backend\Form\FormDataProvider
Definition: AbstractDatabaseRecordProvider.php:16
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:75
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecord
‪static array null getRecord($table, $uid, $fields=' *', $where='', $useDeleteClause=true)
Definition: BackendUtility.php:95
‪TYPO3\CMS\Backend\Form\FormDataProviderInterface
Definition: FormDataProviderInterface.php:23
‪TYPO3\CMS\Backend\Form\FormDataProvider\SiteTcaInline\addForeignSelectorAndUniquePossibleRecords
‪array addForeignSelectorAndUniquePossibleRecords(array $result, string $fieldName)
Definition: SiteTcaInline.php:187
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Backend\Form\FormDataProvider\SiteTcaInline\resolveSiteRelatedChildren
‪array resolveSiteRelatedChildren(array $result, string $fieldName)
Definition: SiteTcaInline.php:122
‪TYPO3\CMS\Backend\Form\InlineStackProcessor
Definition: InlineStackProcessor.php:30
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Backend\Form\FormDataCompiler
Definition: FormDataCompiler.php:25
‪TYPO3\CMS\Backend\Form\FormDataGroup\SiteConfigurationDataGroup
Definition: SiteConfigurationDataGroup.php:33