From c5b7dbbc1d8776eca95478a0e5b0d25e759b1193 Mon Sep 17 00:00:00 2001 From: Andreas Fernandez <a.fernandez@scripting-base.de> Date: Wed, 24 Jan 2018 16:50:17 +0100 Subject: [PATCH] [BUGFIX] Catch exception editing record with deleted relation Editing a record with a deleted related record leads to an uncaught DatabaseRecordException. This patch catches the exception and ignores such records, but logs a warning. Due to possible errors occurring with certain DBMS (e.g. MySQL strict) columns may require a default value now in TCA. Resolves: #83412 Releases: master, 8.7, 7.6 Change-Id: I5adaf385443350ce245dd83da6e5f1a16d9c9afb Reviewed-on: https://review.typo3.org/55752 Tested-by: TYPO3com <no-reply@typo3.com> Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de> Reviewed-by: Sascha Rademacher <sascha.rademacher+typo3@gmail.com> Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de> Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch> Tested-by: Christian Kuhn <lolli@schwarzbu.ch> --- .../Form/FormDataProvider/TcaInline.php | 70 +++++++++++++++++-- 1 file changed, 66 insertions(+), 4 deletions(-) diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php index 1664bb02fcfd..c81e453db587 100644 --- a/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php +++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php @@ -23,6 +23,8 @@ use TYPO3\CMS\Backend\Form\InlineStackProcessor; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Database\RelationHandler; +use TYPO3\CMS\Core\Log\Logger; +use TYPO3\CMS\Core\Log\LogManager; use TYPO3\CMS\Core\Messaging\FlashMessage; use TYPO3\CMS\Core\Messaging\FlashMessageService; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -152,7 +154,20 @@ class TcaInline extends AbstractDatabaseRecordProvider implements FormDataProvid // @todo: format of databaseRow for this field and separate the child compilation to an own provider? if ($result['inlineCompileExistingChildren']) { foreach ($connectedUids as $childUid) { - $result['processedTca']['columns'][$fieldName]['children'][] = $this->compileChild($result, $fieldName, $childUid); + try { + $result['processedTca']['columns'][$fieldName]['children'][] = $this->compileChild($result, $fieldName, $childUid); + } catch (DatabaseRecordException $e) { + // The child could not be compiled, probably it was deleted and a dangling mm record exists + $this->getLogger()->warning( + $e->getMessage(), + [ + 'table' => $childTableName, + 'uid' => $childUid, + 'exception' => $e + ] + ); + continue; + } } } } elseif ($mode === 'keep') { @@ -199,21 +214,60 @@ class TcaInline extends AbstractDatabaseRecordProvider implements FormDataProvid // localized but miss default language record $fieldNameWithDefaultLanguageUid = $GLOBALS['TCA'][$childTableName]['ctrl']['transOrigPointerField']; foreach ($connectedUidsOfLocalizedOverlay as $localizedUid) { - $localizedRecord = $this->getRecordFromDatabase($childTableName, $localizedUid); + try { + $localizedRecord = $this->getRecordFromDatabase($childTableName, $localizedUid); + } catch (DatabaseRecordException $e) { + // The child could not be compiled, probably it was deleted and a dangling mm record exists + $this->getLogger()->warning( + $e->getMessage(), + [ + 'table' => $childTableName, + 'uid' => $localizedUid, + 'exception' => $e + ] + ); + continue; + } $uidOfDefaultLanguageRecord = $localizedRecord[$fieldNameWithDefaultLanguageUid]; if (in_array($uidOfDefaultLanguageRecord, $connectedUidsOfDefaultLanguageRecord)) { // This localized child has a default language record. Remove this record from list of default language records $connectedUidsOfDefaultLanguageRecord = array_diff($connectedUidsOfDefaultLanguageRecord, [$uidOfDefaultLanguageRecord]); } // Compile localized record - $compiledChild = $this->compileChild($result, $fieldName, $localizedUid); + try { + $compiledChild = $this->compileChild($result, $fieldName, $localizedUid); + } catch (DatabaseRecordException $e) { + // The child could not be compiled, probably it was deleted and a dangling mm record exists + $this->getLogger()->warning( + $e->getMessage(), + [ + 'table' => $childTableName, + 'uid' => $localizedUid, + 'exception' => $e + ] + ); + continue; + } $result['processedTca']['columns'][$fieldName]['children'][] = $compiledChild; } if ($showPossible) { foreach ($connectedUidsOfDefaultLanguageRecord as $defaultLanguageUid) { // If there are still uids in $connectedUidsOfDefaultLanguageRecord, these are records that // exist in default language, but are not localized yet. Compile and mark those - $compiledChild = $this->compileChild($result, $fieldName, $defaultLanguageUid); + try { + $compiledChild = $this->compileChild($result, $fieldName, $defaultLanguageUid); + } catch (DatabaseRecordException $e) { + // The child could not be compiled, probably it was deleted and a dangling mm record exists + $this->getLogger()->warning( + $e->getMessage(), + [ + 'table' => $childTableName, + 'uid' => $defaultLanguageUid, + 'exception' => $e + ] + ); + continue; + } $compiledChild['isInlineDefaultLanguageRecordInLocalizedParentContext'] = true; $result['processedTca']['columns'][$fieldName]['children'][] = $compiledChild; } @@ -481,4 +535,12 @@ class TcaInline extends AbstractDatabaseRecordProvider implements FormDataProvid { return $GLOBALS['LANG']; } + + /** + * @return Logger + */ + protected function getLogger() + { + return GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__); + } } -- GitLab