2025-12-01 17:02:01 +03:00

233 lines
6.9 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Repositories;
use App\Models\File;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;
class FileRepository extends BaseRepository implements FileRepositoryInterface
{
public function __construct(File $model)
{
parent::__construct($model);
}
/**
* Get paginated files with filtering
*/
public function paginate(int $perPage = 15, array $filters = []): LengthAwarePaginator
{
$query = $this->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];
}
}