Skip to content

Commit e080fe8

Browse files
committed
[TASK] Migrate EXT:core to Schema API
Some places left out intentionally for the time being: - DatabaseRestrictions (should be dealt with separately) - FlexForm - IconFactory Resolves: #106722 Releases: main Change-Id: I990752108f55d15b1756be715f4167024907aac3 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/89008 Tested-by: Benni Mack <benni@typo3.org> Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch> Tested-by: Christian Kuhn <lolli@schwarzbu.ch> Reviewed-by: Benni Mack <benni@typo3.org> Tested-by: core-ci <typo3@b13.com> Tested-by: Georg Ringer <georg.ringer@gmail.com> Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
1 parent 730a557 commit e080fe8

27 files changed

+287
-195
lines changed

typo3/sysext/backend/Tests/Unit/Utility/BackendUtilityTest.php

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use TYPO3\CMS\Core\Database\RelationHandler;
2929
use TYPO3\CMS\Core\DataHandling\ItemProcessingService;
3030
use TYPO3\CMS\Core\Localization\LanguageService;
31+
use TYPO3\CMS\Core\Messaging\FlashMessageService;
3132
use TYPO3\CMS\Core\Schema\TcaSchemaFactory;
3233
use TYPO3\CMS\Core\Site\SiteFinder;
3334
use TYPO3\CMS\Core\TypoScript\AST\Node\RootNode;
@@ -893,8 +894,11 @@ public function getLabelFromItemlistReturnsCorrectFields(
893894
['pageTsConfig-pid-to-hash-0', 'hash'],
894895
['pageTsConfig-hash-to-object-hash', new PageTsConfig(new RootNode(), [])],
895896
]);
896-
$siteFinderMock = $this->createMock(SiteFinder::class);
897-
GeneralUtility::addInstance(ItemProcessingService::class, new ItemProcessingService($siteFinderMock));
897+
GeneralUtility::addInstance(ItemProcessingService::class, new ItemProcessingService(
898+
$this->createMock(SiteFinder::class),
899+
$this->createMock(TcaSchemaFactory::class),
900+
$this->createMock(FlashMessageService::class)
901+
));
898902
GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerMock);
899903

900904
$label = BackendUtility::getLabelFromItemlist($table, $col, $key);
@@ -1053,8 +1057,11 @@ public function getLabelsFromItemsListReturnsCorrectValue(
10531057
['pageTsConfig-pid-to-hash-0', 'hash'],
10541058
['pageTsConfig-hash-to-object-hash', new PageTsConfig(new RootNode(), [])],
10551059
]);
1056-
$siteFinderMock = $this->createMock(SiteFinder::class);
1057-
GeneralUtility::addInstance(ItemProcessingService::class, new ItemProcessingService($siteFinderMock));
1060+
GeneralUtility::addInstance(ItemProcessingService::class, new ItemProcessingService(
1061+
$this->createMock(SiteFinder::class),
1062+
$this->createMock(TcaSchemaFactory::class),
1063+
$this->createMock(FlashMessageService::class)
1064+
));
10581065
GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerMock);
10591066

10601067
$GLOBALS['TCA'][$table] = $tca;
@@ -1123,8 +1130,11 @@ public function getProcessedValueReturnsLabelsFormItemsProcFuncUsingRow(): void
11231130
['pageTsConfig-pid-to-hash-0', 'hash'],
11241131
['pageTsConfig-hash-to-object-hash', new PageTsConfig(new RootNode(), [])],
11251132
]);
1126-
$siteFinderMock = $this->createMock(SiteFinder::class);
1127-
GeneralUtility::addInstance(ItemProcessingService::class, new ItemProcessingService($siteFinderMock));
1133+
GeneralUtility::addInstance(ItemProcessingService::class, new ItemProcessingService(
1134+
$this->createMock(SiteFinder::class),
1135+
$this->createMock(TcaSchemaFactory::class),
1136+
$this->createMock(FlashMessageService::class)
1137+
));
11281138
GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerMock);
11291139

