Files
portal-api/app/Http/Controllers/Api/Admin/Media/MediaController.php
T
2026-07-25 15:18:48 +07:00

132 lines
4.3 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Controllers\Api\Admin\Media;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class MediaController extends Controller
{
private const IMAGE_MIME_TYPES = [
'image/jpeg',
'image/png',
'image/webp',
'image/gif',
'image/svg+xml',
];
public function index(Request $request): JsonResponse
{
$validated = $request->validate([
'keyword' => ['sometimes', 'nullable', 'string', 'max:255'],
'type' => ['sometimes', 'nullable', 'in:all,image,file'],
'page' => ['sometimes', 'integer', 'min:1'],
'per_page' => ['sometimes', 'integer', 'min:1', 'max:100'],
]);
$keyword = Str::lower((string) ($validated['keyword'] ?? ''));
$type = $validated['type'] ?? 'all';
$page = (int) ($validated['page'] ?? 1);
$perPage = (int) ($validated['per_page'] ?? 24);
$files = collect(Storage::disk('local')->allFiles())
->filter(fn (string $path) => ! Str::startsWith(basename($path), '.'))
->map(fn (string $path) => $this->formatFile($path))
->filter(function (array $file) use ($keyword, $type) {
if ($type === 'image' && ! $file['is_image']) {
return false;
}
if ($type === 'file' && $file['is_image']) {
return false;
}
if ($keyword === '') {
return true;
}
return Str::contains(Str::lower($file['name']), $keyword)
|| Str::contains(Str::lower($file['path']), $keyword)
|| Str::contains(Str::lower((string) $file['mime_type']), $keyword);
})
->sortByDesc('last_modified')
->values();
$total = $files->count();
$items = $files->slice(($page - 1) * $perPage, $perPage)->values();
return response()->json([
'error' => false,
'data' => [
'items' => $items,
'current_page' => $page,
'per_page' => $perPage,
'total' => $total,
'last_page' => (int) ceil($total / $perPage),
],
]);
}
public function destroy(string $id): JsonResponse
{
$path = $this->resolvePathById($id);
if ($path === null) {
return response()->json(['error' => true, 'message' => 'File không tồn tại.'], 404);
}
Storage::disk('local')->delete($path);
return response()->json(['error' => false, 'message' => 'Xoá file thành công.']);
}
public function bulkDestroy(Request $request): JsonResponse
{
$ids = $request->validate(['ids' => ['required', 'array'], 'ids.*' => ['string']])['ids'];
$paths = collect($ids)
->map(fn (string $id) => $this->resolvePathById($id))
->filter()
->values();
Storage::disk('local')->delete($paths->all());
return response()->json([
'error' => false,
'message' => "Đã xoá {$paths->count()} file.",
]);
}
private function resolvePathById(string $id): ?string
{
return collect(Storage::disk('local')->allFiles())
->first(fn (string $path) => sha1($path) === $id);
}
private function formatFile(string $path): array
{
$disk = Storage::disk('local');
$mimeType = $disk->mimeType($path) ?: 'application/octet-stream';
$isPublic = Str::startsWith($path, 'public/');
$publicPath = $isPublic ? Str::after($path, 'public/') : null;
return [
'id' => sha1($path),
'disk' => $isPublic ? 'public' : 'local',
'name' => basename($path),
'path' => $path,
'directory' => trim(dirname($path), '.'),
'mime_type' => $mimeType,
'is_image' => in_array($mimeType, self::IMAGE_MIME_TYPES, true),
'size' => $disk->size($path),
'last_modified' => date(DATE_ATOM, $disk->lastModified($path)),
'url' => $publicPath ? Storage::disk('public')->url($publicPath) : null,
];
}
}