通过CompilerPass注册自定义AttributeBag

Dav*_*vid 4 php symfony

我正在尝试通过将自定义 AttributBags 集成到会话中来整理我的会话变量。在 Symfony < 6.0 中,您可以将自定义 AttributBag 注入会话服务中。

查看相关问题

然而这种方法在 Symfony >= 6.0 中不再有效。这篇博客文章解释了会话服务已被弃用,现在必须通过 request_stack 服务进行访问。对于控制器来说,这工作得很好。

我当前(不起作用)的方法如下所示:定义自定义 AttributBag 类。

class ShoppingCartBag extends AttributeBag {
    public function __construct(string $storageKey = 'shoppingCart') {
        parent::__construct($storageKey);
    }
}
Run Code Online (Sandbox Code Playgroud)

在 Kernel 类中添加自定义 CompilerPass,以便 Symfony 在构建容器时处理所有更改。

class Kernel extends BaseKernel {
    use MicroKernelTrait;

    protected function build(ContainerBuilder $container): void {
        $container->addCompilerPass(new AddShoppingCartBagToSessionService());
    }
}
Run Code Online (Sandbox Code Playgroud)

自定义的 CompilerPass 看起来像这样。

class AddShoppingCartBagToSessionService implements CompilerPassInterface {

    public function process(ContainerBuilder $container) {
        $container->getDefinition('request_stack') //<- Works, but how to access the session?
            ->addMethodCall('getSession') // How to bridge the gap? This thought does not work. I assume it is because the session is not yet instantiated when the container is build.
            ->addMethodCall('registerBag', [new Reference('App\Session\CustomBag\ShoppingCartBag')]);
    }
}
Run Code Online (Sandbox Code Playgroud)

Spe*_*pea 8

正如您正确假设的那样,通过编译器传递执行此操作时,会话尚不存在。

Symfony 使用所谓的SessionFactory来创建会话。因此,您可以做的是session.factory用您自己的实现来装饰现有服务SessionFactoryInterface,并在其中添加您的属性包:

这个修饰会话工厂的实现可能如下所示:

namespace App;

use Symfony\Component\HttpFoundation\Session\SessionFactoryInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

class SessionFactoryWithAttributeBag implements SessionFactoryInterface
{
    public function __construct(private SessionFactoryInterface $delegate)
    {
    }

    public function createSession(): SessionInterface
    {
        $session = $this->delegate->createSession();
        $session->registerBag(new ShoppingCartBag());

        return $session;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以session.factory通过以下方式装饰services.yaml

services:
    App\SessionFactoryWithAttributeBag:
        decorates: session.factory
        arguments: ['@.inner']
Run Code Online (Sandbox Code Playgroud)

现在,每当创建会话时,您的自定义包也会被注册