我正在嘗試通過將自定義 AttributBags 集成到會話中來整理我的會話變數。在 Symfony < 6.0 中,您可以將自定義 AttributBag 注入會話服務。
查看相關問題
- 如何在 symfony 會話中添加額外的包
- 在控制器中使用 Symfony AttributeBags
然而,這種方法在 Symfony >= 6.0 中不再適用。這篇博客文章解釋了會話服務已被棄用,現在必須通過 request_stack 服務訪問。對于控制器,這很好用。
我當前(不起作用)的方法如下所示:定義一個自定義 AttributBag 類。
class ShoppingCartBag extends AttributeBag {
public function __construct(string $storageKey = 'shoppingCart') {
parent::__construct($storageKey);
}
}
在 Kernel 類中添加自定義 CompilerPass,以便 Symfony 在構建容器時處理所有更改。
class Kernel extends BaseKernel {
use MicroKernelTrait;
protected function build(ContainerBuilder $container): void {
$container->addCompilerPass(new AddShoppingCartBagToSessionService());
}
}
自定義 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')]);
}
}
uj5u.com熱心網友回復:
正如您正確假設的那樣,通過編譯器傳遞執行此操作時會話尚不存在。
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;
}
}
然后你可以session.factory通過以下方式裝飾services.yaml:
services:
App\SessionFactoryWithAttributeBag:
decorates: session.factory
arguments: ['@.inner']
現在,每當創建會話時,您的自定義包也會被注冊
uj5u.com熱心網友回復:
這是一個重要的線索,謝謝@Spea!
我采納了他的想法并為會話服務創建了一個新的裝飾器。經過反復試驗,我找到了問題的答案。解決方案看起來像這樣。請注意,實際語法與 Spea 給出的答案略有不同。
通過擴展同樣命名的類來創建自定義 AttributBag。注意設定屬性包的名稱,而不是建構式中的存盤鍵。否則 Symfony 將在您嘗試訪問 ShoppingCartBag 時拋出錯誤。
namepsace App\Session;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
class ShoppingCartBag extends AttributeBag {
public function __construct() {
parent::__construct();
$this->setName('shoppingCart');
}
}
創建一個裝飾器來更改會話服務的行為以獲得所需的結果(在每個會話中包括 ShoppingCartBag)。
namespace App\Decorator;
use App\Session\ShoppingCartBag;
use Symfony\Component\HttpFoundation\Session\SessionFactoryInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
class SessionFactoryShoppingCartBag implements SessionFactoryInterface {
public function __construct(private SessionFactoryInterface $delegate) {}
public function createSession(): SessionInterface {
$session = $this->delegate->createSession();
$session->registerBag(new ShoppingCartBag());
return $session;
}
}
然后通過添加以下代碼在 services.yml 中裝飾會話服務。
services:
App\Decorator\SessionFactoryShoppingCartBag:
decorates: session.factory
arguments: ['@.inner']
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/406905.html
標籤:
