Медиа-библиотека
Обзор
Медиа-библиотека позволяет просматривать все загруженные файлы в одном месте — с поиском, папками и фильтрацией по типу.

BrowsableDriver. Поля File и Image автоматически определяют это и отдают флаг browsable: true на фронтенд.Контракт BrowsableDriver
Расширяет MediaDriver четырьмя методами для работы с библиотекой:
namespace Frame\Core\Contracts;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
interface BrowsableDriver extends MediaDriver
{
public function browse(
?string $search = null,
?string $folder = null,
?string $type = null,
int $perPage = 24,
): LengthAwarePaginator;
public function folders(?string $parent = null): Collection;
public function createFolder(string $name, ?string $parent = null): array;
public function moveToFolder(int|string $id, ?string $folder = null): void;
}
$parent — возвращает дочерние папки. Если null — корневые. Структура папки: id, name, parent.$folder = null — перемещение в корень.API-эндпоинты
Все эндпоинты доступны только для авторизованных пользователей. Если драйвер не реализует BrowsableDriver, возвращается 501 Not Implemented.
Просмотр медиа
GET /api/frame/media
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
search | string | null | Поисковый запрос |
folder | string | null | ID папки для фильтрации |
per_page | int | 24 | Количество на странице |
type | string | null | Тип файлов: image, file |
Список папок
GET /api/frame/media/folders
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
parent | string | null | ID родительской папки |
Создание папки
POST /api/frame/media/folders
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
name | string | Да | Название папки (макс. 255 символов) |
parent | string | Нет | ID родительской папки |
Перемещение медиа
PATCH /api/frame/media/{media}/move
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
folder | string | Нет | ID папки назначения (null = корень) |
Реализация
Пример: драйвер на Spatie Media Library
namespace App\Drivers;
use Frame\Core\Contracts\BrowsableDriver;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Collection;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
class SpatieMediaDriver implements BrowsableDriver
{
public function browse(
?string $search = null,
?string $folder = null,
?string $type = null,
int $perPage = 24,
): LengthAwarePaginator {
return Media::query()
->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%"))
->when($folder, fn ($q) => $q->where('collection_name', $folder))
->latest()
->paginate($perPage);
}
public function folders(?string $parent = null): Collection
{
// Коллекции Spatie как папки
return Media::query()
->select('collection_name')
->distinct()
->pluck('collection_name')
->map(fn (string $name) => [
'id' => $name,
'name' => $name,
'parent' => null,
]);
}
public function createFolder(string $name, ?string $parent = null): array
{
// Коллекции в Spatie создаются при загрузке,
// но можно хранить список в конфиге или таблице
return ['id' => $name, 'name' => $name, 'parent' => $parent];
}
public function moveToFolder(int|string $id, ?string $folder = null): void
{
Media::findOrFail($id)->update([
'collection_name' => $folder ?? 'default',
]);
}
// ... остальные методы MediaDriver
}
Пример: драйвер с файловой системой и БД
namespace App\Drivers;
use App\Models\MediaFile;
use App\Models\MediaFolder;
use Frame\Core\Contracts\BrowsableDriver;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
class DatabaseMediaDriver implements BrowsableDriver
{
public function browse(
?string $search = null,
?string $folder = null,
?string $type = null,
int $perPage = 24,
): LengthAwarePaginator {
return MediaFile::query()
->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%"))
->when($folder, fn ($q) => $q->where('folder_id', $folder))
->latest()
->paginate($perPage);
}
public function folders(?string $parent = null): Collection
{
return MediaFolder::query()
->where('parent_id', $parent)
->get()
->map(fn (MediaFolder $f) => [
'id' => $f->id,
'name' => $f->name,
'parent' => $f->parent_id,
]);
}
public function createFolder(string $name, ?string $parent = null): array
{
$folder = MediaFolder::create([
'name' => $name,
'parent_id' => $parent,
]);
return ['id' => $folder->id, 'name' => $folder->name, 'parent' => $folder->parent_id];
}
public function moveToFolder(int|string $id, ?string $folder = null): void
{
MediaFile::findOrFail($id)->update(['folder_id' => $folder]);
}
// ... остальные методы MediaDriver
}
Фильтрация по типу
Поля Image и File передают свой тип при запросе к медиа-библиотеке. Это позволяет драйверу фильтровать результаты:
- Поле
Imageзапрашивает только изображения - Поле
Fileпоказывает все типы файлов
Реализация фильтрации — на стороне драйвера в методе browse().
Интеграция с полями
Поля File и Image автоматически определяют, поддерживает ли текущий драйвер медиа-библиотеку, и отдают на фронтенд флаг browsable:
{
"type": "image",
"field": "avatar",
"browsable": true,
"max": 1,
"multiple": false
}
Если browsable: true, UI показывает кнопку "Выбрать из библиотеки", которая открывает модальное окно с содержимым медиа-библиотеки.