Хранение и раздача файлов через Ensi Storage

Файлы в платформе делятся на 2 вида: публичные и приватные. Все они хранятся на физическом диске Ensi Storage, который доступен в каждом сервисе в директории storage/ensi.


Структура этого диска:

  • public

    • domain_1

      • hash

        • filename.png

    • domain_2

  • protected

    • domain_1

    • domain_2

При использовании Ensi Local Ctl можно увидеть содержимое диска в ensi-local-ctl/data/es/data


Для скачивания файлов существует 3 способа:

  • Домен https://es-public.project.ru - раздаёт файлы директории public. Доступен всем в интернете. При необходимости эту ссылку можно передать в imgproxy и получить обработанную картинку

  • Домен https://es-protected.project.ru - раздаёт файлы директории protected. Доступен только внутри защищенной среды, например под vpn

  • Эдпоинт раздачи приватных файлов на витрины/админки (Подробнее ниже)

При использовании Ensi Local Ctl домены подниманиюся с помощью ensi global start es


Для работы с файлами в Laravel разработан пакет laravel-ensi-filesystem. После установки пакета появится 3 новых сконфигурированных диска:

  • Диски для работы с файлами текущего домена - с их помощью можно загружать файлы в Ensi Storage и генерировать ссылки для раздачи с доменов

    • ensi_{domain}_public - соответствует папке public/domain/

    • ensi_{domain}_protected - соответствует папке protected/domain/

  • Диск для чтения файлов чужих доменов

    • ensi - соответсвует корню диска

Как загружать файлы

Для загрузки файла создаётся отдельный эндпоинт, например /module/entity/{id}:upload-file

Принимает запрос в формате multipart/form-data и в Action реализует примерно следующий код:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 use Ensi\LaravelEnsiFilesystem\EnsiFilesystemManager; class SaveFileAction { public function __construct(protected EnsiFilesystemManager $fileManager) { } public function execute(int $modelId, UploadedFile $file): Model { /** @var Model $model */ $model = Model::findOrFail($customerId); $hash = Str::random(20); $extension = $file->getClientOriginalExtension(); $fileName = "{$modelId}_{$hash}.{$extension}"; $hashedSubDirs = $this->fileManager->getHashedDirsForFileName($fileName); $disk = Storage::disk($this->fileManager->publicDiskName()); $path = $disk->putFileAs("model/{$hashedSubDirs}", $file, $fileName); if (!$path) { throw new RuntimeException("Unable to save file $fileName to directory model/{$hashedSubDirs}"); } if ($model->file) { $disk->delete($model->file); } $model->file = $path; $model->save(); return $model; } }

Удаление файлов происходит по аналогии

Какие данные о файлах хранить в БД

В БД хранится только путь до файла

Какие данные о файле сервис отдаёт

Для отдачи данных используется класс \Ensi\LaravelEnsiFilesystem\Models\EnsiFile, который на основатии пути генерирует все необходимые для ответа данные. Например: EnsiFile::public($model->file). Также в BaseJsonResource существеют хелперы, например $this->mapPublicFileToResponse($this->file)

Как раздать приватный файл пользователю

Для раздачи файла требуется, чтобы пользователь прошел аутентификацию и можно было проверить доступ к запрашиваемому файлу.

Для этого в gui-backend реализуется эндпоинт, который получает данные о запрашиваевом файле, проверяет доступ пользователя, и отдаёт файл, если проверка пройдена

Данные о файле также генерирует предварительно gui-backend. Состоят они из следующих полей:

  • entity - сущность, файл которой мы пытаемся скачать, например pim/category

  • entity_id - конкретная сущность, файл которой мы пытаемся скачать, например ID категории

  • file_type - если у сущности несколько видов файлов, то тут указывается типа (по сути это обозначение поля в БД), например preview

  • file - если файлов одного типа много, то можно указать path|id на конкретный файл

Пример реализации можно посмотреть тут