vd/app/Domains/File/Services/FileService.php
2018-12-27 17:47:12 +08:00

300 lines
8.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Domains\File\Services;
use Carbon\Carbon;
use App\Core\Service;
use Illuminate\Http\Request;
use App\Models\Account\Account;
use Illuminate\Http\UploadedFile;
use App\Exceptions\BeUsedException;
use Intervention\Image\Facades\Image;
use App\Models\File\File as FileModel;
use App\Exceptions\NotAllowedException;
use Illuminate\Support\Facades\Storage;
use App\Exceptions\UploadFailedException;
use App\Domains\File\Repositories\FileRepository;
use App\Models\File\FileWith as FileFileWithModel;
use App\Domains\File\Repositories\FileWithRepository;
class FileService extends Service
{
protected $user;
protected $fileRepository;
protected $fileWithRepository;
public static $types = ['account/avatar'];
public static $mimeTypes = [
'image' => ['image/jpeg', 'image/gif', 'image/bmp', 'image/png'],
'audio' => ['audio/amr', 'audio/aac', 'audio/ogg', 'audio/mpeg'],
'video' => ['video/mp4', 'video/mpeg', 'video/x-flv', 'video/3gpp', 'video/quicktime', 'video/mov','video/x-m4v']
];
public static $extensions = [
'image' => ['png', 'jpg', 'jpeg', 'gif', 'bmp'],
'audio' => ['amr', 'ogg', 'mpeg'],
'video' => ['mp4', 'mpeg', 'flv', '3gp', 'mov']
];
/**
* 构造函数
*
* @return void
*/
public function __construct(Request $request, FileRepository $fileRepository, FileWithRepository $fileWithRepository)
{
$this->user = $request->user();
$this->fileRepository = $fileRepository;
$this->fileWithRepository = $fileWithRepository;
}
/**
* 文件列表
*
* @param array $conditions
* @return mixed
*/
public function index(array $conditions = [])
{
$limit = $conditions['limit'] ?? 20;
return $this->fileRepository->with('file_withs')->applyConditions()->paginate($limit);
}
/**
* 删除
*
* @return bool
*/
public function destroy($ids)
{
$ids = is_array($ids) ? $ids : [$ids];
if ($this->fileWithRepository->whereIn('file_id', $ids)->count()) {
throw new BeUsedException('文件已被使用, 不能删除');
}
$this->fileRepository->destroy($ids);
return true;
}
/**
* 使用type, type_id查找文件
*
* @param string $type
* @param string|int $typeIds
* @return void
*/
public function fetchByType($type, $typeIds, $force = false)
{
if ($force) {
$this->fileWithRepository->forgetCached();
}
$files = $this->fileWithRepository->with('file')->withType($type, $typeIds)->get();
$files->map(function ($item) {
if ($file = $item->file) {
$file->url = cdn($item->disk, $item->filename, $item->created_at);
$file->cover = $item->thumb ? cdn($item->disk, $this->generateFilePath($item->filename), $item->created_at) : '';
$item->file = $file;
}
});
return $files;
}
/**
* 储存上传文件
*
* @param UploadedFile $file
*
* @throws UploadFailedException
* @return mixed
*/
public function upload(UploadedFile $file, $input = [], $disk = null)
{
$disk = $disk ?: config('filesystems.default');
if ($input['filename']) {
$fileModel = $this->store($file, $input, $disk, true);
} else {
$fileModel = $this->validateFileInDatabase($file, function (UploadedFile $file, string $md5) use ($input, $disk) {
$input['filename'] = $this->generateFilePath($md5);
return $this->store($file, $input, $disk);
});
if ($input['type'] && $input['typeid'] && in_array($input['type'], self::$types)) {
$this->apply($fileModel->id, $input['type'], $input['typeid'], $input['cover'] ?? false);
}
}
return $fileModel;
}
/**
* 添加文件关联
*
* @param array|int $ids
* @param string $type
* @param int|string $typeid
* @return void
*/
public function apply($ids, $type, $typeid, $cover = false)
{
if (!in_array($type, self::$types)) {
throw new NotAllowedException('不允许的上传类型');
}
$ids = is_array($ids) ? $ids : [$ids];
if (empty($ids)) {
return false;
}
if ($this->user instanceof Account) {
$column = 'account_id';
}
$news = [];
$existed_ids = $this->fileRepository->select('id')->whereIn('id', $ids)->get()->pluck('id')->toArray();
foreach ($ids as $id) {
if (!in_array($id, $existed_ids)) {
continue;
}
$new = [
'file_id' => $id,
'account_id' => 0,
'type' => $type,
'type_id' => $typeid,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
];
if ($column) {
$new[$column] = $this->user->id;
}
$news[] = $new;
}
if (empty($news)) {
return false;
}
if ($cover) {
$this->detach($type, $typeid);
}
return $this->fileWithRepository->insert($news);
}
/**
* 取消文件关联
*
* @param string $type
* @param int|string $typeid
* @return boolean
*/
public function detach($type, $typeid)
{
$this->fileWithRepository->withType($type, $typeid)->delete();
return true;
}
/**
* 缩略图文件名
*
* @param string $filename
* @return string
*/
public static function getThumb($filename)
{
return $filename.'.thumb.jpg';
}
/**
* 验证文件是否已上传过返回FileModel实例
*
* @param UploadedFile $file
* @param callable $call
* @return FileModel
*/
protected function validateFileInDatabase(UploadedFile $file, callable $call): ?FileModel
{
$hash = md5_file($file->getRealPath());
return $this->fileRepository->where('hash', $hash)->firstOr(function () use ($file, $call, $hash) {
return call_user_func_array($call, [$file, $hash]);
});
}
/**
* 存储文件
*
* @param UploadedFile $file
* @param array $input
* @param string $disk
* @return mixed
*/
protected function store(UploadedFile $file, $input, $disk, $cover = false)
{
$disk = $disk ?: config('filesystems.default');
$clientHeight = $input['height'] ?? 0;
$clientWidth = $input['width'] ?? 0;
$clientDuration = $input['duration'] ?? 0;
$hash = md5_file($file->getRealPath());
$path = $input['filename'] ?? $this->generateFilePath($hash);
// 图片做旋转处理
if (in_array($file->getClientMimeType(), ['image/jpeg', 'image/bmp', 'image/png'])) {
ini_set('memory_limit', '-1');
try {
Image::make($file->getRealPath())->orientate()->save($file->getRealPath(), 100);
} catch (\Exception $e) {
}
}
list($width, $height) = ($imageInfo = @getimagesize($file->getRealPath())) === false ? [null, null] : $imageInfo;
if (($filename = $file->storeAs($path, '', $disk)) === false) {
throw new UploadFailedException('上传失败');
}
$new = [
'hash' => $hash,
'disk' => $disk,
'filename' => $filename,
'origin_filename' => $file->getClientOriginalName(),
'mimetype' => $file->getClientMimeType(),
'filesize' => $file->getClientSize(),
'width' => $width ?? $clientWidth,
'height' => $height ?? $clientHeight,
'duration' => $clientDuration,
];
$fileModel = $cover ? new FileModel($new) : $this->fileRepository->create($new);
return $fileModel;
}
/**
* 根据文件md5生成文件路径
*
* @param string $hash
* @return void
*/
protected function generateFilePath($hash)
{
return Carbon::now()->format('Y/m/d') . $hash;
}
}