Let's say I have a PHP array of arrays representing a folder structure that goes like this:
array:5 [▼
0 => array:2 [▼
"size" => "9.8 MiB"
"name" => "Game.exe"
]
1 => array:2 [▼
"size" => "3.9 MiB"
"name" => "Launcher.exe"
]
2 => array:2 [▼
"size" => "2 MiB"
"name" => "USRDIR/mask.mpk"
]
3 => array:2 [▼
"size" => "1 MiB"
"name" => "USRDIR/subs.hrt"
]
4 => array:2 [▼
"size" => "10 MiB"
"name" => "USRDIR/fullhd/footage.mkv"
]
And I want to display this information as a folder structure in HTML using an unordeded list of unordered lists, as such:
<ul class="root-folder">
<ul class="folder"><span>FOLDERNAME</span>
<ul class="folder"><span>FOLDERNAME</span>
<li class="file">FILENAME</li>
</ul>
<li class="file">FILENAME</li>
<li class="file">FILENAME</li>
<ul>
<li class="file">FILENAME</li>
<li class="file">FILENAME</li>
</ul>
The first 2 arrays have a 'name' value formed by a string with the following format: "filename.fileextension", meaning these are files in the root this folder. For these I can just throw a <li>
element displaying its values inside the master <ul>
. However, the third array has a 'name' value of "folder/filesize.fileextension", meaning that to represent this visually, I have to make a new <ul>
with new files inside as <li>
elements. There's also the fact that the array will name the same folders multiple times if said folders have more than 1 file in them. Then the last array has 2 folders before the file. What would my syntax look like, and am I doing this in a controller and passing an array to the view to display, or in the Blade template by just passing it the original array?
For now this is what I have but I'm kinda lost:
Controller:
$fileArray = [];
foreach ($files as $key => $file) {
array_push($fileArray, $file);
$fileArray[$key]['size'] = formatBits($file['size']);
$fileArray[$key]['name'] = explode('/', $file['name']);
}
return view('single', [
'fileArray' => $fileArray
]);
Blade template:
<ul>
@foreach ($fileArray as $file)
@if (count($file['name']) > 1)
@foreach ($file['name'] as $folder)
@if ($folder == end($file['name']))
<li>
<span class="file-icon">🗋</span>{{ $folder }}<span class="file-size">({{ $file['size'] }})
</li>
@else
<li>
<span class="file-icon">🗀</span>{{ $folder }}
</li>
@endif
@endforeach
@else
<li>
<span class="file-icon">🗋</span>{{ $file['name'][0] }}<span class="file-size">({{ $file['size'] }})
</li>
@endif
@endforeach
</ul>
This creates a <li>
element for every instance of a string that got separated from the original pathname string in the controller. You should be able to see how this is problematic, as it creates a new <li>
for every time a folder name is mentioned.
I have a short idea:
$files = Paths::all()->toArray();//lets say you do this to have the array you told us ready
$fileArray = [];
foreach ($files as $file) {
if(str_contains($file['name'], '/')){
$split = explode('/', $file['name']);
$name = last($split);
$path = array_chunk($split, sizeof($split)-1)[0];
}else{
$name = $file['name'];
$path = [];
}
$temp = [['name'=>$name, 'size' => formatBits($file['size'])]]; //single value in array too to ease future headaches
while( count($path) > 0 ){
$temp2 = [];
$temp2[ '/'.last( $path ) ] = $temp;
array_pop( $path );
$temp3 = $temp2;
$temp2 = $temp;
$temp = $temp3;
}
$fileArray = array_merge_recursive($fileArray,$temp);
}
return view('single', compact('fileArray'));
In your blade you need to check if the key is in folder syntax.
@php
function compareFiles(array $a, array $b){
if(isset($a['name']) && isset($a['name'])){
return strcmp($a['name'],$b['name']);
}else{
return 0;
}
}
function fileSys($fileArray) {
ksort($fileArray, SORT_STRING); //sorting 'folders' (by key)
uasort($fileArray, "compareFiles"); //sorting 'files' (by value)
foreach($fileArray as $key => $value){
if(str_contains(strval($key), '/')) {
echo "<li><span class=\"file-icon\">🗀</span>".substr($key, 1)."<ul>";
filesys($fileArray[$key]);
echo "</ul></li>";
}
else {
echo "<li><span class=\"file-icon\">🗋</span>".$value['name']."<span class=\"file-size\">(".$value['size'].")</li>";
}
}
}
@endphp
<ul>
{{ fileSys($fileArray) }}
</ul>