我认为
Flysystem
就像是与磁盘(或其他存储机制)交互的接口,没有其他更多的功能。就像我不会要求本地文件系统计算公共URI一样,我也不会要求
Flysystem
这样做。
我创建的对象对应于通过
Flysystem
保存的文件。根据我的需求,我可能会直接在数据库记录中保存公共URI,或者我可能会创建一个自定义getter,根据运行时情况构建公共URI。
使用
Flysystem
,我在写入文件时知道文件的路径。为了跟踪这些文件,我通常会创建一个表示已保存文件的对象:
class SavedFile extends Model
{
protected $fillable = [
'disk',
'path',
'publicURI',
];
}
当我保存文件时,我在数据库中创建了一个记录:
$disk = 'local_example';
$path = '/path/to/file.txt';
$contents = 'lorem ipsum';
$host = 'https://example.com/path/to/storage/root/';
if (Store::disk($disk)->put($path, $contents)) {
SavedFile::create([
'disk' => $disk,
'path' => $path,
'publicURI' => $host . $path,
]);
}
每当我需要公共URI时,只需从
SavedFile
模型中获取即可。这对于简单的应用程序很方便,但如果我需要切换存储提供程序,则会出现问题。
利用继承
另一个巧妙的方法是定义一个方法,根据抽象
SavedFile
模型的子类中定义的变量解析公共URI。这样,我就不需要在数据库中硬编码URI,并且可以通过仅定义几个变量来创建其他存储服务的新类:
abstract class SavedFile extends Model
{
protected $table = 'saved_files';
protected $disk;
protected $host;
protected $fillable = [
'path',
];
public function getPublicURIAttribute()
{
return $this->host . $this->attributes['path'];
}
}
class LocalSavedFile extends SavedFile
{
$disk = 'local_example';
$host = 'https://example.com/path/to/storage/root';
}
class AwsSavedFile extends SavedFile
{
$disk = 'aws_example';
$host = 'https://s3.amazonaws.com/my_awesome_bucket';
}
现在如果我有一堆文件存储在本地文件系统中,有一天我把它们移到亚马逊S3上,我只需要复制这些文件并更改我的IoC绑定定义中的依赖关系,就完成了。无需在大型数据库表上进行耗时且可能危险的查找和替换,因为URI的计算由模型完成:
$localFile = LocalSavedFile::create([
'path' => '/path/to/file.txt'
]);
echo $localFile->publicURI; // https://example.com/path/to/storage/root/path/to/file.txt
$awsFile = AwsSavedFile::find($localFile->id);
echo $awsFile->publicURI; // https://s3.amazonaws.com/my_awesome_bucket/path/to/file.txt
支持公共和私有文件
只需在对象中添加标志:
abstract class SavedFile extends Model
{
protected $table = 'saved_files';
protected $disk;
protected $host;
protected $fillable = [
'path',
'public',
];
public function getPublicURIAttribute()
{
if ($this->attributes['public'] === false) {
return false;
}
return $this->host . $this->attributes['path'];
}
}
class LocalSavedFile extends SavedFile
{
$disk = 'local_example';
$host = 'https://example.com/path/to/storage/root';
}
$localFile = LocalSavedFile::create([
'path' => '/path/to/file.txt',
'public' => false,
]);
var_dump($localFile->publicURI);