From 48d746eb293f8586db7b99148d13a01c61a1780d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20B=C3=BCrk?= <stefan@buerk.tech>
Date: Mon, 18 Dec 2023 16:24:19 +0100
Subject: [PATCH] [BUGFIX] Avoid type errors in `ResourceFactory` methods
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

With #92289 logic has been decoupled from `ResourceFactory`
into the `StorageRepository`. As a side change, native php
types have been added to a couple of methods.

`StorageRepository->findByUid()` parameter type has been set
to integer, which breaks the `null` fallback and retrieving
the default storage `uid: 0` in `ResourceFactory` method
`getStorageObjectFromCombinedIdentifier()`. Even worse is
the fact that `getObjectFromCombinedIdentifier()` does not
even try to cope with a invalid identifier provided.

This change modifies `getObjectFromCombinedIdentifier()` and
`getStorageObjectFromCombinedIdentifier` of `ResourceFactory`
to cope with missing storage identifier by falling back to
the default storage (`0`) with a shuffle of the exploded values.

As a side-effect two PHPStan ignore patterns can be removed
from the PHPStan baseline file.

Used command(s):

  Build/Scripts/runTests.sh -s phpstanGenerateBaseline

Resolves: #102692
Related: #92289
Releases: main, 12.4, 11.5
Change-Id: I8ee9736839f59db7917cb49dd0d62af17ee28cda
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/82232
Tested-by: core-ci <typo3@b13.com>
Tested-by: Stefan Bürk <stefan@buerk.tech>
Reviewed-by: Stefan Bürk <stefan@buerk.tech>
---
 Build/phpstan/phpstan-baseline.neon           | 10 -------
 .../core/Classes/Resource/ResourceFactory.php | 26 ++++++++++++-------
 2 files changed, 17 insertions(+), 19 deletions(-)

diff --git a/Build/phpstan/phpstan-baseline.neon b/Build/phpstan/phpstan-baseline.neon
index acee5c3f0c1b..e172d852e17c 100644
--- a/Build/phpstan/phpstan-baseline.neon
+++ b/Build/phpstan/phpstan-baseline.neon
@@ -970,16 +970,6 @@ parameters:
 			count: 1
 			path: ../../typo3/sysext/core/Classes/Resource/ResourceFactory.php
 
-		-
-			message: "#^Parameter \\#1 \\$uid of method TYPO3\\\\CMS\\\\Core\\\\Resource\\\\StorageRepository\\:\\:findByUid\\(\\) expects int, string given\\.$#"
-			count: 1
-			path: ../../typo3/sysext/core/Classes/Resource/ResourceFactory.php
-
-		-
-			message: "#^Parameter \\#1 \\$uid of method TYPO3\\\\CMS\\\\Core\\\\Resource\\\\StorageRepository\\:\\:findByUid\\(\\) expects int, string\\|null given\\.$#"
-			count: 1
-			path: ../../typo3/sysext/core/Classes/Resource/ResourceFactory.php
-
 		-
 			message: "#^Call to an undefined method TYPO3\\\\CMS\\\\Core\\\\Resource\\\\FileInterface\\:\\:getCombinedIdentifier\\(\\)\\.$#"
 			count: 2
diff --git a/typo3/sysext/core/Classes/Resource/ResourceFactory.php b/typo3/sysext/core/Classes/Resource/ResourceFactory.php
index c7c611575050..48dbea2cb937 100644
--- a/typo3/sysext/core/Classes/Resource/ResourceFactory.php
+++ b/typo3/sysext/core/Classes/Resource/ResourceFactory.php
@@ -366,9 +366,11 @@ class ResourceFactory implements SingletonInterface
      */
     public function getStorageObjectFromCombinedIdentifier($identifier)
     {
-        $parts = GeneralUtility::trimExplode(':', $identifier);
-        $storageUid = count($parts) === 2 ? $parts[0] : null;
-        return $this->storageRepository->findByUid($storageUid);
+        [$storageId, $objectIdentifier] = array_pad(GeneralUtility::trimExplode(':', $identifier), 2, null);
+        if (!MathUtility::canBeInterpretedAsInteger($storageId) && $objectIdentifier === null) {
+            return $this->storageRepository->findByUid(0);
+        }
+        return $this->storageRepository->findByUid((int)$storageId);
     }
 
     /**
@@ -381,13 +383,19 @@ class ResourceFactory implements SingletonInterface
      */
     public function getObjectFromCombinedIdentifier($identifier)
     {
-        [$storageId, $objectIdentifier] = GeneralUtility::trimExplode(':', $identifier);
-        $storage = $this->storageRepository->findByUid($storageId);
-        if ($storage->hasFile($objectIdentifier)) {
-            return $storage->getFile($objectIdentifier);
+        [$storageId, $objectIdentifier] = array_pad(GeneralUtility::trimExplode(':', $identifier), 2, null);
+        if (!MathUtility::canBeInterpretedAsInteger($storageId) && $objectIdentifier === null) {
+            $objectIdentifier = $storageId;
+            $storageId = 0;
         }
-        if ($storage->hasFolder($objectIdentifier)) {
-            return $storage->getFolder($objectIdentifier);
+        if (MathUtility::canBeInterpretedAsInteger($storageId)) {
+            $storage = $this->storageRepository->findByUid($storageId);
+            if ($storage->hasFile($objectIdentifier)) {
+                return $storage->getFile($objectIdentifier);
+            }
+            if ($storage->hasFolder($objectIdentifier)) {
+                return $storage->getFolder($objectIdentifier);
+            }
         }
         throw new ResourceDoesNotExistException('Object with identifier "' . $identifier . '" does not exist in storage', 1329647780);
     }
-- 
GitLab