$fieldConfig) { if (($fieldConfig['config']['type'] ?? '') !== 'siteLanguage') { continue; } if (!$result['tcaSchemata']->has(self::FOREIGN_TABLE)) { throw new \RuntimeException('Table ' . self::FOREIGN_TABLE . ' does not exists', 1624029932); } $foreignTableSchema = $result['tcaSchemata']->get(self::FOREIGN_TABLE); /** @var FieldTypeInterface|null $foreignField */ $foreignField = $foreignTableSchema->hasField(self::FOREIGN_FIELD) ? $foreignTableSchema->getField(self::FOREIGN_FIELD) : null; if ($foreignField?->getType() !== 'select') { throw new \UnexpectedValueException( 'Table ' . $result['tableName'] . ' field ' . $fieldName . ' points to field ' . self::FOREIGN_FIELD . ' of table ' . self::FOREIGN_TABLE . ', but this field ' . 'is either not defined or is not of type select', 1624029933 ); } if (!($foreignField->getConfiguration()['itemsProcFunc'] ?? false)) { throw new \UnexpectedValueException( 'Table ' . $result['tableName'] . ' field ' . $fieldName . ' points to field ' . self::FOREIGN_FIELD . ' of table ' . self::FOREIGN_TABLE . '. This field must define ' . 'an \'itemsProcFunc\'.', 1624029934 ); } $result = $this->addInlineRelatedConfig($result, $fieldName); $result = $this->initializeMinMaxItems($result, $fieldName); $result = $this->initializeAppearance($result, $fieldName); $result = $this->addInlineFirstPid($result); $result = $this->resolveSiteLanguageChildren($result, $fieldName); $result = $this->addUniquePossibleRecords($result, $fieldName); } return $result; } protected function addInlineRelatedConfig(array $result, string $fieldName): array { $config = $result['processedTca']['columns'][$fieldName]['config']; $config['foreign_table'] = self::FOREIGN_TABLE; $config['foreign_selector'] = self::FOREIGN_FIELD; $result['processedTca']['columns'][$fieldName]['config'] = $config; return $result; } protected function initializeMinMaxItems(array $result, string $fieldName): array { $config = $result['processedTca']['columns'][$fieldName]['config']; $config['minitems'] = isset($config['minitems']) ? MathUtility::forceIntegerInRange($config['minitems'], 1) : 1; $config['maxitems'] = isset($config['maxitems']) ? MathUtility::forceIntegerInRange($config['maxitems'], 2) : 99999; $result['processedTca']['columns'][$fieldName]['config'] = $config; return $result; } protected function initializeAppearance(array $result, string $fieldName): array { $config = $result['processedTca']['columns'][$fieldName]['config']; if (!is_array($config['appearance'] ?? false)) { $config['appearance'] = []; } $config['appearance']['showPossibleLocalizationRecords'] = false; $config['appearance']['collapseAll'] = true; $config['appearance']['expandSingle'] = false; $config['appearance']['enabledControls'] = [ 'info' => false, 'new' => false, 'dragdrop' => false, 'sort' => false, 'hide' => false, 'delete' => true, 'localize' => false, ]; $config['size'] = (int)($config['size'] ?? 4); $result['processedTca']['columns'][$fieldName]['config'] = $config; return $result; } protected function addInlineFirstPid(array $result): array { if (($result['inlineFirstPid'] ?? null) !== null || ($result['tableName'] ?? '') !== self::FOREIGN_TABLE) { return $result; } $pid = $result['databaseRow']['pid'] ?? 0; if (!MathUtility::canBeInterpretedAsInteger($pid) || !str_starts_with($pid, 'NEW')) { throw new \RuntimeException( 'inlineFirstPid should either be an integer or a "NEW..." string', 1624310264 ); } $result['inlineFirstPid'] = $pid; return $result; } protected function resolveSiteLanguageChildren(array $result, string $fieldName): array { $connectedUids = []; $result['processedTca']['columns'][$fieldName]['children'] = []; if ($result['command'] === 'edit') { $unprocessedRootPageId = $result['databaseRow']['rootPageId'][0] ?? null; $processedRootPageId = $this->envPlaceholderProcessor->canProcess($unprocessedRootPageId) ? (int)$this->envPlaceholderProcessor->process($unprocessedRootPageId) : (int)$unprocessedRootPageId; $siteConfiguration = []; try { $site = $this->siteFinder->getSiteByRootPageId($processedRootPageId); $siteConfiguration = $site->getConfiguration(); } catch (SiteNotFoundException $e) { } if (is_array($siteConfiguration[$fieldName] ?? false)) { // Add uids of existing site languages $connectedUids = array_keys($siteConfiguration[$fieldName]); } } elseif ($result['command'] === 'new') { // If new, *always* force a relation to the default language ("0") $child = $this->compileDefaultSiteLanguageChild($result, $fieldName); $connectedUids[] = $child['databaseRow']['uid']; $result['processedTca']['columns'][$fieldName]['children'][] = $child; } // Add connected uids as csv field value $result['databaseRow'][$fieldName] = implode(',', $connectedUids); if ($result['inlineCompileExistingChildren']) { foreach ($connectedUids as $uid) { // Compile existing (persisted) site languages if (!str_starts_with((string)$uid, 'NEW')) { $compiledChild = $this->compileChild($result, $fieldName, $uid); $result['processedTca']['columns'][$fieldName]['children'][] = $compiledChild; } } } if ($result['command'] === 'edit') { // If edit, find out if a default language ("0") exists, else add it on top $defaultSysSiteLanguageChildFound = false; foreach ($result['processedTca']['columns'][$fieldName]['children'] as $child) { if (isset($child['databaseRow']['languageId'][0]) && (int)$child['databaseRow']['languageId'][0] === 0) { $defaultSysSiteLanguageChildFound = true; } } if (!$defaultSysSiteLanguageChildFound) { // Compile and add child as first child, since non exists yet $child = $this->compileDefaultSiteLanguageChild($result, $fieldName); $result['databaseRow'][$fieldName] = $child['databaseRow']['uid'] . ',' . $result['databaseRow'][$fieldName]; array_unshift($result['processedTca']['columns'][$fieldName]['children'], $child); } } return $result; } protected function compileDefaultSiteLanguageChild(array $result, string $parentFieldName): array { $inlineTopMostParent = $this->inlineStackProcessor->getStructureLevelFromStructure($result['inlineStructure'], 0); return GeneralUtility::makeInstance(FormDataCompiler::class) ->compile( [ 'request' => $result['request'], 'command' => 'new', 'tableName' => self::FOREIGN_TABLE, 'vanillaUid' => $result['inlineFirstPid'], 'databaseRow' => $this->getDefaultDatabaseRow(), 'returnUrl' => $result['returnUrl'], 'isInlineChild' => true, 'inlineStructure' => [], 'inlineExpandCollapseStateArray' => $result['inlineExpandCollapseStateArray'], 'inlineFirstPid' => $result['inlineFirstPid'], 'inlineParentConfig' => $result['processedTca']['columns'][$parentFieldName]['config'], 'inlineParentUid' => $result['databaseRow']['uid'], 'inlineParentTableName' => $result['tableName'], 'inlineParentFieldName' => $parentFieldName, 'inlineTopMostParentUid' => $result['inlineTopMostParentUid'] ?: ($inlineTopMostParent['uid'] ?? null), 'inlineTopMostParentTableName' => $result['inlineTopMostParentTableName'] ?: ($inlineTopMostParent['table'] ?? ''), 'inlineTopMostParentFieldName' => $result['inlineTopMostParentFieldName'] ?: ($inlineTopMostParent['field'] ?? ''), 'inlineChildChildUid' => 0, // pass through schemata as they are immutable once they are set 'tcaSchemata' => $result['tcaSchemata'], // pass through fullTca as it is immutable once set 'fullTca' => $result['fullTca'], ], GeneralUtility::makeInstance(SiteConfigurationDataGroup::class) ); } protected function compileChild(array $result, string $parentFieldName, int $childUid): array { $inlineTopMostParent = $this->inlineStackProcessor->getStructureLevelFromStructure($result['inlineStructure'], 0); return GeneralUtility::makeInstance(FormDataCompiler::class) ->compile( [ 'request' => $result['request'], 'command' => 'edit', 'tableName' => self::FOREIGN_TABLE, 'vanillaUid' => $childUid, 'returnUrl' => $result['returnUrl'], 'isInlineChild' => true, 'inlineStructure' => $result['inlineStructure'], 'inlineExpandCollapseStateArray' => $result['inlineExpandCollapseStateArray'], 'inlineFirstPid' => $result['inlineFirstPid'], 'inlineParentConfig' => $result['processedTca']['columns'][$parentFieldName]['config'], 'inlineParentUid' => $result['databaseRow']['uid'], 'inlineParentTableName' => $result['tableName'], 'inlineParentFieldName' => $parentFieldName, 'inlineTopMostParentUid' => $result['inlineTopMostParentUid'] ?: ($inlineTopMostParent['uid'] ?? null), 'inlineTopMostParentTableName' => $result['inlineTopMostParentTableName'] ?: ($inlineTopMostParent['table'] ?? ''), 'inlineTopMostParentFieldName' => $result['inlineTopMostParentFieldName'] ?: ($inlineTopMostParent['field'] ?? ''), // pass through schemata as they are immutable once they are set 'tcaSchemata' => $result['tcaSchemata'], // pass through fullTca as it is immutable once set 'fullTca' => $result['fullTca'], ], GeneralUtility::makeInstance(SiteConfigurationDataGroup::class) ); } protected function addUniquePossibleRecords(array $result, string $fieldName): array { $formDataGroup = GeneralUtility::makeInstance(OnTheFly::class); $formDataGroup->setProviderList([TcaSelectItems::class]); $foreignTableSchema = $result['tcaSchemata']->get(self::FOREIGN_TABLE); // Add unique possible records, so they can be used in the selector field $result['processedTca']['columns'][$fieldName]['config']['uniquePossibleRecords'] = GeneralUtility::makeInstance(FormDataCompiler::class) ->compile( [ 'request' => $result['request'], 'command' => 'new', 'tableName' => self::FOREIGN_TABLE, 'pageTsConfig' => $result['pageTsConfig'], 'userTsConfig' => $result['userTsConfig'], 'databaseRow' => $result['databaseRow'], 'processedTca' => [ 'ctrl' => [], 'columns' => [ self::FOREIGN_FIELD => [ 'config' => $foreignTableSchema->getField(self::FOREIGN_FIELD)->getConfiguration(), ], ], ], 'inlineExpandCollapseStateArray' => $result['inlineExpandCollapseStateArray'], // pass through schemata as they are immutable once they are set 'tcaSchemata' => $result['tcaSchemata'], // pass through fullTca as it is immutable once set 'fullTca' => $result['fullTca'], ], $formDataGroup )['processedTca']['columns'][self::FOREIGN_FIELD]['config']['items'] ?? []; return $result; } /** * Create the database row for the default site language based * on an already existing default language from another site. */ protected function getDefaultDatabaseRow(): array { $defaultDatabaseRow = []; foreach ($this->siteFinder->getAllSites() as $site) { foreach ($site->getAllLanguages() as $language) { if ($language->getLanguageId() === 0) { $defaultDatabaseRow['locale'] = $language->getLocale()->posixFormatted(); if ($language->getTitle() !== '') { $defaultDatabaseRow['title'] = $language->getTitle(); } if ($language->getNavigationTitle() !== '') { $defaultDatabaseRow['navigationTitle'] = $language->getNavigationTitle(); } if ($language->getHreflang(true) !== '') { $defaultDatabaseRow['hreflang'] = $language->getHreflang(); } if (str_starts_with($language->getFlagIdentifier(), 'flags-')) { $flagIdentifier = str_replace('flags-', '', $language->getFlagIdentifier()); $defaultDatabaseRow['flag'] = ($flagIdentifier === 'multiple') ? 'global' : $flagIdentifier; } break 2; } } } return $defaultDatabaseRow; } }