在Laravel開(kāi)發(fā)中,我們經(jīng)常需要獲取文件系統(tǒng)中的所有目錄。例如,Storage::disk('local')-youjiankuohaophpcnallDirectories() 方法會(huì)返回一個(gè)包含所有子目錄路徑的扁平化數(shù)組,其格式通常如下所示:
[ "test", "files", "files/2", "files/2/Blocks", "files/2/Blocks/thumbs", "files/shares" ]
然而,在許多應(yīng)用場(chǎng)景中,我們可能需要將這些扁平路徑轉(zhuǎn)換為更直觀、層級(jí)分明的多維樹(shù)形結(jié)構(gòu),以便于在前端界面(如文件管理器、導(dǎo)航菜單)中展示。我們期望的輸出結(jié)構(gòu)類似:
[ ["label" => "test", "path" => "test", "children" => []], ["label" => "files", "path" => "files", "children" => [ ["label" => "2", "path" => "files/2", "children" => [ ["label" => "Blocks", "path" => "files/2/Blocks", "children" => [ ["label" => "thumbs", "path" => "files/2/Blocks/thumbs", "children" => []] ] ] ] ], ["label" => "shares", "path" => "files/shares", "children" => []] ] ], ]
這種轉(zhuǎn)換的核心挑戰(zhàn)在于如何識(shí)別路徑中的層級(jí)關(guān)系,并將其遞歸地組織起來(lái)。
解決此問(wèn)題的關(guān)鍵在于利用遞歸函數(shù)處理層級(jí)數(shù)據(jù),并結(jié)合Laravel Collection的強(qiáng)大數(shù)據(jù)處理能力來(lái)簡(jiǎn)化分組和映射操作。
我們將創(chuàng)建一個(gè)名為 convertPathsToTree 的遞歸函數(shù)。該函數(shù)的核心思想是:
以下是實(shí)現(xiàn)此功能的PHP代碼:
<?php use Illuminate\Support\Collection; /** * 將扁平化的路徑列表轉(zhuǎn)換為多維樹(shù)形結(jié)構(gòu)。 * * @param Collection $paths 預(yù)處理后的路徑集合,每個(gè)路徑是一個(gè)由目錄片段組成的數(shù)組。 * @param string $separator 路徑分隔符,默認(rèn)為 '/'。 * @param string $parent 當(dāng)前節(jié)點(diǎn)的父路徑前綴。 * @return Collection 包含樹(shù)形結(jié)構(gòu)節(jié)點(diǎn)的集合。 */ function convertPathsToTree(Collection $paths, string $separator = '/', string $parent = ''): Collection { return $paths ->groupBy(function (array $parts) { // 根據(jù)路徑的第一個(gè)片段進(jìn)行分組,這代表了當(dāng)前層級(jí)的直接子節(jié)點(diǎn) return $parts[0]; }) ->map(function (Collection $partsCollection, string $key) use ($separator, $parent) { // 提取當(dāng)前分組的子路徑,即移除第一個(gè)片段后的剩余部分 $childrenPaths = $partsCollection->map(function (array $parts) { return array_slice($parts, 1); // 移除第一個(gè)片段 })->filter(); // 過(guò)濾掉空數(shù)組(即只剩下父節(jié)點(diǎn)自身的情況) // 構(gòu)建當(dāng)前節(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu) return [ 'label' => (string) $key, // 當(dāng)前目錄的名稱 'path' => $parent . $key, // 完整路徑 'children' => convertPathsToTree( // 遞歸調(diào)用,構(gòu)建子節(jié)點(diǎn) $childrenPaths, $separator, $parent . $key . $separator // 更新父路徑前綴 ), ]; }) ->values(); // 重置集合的鍵,使其成為一個(gè)從0開(kāi)始的索引數(shù)組 }
在調(diào)用 convertPathsToTree 函數(shù)之前,我們需要對(duì)原始的扁平化路徑數(shù)據(jù)進(jìn)行預(yù)處理。原始數(shù)據(jù)是字符串?dāng)?shù)組,而我們的遞歸函數(shù)期望每個(gè)路徑都是一個(gè)由目錄片段組成的數(shù)組。
假設(shè)我們有以下原始路徑數(shù)據(jù):
use Illuminate\Support\Collection; $data = collect([ 'test', 'files', 'files/2', 'files/2/Blocks', 'files/2/Blocks/thumbs', 'files/shares', ]);
我們需要使用 explode() 函數(shù)將每個(gè)字符串路徑拆分成數(shù)組片段:
$processedData = $data->map(function (string $item) { return explode('/', $item); }); /* $processedData 現(xiàn)在看起來(lái)像這樣: [ ['test'], ['files'], ['files', '2'], ['files', '2', 'Blocks'], ['files', '2', 'Blocks', 'thumbs'], ['files', 'shares'], ] */
將上述步驟結(jié)合起來(lái),我們可以輕松地將扁平路徑轉(zhuǎn)換為樹(shù)形結(jié)構(gòu):
<?php require 'vendor/autoload.php'; // 確保Composer自動(dòng)加載 use Illuminate\Support\Collection; /** * 將扁平化的路徑列表轉(zhuǎn)換為多維樹(shù)形結(jié)構(gòu)。 * * @param Collection $paths 預(yù)處理后的路徑集合,每個(gè)路徑是一個(gè)由目錄片段組成的數(shù)組。 * @param string $separator 路徑分隔符,默認(rèn)為 '/'。 * @param string $parent 當(dāng)前節(jié)點(diǎn)的父路徑前綴。 * @return Collection 包含樹(shù)形結(jié)構(gòu)節(jié)點(diǎn)的集合。 */ function convertPathsToTree(Collection $paths, string $separator = '/', string $parent = ''): Collection { return $paths ->groupBy(function (array $parts) { return $parts[0]; }) ->map(function (Collection $partsCollection, string $key) use ($separator, $parent) { $childrenPaths = $partsCollection->map(function (array $parts) { return array_slice($parts, 1); })->filter(); return [ 'label' => (string) $key, 'path' => $parent . $key, 'children' => convertPathsToTree( $childrenPaths, $separator, $parent . $key . $separator ), ]; }) ->values(); } // 1. 原始路徑數(shù)據(jù)(通常來(lái)自 Storage::allDirectories()) $originalPaths = collect([ 'test', 'files', 'files/2', 'files/2/Blocks', 'files/2/Blocks/thumbs', 'files/shares', ]); // 2. 預(yù)處理數(shù)據(jù):將字符串路徑拆分為數(shù)組片段 $processedPaths = $originalPaths->map(function (string $item) { return explode('/', $item); }); // 3. 調(diào)用函數(shù)生成樹(shù)形結(jié)構(gòu) $tree = convertPathsToTree($processedPaths); // 輸出結(jié)果,使用 JSON_PRETTY_PRINT 使輸出更易讀,JSON_UNESCAPED_UNICODE 避免中文亂碼 echo json_encode($tree->toArray(), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); /* 預(yù)期輸出: [ { "label": "test", "path": "test", "children": [] }, { "label": "files", "path": "files", "children": [ { "label": "2", "path": "files/2", "children": [ { "label": "Blocks", "path": "files/2/Blocks", "children": [ { "label": "thumbs", "path": "files/2/Blocks/thumbs", "children": [] } ] } ] }, { "label": "shares", "path": "files/shares", "children": [] } ] } ] */
$treeArray = convertPathsToTree($processedPaths)->toArray();
通過(guò)結(jié)合Laravel Collection的強(qiáng)大數(shù)據(jù)處理能力和遞歸算法,我們成功地將扁平化的目錄路徑列表轉(zhuǎn)換為結(jié)構(gòu)清晰、易于管理和展示的多維樹(shù)形數(shù)組。這種方法不僅提高了代碼的可讀性和維護(hù)性,也為前端展示文件系統(tǒng)提供了極大的便利。掌握這一技巧,將使你在處理文件目錄數(shù)據(jù)時(shí)更加得心應(yīng)手。
以上就是Laravel:將扁平化目錄路徑轉(zhuǎn)換為多維樹(shù)形結(jié)構(gòu)教程的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!
每個(gè)人都需要一臺(tái)速度更快、更穩(wěn)定的 PC。隨著時(shí)間的推移,垃圾文件、舊注冊(cè)表數(shù)據(jù)和不必要的后臺(tái)進(jìn)程會(huì)占用資源并降低性能。幸運(yùn)的是,許多工具可以讓 Windows 保持平穩(wěn)運(yùn)行。
微信掃碼
關(guān)注PHP中文網(wǎng)服務(wù)號(hào)
QQ掃碼
加入技術(shù)交流群
Copyright 2014-2025 http://ipnx.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號(hào)