finisherContext->getFormRuntime(); $uploadFolders = []; $elements = $formRuntime->getFormDefinition()->getRenderablesRecursively(); foreach ($elements as $element) { if (!$element instanceof FileUpload) { continue; } $file = $formRuntime[$element->getIdentifier()]; if (!$file) { continue; } if ($file instanceof ExtbaseFileReference) { $file = $file->getOriginalResource(); } if ($file instanceof FileReference) { $this->deleteFileAndCollectFolder($file, $uploadFolders); } elseif ($file instanceof ObjectStorage) { foreach ($file as $singleFile) { if ($singleFile instanceof ExtbaseFileReference) { $singleFile = $singleFile->getOriginalResource(); } if ($singleFile instanceof FileReference) { $this->deleteFileAndCollectFolder($singleFile, $uploadFolders); } } } } $this->deleteEmptyUploadFolders($uploadFolders); } /** * Deletes the file and collects its parent folder for later cleanup. * * @param array $uploadFolders */ private function deleteFileAndCollectFolder(FileReference $file, array &$uploadFolders): void { $folder = $file->getParentFolder(); if ($folder instanceof Folder) { $uploadFolders[$folder->getCombinedIdentifier()] = $folder; } $file->getStorage()->deleteFile($file->getOriginalFile()); } /** * note: * TYPO3\CMS\Form\Mvc\Property\TypeConverter\UploadedFileReferenceConverter::importUploadedResource() * creates a sub-folder for file uploads (e.g. .../form_<40-chars-hash>/actual.file) * @param Folder[] $folders */ protected function deleteEmptyUploadFolders(array $folders): void { foreach ($folders as $folder) { if ($this->isEmptyFolder($folder)) { $folder->delete(); } } } protected function isEmptyFolder(Folder $folder): bool { return $folder->getFileCount() === 0 && $folder->getStorage()->countFoldersInFolder($folder) === 0; } }