11301140
$row = [

typo3/sysext/core/Classes/Authentication/BackendUserAuthentication.php

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,17 @@
2929
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
3030
use TYPO3\CMS\Core\Database\Query\Restriction\RootLevelRestriction;
3131
use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction;
32+
use TYPO3\CMS\Core\DataHandling\TableColumnType;
3233
use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
3334
use TYPO3\CMS\Core\Http\ImmediateResponseException;
3435
use TYPO3\CMS\Core\Http\RedirectResponse;
3536
use TYPO3\CMS\Core\Package\PackageManager;
3637
use TYPO3\CMS\Core\Resource\Filter\FileNameFilter;
3738
use TYPO3\CMS\Core\Resource\StorageRepository;
3839
use TYPO3\CMS\Core\Routing\BackendEntryPointResolver;
40+
use TYPO3\CMS\Core\Schema\Capability\TcaSchemaCapability;
41+
use TYPO3\CMS\Core\Schema\TcaSchema;
42+
use TYPO3\CMS\Core\Schema\TcaSchemaFactory;
3943
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
4044
use TYPO3\CMS\Core\SysLog\Action as SystemLogGenericAction;
4145
use TYPO3\CMS\Core\SysLog\Error as SystemLogErrorClassification;
@@ -321,6 +325,10 @@ public function isInWebMount($idOrRow, $readPerms = '')
321325
if ($this->isAdmin()) {
322326
return 1;
323327
}
328+
$schema = GeneralUtility::makeInstance(TcaSchemaFactory::class)->get('pages');
329+
$languageCapability = $schema->getCapability(TcaSchemaCapability::Language);
330+
$languageFieldName = $languageCapability->getLanguageField()->getName();
331+
$transOrigPointerFieldName = $languageCapability->getTranslationOriginPointerField()->getName();
324332
$checkRec = [];
325333
$fetchPageFromDatabase = true;
326334
if (is_array($idOrRow)) {
@@ -330,7 +338,7 @@ public function isInWebMount($idOrRow, $readPerms = '')
330338
$checkRec = $idOrRow;
331339
$id = (int)$idOrRow['uid'];
332340
// ensure the required fields are present on the record
333-
if (isset($checkRec['t3ver_oid'], $checkRec[$GLOBALS['TCA']['pages']['ctrl']['languageField']], $checkRec[$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']])) {
341+
if (isset($checkRec['t3ver_oid'], $checkRec[$languageFieldName], $checkRec[$transOrigPointerFieldName])) {
334342
$fetchPageFromDatabase = false;
335343
}
336344
} else {
@@ -341,18 +349,19 @@ public function isInWebMount($idOrRow, $readPerms = '')
341349
$checkRec = BackendUtility::getRecord(
342350
'pages',
343351
$id,
344-
't3ver_oid,' . $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'] . ',' . $GLOBALS['TCA']['pages']['ctrl']['languageField']
352+
't3ver_oid,' . $transOrigPointerFieldName . ',' . $languageFieldName
345353
);
346354
}
355+
if (!is_array($checkRec)) {
356+
return null;
357+
}
347358
if ((int)($checkRec['t3ver_oid'] ?? 0) > 0) {
348359
$id = (int)$checkRec['t3ver_oid'];
349360
}
350361
// if current rec is a translation then get uid from l10n_parent instead
351362
// because web mounts point to pages in default language and rootline returns uids of default languages
352-
if ((int)($checkRec[$GLOBALS['TCA']['pages']['ctrl']['languageField'] ?? null] ?? 0) !== 0
353-
&& (int)($checkRec[$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'] ?? null] ?? 0) !== 0
354-
) {
355-
$id = (int)$checkRec[$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']];
363+
if ((int)($checkRec[$languageFieldName]) !== 0 && (int)($checkRec[$transOrigPointerFieldName]) !== 0) {
364+
$id = (int)$checkRec[$transOrigPointerFieldName];
356365
}
357366
if (!$readPerms) {
358367
$readPerms = $this->getPagePermsClause(Permission::PAGE_SHOW);
@@ -600,18 +609,26 @@ public function checkLanguageAccess($langValue)
600609
/**
601610
* Check if user has access to all existing localizations for a certain record
602611
*
603-
* @param string $table The table
612+
* @param string|TcaSchema $table The table/schema
604613
* @param array $record The current record
605614
* @return bool
606615
*/
607-
public function checkFullLanguagesAccess(string $table, array $record): bool
616+
public function checkFullLanguagesAccess(string|TcaSchema $table, array $record): bool
608617
{
609618
if (!$this->checkLanguageAccess(0)) {
610619
return false;
611620
}
621+
if ($table instanceof TcaSchema) {
622+
$schema = $table;
623+
$table = $table->getName();
624+
} else {
625+
$schema = GeneralUtility::makeInstance(TcaSchemaFactory::class)->get($table);
626+
}
612627

613-
if (BackendUtility::isTableLocalizable($table)) {
614-
$pointerField = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'];
628+
if ($schema->isLanguageAware()) {
629+
$languageCapability = $schema->getCapability(TcaSchemaCapability::Language);
630+
$languageField = $languageCapability->getLanguageField()->getName();
631+
$pointerField = $languageCapability->getTranslationOriginPointerField()->getName();
615632
$pointerValue = $record[$pointerField] > 0 ? $record[$pointerField] : $record['uid'];
616633
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
617634
$queryBuilder->getRestrictions()
@@ -630,7 +647,7 @@ public function checkFullLanguagesAccess(string $table, array $record): bool
630647
->fetchAllAssociative();
631648

632649
foreach ($recordLocalizations as $recordLocalization) {
633-
if (!$this->checkLanguageAccess($recordLocalization[$GLOBALS['TCA'][$table]['ctrl']['languageField']])) {
650+
if (!$this->checkLanguageAccess($recordLocalization[$languageField])) {
634651
return false;
635652
}
636653
}
@@ -656,60 +673,63 @@ public function checkFullLanguagesAccess(string $table, array $record): bool
656673
*/
657674
public function recordEditAccessInternals(string $table, array $row, $newRecord = false, $_ = null, $checkFullLanguageAccess = false): bool
658675
{
659-
if (!isset($GLOBALS['TCA'][$table])) {
676+
$schemaFactory = GeneralUtility::makeInstance(TcaSchemaFactory::class);
677+
if (!$schemaFactory->has($table)) {
660678
return false;
661679
}
680+
$schema = $schemaFactory->get($table);
662681
// Always return TRUE for Admin users.
663682
if ($this->isAdmin()) {
664683
return true;
665684
}
666685
// Checking languages:
667-
if ($table === 'pages' && $checkFullLanguageAccess && !$this->checkFullLanguagesAccess($table, $row)) {
686+
if ($table === 'pages' && $checkFullLanguageAccess && !$this->checkFullLanguagesAccess($schema, $row)) {
668687
return false;
669688
}
670-
if ($GLOBALS['TCA'][$table]['ctrl']['languageField'] ?? false) {
689+
if ($schema->isLanguageAware()) {
690+
$languageCapability = $schema->getCapability(TcaSchemaCapability::Language);
691+
$languageField = $languageCapability->getLanguageField()->getName();
692+
671693
// Language field must be found in input row - otherwise it does not make sense.
672-
if (isset($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']])) {
673-
if (!$this->checkLanguageAccess($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']])) {
694+
if (isset($row[$languageField])) {
695+
if (!$this->checkLanguageAccess($row[$languageField])) {
674696
$this->errorMsg = 'ERROR: Language was not allowed.';
675697
return false;
676698
}
677699
if (
678-
$checkFullLanguageAccess && $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] == 0
700+
$checkFullLanguageAccess && $row[$languageField] == 0
679701
&& !$this->checkFullLanguagesAccess($table, $row)
680702
) {
681703
$this->errorMsg = 'ERROR: Related/affected language was not allowed.';
682704
return false;
683705
}
684706
} else {
685-
$this->errorMsg = 'ERROR: The "languageField" field named "'
686-
. $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '" was not found in testing record!';
707+
$this->errorMsg = 'ERROR: The "languageField" field named "' . $languageField . '" was not found in testing record!';
687708
return false;
688709
}
689710
}
690711
// Checking authMode fields:
691-
if (is_array($GLOBALS['TCA'][$table]['columns'])) {
692-
foreach ($GLOBALS['TCA'][$table]['columns'] as $fieldName => $fieldValue) {
693-
if (isset($row[$fieldName])
694-
&& ($fieldValue['config']['type'] ?? '') === 'select'
695-
&& ($fieldValue['config']['authMode'] ?? false)
696-
&& !$this->checkAuthMode($table, $fieldName, $row[$fieldName])) {
697-
$this->errorMsg = 'ERROR: authMode "' . $fieldValue['config']['authMode']
698-
. '" failed for field "' . $fieldName . '" with value "'
699-
. $row[$fieldName] . '" evaluated';
700-
return false;
701-
}
712+
foreach ($schema->getFields() as $fieldName => $fieldType) {
713+
if (isset($row[$fieldName])
714+
&& $fieldType->isType(TableColumnType::SELECT)
715+
&& ($fieldType->getConfiguration()['authMode'] ?? false)
716+
&& !$this->checkAuthMode($table, $fieldName, $row[$fieldName])) {
717+
$this->errorMsg = 'ERROR: authMode "' . $fieldType->getConfiguration()['authMode']
718+
. '" failed for field "' . $fieldName . '" with value "'
719+
. $row[$fieldName] . '" evaluated';
720+
return false;
702721
}
703722
}
704723
// Checking "editlock" feature (doesn't apply to new records)
705-
if (!$newRecord && ($GLOBALS['TCA'][$table]['ctrl']['editlock'] ?? false)) {
706-
if (isset($row[$GLOBALS['TCA'][$table]['ctrl']['editlock']])) {
707-
if ($row[$GLOBALS['TCA'][$table]['ctrl']['editlock']]) {
724+
if (!$newRecord && $schema->hasCapability(TcaSchemaCapability::EditLock)) {
725+
$editLockFieldName = $schema->getCapability(TcaSchemaCapability::EditLock)->getFieldName();
726+
if (isset($row[$editLockFieldName])) {
727+
if ($row[$editLockFieldName]) {
708728
$this->errorMsg = 'ERROR: Record was locked for editing. Only admin users can change this state.';
709729
return false;
710730
}
711731
} else {
712-
$this->errorMsg = 'ERROR: The "editLock" field named "' . $GLOBALS['TCA'][$table]['ctrl']['editlock']
732+
$this->errorMsg = 'ERROR: The "editLock" field named "' . $editLockFieldName
713733
. '" was not found in testing record!';
714734
return false;
715735
}

typo3/sysext/core/Classes/DataHandling/ItemProcessingService.php

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use TYPO3\CMS\Core\Messaging\FlashMessage;
2323
use TYPO3\CMS\Core\Messaging\FlashMessageService;
2424
use TYPO3\CMS\Core\Schema\Struct\SelectItem;
25+
use TYPO3\CMS\Core\Schema\TcaSchemaFactory;
2526
use TYPO3\CMS\Core\Site\Entity\NullSite;
2627
use TYPO3\CMS\Core\Site\Entity\SiteInterface;
2728
use TYPO3\CMS\Core\Site\SiteFinder;
@@ -35,7 +36,9 @@
3536
class ItemProcessingService
3637
{
3738
public function __construct(
38-
protected readonly SiteFinder $siteFinder
39+
protected readonly SiteFinder $siteFinder,
40+
protected readonly TcaSchemaFactory $tcaSchemaFactory,
41+
protected readonly FlashMessageService $flashMessageService,
3942
) {}
4043

4144
/**
@@ -78,13 +81,18 @@ public function getProcessingItems($table, $realPid, $field, $row, $tcaConfig, $
7881
$params['items']
7982
);
8083
} catch (\Exception $exception) {
81-
$languageService = $this->getLanguageService();
82-
$fieldLabel = $field;
83-
if (isset($GLOBALS['TCA'][$table]['columns'][$field]['label'])) {
84-
$fieldLabel = $languageService->sL($GLOBALS['TCA'][$table]['columns'][$field]['label']);
84+
$fieldLabel = '';
85+
if ($this->tcaSchemaFactory->has($table)) {
86+
$schema = $this->tcaSchemaFactory->get($table);
87+
if ($schema->hasField($field)) {
88+
$fieldLabel = $this->getLanguageService()->sL($schema->getField($field)->getLabel());
89+
}
90+
}
91+
if (!$fieldLabel) {
92+
$fieldLabel = $field;
8593
}
8694
$message = sprintf(
87-
$languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:error.items_proc_func_error'),
95+
$this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:error.items_proc_func_error'),
8896
$fieldLabel,
8997
$exception->getMessage()
9098
);
@@ -95,8 +103,7 @@ public function getProcessingItems($table, $realPid, $field, $row, $tcaConfig, $
95103
ContextualFeedbackSeverity::ERROR,
96104
true
97105
);
98-
$flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
99-
$defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
106+
$defaultFlashMessageQueue = $this->flashMessageService->getMessageQueueByIdentifier();
100107
$defaultFlashMessageQueue->enqueue($flashMessage);
101108
}
102109

typo3/sysext/core/Classes/DataHandling/Model/RecordStateFactory.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
namespace TYPO3\CMS\Core\DataHandling\Model;
1919

20+
use TYPO3\CMS\Core\Schema\Capability\TcaSchemaCapability;
21+
use TYPO3\CMS\Core\Schema\TcaSchemaFactory;
2022
use TYPO3\CMS\Core\Utility\GeneralUtility;
2123

2224
/**
@@ -69,12 +71,17 @@ public function fromArray(array $data, $pageId = null, $recordId = null): Record
6971
*/
7072
protected function resolveAspectFieldNames(): array
7173
{
74+
$schema = GeneralUtility::makeInstance(TcaSchemaFactory::class)->get($this->name);
75+
$languageCapability = null;
76+
if ($schema->isLanguageAware()) {
77+
$languageCapability = $schema->getCapability(TcaSchemaCapability::Language);
78+
}
7279
return [
7380
'workspace' => 't3ver_wsid',
7481
'versionParent' => 't3ver_oid',
75-
'language' => $GLOBALS['TCA'][$this->name]['ctrl']['languageField'] ?? null,
76-
'languageParent' => $GLOBALS['TCA'][$this->name]['ctrl']['transOrigPointerField'] ?? null,
77-
'languageSource' => $GLOBALS['TCA'][$this->name]['ctrl']['translationSource'] ?? null,
82+
'language' => $languageCapability?->getLanguageField()?->getName(),
83+
'languageParent' => $languageCapability?->getTranslationOriginPointerField()?->getName(),
84+
'languageSource' => $languageCapability?->getTranslationSourceField()?->getName(),
7885
];
7986
}
8087

0 commit comments

Comments
 (0)