$files */ public function storeMany(Ticket $ticket, array $files, int $userId, ?Comment $comment = null): void { foreach ($files as $file) { if (! $this->isSupportedUpload($file)) { continue; } $disk = (string) config('helpdesk.disk', 'public'); $originalName = $this->originalName($file); $mimeType = $this->mimeType($file); $size = $this->size($file); $path = $file->store('tickets/' . $ticket->id, $disk); if (! is_string($path) || $path === '') { continue; } if ($size === 0) { $size = (int) Storage::disk($disk)->size($path); } Attachment::query()->create([ 'ticket_id' => $ticket->id, 'comment_id' => $comment?->id, 'user_id' => $userId, 'disk' => $disk, 'path' => $path, 'original_name' => $originalName, 'mime_type' => $mimeType, 'size' => $size, ]); } } /** * Delete a stored attachment and its backing file. */ public function delete(Attachment $attachment): void { Storage::disk($attachment->disk)->delete($attachment->path); $attachment->delete(); } /** * Determine whether the value is a storeable uploaded file. */ private function isSupportedUpload(mixed $file): bool { if ($file instanceof TemporaryUploadedFile) { return true; } return $file instanceof UploadedFile && $file->isValid(); } /** * Return the uploaded file's original client filename. */ private function originalName(mixed $file): string { return (string) $file->getClientOriginalName(); } /** * Return the uploaded file's reported mime type. */ private function mimeType(mixed $file): string { return (string) ($file->getClientMimeType() ?: $file->getMimeType() ?: 'application/octet-stream'); } /** * Return the uploaded file's byte size. */ private function size(mixed $file): int { return (int) ($file->getSize() ?: 0); } }