isValid()) { continue; } $path = $this->storeAttachment($file); $stored[] = [ 'report_id' => $reportId, 'file_path' => $path, 'original_name' => $file->getClientOriginalName(), 'mime_type' => $file->getClientMimeType(), 'file_size' => $file->getSize(), 'created_at' => now(), ]; } if ($stored !== []) { ClassProgressAttachment::query()->insert($stored); } return $stored; } public function resolvePath(string $path): ?string { $path = trim($path); if ($path === '') { return null; } $candidates = []; if (str_starts_with($path, 'storage/')) { $relative = ltrim(substr($path, strlen('storage/')), '/'); $candidates[] = storage_path('app/public/' . $relative); } if (str_starts_with($path, 'writable/uploads/')) { $relative = ltrim(substr($path, strlen('writable/uploads/')), '/'); $candidates[] = storage_path('app/' . $relative); $candidates[] = storage_path('app/public/' . $relative); } $candidates[] = storage_path('app/' . ltrim($path, '/')); $candidates[] = storage_path('app/public/' . ltrim($path, '/')); foreach ($candidates as $candidate) { if (is_file($candidate)) { return $candidate; } } return null; } private function storeAttachment(UploadedFile $file): string { $disk = (string) config('progress.attachments.disk', 'public'); $directory = (string) config('progress.attachments.directory', 'class_material'); try { $path = $file->store($directory, $disk); } catch (\Throwable $e) { Log::error('Failed to store class progress attachment.', [ 'error' => $e->getMessage(), ]); throw $e; } return 'storage/' . ltrim($path, '/'); } }