[BUGFIX] Fix serialization of FileReference objects 41/64841/4
authorBenjamin Franzke <bfr@qbus.de>
Mon, 8 Jun 2020 19:37:41 +0000 (21:37 +0200)
committerDaniel Goerz <daniel.goerz@posteo.de>
Tue, 30 Jun 2020 18:01:59 +0000 (20:01 +0200)
FileReferences objects contain references to File
objects which itself contain service dependencies
(e.g. event dispatcher) which are not seralizable.

This leads to problems for instance when having
a multi-step form containing file uploads where
file reference objects are being serialized.

Resolves: #91196
Releases: master, 10.4
Change-Id: I7650186adc5c61528e1a1adcf06b8d6cf67a55cd
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/64841
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Daniel Goerz <daniel.goerz@posteo.de>
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Reviewed-by: Daniel Goerz <daniel.goerz@posteo.de>
typo3/sysext/core/Classes/Resource/FileReference.php

index bd757a3..447aa8c 100644 (file)
@@ -40,15 +40,6 @@ class FileReference implements FileInterface
     protected $propertiesOfFileReference;
 
     /**
-     * The identifier of this file to identify it on the storage.
-     * On some drivers, this is the path to the file, but drivers could also just
-     * provide any other unique identifier for this file on the specific storage.
-     *
-     * @var string
-     */
-    protected $uidOfFileReference;
-
-    /**
      * The file name of this file. It's either the fileName of the original underlying file,
      * or the overlay file name supplied by the user for this particular usage (FileReference) of the file.
      *
@@ -79,8 +70,8 @@ class FileReference implements FileInterface
      * @param array $fileReferenceData
      * @param ResourceFactory $factory
      *
-     * @throws \RuntimeException
      * @throws \InvalidArgumentException
+     * @throws Exception\FileDoesNotExistException
      */
     public function __construct(array $fileReferenceData, $factory = null)
     {
@@ -88,17 +79,23 @@ class FileReference implements FileInterface
         if (!$fileReferenceData['uid_local']) {
             throw new \InvalidArgumentException('Incorrect reference to original file given for FileReference.', 1300098528);
         }
-        if (!$factory) {
+        $this->originalFile = $this->getFileObject((int)$fileReferenceData['uid_local'], $factory);
+        $this->name = $fileReferenceData['name'] !== '' ? $fileReferenceData['name'] : $this->originalFile->getName();
+    }
+
+    /**
+     * @param int $uidLocal
+     * @param ResourceFactory|null $factory
+     * @return FileInterface
+     *
+     * @throws Exception\FileDoesNotExistException
+     */
+    private function getFileObject(int $uidLocal, ResourceFactory $factory = null): FileInterface
+    {
+        if ($factory === null) {
             $factory = GeneralUtility::makeInstance(ResourceFactory::class);
         }
-        $this->originalFile = $factory->getFileObject($fileReferenceData['uid_local']);
-        if (!is_object($this->originalFile)) {
-            throw new \RuntimeException(
-                'Original file not found for FileReference. UID given: "' . $fileReferenceData['uid_local'] . '"',
-                1300098529
-            );
-        }
-        $this->name = $fileReferenceData['name'] !== '' ? $fileReferenceData['name'] : $this->originalFile->getName();
+        return $factory->getFileObject($uidLocal);
     }
 
     /*******************************
@@ -518,4 +515,24 @@ class FileReference implements FileInterface
     {
         return $this->originalFile->getParentFolder();
     }
+
+    /**
+     * Avoids exporting original file object which contains
+     * singleton dependencies that must not be serialized.
+     *
+     * @return string[]
+     */
+    public function __sleep(): array
+    {
+        $keys = get_object_vars($this);
+        unset($keys['originalFile']);
+        return array_keys($keys);
+    }
+
+    public function __wakeup(): void
+    {
+        $this->originalFile = $this->getFileObject(
+            (int)$this->propertiesOfFileReference['uid_local']
+        );
+    }
 }