126 lines
4.5 KiB
PHP
126 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Requests;
|
|
|
|
|
|
use App\Http\Requests\ParentId;
|
|
use App\Models\File;
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
class UploadFiles extends ParentId
|
|
{
|
|
// authorization handled by ParentId
|
|
// validation
|
|
|
|
protected function prepareForValidation() {
|
|
$paths = array_filter($this->paths ?? [],
|
|
fn($f) => $f != null
|
|
);
|
|
|
|
$this->merge([
|
|
'file_paths' => $paths,
|
|
'folder_name' => $this->getFolder($paths)
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Get the validation rules that apply to the request.
|
|
*
|
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
|
*/
|
|
public function rules(): array
|
|
{
|
|
return array_merge(parent::rules(),
|
|
[
|
|
'files.*' => [
|
|
'required',
|
|
'file',
|
|
function ($attribute, $value, $fail) {
|
|
// if this is not a folder, apply file validation to file
|
|
if (!$this->folder_name) {
|
|
// find if a file with the same parameters already exists
|
|
$file = File::query()
|
|
->where('name', $value->getClientOriginalName())
|
|
->where('created_by', Auth::id())
|
|
->where('parent_id', $this->parent_id)
|
|
->whereNull('deleted_at');
|
|
|
|
if ($file->exists()) {
|
|
$fail('File already exists.');
|
|
}
|
|
}
|
|
|
|
}
|
|
],
|
|
'folder_name' => [
|
|
'nullable',
|
|
'string',
|
|
function ($attribute, $value, $fail) {
|
|
// if the folder name was passed in, that is if the path was not empty
|
|
if ($value) {
|
|
// find if a folder with the same parameters already exists
|
|
$folder = File::query()
|
|
->where('name', $value)
|
|
->where('created_by', Auth::id())
|
|
->where('parent_id', $this->parent_id)
|
|
->whereNull('deleted_at');
|
|
|
|
if ($folder->exists()) {
|
|
$fail('Folder already exists.');
|
|
}
|
|
}
|
|
}
|
|
]
|
|
]);
|
|
}
|
|
|
|
protected function passedValidation() {
|
|
// get validated data
|
|
$data = $this->validated();
|
|
|
|
// replace object with file tree (function below)
|
|
$this->replace([
|
|
'file_tree' => $this->makeTree($this->file_paths, $data['files'])
|
|
]);
|
|
}
|
|
|
|
// returns folder path for uploaded file
|
|
public function getFolder($paths) {
|
|
if (!$paths) return null;
|
|
$url = explode("/", $paths[0]);
|
|
return $url[0];
|
|
}
|
|
|
|
// makes file tree from paths and files
|
|
private function makeTree($paths, $files) {
|
|
// match $paths array count to $files array count in case there is a difference between the two
|
|
$paths = array_slice($paths, 0, count($files));
|
|
// filter away empty values
|
|
$paths = array_filter($paths, fn($path) => $path != null);
|
|
// build the tree
|
|
$fileTree = [];
|
|
|
|
foreach ($paths as $index => $path) {
|
|
// get full path as array of url components separated by slashes
|
|
$url = explode("/", $path);
|
|
$node = &$fileTree; // get node on file tree - passed by reference for modification
|
|
|
|
foreach ($url as $urlIndex => $urlComponent) {
|
|
// if there is no node value at the current $urlIndex, make empty array for value
|
|
// example: /test/file.png
|
|
// $node[$urlComponent] at test becomes empty array holding the files inside
|
|
if(!isset($node[$urlComponent])) {
|
|
$node[$urlComponent] = [];
|
|
}
|
|
|
|
// if at the last index in $url, the current index is the uploaded file itself
|
|
// file can be found at the files array at the same index as $index since $paths has been filtered
|
|
// otherwise, set $node to current node and continue loop
|
|
$urlIndex == (count($url) - 1) ? $node[$urlComponent] = $files[$index] : $node = &$node[$urlComponent];
|
|
}
|
|
}
|
|
|
|
// return completed $fileTree after loop complete and nodes are made for every file
|
|
return $fileTree;
|
|
}
|
|
}
|