getClientOriginalName(); // Store file in a folder named after the model $folderName = strtolower(class_basename($model)); $filePath = $file->storeAs("documents/{$folderName}", $fileName, 'public'); // Create document record return Document::create([ 'documentable_type' => get_class($model), 'documentable_id' => $model->id, 'document_name' => $file->getClientOriginalName(), 'document_path' => $filePath, 'file_size' => $file->getSize(), 'mime_type' => $file->getClientMimeType(), 'document_type' => $documentType, 'description' => $description, 'uploaded_by' => auth()->id(), ]); } /** * Delete a document. */ public function deleteDocument(int $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('document_type', $documentType); } return $query->with('uploadedBy')->get(); } /** * Get document by ID with validation. */ public function getDocument(int $documentId): Document { return Document::with('uploadedBy')->findOrFail($documentId); } /** * Download a document. */ public function downloadDocument(int $documentId) { $document = $this->getDocument($documentId); if (! Storage::exists($document->document_path)) { throw new Exception('File not found'); } return Storage::download($document->document_path, $document->document_name); } /** * Get documents count for a model. */ public function getDocumentsCount(Model $model, ?string $documentType = null): int { $query = $model->documents(); if ($documentType) { $query->where('document_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 // Check file size if ($file->getSize() > $maxSize) { throw new Exception('File size exceeds maximum limit of '.$this->getMaxFileSize().'KB'); } // Check mime type 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; } }