Добрый день.
Продолжаю изучать Laravel, и у меня возникала необходимость реализовать контроллируемое скачивание файлов (возможно, это называется как-то по-другому).
Задача: файлы не должны быть доступны по прямой ссылке вида
http://domain.com/storage/public/sdfjkshfjkhsdf.doc
а должны скачивать по ссылке вида
http://domain.com/file/123
где 123 - это id файла в таблице файлов. Чтобы я мог проверить права доступа пользователя к данному файлу.
Что сделал я? Создал таблицу:
$table->increments('id');
$table->string('fileable_type', 255);
$table->integer('fileable_id');
$table->unsignedInteger('size'); // размер файла
$table->string('content_type', 50); // content-type
$table->string('path', 255); // путь к файлу
$table->string('original_name', 255); // оригинальное имя файла
$table->timestamps();
Т.к. файлы могут загружаться к разным сущностям, то использую полиморфные связи в моделях.
Модель File:
class File extends Model
{
protected $table = 'files';
public function fileable()
{
return $this->morphTo();
}
}
Например, модель Custom (это таможня, если что:) ):
class Custom extends Model
{
protected $table = 'customs';
public function files()
{
return $this->morphMany('App\File', 'fileable');
}
}
Теперь в контроллере CustomController сохраняю поля и файл приблизительно так:
public function update(UpdateCustomRequest $request, $id)
{
// Save files
if ($request->hasFile('contract')) {
$folder = 'private/'.str_random(4);
$contract = $request->file('contract');
$path = $contract->store($folder);
DB::table('files')->insert([
'fileable_type' => 'App\Custom',
'fileable_id' => $id,
'size' => $contract->getClientSize(),
'content_type' => $contract->getClientMimeType(),
'path' => $path,
'original_name' => $contract->getClientOriginalName(),
]);
}
}
Я понимаю, что работу с БД нужно вынести в модель. Но тогда в модель нужно будет передавать:
- и значение fileable_type (тип сущности, к которой загружается файл)
- и значение fileable_id (id сущности, к которой загружается файл)
- и сам файл $contract
Как-то много всего и не красиво. Мне такое решение не нравится.
Как можно реализовать это лучше? С точки зрения laravel, правильности и красоты кода.
Возможно, есть готовые решения для такой задачи и в них можно подглядеть реализацию?