625 lines
30 KiB
PHP
625 lines
30 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* This file is part of the TYPO3 CMS project.
|
|
*
|
|
* It is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License, either version 2
|
|
* of the License, or any later version.
|
|
*
|
|
* For the full copyright and license information, please read the
|
|
* LICENSE.txt file that was distributed with this source code.
|
|
*
|
|
* The TYPO3 project - inspiring people to share!
|
|
*/
|
|
|
|
namespace TYPO3\CMS\Core\Configuration\Tca;
|
|
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
use TYPO3\CMS\Core\Utility\StringUtility;
|
|
|
|
/**
|
|
* Prepare TCA. Used in bootstrap and Flex Form Data Structures,
|
|
* executed *after* TcaMigration.
|
|
* This is used to add *internal TCA details* needed by core.
|
|
* For instance, type=category fields receive all the relation
|
|
* details in order to work properly.
|
|
*
|
|
* @internal Class and API may change any time.
|
|
*/
|
|
readonly class TcaPreparation
|
|
{
|
|
/**
|
|
* Prepare TCA
|
|
*
|
|
* This class is typically called within bootstrap with empty caches after all TCA
|
|
* files from extensions have been loaded. The preparation is then applied and
|
|
* the prepared result is cached.
|
|
* For flex form TCA, this class is called dynamically if opening a record in the backend.
|
|
*
|
|
* See unit tests for details.
|
|
*/
|
|
public function prepare(array $tca, bool $isFlexForm = false): array
|
|
{
|
|
$tca = $this->configureCategoryRelations($tca, $isFlexForm);
|
|
$tca = $this->configureFileReferences($tca, $isFlexForm);
|
|
$tca = $this->configureEmailSoftReferences($tca);
|
|
$tca = $this->configureLinkSoftReferences($tca);
|
|
$tca = $this->configureSelectSingle($tca);
|
|
$tca = $this->configureRelationshipToOne($tca);
|
|
$tca = $this->addSystemFieldsToShowitemTypes($tca);
|
|
$tca = $this->addIgnoredPageTypeRestrictionRecords($tca);
|
|
return $tca;
|
|
}
|
|
|
|
/**
|
|
* Prepares TCA configuration of type='category' fields.
|
|
*
|
|
* It adds some TCA config settings so category fields end up with similar
|
|
* config as type='select' field, but in a more restricted way.
|
|
* Some settings could also be set in TCA directly, but some fields
|
|
* can not be overridden, e.g. foreign_table.
|
|
*
|
|
* This also sets necessary MM properties, in case relationship is
|
|
* set to "manyToMany", which is the default. Note it is "oneToMany"
|
|
* with flex forms, since flex forms do NOT support "manyToMany".
|
|
*
|
|
* Finally, all category fields with a "manyToMany" relationship are
|
|
* added to the MM_oppositeUsage of sys_category "items".
|
|
*
|
|
* Important: Since this method defines a "foreign_table_where", this
|
|
* must always be executed before prepareQuotingOfTableNamesAndColumnNames().
|
|
*/
|
|
protected function configureCategoryRelations(array $tca, bool $isFlexForm): array
|
|
{
|
|
foreach ($tca as $table => &$tableDefinition) {
|
|
if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
|
|
continue;
|
|
}
|
|
foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
|
|
if (($fieldConfig['config']['type'] ?? '') !== 'category') {
|
|
continue;
|
|
}
|
|
if (!isset($fieldConfig['label'])) {
|
|
$fieldConfig['label'] = 'LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_category.categories';
|
|
}
|
|
// Force foreign_table for type category
|
|
$fieldConfig['config']['foreign_table'] = 'sys_category';
|
|
// Initialize default column configuration and merge it with already defined
|
|
$fieldConfig['config']['size'] ??= 20;
|
|
$defaultTag = \Local\Multilanguage\Service\DefaultLanguageTagService::getTag();
|
|
$fieldConfig['config']['foreign_table_where'] ??= " AND {#sys_category}.{#language_tag} IN ('" . $defaultTag . "', '')";
|
|
if (empty($fieldConfig['config']['relationship'])) {
|
|
// In case no relationship is given, set "manyToMany" for non flex form, but "oneToMany" with flex form.
|
|
$fieldConfig['config']['relationship'] = $isFlexForm ? 'oneToMany' : 'manyToMany';
|
|
}
|
|
|
|
// Sanitize 'relationship'
|
|
if ($isFlexForm && !in_array($fieldConfig['config']['relationship'], ['oneToOne', 'oneToMany'], true)) {
|
|
throw new \UnexpectedValueException(
|
|
'"relationship" must be one of "oneToOne" or "oneToMany", "manyToMany" is not supported as "relationship"'
|
|
. ' for field ' . $fieldName . ' of type "category" in flexform.',
|
|
1627640208
|
|
);
|
|
}
|
|
if (!in_array($fieldConfig['config']['relationship'], ['oneToOne', 'oneToMany', 'manyToMany'], true)) {
|
|
throw new \RuntimeException(
|
|
$fieldName . ' of table ' . $table . ' is defined as type category with relationship "'
|
|
. $fieldConfig['config']['relationship'] . '", but only "oneToOne", "oneToMany" and "manyToMany"'
|
|
. ' are allowed.',
|
|
1627898896
|
|
);
|
|
}
|
|
|
|
// Set the maxitems value (necessary for DataHandling and FormEngine)
|
|
if ($fieldConfig['config']['relationship'] === 'oneToOne') {
|
|
// In case relationship is set to "oneToOne", the database column for this
|
|
// field will be an integer column. This means, only one uid can be stored.
|
|
// Therefore, maxitems must be 1. Sanitize for flex form fields as well.
|
|
if ((int)($fieldConfig['config']['maxitems'] ?? 0) > 1) {
|
|
throw new \RuntimeException(
|
|
$fieldName . ' of table ' . $table . ' is defined as type category with an oneToOne relationship. '
|
|
. 'Therefore maxitems must be 1. Otherwise, use oneToMany or manyToMany as relationship instead.',
|
|
1627335016
|
|
);
|
|
}
|
|
$fieldConfig['config']['maxitems'] = 1;
|
|
} elseif (!($fieldConfig['config']['maxitems'] ?? false)) {
|
|
// In case maxitems is not set or set to 0, set the default value "99999"
|
|
$fieldConfig['config']['maxitems'] = 99999;
|
|
} elseif ($fieldConfig['config']['relationship'] === 'oneToMany'
|
|
&& (int)($fieldConfig['config']['maxitems'] ?? 0) === 1
|
|
) {
|
|
throw new \RuntimeException(
|
|
$fieldName . ' of table ' . $table . ' is defined as type category with a ' . $fieldConfig['config']['relationship']
|
|
. ' relationship. Therefore, maxitems can not be set to 1. Use oneToOne as relationship instead.',
|
|
1627335017
|
|
);
|
|
}
|
|
|
|
// Add the default value if not set
|
|
if (!isset($fieldConfig['config']['default'])
|
|
&& $fieldConfig['config']['relationship'] !== 'oneToMany'
|
|
) {
|
|
// @todo: This is db wise not accurate: A oneToOne relation without a relation being assigned,
|
|
// @todo: should have NULL as value, not 0, since 0 looks like a uid, but it isn't.
|
|
// @todo: The field should be nullable and DH should handle that.
|
|
$fieldConfig['config']['default'] = 0;
|
|
}
|
|
|
|
// Add MM related properties in case relationship is set to "manyToMany".
|
|
// This will not be done for the sys_category table itself. Not relevant with flex forms.
|
|
if ($fieldConfig['config']['relationship'] === 'manyToMany' && $table !== 'sys_category') {
|
|
// Note these settings are hard coded here and can't be overridden.
|
|
$fieldConfig['config'] = array_replace_recursive($fieldConfig['config'], [
|
|
'MM' => 'sys_category_record_mm',
|
|
'MM_opposite_field' => 'items',
|
|
'MM_match_fields' => [
|
|
'tablenames' => $table,
|
|
'fieldname' => $fieldName,
|
|
],
|
|
]);
|
|
// Register opposite references for the foreign side of a category relation
|
|
if (empty($tca['sys_category']['columns']['items']['config']['MM_oppositeUsage'][$table])) {
|
|
$tca['sys_category']['columns']['items']['config']['MM_oppositeUsage'][$table] = [];
|
|
}
|
|
if (!in_array($fieldName, $tca['sys_category']['columns']['items']['config']['MM_oppositeUsage'][$table], true)) {
|
|
$tca['sys_category']['columns']['items']['config']['MM_oppositeUsage'][$table][] = $fieldName;
|
|
}
|
|
// Take specific value of exclude flag into account
|
|
if (!isset($fieldConfig['exclude'])) {
|
|
$fieldConfig['exclude'] = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $tca;
|
|
}
|
|
|
|
protected function configureFileReferences(array $tca, bool $isFlexForm): array
|
|
{
|
|
foreach ($tca as $table => &$tableDefinition) {
|
|
if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
|
|
continue;
|
|
}
|
|
foreach ($tableDefinition['columns'] as $fieldName => &$fieldConfig) {
|
|
if (($fieldConfig['config']['type'] ?? '') === 'file') {
|
|
// Set static values for this type. Most of them are not needed due to the
|
|
// dedicated TCA type. However a lot of underlying code in DataHandler and
|
|
// friends relies on those keys, especially "foreign_table" and "foreign_selector".
|
|
// @todo Check which of those values can be removed since only used by FormEngine
|
|
$fieldConfig['config'] = array_replace_recursive($fieldConfig['config'], [
|
|
'foreign_table' => 'sys_file_reference',
|
|
'foreign_field' => 'uid_foreign',
|
|
'foreign_sortby' => 'sorting_foreign',
|
|
'foreign_table_field' => 'tablenames',
|
|
'foreign_label' => 'uid_local',
|
|
'foreign_selector' => 'uid_local',
|
|
]);
|
|
if (!isset($fieldConfig['config']['foreign_match_fields']['fieldname'])) {
|
|
$fieldConfig['config']['foreign_match_fields']['fieldname'] = $fieldName;
|
|
}
|
|
if (!$isFlexForm) {
|
|
$fieldConfig['config']['foreign_match_fields']['tablenames'] = $table;
|
|
}
|
|
$fieldConfig['config'] = $this->configureAllowedDisallowedFileExtensions($fieldConfig['config']);
|
|
}
|
|
if (is_array($fieldConfig['config']['overrideChildTca'] ?? null)) {
|
|
$fieldConfig['config']['overrideChildTca'] = $this->configureAllowedDisallowedInOverrideChildTca($fieldConfig['config']['overrideChildTca']);
|
|
}
|
|
}
|
|
unset($fieldConfig);
|
|
if (is_array($tableDefinition['types'] ?? null)) {
|
|
foreach ($tableDefinition['types'] as &$typeConfig) {
|
|
if (!isset($typeConfig['columnsOverrides']) || !is_array($typeConfig['columnsOverrides'])) {
|
|
continue;
|
|
}
|
|
foreach ($typeConfig['columnsOverrides'] as &$columnsOverridesConfig) {
|
|
if (!isset($columnsOverridesConfig['config']) || !is_array($columnsOverridesConfig['config'])) {
|
|
continue;
|
|
}
|
|
$columnsOverridesConfig['config'] = $this->configureAllowedDisallowedFileExtensions($columnsOverridesConfig['config']);
|
|
if (is_array($columnsOverridesConfig['config']['overrideChildTca'] ?? null)) {
|
|
$columnsOverridesConfig['config']['overrideChildTca'] = $this->configureAllowedDisallowedInOverrideChildTca($columnsOverridesConfig['config']['overrideChildTca']);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $tca;
|
|
}
|
|
|
|
/**
|
|
* configureFileReferences() helper
|
|
*/
|
|
protected function configureAllowedDisallowedInOverrideChildTca(array $overrideChildTcaConfig): array
|
|
{
|
|
if (is_array($overrideChildTcaConfig['columns'] ?? null)) {
|
|
foreach ($overrideChildTcaConfig['columns'] as &$overrideChildTcaColumnConfig) {
|
|
if (!isset($overrideChildTcaColumnConfig['config'])) {
|
|
continue;
|
|
}
|
|
$overrideChildTcaColumnConfig['config'] = $this->configureAllowedDisallowedFileExtensions($overrideChildTcaColumnConfig['config']);
|
|
}
|
|
unset($overrideChildTcaColumnConfig);
|
|
}
|
|
if (is_array($overrideChildTcaConfig['types'] ?? null)) {
|
|
foreach ($overrideChildTcaConfig['types'] as &$overrideChildTcaTypeConfig) {
|
|
if (!isset($overrideChildTcaTypeConfig['config'])) {
|
|
continue;
|
|
}
|
|
$overrideChildTcaTypeConfig['config'] = $this->configureAllowedDisallowedFileExtensions($overrideChildTcaTypeConfig['config']);
|
|
}
|
|
}
|
|
return $overrideChildTcaConfig;
|
|
}
|
|
|
|
/**
|
|
* configureFileReferences() helper
|
|
*/
|
|
protected function configureAllowedDisallowedFileExtensions(array $config): array
|
|
{
|
|
if (!empty($allowed = ($config['allowed'] ?? null))) {
|
|
$config['allowed'] = $this->prepareFileExtensions($allowed);
|
|
}
|
|
if (!empty($disallowed = ($config['disallowed'] ?? null))) {
|
|
$config['disallowed'] = $this->prepareFileExtensions($disallowed);
|
|
}
|
|
return $config;
|
|
}
|
|
|
|
/**
|
|
* configureFileReferences() helper: Ensures format, replaces placeholders and remove duplicates
|
|
*/
|
|
protected function prepareFileExtensions(mixed $fileExtensions): string
|
|
{
|
|
if (is_array($fileExtensions)) {
|
|
$fileExtensions = implode(',', $fileExtensions);
|
|
} else {
|
|
$fileExtensions = (string)$fileExtensions;
|
|
}
|
|
// Replace placeholders with the corresponding $GLOBALS value for now
|
|
if (preg_match_all('/common-(image|text|media)-types/', $fileExtensions, $matches)) {
|
|
foreach ($matches[1] as $key => $type) {
|
|
$fileExtensions = str_replace(
|
|
$matches[0][$key],
|
|
$GLOBALS['TYPO3_CONF_VARS'][$type === 'image' ? 'GFX' : 'SYS'][$type . 'file_ext'] ?? '',
|
|
$fileExtensions
|
|
);
|
|
}
|
|
}
|
|
return StringUtility::uniqueList($fileExtensions);
|
|
}
|
|
|
|
/**
|
|
* Add "'softref' = 'email[subst]'" to all 'type' = 'email' column fields.
|
|
*/
|
|
protected function configureEmailSoftReferences(array $tca): array
|
|
{
|
|
foreach ($tca as &$tableDefinition) {
|
|
if (!is_array($tableDefinition['columns'] ?? null)) {
|
|
continue;
|
|
}
|
|
foreach ($tableDefinition['columns'] as &$fieldConfig) {
|
|
if (($fieldConfig['config']['type'] ?? null) === 'email') {
|
|
// Hard set/override: 'softref' is not listed as property for type=email at all,
|
|
// there is little need to have this configurable.
|
|
$fieldConfig['config']['softref'] = 'email[subst]';
|
|
}
|
|
}
|
|
}
|
|
return $tca;
|
|
}
|
|
|
|
/**
|
|
* Add "'softref' = 'typolink'" to all 'type' = 'link' column fields.
|
|
*/
|
|
protected function configureLinkSoftReferences(array $tca): array
|
|
{
|
|
foreach ($tca as &$tableDefinition) {
|
|
if (!is_array($tableDefinition['columns'] ?? null)) {
|
|
continue;
|
|
}
|
|
foreach ($tableDefinition['columns'] as &$fieldConfig) {
|
|
if (($fieldConfig['config']['type'] ?? null) === 'link') {
|
|
// Hard set/override: 'softref' is not listed as property for type=link at all,
|
|
// there is little need to have this configurable.
|
|
$fieldConfig['config']['softref'] = 'typolink';
|
|
}
|
|
}
|
|
}
|
|
return $tca;
|
|
}
|
|
|
|
/**
|
|
* Add "'relationship' for TCA type "select" fields, having "selectSingle" set as renderType and are
|
|
* pointing to a "foreign_table". Depending on further configuration, this will set the "relationship"
|
|
* to either "manyToMany" (in case "MM" is set) or to "manyToOne".
|
|
* Already defined "relationship" is not overwritten!
|
|
*
|
|
* This is mainly done to prevent checks on the renderType, which should be avoided.
|
|
*/
|
|
protected function configureSelectSingle(array $tca): array
|
|
{
|
|
foreach ($tca as &$tableDefinition) {
|
|
if (!is_array($tableDefinition['columns'] ?? null)) {
|
|
continue;
|
|
}
|
|
foreach ($tableDefinition['columns'] as &$fieldConfig) {
|
|
if (($fieldConfig['config']['type'] ?? null) !== 'select'
|
|
|| ($fieldConfig['config']['renderType'] ?? null) !== 'selectSingle'
|
|
|| !isset($fieldConfig['config']['foreign_table'])
|
|
|| isset($fieldConfig['config']['relationship'])
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
if (isset($fieldConfig['config']['MM'])) {
|
|
$fieldConfig['config']['relationship'] = 'manyToMany';
|
|
} else {
|
|
$fieldConfig['config']['relationship'] = 'manyToOne';
|
|
}
|
|
}
|
|
}
|
|
return $tca;
|
|
}
|
|
|
|
/**
|
|
* Add "'maxitems' => 1" to all relation type column fields with 'relationship' set to 'oneToOne' or 'manyToOne'.
|
|
*/
|
|
protected function configureRelationshipToOne(array $tca): array
|
|
{
|
|
foreach ($tca as &$tableDefinition) {
|
|
if (!is_array($tableDefinition['columns'] ?? null)) {
|
|
continue;
|
|
}
|
|
foreach ($tableDefinition['columns'] as &$fieldConfig) {
|
|
$type = $fieldConfig['config']['type'] ?? null;
|
|
if (in_array($type, ['select', 'inline', 'group', 'folder', 'file'], true)
|
|
&& in_array($fieldConfig['config']['relationship'] ?? null, ['oneToOne', 'manyToOne'], true)
|
|
) {
|
|
// Hard set/override: 'maxitems' to 1, since relationship [x]ToOne - as the name suggests -
|
|
// only allows a single item to be selected.
|
|
$fieldConfig['config']['maxitems'] = 1;
|
|
}
|
|
}
|
|
}
|
|
return $tca;
|
|
}
|
|
|
|
/**
|
|
* Ensure that all system fields (CType, colPos, hidden etc.) are automatically added
|
|
* to the showitem list of all CTypes in tt_content. As custom CTypes might have added
|
|
* the fields, the respective fields also need to be removed first.
|
|
*/
|
|
protected function addSystemFieldsToShowitemTypes(array $tca): array
|
|
{
|
|
// @todo Only deal with this for tt_content in v13, as other parts might be too intrusive
|
|
// might change in v14
|
|
if (!isset($tca['tt_content'])) {
|
|
return $tca;
|
|
}
|
|
// Only proceed in case the record type field is defined
|
|
$typeField = (string)($tca['tt_content']['ctrl']['type'] ?? '');
|
|
if ($typeField === '') {
|
|
return $tca;
|
|
}
|
|
// Build list of values (fields and palettes) which should be removed
|
|
// from custom palettes, because they will be added automatically.
|
|
$listOfValuesToRemove = [
|
|
'--div--;core.form.tabs:general',
|
|
'--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general',
|
|
'--div--;core.form.tabs:language',
|
|
'--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language',
|
|
'--div--;core.form.tabs:access',
|
|
'--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access',
|
|
'--div--;core.form.tabs:notes',
|
|
'--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes',
|
|
'--palette--;;general',
|
|
'--palette--;;language',
|
|
'--palette--;;access',
|
|
'--palette--;;hidden',
|
|
'colPos',
|
|
];
|
|
$listOfValuesToRemove[] = $typeField;
|
|
if (($languageField = (string)($tca['tt_content']['ctrl']['languageField'] ?? '')) !== '') {
|
|
$listOfValuesToRemove[] = $languageField;
|
|
}
|
|
if (($transOrigPointerField = (string)($tca['tt_content']['ctrl']['transOrigPointerField'] ?? '')) !== '') {
|
|
$listOfValuesToRemove[] = $transOrigPointerField;
|
|
}
|
|
$enablecolumns = $tca['tt_content']['ctrl']['enablecolumns'] ?? [];
|
|
foreach ($enablecolumns as $fieldName) {
|
|
$listOfValuesToRemove[] = $fieldName;
|
|
}
|
|
if (($editlock = (string)($tca['tt_content']['ctrl']['editlock'] ?? '')) !== '') {
|
|
$listOfValuesToRemove[] = $editlock;
|
|
}
|
|
if (($descriptionColumn = (string)($tca['tt_content']['ctrl']['descriptionColumn'] ?? '')) !== '') {
|
|
$listOfValuesToRemove[] = $descriptionColumn;
|
|
}
|
|
|
|
// Remove any system field from custom palettes
|
|
foreach ($tca['tt_content']['palettes'] as $paletteName => &$paletteConfig) {
|
|
if (in_array($paletteName, ['general', 'language', 'access', 'hidden'], true)) {
|
|
continue;
|
|
}
|
|
$showItemSplitted = GeneralUtility::trimExplode(',', $paletteConfig['showitem'], true);
|
|
$paletteConfig['showitem'] = implode(',', array_diff($this->removeCustomFieldLabels($showItemSplitted, $listOfValuesToRemove), $listOfValuesToRemove));
|
|
}
|
|
unset($paletteConfig);
|
|
|
|
// Process the content types
|
|
foreach ($tca['tt_content']['types'] as $type => $typeInformation) {
|
|
// Remove any of the special fields from the content type's current showitem
|
|
$showItemSplitted = GeneralUtility::trimExplode(',', $typeInformation['showitem'] ?? '', true);
|
|
$showItemFiltered = array_diff($this->removeCustomFieldLabels($showItemSplitted, $listOfValuesToRemove), $listOfValuesToRemove);
|
|
|
|
// Extract all fields of the extended tab to add it at the end
|
|
[$showItemList, $extendedParts] = $this->extractExtendedParts($showItemFiltered);
|
|
|
|
// Add record type field (usually "CType") and colPos either using the "general" palette
|
|
// or manually, in case the palette does not exist or does not contain the fields.
|
|
$generalPaletteItems = $this->removeCustomFieldLabels(GeneralUtility::trimExplode(',', $tca['tt_content']['palettes']['general']['showitem'] ?? '', true), $listOfValuesToRemove);
|
|
if (in_array($typeField, $generalPaletteItems, true) && in_array('colPos', $generalPaletteItems, true)) {
|
|
$showItemParts = ['--palette--;;general'];
|
|
} else {
|
|
$showItemParts = [
|
|
$typeField,
|
|
'colPos',
|
|
];
|
|
}
|
|
|
|
// Because FormEngine will add the general tab automatically, we will not do this here
|
|
// However, if the first item in the $showItemList is actually a tab (--div--), we need to
|
|
// add if before the "first fields"
|
|
if (str_starts_with($showItemList[0] ?? '', '--div--')) {
|
|
array_unshift($showItemParts, $showItemList[0]);
|
|
unset($showItemList[0]);
|
|
}
|
|
$showItemParts = array_merge($showItemParts, $showItemList);
|
|
|
|
// Add language field either using the "language" palette or manually,
|
|
// in case the palette does not exist or does not contain the field.
|
|
if ($languageField !== '') {
|
|
$showItemParts[] = '--div--;core.form.tabs:language';
|
|
$languagePaletteItems = $this->removeCustomFieldLabels(GeneralUtility::trimExplode(',', $tca['tt_content']['palettes']['language']['showitem'] ?? '', true), $listOfValuesToRemove);
|
|
if (in_array($languageField, $languagePaletteItems, true)
|
|
&& ($transOrigPointerField === '' || in_array($transOrigPointerField, $languagePaletteItems, true))
|
|
) {
|
|
$showItemParts[] = '--palette--;;language';
|
|
} else {
|
|
$showItemParts[] = $languageField;
|
|
if ($transOrigPointerField) {
|
|
$showItemParts[] = $transOrigPointerField;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add enable fields either using the "hidden" amd "access" palettes or
|
|
// manually, in case the palettes do not exist or do not contain the fields.
|
|
if ($enablecolumns !== [] || $editlock !== '') {
|
|
$showItemParts[] = '--div--;core.form.tabs:access';
|
|
if (isset($enablecolumns['disabled'])) {
|
|
$hiddenPaletteParts = $this->removeCustomFieldLabels(GeneralUtility::trimExplode(',', $tca['tt_content']['palettes']['hidden']['showitem'] ?? '', true), $listOfValuesToRemove);
|
|
if (in_array($enablecolumns['disabled'], $hiddenPaletteParts, true)) {
|
|
$showItemParts[] = '--palette--;;hidden';
|
|
} else {
|
|
$showItemParts[] = $enablecolumns['disabled'];
|
|
}
|
|
}
|
|
if ((isset($enablecolumns['starttime']) || isset($enablecolumns['endtime']) || isset($enablecolumns['fe_group']) || $editlock)) {
|
|
$accessPaletteParts = $this->removeCustomFieldLabels(GeneralUtility::trimExplode(',', $tca['tt_content']['palettes']['access']['showitem'] ?? '', true), $listOfValuesToRemove);
|
|
if ((!isset($enablecolumns['starttime']) || in_array($enablecolumns['starttime'], $accessPaletteParts, true))
|
|
&& (!isset($enablecolumns['endtime']) || in_array($enablecolumns['endtime'], $accessPaletteParts, true))
|
|
&& (!isset($enablecolumns['fe_group']) || in_array($enablecolumns['fe_group'], $accessPaletteParts, true))
|
|
&& (!$editlock || in_array($editlock, $accessPaletteParts, true))
|
|
) {
|
|
$showItemParts[] = '--palette--;;access';
|
|
} else {
|
|
if (isset($enablecolumns['starttime'])) {
|
|
$showItemParts[] = $enablecolumns['starttime'];
|
|
}
|
|
if (isset($enablecolumns['endtime'])) {
|
|
$showItemParts[] = $enablecolumns['endtime'];
|
|
}
|
|
if (isset($enablecolumns['fe_group'])) {
|
|
$showItemParts[] = $enablecolumns['fe_group'];
|
|
}
|
|
if ($editlock) {
|
|
$showItemParts[] = $editlock;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add description column if defined
|
|
if ($descriptionColumn !== '') {
|
|
$showItemParts[] = '--div--;core.form.tabs:notes,' . $descriptionColumn;
|
|
}
|
|
|
|
// Add extended tab at the end - if it exists
|
|
$showItemParts = array_merge($showItemParts, $extendedParts);
|
|
|
|
// Merge parts together
|
|
$tca['tt_content']['types'][$type]['showitem'] = trim(implode(',', $showItemParts), ',');
|
|
}
|
|
return $tca;
|
|
}
|
|
|
|
private function extractExtendedParts(array $showItemFiltered): array
|
|
{
|
|
$extendedParts = [];
|
|
$addFields = false;
|
|
foreach ($showItemFiltered as $key => $part) {
|
|
if ($part === '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended' || $part === '--div--;core.form.tabs:extended') {
|
|
$extendedParts[] = $part;
|
|
$addFields = true;
|
|
unset($showItemFiltered[$key]);
|
|
} elseif ($addFields) {
|
|
if (str_starts_with($part, '--div--')) {
|
|
break;
|
|
}
|
|
$extendedParts[] = $part;
|
|
unset($showItemFiltered[$key]);
|
|
}
|
|
}
|
|
return [$showItemFiltered, $extendedParts];
|
|
}
|
|
|
|
private function removeCustomFieldLabels(array $showitemParts, array $fieldList): array
|
|
{
|
|
if ($fieldList === []) {
|
|
return $showitemParts;
|
|
}
|
|
foreach ($showitemParts as &$showItem) {
|
|
// Tabs keep their labels
|
|
if (str_starts_with($showItem, '--div--')) {
|
|
continue;
|
|
}
|
|
// Remove label of palette
|
|
if (str_starts_with($showItem, '--palette--')) {
|
|
$parts = GeneralUtility::trimExplode(';', $showItem, true, 3);
|
|
// Palette without label, continue.
|
|
if (count($parts) !== 3) {
|
|
continue;
|
|
}
|
|
$paletteName = '--palette--;;' . $parts[2];
|
|
if (in_array($paletteName, $fieldList, true)) {
|
|
$showItem = $paletteName;
|
|
}
|
|
continue;
|
|
}
|
|
// This must be a field.
|
|
$parts = GeneralUtility::trimExplode(';', $showItem, true, 2);
|
|
$fieldName = $parts[0];
|
|
// Just keep the first part => the fieldname in case field is defined in the $fieldList
|
|
if (in_array($fieldName, $fieldList, true)) {
|
|
$showItem = $fieldName;
|
|
}
|
|
}
|
|
return $showitemParts;
|
|
}
|
|
|
|
protected function addIgnoredPageTypeRestrictionRecords(array $tca): array
|
|
{
|
|
$allowedRecordTypes = [];
|
|
foreach ($tca as $table => $configuration) {
|
|
if ($configuration['ctrl']['security']['ignorePageTypeRestriction'] ?? false) {
|
|
$allowedRecordTypes[] = $table;
|
|
}
|
|
}
|
|
if ($allowedRecordTypes === []) {
|
|
return $tca;
|
|
}
|
|
$mergedAllowedRecords = array_merge(
|
|
$tca['pages']['ctrl']['defaultAllowedRecordTypes'] ?? [],
|
|
$allowedRecordTypes
|
|
);
|
|
$tca['pages']['ctrl']['defaultAllowedRecordTypes'] = array_unique($mergedAllowedRecords);
|
|
return $tca;
|
|
}
|
|
}
|