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