getClientOriginalName(); $folderName = strtolower(class_basename($model)); $filePath = $file->storeAs("documents/{$folderName}", $fileName, Document::STORAGE_DISK); return $model->documents()->create([ 'name' => $file->getClientOriginalName(), 'path' => $filePath, 'file_size' => $file->getSize(), 'mime_type' => $file->getClientMimeType(), 'type' => $documentType, 'description' => $description, 'uploaded_by' => auth()->id(), ]); } /** * Store generated file contents (e.g. PDF) for a model. */ public function storeGeneratedDocument(Model $model, string $contents, string $fileName, string $documentType = 'general', string $mimeType = 'application/pdf', ?string $description = null,): Document { $folderName = strtolower(class_basename($model)); $storedFileName = time().'_'.$fileName; $filePath = "documents/{$folderName}/{$storedFileName}"; Storage::disk(Document::STORAGE_DISK)->put($filePath, $contents); return $model->documents()->create([ 'name' => $fileName, 'path' => $filePath, 'file_size' => strlen($contents), 'mime_type' => $mimeType, 'type' => $documentType, 'description' => $description, 'uploaded_by' => auth()->id(), ]); } /** * Delete a document. */ public function deleteDocument(string $documentId): bool { $document = Document::findOrFail($documentId); return $document->delete(); } /** * Get all documents for a model. */ public function getDocuments(Model $model, ?string $documentType = null) { $query = $model->documents(); if ($documentType) { $query->where('type', $documentType); } return $query->with('uploadedBy')->get(); } /** * Get document by ID with validation. */ public function getDocument(string $documentId): Document { return Document::with('uploadedBy')->findOrFail($documentId); } /** * Download a document. */ public function downloadDocument(string $documentId) { $document = $this->getDocument($documentId); $disk = Storage::disk(Document::STORAGE_DISK); if (! $disk->exists($document->path)) { throw new Exception('File not found'); } return $disk->download($document->path, $document->name); } /** * Get documents count for a model. */ public function getDocumentsCount(Model $model, ?string $documentType = null): int { $query = $model->documents(); if ($documentType) { $query->where('type', $documentType); } return $query->count(); } /** * Check if model has documents. */ public function hasDocuments(Model $model, ?string $documentType = null): bool { return $this->getDocumentsCount($model, $documentType) > 0; } /** * Get supported file types. */ public function getSupportedFileTypes(): array { return [ 'pdf' => 'application/pdf', 'doc' => 'application/msword', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif', ]; } /** * Get max file size in KB. */ public function getMaxFileSize(): int { return 10240; // 10MB } /** * Validate file upload. */ public function validateFile(UploadedFile $file): bool { $supportedTypes = $this->getSupportedFileTypes(); $maxSize = $this->getMaxFileSize() * 1024; // Convert to bytes if ($file->getSize() > $maxSize) { throw new Exception('File size exceeds maximum limit of '.$this->getMaxFileSize().'KB'); } if (! in_array($file->getClientMimeType(), $supportedTypes)) { throw new Exception('File type not supported. Supported types: '.implode(', ', array_keys($supportedTypes))); } return true; } /** * Bulk delete documents for a model. */ public function bulkDeleteDocuments(Model $model, array $documentIds): int { $deletedCount = 0; foreach ($documentIds as $documentId) { $document = $model->documents()->find($documentId); if ($document) { $document->delete(); $deletedCount++; } } return $deletedCount; } }