在我的Symfony 6项目中,我需要在每个用户会话中存储上传的大文件。
由于直接将这些文件存储在会话中不是一个好主意,我使用的flysystem具有每个会话id的目录和清理过程。
到目前为止还不错
现在,由于我不想每次使用当前会话id作为基本目录直接配置flysystem存储作为服务时都生成每个会话id的文件路径,如下所示:
flysystem:
storages:
session.storage:
adapter: 'local'
options:
directory: '%env(APP_SESSION_STORAGE_PATH)%/%sessionId%'
这显然不起作用,因为没有%sessionId%
,但我如何才能做到这一点?
我也尝试过使用工厂,但这也感觉过于复杂,因为我必须从flysystem-bundle
复制逻辑来初始化此服务。
我知道这个服务只在http上下文中工作。
只是代码的想法。就在你的";。。必须从flysystem捆绑包中复制逻辑&";。哇!我认为你试图克服复杂的
我不知道你的应用程序逻辑。然而就像:
// config/services.yaml
services:
_defaults:
//..
bind:
$bigFileSessionStoragePath: '%env(APP_SESSION_BIG_FILE_STORAGE_PATH)%'
您的服务:
// BigFileSessionStorage.php
namespace Acme/Storage;
use SymfonyComponentFilesystemFilesystem;
use SymfonyComponentHttpFoundationFileFile;
use SymfonyComponentHttpFoundationRequestStack;
class BigFileSessionStorage
{
private string $bigFileSessionDirPath;
public function __construct(
private RequestStack $requestStack,
private Filesystem $filesystem,
private string $bigFileSessionStoragePath
){}
public function storeBigSessionFile(File $bigSessionFile){
$sessionBifFileDir = $this->getBigFileSessionDirectory();
// move a Big File ..
$this->filesystem->copy(...)
}
public function getBigFileSessionDirectory(): string{
$sessionId = $this->requestStack->getSession()->getId();
$path = $this->bigFileSessionDirPath.DIRECTORY_SEPARATOR.$sessionId;
if (!$this->filesystem->exists($path)){
$this->filesystem->mkdir($path);
$this->bigFileSessionDirPath = $path;
}
return $this->bigFileSessionDirPath;
}
// TODO & so on
public function removeBigFileSessionDirectory(){}
}
然后在你需要的地方注入这个服务。
基于@voodoo417答案的想法,我最终为FilesystemOperator
创建了一个装饰器。我对这个解决方案不太满意,因为它包含了很多样板装饰器代码,只是为了修改根目录,在那里可以首先配置根目录。
但它是有效的,结果正是我想要的。
flysystem:
storages:
baseSession.storage:
adapter: 'local'
options:
directory: '%env(APP_SESSION_STORAGE_PATH)%'
class SessionStorage implements FilesystemOperator
{
public function __construct(
private FilesystemOperator $baseSessionStorage,
private RequestStack $requestStack,
) {}
private function chroot(string $location): string
{
$session = $this->requestStack->getSession();
$sessionId = $session->getId();
// TODO: Don't allow /../ syntax to access other sessions
return "/{$sessionId}/" . ltrim($location, '/');
}
public function fileExists(string $location): bool
{
return $this->baseSessionStorage->fileExists($this->chroot($location));
}
// ... decorate all the other methods of FilesystemOperator
}
现在,我可以在应用程序中的任何位置(在http上下文中(使用SessionStorage
,并且可以在控制台命令(cron(中使用FilesystemOperator $baseSessionStorage
来清理文件。