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> */ 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; } }