From a76907a42100a0169134c3490567b6b706122336 Mon Sep 17 00:00:00 2001 From: Stigi Date: Wed, 18 Feb 2026 08:57:14 +0100 Subject: [PATCH 1/2] Add dynamic page placeholders and backend path preview Dynamic Page Placeholders: You can now use placeholders like {title}, {subtitle}, or {nav_title} within the folder path configuration. The values are fetched from the current page record, converted to lowercase, and cleaned of special characters (slugified) to ensure valid directory names. This feature is triggered by setting variableformat = 1 in the TSconfig. Backend Path Preview: Added logic to resolve the final destination path (including storage base paths) and pass this data to the TYPO3 backend via JavaScript. This allows for displaying the actual target folder to editors directly within the record form, improving clarity and preventing upload errors. --- .../Backend/DefaultUploadFolder.php | 204 ++++++++++++++---- 1 file changed, 165 insertions(+), 39 deletions(-) diff --git a/Classes/EventListener/Backend/DefaultUploadFolder.php b/Classes/EventListener/Backend/DefaultUploadFolder.php index 086ffd5..5fbe058 100644 --- a/Classes/EventListener/Backend/DefaultUploadFolder.php +++ b/Classes/EventListener/Backend/DefaultUploadFolder.php @@ -5,14 +5,17 @@ namespace BeechIt\DefaultUploadFolder\EventListener\Backend; use TYPO3\CMS\Backend\Utility\BackendUtility; +use TYPO3\CMS\Core\Page\PageRenderer; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Utility\File\ExtendedFileUtility; use TYPO3\CMS\Core\Resource\Event\AfterDefaultUploadFolderWasResolvedEvent; use TYPO3\CMS\Core\Resource\Exception\FolderDoesNotExistException; use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException; use TYPO3\CMS\Core\Resource\Folder; use TYPO3\CMS\Core\Resource\FolderInterface; use TYPO3\CMS\Core\Resource\ResourceFactory; -use TYPO3\CMS\Core\Utility\File\ExtendedFileUtility; -use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior; + class DefaultUploadFolder { @@ -34,15 +37,15 @@ public function __invoke(AfterDefaultUploadFolderWasResolvedEvent $event): void $userTsConfig = $GLOBALS['BE_USER']->getTsConfig(); $subFolder = ''; if ($table !== null && $field !== null) { - $subFolder = $this->getDefaultUploadFolderForTableAndField($table, $field, $pageTs, $userTsConfig); + $subFolder = $this->getDefaultUploadFolderForTableAndField($table, $field, $pageTs, $userTsConfig, (int)$pid); } if (trim($subFolder) === '' && $field !== null) { - $subFolder = $this->getDefaultUploadFolderForTable($table, $pageTs, $userTsConfig); + $subFolder = $this->getDefaultUploadFolderForTable($table, $pageTs, $userTsConfig, (int)$pid); } if (trim($subFolder) === '') { - $subFolder = $this->getDefaultUploadFolderForAllTables($pageTs, $userTsConfig); + $subFolder = $this->getDefaultUploadFolderForAllTables($pageTs, $userTsConfig, (int)$pid); } // Folder by combined identifier @@ -65,8 +68,74 @@ public function __invoke(AfterDefaultUploadFolderWasResolvedEvent $event): void if ($uploadFolder instanceof FolderInterface) { $event->setUploadFolder($uploadFolder); } + + $this->showUploadFolderInfo($table, $field, $subFolder, (int)$pid); + } + + /** + * Zeigt Informationen zum aktuellen Upload-Ordner an + * + * @param string|null $table + * @param string|null $field + * @param string $uploadFolder + * @param int $pid + */ + protected function showUploadFolderInfo(?string $table, ?string $field, string $uploadFolder, int $pid): void + { + + + // Prüfen, ob die notwendigen Daten vorhanden sind + if (!$table || !$field || !$uploadFolder) { + return; + } + + + // Prüfe die Gültigkeit des Ordners und bereite Informationen vor + $uploadFolderPath = $uploadFolder; + $isValidPath = true; + $errorMessage = ''; + + if (preg_match('/^(\d+):(.*)$/', $uploadFolder, $matches)) { + + + $storageUid = (int)$matches[1]; + $folderPath = $matches[2]; + + try { + // Versuche den Storage zu laden + $storage = GeneralUtility::makeInstance(ResourceFactory::class)->getStorageObject($storageUid); + + if (!$storage->isOnline()) { + $isValidPath = false; + $errorMessage = 'Storage ist falsch oder nicht erreichbar'; + } else { + $configuration = $storage->getConfiguration(); + $basePath = $configuration['basePath'] ?? ''; + + if ($basePath) { + $uploadFolderPath = $basePath . $folderPath; + } + } + } catch (\Exception $e) { + $isValidPath = false; + $errorMessage = 'Storage mit ID ' . $storageUid . ' existiert nicht'; + } + } + + // JavaScript-Code einfügen, um die Information im Formular anzuzeigen + $pageRenderer = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Page\PageRenderer::class); + + $js = ' + if (!window.uploadFolderInfo) window.uploadFolderInfo = {}; + window.uploadFolderInfo[' . json_encode($field) . '] = ' . json_encode($uploadFolderPath) . '; + '; + + $pageRenderer->addJsInlineCode('uploadFolderData_' . $field, $js, false, false, true); + $pageRenderer->addJsFile('EXT:default_upload_folder/Resources/Public/JavaScript/test.js'); + } + /** * Create upload folder * @@ -106,10 +175,13 @@ private function createUploadFolder($combinedFolderIdentifier): ?Folder ], ]; + $fileProcessor = GeneralUtility::makeInstance(ExtendedFileUtility::class); + $fileProcessor->setExistingFilesConflictMode(DuplicationBehavior::RENAME); $fileProcessor->setActionPermissions(); $fileProcessor->start($data); $fileProcessor->processData(); + return GeneralUtility::makeInstance(ResourceFactory::class)->getFolderObjectFromCombinedIdentifier( $combinedFolderIdentifier ); @@ -122,22 +194,24 @@ private function createUploadFolder($combinedFolderIdentifier): ?Folder * @param string $field * @param array $defaultPageTs * @param array $userTsConfig + * @param int $pid * @return string */ protected function getDefaultUploadFolderForTableAndField( string $table, string $field, array $defaultPageTs, - array $userTsConfig + array $userTsConfig, + int $pid ): string { $subFolder = $defaultPageTs[self::DEFAULT_UPLOAD_FOLDERS][$table . '.'][$field] ?? ''; - $dateFormatConfig = $defaultPageTs[self::DEFAULT_UPLOAD_FOLDERS][$table . '.'][$field . '.'] ?? []; - $subFolder = $this->checkAndConvertForDateFormat($subFolder, $dateFormatConfig); + $config = $defaultPageTs[self::DEFAULT_UPLOAD_FOLDERS][$table . '.'][$field . '.'] ?? []; + $subFolder = $this->checkAndConvertForVariable($subFolder, $config, $pid); if (empty($subFolder)) { $subFolder = $userTsConfig[self::DEFAULT_UPLOAD_FOLDERS][$table . '.'][$field] ?? ''; - $dateFormatConfig = $userTsConfig[self::DEFAULT_UPLOAD_FOLDERS][$table . '.'][$field . '.'] ?? []; - $subFolder = $this->checkAndConvertForDateFormat($subFolder, $dateFormatConfig); + $config = $userTsConfig[self::DEFAULT_UPLOAD_FOLDERS][$table . '.'][$field . '.'] ?? []; + $subFolder = $this->checkAndConvertForVariable($subFolder, $config, $pid); } return $subFolder; } @@ -148,22 +222,24 @@ protected function getDefaultUploadFolderForTableAndField( * @param string $table * @param array $defaultPageTs * @param array $userTsConfig + * @param int $pid * @return string */ protected function getDefaultUploadFolderForTable( string $table, array $defaultPageTs, - array $userTsConfig + array $userTsConfig, + int $pid ): string { $subFolder = $defaultPageTs[self::DEFAULT_UPLOAD_FOLDERS][$table] ?? ''; - $dateFormatConfig = $defaultPageTs[self::DEFAULT_UPLOAD_FOLDERS][$table . '.'] ?? []; - $subFolder = $this->checkAndConvertForDateFormat($subFolder, $dateFormatConfig); + $config = $defaultPageTs[self::DEFAULT_UPLOAD_FOLDERS][$table . '.'] ?? []; + $subFolder = $this->checkAndConvertForVariable($subFolder, $config, $pid); if (empty($subFolder)) { $subFolder = $userTsConfig[self::DEFAULT_UPLOAD_FOLDERS][$table] ?? ''; - $dateFormatConfig = $userTsConfig[self::DEFAULT_UPLOAD_FOLDERS][$table . '.'] ?? []; - $subFolder = $this->checkAndConvertForDateFormat($subFolder, $dateFormatConfig); + $config = $userTsConfig[self::DEFAULT_UPLOAD_FOLDERS][$table . '.'] ?? []; + $subFolder = $this->checkAndConvertForVariable($subFolder, $config, $pid); } return $subFolder; } @@ -173,53 +249,103 @@ protected function getDefaultUploadFolderForTable( * * @param array $defaultPageTs * @param array $userTsConfig + * @param int $pid * @return string */ protected function getDefaultUploadFolderForAllTables( array $defaultPageTs, - array $userTsConfig + array $userTsConfig, + int $pid ): string { $subFolder = $defaultPageTs[self::DEFAULT_UPLOAD_FOLDERS][self::DEFAULT_FOR_ALL_TABLES] ?? ''; - $dateFormatConfig = $defaultPageTs[self::DEFAULT_UPLOAD_FOLDERS][self::DEFAULT_FOR_ALL_TABLES . '.'] ?? []; - $subFolder = $this->checkAndConvertForDateFormat($subFolder, $dateFormatConfig); + $config = $defaultPageTs[self::DEFAULT_UPLOAD_FOLDERS][self::DEFAULT_FOR_ALL_TABLES . '.'] ?? []; + $subFolder = $this->checkAndConvertForVariable($subFolder, $config, $pid); if (empty($subFolder)) { $subFolder = $userTsConfig[self::DEFAULT_UPLOAD_FOLDERS][self::DEFAULT_FOR_ALL_TABLES] ?? ''; - $dateFormatConfig = $userTsConfig[self::DEFAULT_UPLOAD_FOLDERS][self::DEFAULT_FOR_ALL_TABLES . '.'] ?? []; - $subFolder = $this->checkAndConvertForDateFormat($subFolder, $dateFormatConfig); + $config = $userTsConfig[self::DEFAULT_UPLOAD_FOLDERS][self::DEFAULT_FOR_ALL_TABLES . '.'] ?? []; + $subFolder = $this->checkAndConvertForVariable($subFolder, $config, $pid); } return $subFolder; } + protected function slugify(string $string): string + { + $string = trim($string); + $string = mb_strtolower($string, 'UTF-8'); + + // Umlaute ersetzen + $umlaute = ['ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue', 'ß' => 'ss']; + $string = strtr($string, $umlaute); + + // Sonderzeichen entfernen + $string = preg_replace('/[^a-z0-9\s\-]/', '', $string); + + // Leerzeichen und Doppelte Dashes zu einem + $string = preg_replace('/[\s\-]+/', '-', $string); + + return trim($string, '-'); + } + + /** - * Check and convert for date format + * Check and convert for variables * * @param $subFolder - * @param $dateFormatConfig - * @return string $subFolder + * @param $config + * @param $pid + * @return string */ - protected function checkAndConvertForDateFormat($subFolder, $dateFormatConfig): string + protected function checkAndConvertForVariable($subFolder, $config, int $pid): string { + + + if (trim($subFolder) === '') { return $subFolder; } - if (!isset($dateFormatConfig['dateformat']) || (int)$dateFormatConfig['dateformat'] !== 1) { - return $subFolder; + + // Handle date variables + //Exmaple: 1:user_upload/news/{y}/{m}/ + if (isset($config['dateformat']) && (int)$config['dateformat'] === 1) { + $datePlaceholders = [ + '{Y}', '{y}', + '{m}', '{n}', + '{j}', '{d}', + '{W}', '{w}', + ]; + $dateReplacements = [ + date('Y'), date('y'), + date('m'), date('n'), + date('j'), date('d'), + date('W'), date('w'), + ]; + $subFolder = str_replace($datePlaceholders, $dateReplacements, $subFolder); } - $strReplace = [ - '{Y}', '{y}', - '{m}', '{n}', - '{j}', '{d}', - '{W}', '{w}', - ]; - $replaceWith = [ - date('Y'), date('y'), - date('m'), date('n'), - date('j'), date('d'), - date('W'), date('w'), - ]; - return str_replace($strReplace, $replaceWith, $subFolder); + + // Handle page related variables + // Example: 1:user_upload/{title}/images/ + if (!empty($config['variableformat']) && (int)$config['variableformat'] === 1) { + + $fields = ['title', 'nav_title', 'subtitle']; + $page = BackendUtility::getRecord('pages', $pid, implode(',', $fields)) ?: []; + + foreach ($fields as $field) { + $subFolder = str_replace( + '{' . $field . '}', + $this->slugify($page[$field] ?? ''), + $subFolder + ); + } + } + + // Prüfen: Enthält der Subfolder noch Platzhalter {xyz} ? + if (preg_match('/\{[^}]+\}/', $subFolder)) { + return ''; + } + + return $subFolder; } } From 52cb3d6c374f6eeed3d174574087205018205b2f Mon Sep 17 00:00:00 2001 From: Stigi Date: Wed, 18 Feb 2026 09:10:25 +0100 Subject: [PATCH 2/2] Replace test.js with PathInfo.js in upload folder --- Classes/EventListener/Backend/DefaultUploadFolder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/EventListener/Backend/DefaultUploadFolder.php b/Classes/EventListener/Backend/DefaultUploadFolder.php index 5fbe058..d8d9224 100644 --- a/Classes/EventListener/Backend/DefaultUploadFolder.php +++ b/Classes/EventListener/Backend/DefaultUploadFolder.php @@ -131,7 +131,7 @@ protected function showUploadFolderInfo(?string $table, ?string $field, string $ '; $pageRenderer->addJsInlineCode('uploadFolderData_' . $field, $js, false, false, true); - $pageRenderer->addJsFile('EXT:default_upload_folder/Resources/Public/JavaScript/test.js'); + $pageRenderer->addJsFile('EXT:default_upload_folder/Resources/Public/JavaScript/PathInfo.js'); }