model->newQuery(); // Apply filters if (!empty($filters['search'])) { $query->where('file_name', 'like', '%' . $filters['search'] . '%'); } if (!empty($filters['mime_type'])) { $query->where('mime_type', 'like', '%' . $filters['mime_type'] . '%'); } if (!empty($filters['uploaded_by'])) { $query->where('uploaded_by', $filters['uploaded_by']); } if (!empty($filters['category'])) { // Extract category from storage_uri path $query->where('storage_uri', 'like', '%/' . $filters['category'] . '/%'); } if (!empty($filters['client_id'])) { // Extract client files from storage path $query->where('storage_uri', 'like', '%/client/' . $filters['client_id'] . '/%'); } // Date range filter if (!empty($filters['date_from'])) { $query->whereDate('uploaded_at', '>=', $filters['date_from']); } if (!empty($filters['date_to'])) { $query->whereDate('uploaded_at', '<=', $filters['date_to']); } // Apply sorting $sortField = $filters['sort_by'] ?? 'uploaded_at'; $sortDirection = $filters['sort_direction'] ?? 'desc'; $query->orderBy($sortField, $sortDirection); return $query->paginate($perPage); } /** * Get files by category/type (e.g., devis, facture) */ public function getByCategory(string $category, int $perPage = 15): LengthAwarePaginator { return $this->model->newQuery() ->where('storage_uri', 'like', '%/' . $category . '/%') ->orderBy('uploaded_at', 'desc') ->paginate($perPage); } /** * Get files by client ID */ public function getByClient(int $clientId, int $perPage = 15): LengthAwarePaginator { return $this->model->newQuery() ->where('storage_uri', 'like', '%/client/' . $clientId . '/%') ->orderBy('uploaded_at', 'desc') ->paginate($perPage); } /** * Get files by user/uploader */ public function getByUploader(int $uploaderId, int $perPage = 15): LengthAwarePaginator { return $this->model->newQuery() ->where('uploaded_by', $uploaderId) ->orderBy('uploaded_at', 'desc') ->paginate($perPage); } /** * Search files by filename */ public function search(string $searchTerm, int $perPage = 15): LengthAwarePaginator { return $this->model->newQuery() ->where('file_name', 'like', '%' . $searchTerm . '%') ->orWhere('storage_uri', 'like', '%' . $searchTerm . '%') ->orderBy('uploaded_at', 'desc') ->paginate($perPage); } /** * Get recent files */ public function getRecent(int $limit = 10): Collection { return $this->model->newQuery() ->orderBy('uploaded_at', 'desc') ->limit($limit) ->get(); } /** * Get files by storage path pattern */ public function getByPathPattern(string $pattern, int $perPage = 15): LengthAwarePaginator { return $this->model->newQuery() ->where('storage_uri', 'like', '%' . $pattern . '%') ->orderBy('uploaded_at', 'desc') ->paginate($perPage); } /** * Get files organized by path structure */ public function getOrganizedFiles(): Collection { $files = $this->model->newQuery() ->orderBy('storage_uri') ->get(); // Group files by their organized path structure $organized = collect(); foreach ($files as $file) { $pathParts = explode('/', $file->storage_uri); // Skip if not enough path parts if (count($pathParts) < 3) { continue; } // Extract structure like: category/subcategory/filename $category = $pathParts[count($pathParts) - 3] ?? 'root'; $subcategory = $pathParts[count($pathParts) - 2] ?? 'general'; $key = $category . '/' . $subcategory; if (!$organized->has($key)) { $organized->put($key, collect([ 'category' => $category, 'subcategory' => $subcategory, 'files' => collect(), 'count' => 0 ])); } $group = $organized->get($key); $group['files']->push($file); $group['count']++; } return $organized; } /** * Get storage usage statistics */ public function getStorageStats(): array { $totalFiles = $this->model->newQuery()->count(); $totalSize = $this->model->newQuery()->sum('size_bytes'); $byType = $this->model->newQuery() ->selectRaw('mime_type, COUNT(*) as count, SUM(size_bytes) as total_size') ->groupBy('mime_type') ->get(); $byCategory = $this->model->newQuery() ->selectRaw('storage_uri, COUNT(*) as count, SUM(size_bytes) as total_size') ->get() ->map(function ($item) { $pathParts = explode('/', $item->storage_uri); $category = $pathParts[count($pathParts) - 3] ?? 'root'; return [ 'category' => $category, 'count' => $item->count, 'total_size' => $item->total_size, ]; }) ->groupBy('category') ->map(function ($items) { return [ 'count' => $items->sum('count'), 'total_size' => $items->sum('total_size'), ]; }); return [ 'total_files' => $totalFiles, 'total_size_bytes' => $totalSize, 'total_size_formatted' => $this->formatBytes($totalSize), 'by_type' => $byType, 'by_category' => $byCategory, ]; } /** * Format bytes to human readable format */ private function formatBytes(int $bytes, int $precision = 2): string { if ($bytes === 0) { return '0 B'; } $units = ['B', 'KB', 'MB', 'GB', 'TB']; $base = 1024; $factor = floor((strlen($bytes) - 1) / 3); return sprintf("%.{$precision}f", $bytes / pow($base, $factor)) . ' ' . $units[$factor]; } }