diff --git a/typo3/sysext/backend/Classes/Utility/BackendUtility.php b/typo3/sysext/backend/Classes/Utility/BackendUtility.php index 3e1818a94bf29ee2be1f1f21bf54e98d544f16fa..8557d591e1915b0a53943db45b8d713b73103ef1 100644 --- a/typo3/sysext/backend/Classes/Utility/BackendUtility.php +++ b/typo3/sysext/backend/Classes/Utility/BackendUtility.php @@ -1415,14 +1415,15 @@ class BackendUtility $recordTitle = $params['title']; } else { // No userFunc: Build label + $ctrlLabel = $GLOBALS['TCA'][$table]['ctrl']['label'] ?? ''; $recordTitle = self::getProcessedValue( $table, - $GLOBALS['TCA'][$table]['ctrl']['label'], - $row[$GLOBALS['TCA'][$table]['ctrl']['label']], + $ctrlLabel, + $row[$ctrlLabel] ?? '', 0, false, false, - $row['uid'], + $row['uid'] ?? null, $forceResult ) ?? ''; if (!empty($GLOBALS['TCA'][$table]['ctrl']['label_alt']) @@ -1434,7 +1435,7 @@ class BackendUtility $tA[] = $recordTitle; } foreach ($altFields as $fN) { - $recordTitle = trim(strip_tags($row[$fN])); + $recordTitle = trim(strip_tags($row[$fN] ?? '')); if ((string)$recordTitle !== '') { $recordTitle = self::getProcessedValue($table, $fN, $recordTitle, 0, false, false, $row['uid']); if (!$GLOBALS['TCA'][$table]['ctrl']['label_alt_force']) { @@ -1443,7 +1444,7 @@ class BackendUtility $tA[] = $recordTitle; } } - if ($GLOBALS['TCA'][$table]['ctrl']['label_alt_force']) { + if ($GLOBALS['TCA'][$table]['ctrl']['label_alt_force'] ?? false) { $recordTitle = implode(', ', $tA); } } diff --git a/typo3/sysext/core/Classes/DataHandling/DataHandler.php b/typo3/sysext/core/Classes/DataHandling/DataHandler.php index 11c07f106f478d978cc75bfe2faddc7909c4a453..ca1772c971cd1f22b34b27976539829f04d76976 100644 --- a/typo3/sysext/core/Classes/DataHandling/DataHandler.php +++ b/typo3/sysext/core/Classes/DataHandling/DataHandler.php @@ -1330,7 +1330,7 @@ class DataHandler implements LoggerAwareInterface $originalLanguage_diffStorage[$field] = (string)($originalLanguageRecord[$field] ?? ''); $diffStorageFlag = true; } - } elseif ($GLOBALS['TCA'][$table]['ctrl']['origUid'] === $field) { + } elseif (isset($GLOBALS['TCA'][$table]['ctrl']['origUid']) && $GLOBALS['TCA'][$table]['ctrl']['origUid'] === $field) { // Allow value for original UID to pass by... $fieldArray[$field] = $fieldValue; } @@ -1627,7 +1627,7 @@ class DataHandler implements LoggerAwareInterface $evalCodesArray = GeneralUtility::trimExplode(',', $tcaFieldConf['eval'], true); $this->runtimeCache->set($cacheId, $evalCodesArray); } - $valueArray = $this->checkValue_text_Eval($value, $evalCodesArray, $tcaFieldConf['is_in']); + $valueArray = $this->checkValue_text_Eval($value, $evalCodesArray, $tcaFieldConf['is_in'] ?? ''); } else { $valueArray = ['value' => $value]; } @@ -1806,7 +1806,7 @@ class DataHandler implements LoggerAwareInterface */ protected function checkValueForCheck($res, $value, $tcaFieldConf, $table, $id, $realPid, $field) { - $items = $tcaFieldConf['items']; + $items = $tcaFieldConf['items'] ?? null; if (!empty($tcaFieldConf['itemsProcFunc'])) { /** @var ItemProcessingService $processingService */ $processingService = GeneralUtility::makeInstance(ItemProcessingService::class); @@ -1888,7 +1888,7 @@ class DataHandler implements LoggerAwareInterface } // if no value was found and an itemsProcFunc is defined, check that for the value - if ($tcaFieldConf['itemsProcFunc'] && empty($res['value'])) { + if (!empty($tcaFieldConf['itemsProcFunc']) && empty($res['value'])) { $processingService = GeneralUtility::makeInstance(ItemProcessingService::class); $processedItems = $processingService->getProcessingItems( $table, @@ -3133,7 +3133,7 @@ class DataHandler implements LoggerAwareInterface foreach ($row as $field => $value) { if (!in_array($field, $nonFields, true)) { // Get TCA configuration for the field: - $conf = $GLOBALS['TCA'][$table]['columns'][$field]['config']; + $conf = $GLOBALS['TCA'][$table]['columns'][$field]['config'] ?? []; // Preparation/Processing of the value: // "pid" is hardcoded of course: // isset() won't work here, since values can be NULL in each of the arrays @@ -3148,11 +3148,18 @@ class DataHandler implements LoggerAwareInterface $value = $copyAfterFields[$field]; } else { // Hide at copy may override: - if ($first && $field == $enableField && $GLOBALS['TCA'][$table]['ctrl']['hideAtCopy'] && !$this->neverHideAtCopy && !$tE['disableHideAtCopy']) { + if ($first && $field == $enableField + && ($GLOBALS['TCA'][$table]['ctrl']['hideAtCopy'] ?? false) + && !$this->neverHideAtCopy + && !($tE['disableHideAtCopy'] ?? false) + ) { $value = 1; } // Prepend label on copy: - if ($first && $field == $headerField && $GLOBALS['TCA'][$table]['ctrl']['prependAtCopy'] && !$tE['disablePrependAtCopy']) { + if ($first && $field == $headerField + && ($GLOBALS['TCA'][$table]['ctrl']['prependAtCopy'] ?? false) + && !($tE['disablePrependAtCopy'] ?? false) + ) { $value = $this->getCopyHeader($table, $this->resolvePid($table, $destPid), $field, $this->clearPrefixFromValue($table, $value), 0); } // Processing based on the TCA config field type (files, references, flexforms...) @@ -3163,11 +3170,11 @@ class DataHandler implements LoggerAwareInterface } } // Overriding values: - if ($GLOBALS['TCA'][$table]['ctrl']['editlock']) { + if ($GLOBALS['TCA'][$table]['ctrl']['editlock'] ?? false) { $data[$table][$theNewID][$GLOBALS['TCA'][$table]['ctrl']['editlock']] = 0; } // Setting original UID: - if ($GLOBALS['TCA'][$table]['ctrl']['origUid']) { + if ($GLOBALS['TCA'][$table]['ctrl']['origUid'] ?? false) { $data[$table][$theNewID][$GLOBALS['TCA'][$table]['ctrl']['origUid']] = $uid; } // Do the copy by simply submitting the array through DataHandler: @@ -3452,7 +3459,7 @@ class DataHandler implements LoggerAwareInterface foreach ($row as $field => $value) { if (!in_array($field, $nonFields, true)) { // Get TCA configuration for the field: - $conf = $GLOBALS['TCA'][$table]['columns'][$field]['config']; + $conf = $GLOBALS['TCA'][$table]['columns'][$field]['config'] ?? false; if (is_array($conf)) { // Processing based on the TCA config field type (files, references, flexforms...) $value = $this->copyRecord_procBasedOnFieldType($table, $uid, $field, $value, $row, $conf, $pid, 0, $workspaceOptions); @@ -3463,7 +3470,7 @@ class DataHandler implements LoggerAwareInterface } $row['pid'] = $pid; // Setting original UID: - if ($GLOBALS['TCA'][$table]['ctrl']['origUid']) { + if ($GLOBALS['TCA'][$table]['ctrl']['origUid'] ?? '') { $row[$GLOBALS['TCA'][$table]['ctrl']['origUid']] = $uid; } // Do the copy by internal function @@ -3559,7 +3566,7 @@ class DataHandler implements LoggerAwareInterface $value = $this->copyRecord_processInline($table, $uid, $field, $value, $row, $conf, $realDestPid, $language, $workspaceOptions); } // For "flex" fieldtypes we need to traverse the structure for two reasons: If there are file references they have to be prepended with absolute paths and if there are database reference they MIGHT need to be remapped (still done in remapListedDBRecords()) - if ($conf['type'] === 'flex') { + if (isset($conf['type']) && $conf['type'] === 'flex') { // Get current value array: $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class); $dataStructureIdentifier = $flexFormTools->getDataStructureIdentifier( @@ -3594,7 +3601,7 @@ class DataHandler implements LoggerAwareInterface protected function copyRecord_processManyToMany($table, $uid, $field, $value, $conf, $language) { $allowedTables = $conf['type'] === 'group' ? $conf['allowed'] : $conf['foreign_table']; - $prependName = $conf['type'] === 'group' ? $conf['prepend_tname'] : ''; + $prependName = $conf['type'] === 'group' ? ($conf['prepend_tname'] ?? '') : ''; $mmTable = isset($conf['MM']) && $conf['MM'] ? $conf['MM'] : ''; $localizeForeignTable = isset($conf['foreign_table']) && BackendUtility::isTableLocalizable($conf['foreign_table']); // Localize referenced records of select fields: @@ -4143,7 +4150,7 @@ class DataHandler implements LoggerAwareInterface if (is_array($row) && (int)$destPid !== (int)$row['pid']) { $conf = $GLOBALS['TCA'][$table]['columns']; foreach ($row as $field => $value) { - $this->moveRecord_procBasedOnFieldType($table, $uid, $destPid, $field, $value, $conf[$field]['config']); + $this->moveRecord_procBasedOnFieldType($table, $uid, $destPid, $field, $value, $conf[$field]['config'] ?? []); } } } @@ -4162,7 +4169,7 @@ class DataHandler implements LoggerAwareInterface public function moveRecord_procBasedOnFieldType($table, $uid, $destPid, $field, $value, $conf) { $dbAnalysis = null; - if ($conf['type'] === 'inline') { + if (!empty($conf['type']) && $conf['type'] === 'inline') { $foreign_table = $conf['foreign_table']; $moveChildrenWithParent = !isset($conf['behaviour']['disableMovingChildrenWithParent']) || !$conf['behaviour']['disableMovingChildrenWithParent']; if ($foreign_table && $moveChildrenWithParent) { @@ -4340,18 +4347,19 @@ class DataHandler implements LoggerAwareInterface } // Copy the type (if defined in both tables) from the original record so that translation has same type as original record if (isset($GLOBALS['TCA'][$table]['ctrl']['type'])) { - $overrideValues[$GLOBALS['TCA'][$table]['ctrl']['type']] = $row[$GLOBALS['TCA'][$table]['ctrl']['type']]; + // @todo: Possible bug here? type can be something like 'table:field', which is then null in $row, writing null to $overrideValues + $overrideValues[$GLOBALS['TCA'][$table]['ctrl']['type']] = $row[$GLOBALS['TCA'][$table]['ctrl']['type']] ?? null; } // Set exclude Fields: foreach ($GLOBALS['TCA'][$table]['columns'] as $fN => $fCfg) { $translateToMsg = ''; // Check if we are just prefixing: - if ($fCfg['l10n_mode'] === 'prefixLangTitle') { + if (isset($fCfg['l10n_mode']) && $fCfg['l10n_mode'] === 'prefixLangTitle') { if (($fCfg['config']['type'] === 'text' || $fCfg['config']['type'] === 'input') && (string)$row[$fN] !== '') { [$tscPID] = BackendUtility::getTSCpid($table, $uid, ''); $TSConfig = BackendUtility::getPagesTSconfig($tscPID)['TCEMAIN.'] ?? []; $tE = $this->getTableEntries($table, $TSConfig); - if (!empty($TSConfig['translateToMessage']) && !$tE['disablePrependAtCopy']) { + if (!empty($TSConfig['translateToMessage']) && !($tE['disablePrependAtCopy'] ?? false)) { $translateToMsg = $this->getLanguageService()->sL($TSConfig['translateToMessage']); $translateToMsg = @sprintf($translateToMsg, $langRec['title']); } @@ -5002,7 +5010,7 @@ class DataHandler implements LoggerAwareInterface return; } foreach ($row as $field => $value) { - $this->deleteRecord_procBasedOnFieldType($table, $uid, $field, $value, $conf[$field]['config']); + $this->deleteRecord_procBasedOnFieldType($table, $uid, $field, $value, $conf[$field]['config'] ?? []); } } @@ -5018,8 +5026,11 @@ class DataHandler implements LoggerAwareInterface * @see deleteRecord() * @internal should only be used from within DataHandler */ - public function deleteRecord_procBasedOnFieldType($table, $uid, $field, $value, $conf) + public function deleteRecord_procBasedOnFieldType($table, $uid, $field, $value, $conf): void { + if (!isset($conf['type'])) { + return; + } if ($conf['type'] === 'inline') { $foreign_table = $conf['foreign_table']; if ($foreign_table) { @@ -5047,7 +5058,7 @@ class DataHandler implements LoggerAwareInterface } elseif ($this->isReferenceField($conf)) { $allowedTables = $conf['type'] === 'group' ? $conf['allowed'] : $conf['foreign_table']; $dbAnalysis = $this->createRelationHandlerInstance(); - $dbAnalysis->start($value, $allowedTables, $conf['MM'], $uid, $table, $conf); + $dbAnalysis->start($value, $allowedTables, $conf['MM'] ?? '', $uid, $table, $conf); foreach ($dbAnalysis->itemArray as $v) { $this->updateRefIndex($v['table'], $v['id']); } @@ -5594,7 +5605,7 @@ class DataHandler implements LoggerAwareInterface 't3ver_state' => (string)($delete ? new VersionState(VersionState::DELETE_PLACEHOLDER) : new VersionState(VersionState::DEFAULT_STATE)), 't3ver_stage' => 0, ]; - if ($GLOBALS['TCA'][$table]['ctrl']['editlock']) { + if ($GLOBALS['TCA'][$table]['ctrl']['editlock'] ?? false) { $overrideArray[$GLOBALS['TCA'][$table]['ctrl']['editlock']] = 0; } // Checking if the record already has a version in the current workspace of the backend user @@ -5641,16 +5652,14 @@ class DataHandler implements LoggerAwareInterface foreach ($GLOBALS['TCA'][$table]['columns'] as $field => $fConf) { $conf = $fConf['config']; if ($this->isReferenceField($conf)) { - $allowedTables = $conf['type'] === 'group' ? $conf['allowed'] : $conf['foreign_table']; - $prependName = $conf['type'] === 'group' ? $conf['prepend_tname'] : ''; - if ($conf['MM']) { - /** @var RelationHandler $dbAnalysis */ + $allowedTables = $conf['type'] === 'group' ? ($conf['allowed'] ?? '') : $conf['foreign_table']; + $prependName = $conf['type'] === 'group' ? ($conf['prepend_tname'] ?? '') : ''; + if ($conf['MM'] ?? false) { $dbAnalysis = $this->createRelationHandlerInstance(); $dbAnalysis->start('', $allowedTables, $conf['MM'], $id, $table, $conf); if (!empty($dbAnalysis->getValueArray($prependName))) { $this->version_remapMMForVersionSwap_reg[$id][$field] = [$dbAnalysis, $conf['MM'], $prependName]; } - /** @var RelationHandler $dbAnalysis */ $dbAnalysis = $this->createRelationHandlerInstance(); $dbAnalysis->start('', $allowedTables, $conf['MM'], $swapWith, $table, $conf); if (!empty($dbAnalysis->getValueArray($prependName))) { @@ -5882,16 +5891,16 @@ class DataHandler implements LoggerAwareInterface // Allowed tables for references. $allowedTables = $conf['type'] === 'group' ? $conf['allowed'] : $conf['foreign_table']; // Table name to prepend the UID - $prependName = $conf['type'] === 'group' ? $conf['prepend_tname'] : ''; + $prependName = $conf['type'] === 'group' ? ($conf['prepend_tname'] ?? '') : ''; // Which tables that should possibly not be remapped - $dontRemapTables = GeneralUtility::trimExplode(',', $conf['dontRemapTablesOnCopy'], true); + $dontRemapTables = GeneralUtility::trimExplode(',', $conf['dontRemapTablesOnCopy'] ?? '', true); // Convert value to list of references: $dbAnalysis = $this->createRelationHandlerInstance(); - $dbAnalysis->registerNonTableValues = $conf['type'] === 'select' && $conf['allowNonIdValues']; - $dbAnalysis->start($value, $allowedTables, $conf['MM'], $MM_localUid, $table, $conf); + $dbAnalysis->registerNonTableValues = $conf['type'] === 'select' && ($conf['allowNonIdValues'] ?? false); + $dbAnalysis->start($value, $allowedTables, $conf['MM'] ?? '', $MM_localUid, $table, $conf); // Traverse those references and map IDs: foreach ($dbAnalysis->itemArray as $k => $v) { - $mapID = $this->copyMappingArray_merged[$v['table']][$v['id']]; + $mapID = $this->copyMappingArray_merged[$v['table']][$v['id']] ?? 0; if ($mapID && !in_array($v['table'], $dontRemapTables, true)) { $dbAnalysis->itemArray[$k]['id'] = $mapID; $set = true; @@ -5923,7 +5932,7 @@ class DataHandler implements LoggerAwareInterface } // If a change has been done, set the new value(s) if ($set) { - if ($conf['MM']) { + if ($conf['MM'] ?? false) { $dbAnalysis->writeMM($conf['MM'], $MM_localUid, $prependName); } else { return $dbAnalysis->getValueArray($prependName); @@ -6225,28 +6234,32 @@ class DataHandler implements LoggerAwareInterface * @param array $registerDBList Reference to the $registerDBList array that was created/updated by versionizing calls to DataHandler in process_datamap. * @internal should only be used from within DataHandler */ - public function getVersionizedIncomingFieldArray($table, $id, &$incomingFieldArray, &$registerDBList) - { - if (is_array($registerDBList[$table][$id])) { - foreach ($incomingFieldArray as $field => $value) { - $fieldConf = $GLOBALS['TCA'][$table]['columns'][$field]['config']; - if ($registerDBList[$table][$id][$field] && ($foreignTable = $fieldConf['foreign_table'])) { - $newValueArray = []; - $origValueArray = is_array($value) ? $value : explode(',', $value); - // Update the uids of the copied records, but also take care about new records: - foreach ($origValueArray as $childId) { - $newValueArray[] = $this->autoVersionIdMap[$foreignTable][$childId] ?: $childId; - } - // Set the changed value to the $incomingFieldArray - $incomingFieldArray[$field] = implode(',', $newValueArray); + public function getVersionizedIncomingFieldArray($table, $id, &$incomingFieldArray, &$registerDBList): void + { + if (!isset($registerDBList[$table][$id]) || !is_array($registerDBList[$table][$id])) { + return; + } + foreach ($incomingFieldArray as $field => $value) { + $fieldConf = $GLOBALS['TCA'][$table]['columns'][$field]['config']; + $foreignTable = $fieldConf['foreign_table'] ?? ''; + if (($registerDBList[$table][$id][$field] ?? false) + && !empty($foreignTable) + ) { + $newValueArray = []; + $origValueArray = is_array($value) ? $value : explode(',', $value); + // Update the uids of the copied records, but also take care about new records: + foreach ($origValueArray as $childId) { + $newValueArray[] = $this->autoVersionIdMap[$foreignTable][$childId] ?? $childId; } - } - // Clean up the $registerDBList array: - unset($registerDBList[$table][$id]); - if (empty($registerDBList[$table])) { - unset($registerDBList[$table]); + // Set the changed value to the $incomingFieldArray + $incomingFieldArray[$field] = implode(',', $newValueArray); } } + // Clean up the $registerDBList array: + unset($registerDBList[$table][$id]); + if (empty($registerDBList[$table])) { + unset($registerDBList[$table]); + } } /** @@ -6853,12 +6866,12 @@ class DataHandler implements LoggerAwareInterface public function getRecordPropertiesFromRow($table, $row) { if ($GLOBALS['TCA'][$table]) { - $liveUid = ($row['t3ver_oid'] ?? null) ? $row['t3ver_oid'] : $row['uid']; + $liveUid = ($row['t3ver_oid'] ?? null) ? ($row['t3ver_oid'] ?? null) : ($row['uid'] ?? null); return [ 'header' => BackendUtility::getRecordTitle($table, $row), - 'pid' => $row['pid'], - 'event_pid' => $this->eventPid($table, (int)$liveUid, $row['pid']), - 't3ver_state' => BackendUtility::isTableWorkspaceEnabled($table) ? $row['t3ver_state'] : '' + 'pid' => $row['pid'] ?? null, + 'event_pid' => $this->eventPid($table, (int)$liveUid, $row['pid'] ?? null), + 't3ver_state' => BackendUtility::isTableWorkspaceEnabled($table) ? ($row['t3ver_state'] ?? '') : '' ]; } return null; @@ -7477,7 +7490,7 @@ class DataHandler implements LoggerAwareInterface // If there is an element, find its localized record in specified localization language if ($previousRow = $queryBuilder->execute()->fetch()) { $previousLocalizedRecord = BackendUtility::getRecordLocalization($table, $previousRow['uid'], $language); - if (is_array($previousLocalizedRecord[0])) { + if (isset($previousLocalizedRecord[0]) && is_array($previousLocalizedRecord[0])) { $previousLocalizedRecordUid = $previousLocalizedRecord[0]['uid']; } } @@ -7591,7 +7604,7 @@ class DataHandler implements LoggerAwareInterface } // Unset the fields which are similar: foreach ($fieldArray as $col => $val) { - $fieldConfiguration = $GLOBALS['TCA'][$table]['columns'][$col]['config']; + $fieldConfiguration = $GLOBALS['TCA'][$table]['columns'][$col]['config'] ?? []; $isNullField = (!empty($fieldConfiguration['eval']) && GeneralUtility::inList($fieldConfiguration['eval'], 'null')); // Unset fields if stored and submitted values are equal - except the current field holds MM relations. @@ -7740,8 +7753,8 @@ class DataHandler implements LoggerAwareInterface */ public function getTableEntries($table, $TSconfig) { - $tA = is_array($TSconfig['table.'][$table . '.']) ? $TSconfig['table.'][$table . '.'] : []; - $dA = is_array($TSconfig['default.']) ? $TSconfig['default.'] : []; + $tA = is_array($TSconfig['table.'][$table . '.'] ?? false) ? $TSconfig['table.'][$table . '.'] : []; + $dA = is_array($TSconfig['default.'] ?? false) ? $TSconfig['default.'] : []; ArrayUtility::mergeRecursiveWithOverrule($dA, $tA); return $dA; } @@ -7879,7 +7892,7 @@ class DataHandler implements LoggerAwareInterface $newData = []; foreach ($GLOBALS['TCA'][$table]['columns'] as $field => $conf) { if ($conf['config']['type'] === 'input' && (string)$curData[$field] !== '') { - $evalCodesArray = GeneralUtility::trimExplode(',', $conf['config']['eval'], true); + $evalCodesArray = GeneralUtility::trimExplode(',', $conf['config']['eval'] ?? '', true); if (in_array('uniqueInPid', $evalCodesArray, true)) { $newV = $this->getUnique($table, $field, $curData[$field], $uid, $curData['pid']); if ((string)$newV !== (string)$curData[$field]) { @@ -7958,7 +7971,7 @@ class DataHandler implements LoggerAwareInterface */ public function fixCopyAfterDuplFields($table, $uid, $prevUid, $update, $newData = []) { - if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['copyAfterDuplFields']) { + if ($GLOBALS['TCA'][$table]['ctrl']['copyAfterDuplFields'] ?? false) { $prevData = $this->recordInfo($table, $prevUid, '*'); $theFields = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['copyAfterDuplFields'], true); foreach ($theFields as $field) { @@ -8011,8 +8024,8 @@ class DataHandler implements LoggerAwareInterface */ public function isReferenceField($conf) { - return $conf['type'] === 'group' && $conf['internal_type'] === 'db' - || $conf['type'] === 'select' && ($conf['foreign_table'] ?? false); + return isset($conf['type'], $conf['internal_type']) && $conf['type'] === 'group' && $conf['internal_type'] === 'db' + || isset($conf['type'], $conf['foreign_table']) && $conf['type'] === 'select' && $conf['foreign_table']; } /** @@ -8025,7 +8038,7 @@ class DataHandler implements LoggerAwareInterface */ public function getInlineFieldType($conf) { - if ($conf['type'] !== 'inline' || !$conf['foreign_table']) { + if (empty($conf['type']) || $conf['type'] !== 'inline' || empty($conf['foreign_table'])) { return false; } if ($conf['foreign_field'] ?? false) { @@ -8213,7 +8226,7 @@ class DataHandler implements LoggerAwareInterface } static::$recordsToClearCacheFor[$table][] = (int)$uid; if ($pid !== null) { - if (!is_array(static::$recordPidsForDeletedRecords[$table])) { + if (!isset(static::$recordPidsForDeletedRecords[$table]) || !is_array(static::$recordPidsForDeletedRecords[$table])) { static::$recordPidsForDeletedRecords[$table] = []; } static::$recordPidsForDeletedRecords[$table][$uid][] = (int)$pid; @@ -8614,7 +8627,7 @@ class DataHandler implements LoggerAwareInterface { $localizationParentFieldName = $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']; $row = $this->recordInfo('pages', $pageId, $localizationParentFieldName); - $localizationParent = (int)$row[$localizationParentFieldName]; + $localizationParent = (int)($row[$localizationParentFieldName] ?? 0); if ($localizationParent > 0) { return $localizationParent; } @@ -8636,6 +8649,7 @@ class DataHandler implements LoggerAwareInterface $result = $fieldArray; foreach ($fieldArray as $field => $value) { if (!MathUtility::canBeInterpretedAsInteger($value) + && isset($GLOBALS['TCA'][$table]['columns'][$field]['config']['type']) && $GLOBALS['TCA'][$table]['columns'][$field]['config']['type'] === 'inline' && ($GLOBALS['TCA'][$table]['columns'][$field]['config']['foreign_field'] ?? false) ) { diff --git a/typo3/sysext/core/Classes/DataHandling/ItemProcessingService.php b/typo3/sysext/core/Classes/DataHandling/ItemProcessingService.php index 7e605a63761a32e8334a7cf28153ece302fba99b..bcdae62281fbbe286dde1d33194f87a664b2a290 100644 --- a/typo3/sysext/core/Classes/DataHandling/ItemProcessingService.php +++ b/typo3/sysext/core/Classes/DataHandling/ItemProcessingService.php @@ -41,12 +41,12 @@ class ItemProcessingService { $pageId = $table === 'pages' ? $row['uid'] : $row['pid']; $TSconfig = BackendUtility::getPagesTSconfig($pageId); - $fieldTSconfig = $TSconfig['TCEFORM.'][$table . '.'][$field . '.']; + $fieldTSconfig = $TSconfig['TCEFORM.'][$table . '.'][$field . '.'] ?? []; $params = []; $params['items'] = &$selectedItems; $params['config'] = $tcaConfig; - $params['TSconfig'] = $fieldTSconfig['itemsProcFunc.']; + $params['TSconfig'] = $fieldTSconfig['itemsProcFunc.'] ?? null; $params['table'] = $table; $params['row'] = $row; $params['field'] = $field; diff --git a/typo3/sysext/core/Classes/Database/RelationHandler.php b/typo3/sysext/core/Classes/Database/RelationHandler.php index 9799bac6038dedfa182730fd19c12d3a4016a2f4..23fe1aca33a0fd7285d7453e1349152afa609884 100644 --- a/typo3/sysext/core/Classes/Database/RelationHandler.php +++ b/typo3/sysext/core/Classes/Database/RelationHandler.php @@ -16,6 +16,7 @@ namespace TYPO3\CMS\Core\Database; use TYPO3\CMS\Backend\Utility\BackendUtility; +use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Database\Platform\PlatformInformation; use TYPO3\CMS\Core\Database\Query\QueryHelper; use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction; @@ -201,8 +202,9 @@ class RelationHandler */ protected function getWorkspaceId(): int { + $backendUser = $GLOBALS['BE_USER'] ?? null; if (!isset($this->workspaceId)) { - $this->workspaceId = (int)$GLOBALS['BE_USER']->workspace; + $this->workspaceId = $backendUser instanceof BackendUserAuthentication ? (int)($backendUser->workspace) : 0; } return $this->workspaceId; } diff --git a/typo3/sysext/core/Classes/Utility/RootlineUtility.php b/typo3/sysext/core/Classes/Utility/RootlineUtility.php index 9a9be05ad32ee43b02c087bf46da5720e06afb49..1898d9a5cde8605f04d4c8ea0574b26677ac21a9 100644 --- a/typo3/sysext/core/Classes/Utility/RootlineUtility.php +++ b/typo3/sysext/core/Classes/Utility/RootlineUtility.php @@ -492,7 +492,7 @@ class RootlineUtility } $page = $this->resolvePageRecord($pageId); - if (!VersionState::cast($page['t3ver_state'])->equals(VersionState::MOVE_POINTER)) { + if (!isset($page['t3ver_state']) || !VersionState::cast($page['t3ver_state'])->equals(VersionState::MOVE_POINTER)) { return $pageId; } diff --git a/typo3/sysext/frontend/Classes/ContentObject/ContentContentObject.php b/typo3/sysext/frontend/Classes/ContentObject/ContentContentObject.php index 904ad04a9c97e1d7373941a6b86054b53a7cd9d9..04340bcf532d59a3a865569e30cfa2a11754fe63 100644 --- a/typo3/sysext/frontend/Classes/ContentObject/ContentContentObject.php +++ b/typo3/sysext/frontend/Classes/ContentObject/ContentContentObject.php @@ -42,7 +42,11 @@ class ContentContentObject extends AbstractContentObject // If the currentRecord is set, we register, that this record has invoked this function. // It should not be allowed to do this again then!! if ($originalRec) { - ++$frontendController->recordRegister[$originalRec]; + if (isset($frontendController->recordRegister[$originalRec])) { + ++$frontendController->recordRegister[$originalRec]; + } else { + $frontendController->recordRegister[$originalRec] = 1; + } } $conf['table'] = trim((string)$this->cObj->stdWrapValue('table', $conf ?? [])); $conf['select.'] = !empty($conf['select.']) ? $conf['select.'] : []; @@ -83,10 +87,11 @@ class ContentContentObject extends AbstractContentObject $_procObj = GeneralUtility::makeInstance($className); $_procObj->modifyDBRow($row, $conf['table']); } - if (!$frontendController->recordRegister[$conf['table'] . ':' . $row['uid']]) { + $registerField = $conf['table'] . ':' . $row['uid']; + if (!($frontendController->recordRegister[$registerField] ?? false)) { $this->cObj->currentRecordNumber++; $cObj->parentRecordNumber = $this->cObj->currentRecordNumber; - $frontendController->currentRecord = $conf['table'] . ':' . $row['uid']; + $frontendController->currentRecord = $registerField; $this->cObj->lastChanged($row['tstamp']); $cObj->start($row, $conf['table'], $this->request); $tmpValue = $cObj->cObjGetSingle($renderObjName, $renderObjConf, $renderObjKey); diff --git a/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php b/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php index 833dd4ca49bf3c1ff74dff3843504aeb33441b0e..9c24a3a85eaba76ed2260433a1c6969f1cca5430 100644 --- a/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php +++ b/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php @@ -455,7 +455,7 @@ class ContentObjectRenderer implements LoggerAwareInterface public function __construct(TypoScriptFrontendController $typoScriptFrontendController = null, ContainerInterface $container = null) { $this->typoScriptFrontendController = $typoScriptFrontendController; - $this->contentObjectClassMap = $GLOBALS['TYPO3_CONF_VARS']['FE']['ContentObjects']; + $this->contentObjectClassMap = $GLOBALS['TYPO3_CONF_VARS']['FE']['ContentObjects'] ?? []; $this->container = $container; } @@ -4504,13 +4504,13 @@ class ContentObjectRenderer implements LoggerAwareInterface $keys = explode('|', $keyString); $numberOfLevels = count($keys); $rootKey = trim($keys[0]); - $value = isset($source) ? $source[$rootKey] : $GLOBALS[$rootKey]; + $value = isset($source) ? ($source[$rootKey] ?? '') : ($GLOBALS[$rootKey] ?? ''); for ($i = 1; $i < $numberOfLevels && isset($value); $i++) { $currentKey = trim($keys[$i]); if (is_object($value)) { $value = $value->{$currentKey}; } elseif (is_array($value)) { - $value = $value[$currentKey]; + $value = $value[$currentKey] ?? ''; } else { $value = ''; break; @@ -5742,8 +5742,8 @@ class ContentObjectRenderer implements LoggerAwareInterface foreach ($properties as $property) { $conf[$property] = trim( isset($conf[$property . '.']) - ? $this->stdWrap($conf[$property], $conf[$property . '.']) - : $conf[$property] + ? $this->stdWrap($conf[$property] ?? '', $conf[$property . '.'] ?? []) + : ($conf[$property] ?? null) ); if ($conf[$property] === '') { unset($conf[$property]); @@ -5804,7 +5804,7 @@ class ContentObjectRenderer implements LoggerAwareInterface $conf['pidInList'] = implode(',', $expandedPidList); } } - if ((string)$conf['pidInList'] === '') { + if ((string)($conf['pidInList'] ?? '') === '') { $conf['pidInList'] = 'this'; } @@ -5816,28 +5816,28 @@ class ContentObjectRenderer implements LoggerAwareInterface $queryBuilder->getRestrictions()->removeAll(); $queryBuilder->select('*')->from($table); - if ($queryParts['where']) { + if ($queryParts['where'] ?? false) { $queryBuilder->where($queryParts['where']); } - if ($queryParts['groupBy']) { + if ($queryParts['groupBy'] ?? false) { $queryBuilder->groupBy(...$queryParts['groupBy']); } - if (is_array($queryParts['orderBy'])) { + if (is_array($queryParts['orderBy'] ?? false)) { foreach ($queryParts['orderBy'] as $orderBy) { $queryBuilder->addOrderBy(...$orderBy); } } // Fields: - if ($conf['selectFields']) { + if ($conf['selectFields'] ?? false) { $queryBuilder->selectLiteral($this->sanitizeSelectPart($conf['selectFields'], $table)); } // Setting LIMIT: $error = false; - if ($conf['max'] || $conf['begin']) { + if (($conf['max'] ?? false) || ($conf['begin'] ?? false)) { // Finding the total number of records, if used: if (strpos(strtolower($conf['begin'] . $conf['max']), 'total') !== false) { $countQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table); @@ -5872,7 +5872,7 @@ class ContentObjectRenderer implements LoggerAwareInterface if (!$error) { // Setting up tablejoins: - if ($conf['join']) { + if ($conf['join'] ?? false) { $joinParts = QueryHelper::parseJoin($conf['join']); $queryBuilder->join( $table, @@ -5880,7 +5880,7 @@ class ContentObjectRenderer implements LoggerAwareInterface $joinParts['tableAlias'], $joinParts['joinCondition'] ); - } elseif ($conf['leftjoin']) { + } elseif ($conf['leftjoin'] ?? false) { $joinParts = QueryHelper::parseJoin($conf['leftjoin']); $queryBuilder->leftJoin( $table, @@ -5888,7 +5888,7 @@ class ContentObjectRenderer implements LoggerAwareInterface $joinParts['tableAlias'], $joinParts['joinCondition'] ); - } elseif ($conf['rightjoin']) { + } elseif ($conf['rightjoin'] ?? false) { $joinParts = QueryHelper::parseJoin($conf['rightjoin']); $queryBuilder->rightJoin( $table, @@ -6029,7 +6029,7 @@ class ContentObjectRenderer implements LoggerAwareInterface && !empty($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) ); - if (trim($conf['uidInList'])) { + if (trim($conf['uidInList'] ?? '')) { $listArr = GeneralUtility::intExplode(',', str_replace('this', (string)$tsfe->contentPid, $conf['uidInList'])); // If moved records shall be considered, select via t3ver_oid @@ -6172,9 +6172,10 @@ class ContentObjectRenderer implements LoggerAwareInterface $languageQuery = $expressionBuilder->in($languageField, [0, -1]); // Use this option to include records that don't have a default language counterpart ("free mode") // (originalpointerfield is 0 and the language field contains the requested language) - if (isset($conf['includeRecordsWithoutDefaultTranslation']) || $conf['includeRecordsWithoutDefaultTranslation.']) { - $includeRecordsWithoutDefaultTranslation = isset($conf['includeRecordsWithoutDefaultTranslation.']) ? - $this->stdWrap($conf['includeRecordsWithoutDefaultTranslation'], $conf['includeRecordsWithoutDefaultTranslation.']) : $conf['includeRecordsWithoutDefaultTranslation']; + if (isset($conf['includeRecordsWithoutDefaultTranslation']) || !empty($conf['includeRecordsWithoutDefaultTranslation.'])) { + $includeRecordsWithoutDefaultTranslation = isset($conf['includeRecordsWithoutDefaultTranslation.']) + ? $this->stdWrap($conf['includeRecordsWithoutDefaultTranslation'], $conf['includeRecordsWithoutDefaultTranslation.']) + : $conf['includeRecordsWithoutDefaultTranslation']; $includeRecordsWithoutDefaultTranslation = trim($includeRecordsWithoutDefaultTranslation) !== ''; } else { // Option was not explicitly set, check what's in for the language overlay type. @@ -6267,7 +6268,7 @@ class ContentObjectRenderer implements LoggerAwareInterface */ public function getQueryMarkers($table, $conf) { - if (!is_array($conf['markers.'])) { + if (!isset($conf['markers.']) || !is_array($conf['markers.'])) { return []; } // Parse markers and prepare their values diff --git a/typo3/sysext/frontend/Tests/Unit/ContentObject/ContentObjectRendererTest.php b/typo3/sysext/frontend/Tests/Unit/ContentObject/ContentObjectRendererTest.php index 1ae6b6eccf165abc4791ae62db3050c9cfdd1329..42d0888d4fd0031b2ba3e97763835e8778df5a11 100644 --- a/typo3/sysext/frontend/Tests/Unit/ContentObject/ContentObjectRendererTest.php +++ b/typo3/sysext/frontend/Tests/Unit/ContentObject/ContentObjectRendererTest.php @@ -8063,6 +8063,96 @@ class ContentObjectRendererTest extends UnitTestCase ); } + public function getGlobalDataProvider(): array + { + return [ + 'simple' => [ + 'foo', + 'HTTP_SERVER_VARS | something', + [ + 'HTTP_SERVER_VARS' => [ + 'something' => 'foo', + ] + ], + null + ], + 'simple source fallback' => [ + 'foo', + 'HTTP_SERVER_VARS | something', + null, + [ + 'HTTP_SERVER_VARS' => [ + 'something' => 'foo', + ] + ], + ], + 'globals ignored if source given' => [ + '', + 'HTTP_SERVER_VARS | something', + [ + 'HTTP_SERVER_VARS' => [ + 'something' => 'foo', + ] + ], + [ + 'HTTP_SERVER_VARS' => [ + 'something-else' => 'foo', + ] + ], + ], + 'sub array is returned as empty string' => [ + '', + 'HTTP_SERVER_VARS | something', + [ + 'HTTP_SERVER_VARS' => [ + 'something' => [ 'foo' ], + ] + ], + null + ], + 'does not exist' => [ + '', + 'HTTP_SERVER_VARS | something', + [ + 'HTTP_SERVER_VARS' => [ + 'something-else' => 'foo', + ] + ], + null + ], + 'does not exist in source' => [ + '', + 'HTTP_SERVER_VARS | something', + null, + [ + 'HTTP_SERVER_VARS' => [ + 'something-else' => 'foo', + ] + ] + ], + ]; + } + + /** + * @test + * @dataProvider getGlobalDataProvider + * @param mixed $expected + * @param string $key + * @param array $globals + * @param null $source + */ + public function getGlobalReturnsExpectedResult($expected, string $key, ?array $globals, ?array $source): void + { + if (isset($globals['HTTP_SERVER_VARS'])) { + // Note we can't simply $GLOBALS = $globals, since phpunit backupGlobals works on existing array keys. + $GLOBALS['HTTP_SERVER_VARS'] = $globals['HTTP_SERVER_VARS']; + } + self::assertSame( + $expected, + (new ContentObjectRenderer())->getGlobal($key, $source) + ); + } + /*************************************************************************** * End: Mixed tests ***************************************************************************/ diff --git a/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php b/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php index 680e3ed8d7db825dc2f7329f63bf2b2677b8615d..623696bd48c1b7fab9081dd3a68a984ba78b41e8 100644 --- a/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php +++ b/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php @@ -1488,7 +1488,7 @@ class DataHandlerHook $listArr = []; foreach ($GLOBALS['TCA'][$table]['columns'] ?? [] as $field => $configArr) { if ($configArr['config']['type'] === 'input') { - $evalCodesArray = GeneralUtility::trimExplode(',', $configArr['config']['eval'], true); + $evalCodesArray = GeneralUtility::trimExplode(',', $configArr['config']['eval'] ?? '', true); if (in_array('uniqueInPid', $evalCodesArray) || in_array('unique', $evalCodesArray)) { $listArr[] = $field; } diff --git a/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php b/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php index 3e725f808126974efa9ff7c9ed998f688d9c1abf..7ea12131403af39766b871223a69921d334fe2d7 100644 --- a/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php +++ b/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php @@ -839,7 +839,7 @@ class WorkspaceService implements SingletonInterface protected function isLanguageAccessibleForCurrentUser($table, array $record) { if (BackendUtility::isTableLocalizable($table)) { - $languageUid = $record[$GLOBALS['TCA'][$table]['ctrl']['languageField']]; + $languageUid = $record[$GLOBALS['TCA'][$table]['ctrl']['languageField']] ?? 0; } else { return true; }