diff --git a/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/README.md b/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/README.md index 3b462fb..5e62d41 100644 --- a/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/README.md +++ b/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/README.md @@ -23,6 +23,8 @@ class Type << (F,LightGreen) >> #RoyalBlue { # getAllow(object $data) : string # getAllowSpan(object $data) : string # getAllowFormats(object $data) : ?array + # getFileTypePath(object $data) : ?string + # getLastFolderName(string $path) : ?string } note right of Type::__construct @@ -86,6 +88,25 @@ note right of Type::getAllowFormats since: 5.0.2 return: ?array end note + +note left of Type::getFileTypePath + Retrieves the file type path based on provided data. +Performs safety checks and returns either a cleaned path if it exists +and is a writable directory, or constructs a relative path to the 'images' folder +based on the last folder name from the given path. + + since: 5.0.2 + return: ?string +end note + +note right of Type::getLastFolderName + Recursively retrieves the last folder name from a given path, ignoring any file names. +If the last part of the path contains a dot (indicating a file), it moves up the directory tree +until it finds a valid folder name. Returns null if no valid folder is found. + + since: 5.0.2 + return: ?string +end note @enduml ``` diff --git a/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/code.php b/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/code.php index 5eb289c..f971fe3 100644 --- a/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/code.php +++ b/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/code.php @@ -12,6 +12,7 @@ namespace VDM\Joomla\Componentbuilder\File; +use Joomla\Filesystem\Path; use VDM\Joomla\Interfaces\Data\ItemInterface as Item; @@ -91,10 +92,6 @@ final class Type if (($fileType = $this->details($guid)) !== null && $this->validTarget($fileType, $target)) { - // some safety checks - $path = isset($fileType->path) && is_string($fileType->path) && trim($fileType->path) !== '' ? trim($fileType->path) : null; - $path = ($path !== null && is_dir($path) && is_writable($path)) ? $path : null; - return [ 'name' => $fileType->name ?? 'files', 'access' => $fileType->access ?? 1, @@ -103,7 +100,7 @@ final class Type 'type' => $this->getFieldName($fileType), 'formats' => $this->getAllowFormats($fileType) ?? [], 'filter' => $fileType->filter ?? null, - 'path' => $path + 'path' => $this->getFileTypePath($fileType) ]; } @@ -231,6 +228,74 @@ final class Type } return null; + } + + /** + * Retrieves the file type path based on provided data. + * + * Performs safety checks and returns either a cleaned path if it exists + * and is a writable directory, or constructs a relative path to the 'images' folder + * based on the last folder name from the given path. + * + * @param object $data The type data object containing path information. + * + * @return string|null Returns the cleaned file path or null if no valid path is found. + * @since 5.0.2 + */ + protected function getFileTypePath(object $data): ?string + { + // Validate the provided path data + $path = isset($data->path) && is_string($data->path) && trim($data->path) !== '' ? + Path::clean(trim($data->path)) : null; + + // Return the path if it's a valid directory and writable + if ($path !== null && is_dir($path) && is_writable($path)) + { + return $path; + } + + // If no valid path is found, try to derive a relative path from the 'images' folder + if ($path !== null && ($folder = $this->getLastFolderName($path)) !== null) + { + return JPATH_SITE . '/images/' . $folder; + } + + return null; + } + + /** + * Recursively retrieves the last folder name from a given path, ignoring any file names. + * If the last part of the path contains a dot (indicating a file), it moves up the directory tree + * until it finds a valid folder name. Returns null if no valid folder is found. + * + * @param string $path The file system path from which to extract the last folder name. + * + * @return string|null Returns the last folder name if found, or null if no valid folder exists. + * @since 5.0.2 + */ + protected function getLastFolderName(string $path): ?string + { + // Remove any trailing slashes to avoid an empty result + $path = rtrim($path, '/\\'); + + // If the path becomes empty, return null (base case) + if (empty($path)) + { + return null; + } + + // Get the last part of the path + $lastPart = basename($path); + + // If the last part contains a dot (and it's not a hidden folder), move up the directory tree + if (strpos($lastPart, '.') > 0) + { + // If it contains a dot, treat it as a file and move up one level + return $this->getLastFolderName(dirname($path)); + } + + // Return the last folder name (if it's valid and not a file) + return $lastPart; } } diff --git a/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/code.power b/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/code.power index d800e2c..3e2977a 100644 --- a/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/code.power +++ b/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/code.power @@ -67,10 +67,6 @@ if (($fileType = $this->details($guid)) !== null && $this->validTarget($fileType, $target)) { - // some safety checks - $path = isset($fileType->path) && is_string($fileType->path) && trim($fileType->path) !== '' ? trim($fileType->path) : null; - $path = ($path !== null && is_dir($path) && is_writable($path)) ? $path : null; - return [ 'name' => $fileType->name ?? 'files', 'access' => $fileType->access ?? 1, @@ -79,7 +75,7 @@ 'type' => $this->getFieldName($fileType), 'formats' => $this->getAllowFormats($fileType) ?? [], 'filter' => $fileType->filter ?? null, - 'path' => $path + 'path' => $this->getFileTypePath($fileType) ]; } @@ -207,4 +203,72 @@ } return null; + } + + /** + * Retrieves the file type path based on provided data. + * + * Performs safety checks and returns either a cleaned path if it exists + * and is a writable directory, or constructs a relative path to the 'images' folder + * based on the last folder name from the given path. + * + * @param object $data The type data object containing path information. + * + * @return string|null Returns the cleaned file path or null if no valid path is found. + * @since 5.0.2 + */ + protected function getFileTypePath(object $data): ?string + { + // Validate the provided path data + $path = isset($data->path) && is_string($data->path) && trim($data->path) !== '' ? + Path::clean(trim($data->path)) : null; + + // Return the path if it's a valid directory and writable + if ($path !== null && is_dir($path) && is_writable($path)) + { + return $path; + } + + // If no valid path is found, try to derive a relative path from the 'images' folder + if ($path !== null && ($folder = $this->getLastFolderName($path)) !== null) + { + return JPATH_SITE . '/images/' . $folder; + } + + return null; + } + + /** + * Recursively retrieves the last folder name from a given path, ignoring any file names. + * If the last part of the path contains a dot (indicating a file), it moves up the directory tree + * until it finds a valid folder name. Returns null if no valid folder is found. + * + * @param string $path The file system path from which to extract the last folder name. + * + * @return string|null Returns the last folder name if found, or null if no valid folder exists. + * @since 5.0.2 + */ + protected function getLastFolderName(string $path): ?string + { + // Remove any trailing slashes to avoid an empty result + $path = rtrim($path, '/\\'); + + // If the path becomes empty, return null (base case) + if (empty($path)) + { + return null; + } + + // Get the last part of the path + $lastPart = basename($path); + + // If the last part contains a dot (and it's not a hidden folder), move up the directory tree + if (strpos($lastPart, '.') > 0) + { + // If it contains a dot, treat it as a file and move up one level + return $this->getLastFolderName(dirname($path)); + } + + // Return the last folder name (if it's valid and not a file) + return $lastPart; } \ No newline at end of file diff --git a/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/settings.json b/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/settings.json index b5ac909..21a95e9 100644 --- a/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/settings.json +++ b/src/12a2a8de-a893-4dbb-a53d-b52de4f6cb0e/settings.json @@ -1,5 +1,5 @@ { - "add_head": "0", + "add_head": "1", "add_licensing_template": "2", "extends": "", "guid": "12a2a8de-a893-4dbb-a53d-b52de4f6cb0e", @@ -19,6 +19,6 @@ "namespace": "[[[NamespacePrefix]]]\\Joomla\\[[[ComponentNamespace]]].File.Type", "description": "File Type Class\r\n\r\n@since 5.0.2", "licensing_template": "\/**\r\n * @package Joomla.Component.Builder\r\n *\r\n * @created 3rd September, 2020\r\n * @author Llewellyn van der Merwe \r\n * @git Joomla Component Builder \r\n * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.\r\n * @license GNU General Public License version 2 or later; see LICENSE.txt\r\n *\/\r\n", - "head": "", + "head": "use Joomla\\Filesystem\\Path;", "composer": "" } \ No newline at end of file diff --git a/src/d7600b43-771a-4747-9f5d-952765721799/code.php b/src/d7600b43-771a-4747-9f5d-952765721799/code.php index a209783..eff041d 100644 --- a/src/d7600b43-771a-4747-9f5d-952765721799/code.php +++ b/src/d7600b43-771a-4747-9f5d-952765721799/code.php @@ -18,6 +18,8 @@ use Joomla\Filesystem\File; use Joomla\Filesystem\Folder; use Joomla\Filesystem\Path; use VDM\Joomla\Utilities\Component\Helper; +use VDM\Joomla\Utilities\MimeHelper; +use VDM\Joomla\Utilities\StringHelper; /** diff --git a/src/d7600b43-771a-4747-9f5d-952765721799/settings.json b/src/d7600b43-771a-4747-9f5d-952765721799/settings.json index 7eee705..50d65e9 100644 --- a/src/d7600b43-771a-4747-9f5d-952765721799/settings.json +++ b/src/d7600b43-771a-4747-9f5d-952765721799/settings.json @@ -4,14 +4,7 @@ "extends": "", "guid": "d7600b43-771a-4747-9f5d-952765721799", "implements": null, - "load_selection": { - "load_selection0": { - "load": "f11dc790-713e-4706-9a85-a318ed3ad56e" - }, - "load_selection1": { - "load": "1f28cb53-60d9-4db1-b517-3c7dc6b429ef" - } - }, + "load_selection": null, "name": "UploadHelper", "power_version": "1.0.0", "system_name": "Utilities UploadHelper", @@ -20,6 +13,14 @@ "use_selection0": { "use": "640b5352-fb09-425f-a26e-cd44eda03f15", "as": "default" + }, + "use_selection1": { + "use": "f11dc790-713e-4706-9a85-a318ed3ad56e", + "as": "default" + }, + "use_selection2": { + "use": "1f28cb53-60d9-4db1-b517-3c7dc6b429ef", + "as": "default" } }, "extendsinterfaces": null,