From cfb79e94ac4ace50c818657deca85935288982d3 Mon Sep 17 00:00:00 2001
From: Benjamin Serfhos <serfhos@gmail.com>
Date: Fri, 15 Sep 2023 10:04:59 +0200
Subject: [PATCH] [BUGFIX] Handle FileDoesNotExistException in
 `cleanup:missingrelations`
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

It's possible that file references to files exists, where
the physical file is missing. That stopped further file
reference processing in the ext:lowlevel cleanup command
`cleanup:missingrelations`.

Therefore, this change explicitly catches the concrete
`\TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException`
exception and outputs the message, without interrupting the
processing of further files.

The handling code is moved to a dedicated method to clean
up code duplication on the same step as a side-change.

Other unforeseen errors still stop the execution.

Resolves: #101924
Releases: main, 12.4
Change-Id: I2c8dba34a6f99d891408b5cc8fd86bddcb3c90c2
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/81024
Tested-by: core-ci <typo3@b13.com>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Oliver Klee <typo3-coding@oliverklee.de>
Tested-by: Stefan Bürk <stefan@buerk.tech>
Reviewed-by: Stefan Bürk <stefan@buerk.tech>
---
 .../Command/MissingRelationsCommand.php       | 40 +++++++++++--------
 1 file changed, 24 insertions(+), 16 deletions(-)

diff --git a/typo3/sysext/lowlevel/Classes/Command/MissingRelationsCommand.php b/typo3/sysext/lowlevel/Classes/Command/MissingRelationsCommand.php
index 456e670511a1..7efe7983dba6 100644
--- a/typo3/sysext/lowlevel/Classes/Command/MissingRelationsCommand.php
+++ b/typo3/sysext/lowlevel/Classes/Command/MissingRelationsCommand.php
@@ -29,6 +29,7 @@ use TYPO3\CMS\Core\Core\Bootstrap;
 use TYPO3\CMS\Core\Database\Connection;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\ReferenceIndex;
+use TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException;
 use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
@@ -337,14 +338,7 @@ If you want to get more detailed information, use the --verbose option.')
                 $io->writeln('Removing references in offline versions which there are references pointing towards.');
             }
             foreach ($references as $hash => $recordReference) {
-                $io->writeln('Removing reference in record "' . $recordReference . '" (Hash: ' . $hash . ')');
-                if (!$dryRun) {
-                    $sysRefObj = GeneralUtility::makeInstance(ReferenceIndex::class);
-                    $error = $sysRefObj->setReferenceValue($hash, null);
-                    if ($error) {
-                        $io->error('ReferenceIndex::setReferenceValue() reported "' . $error . '"');
-                    }
-                }
+                $this->removeReference($hash, $recordReference, $dryRun, $io);
             }
         }
 
@@ -354,15 +348,29 @@ If you want to get more detailed information, use the --verbose option.')
                 $io->writeln('Removing references to non-existing records.');
             }
             foreach ($references as $hash => $recordReference) {
-                $io->writeln('Removing reference in record "' . $recordReference . '" (Hash: ' . $hash . ')');
-                if (!$dryRun) {
-                    $sysRefObj = GeneralUtility::makeInstance(ReferenceIndex::class);
-                    $error = $sysRefObj->setReferenceValue($hash, null);
-                    if ($error) {
-                        $io->error('ReferenceIndex::setReferenceValue() reported "' . $error . '"');
-                    }
-                }
+                $this->removeReference($hash, $recordReference, $dryRun, $io);
+            }
+        }
+    }
+
+    /**
+     * Remove a reference to a missing record
+     */
+    protected function removeReference(string $hash, string $recordReference, bool $dryRun, SymfonyStyle $io): void
+    {
+        $io->writeln('Removing reference in record "' . $recordReference . '" (Hash: ' . $hash . ')');
+        if ($dryRun) {
+            return;
+        }
+
+        $sysRefObj = GeneralUtility::makeInstance(ReferenceIndex::class);
+        try {
+            $error = $sysRefObj->setReferenceValue($hash, null);
+            if ($error) {
+                $io->error('ReferenceIndex::setReferenceValue() reported "' . $error . '"');
             }
+        } catch (FileDoesNotExistException $e) {
+            $io->error('Unexpected exception thrown: ' . $e->getMessage());
         }
     }
 
-- 
GitLab