Laravel:是否可以将Session作为依赖项注入?

3

简版

我想实现的是将session用作类的依赖项,最好是使用 Laravel 的服务提供程序。这可能吗?

详细版

最近我发现服务提供程序无法访问session,因为...

在 Laravel 中,会话由 StartSession 中间件处理,该中间件在所有服务提供程序引导阶段之后执行。

(参考链接)

这对我来说非常不方便。我一直在创建一个电子商务网站,购物车正在使用session,而session应该保存客户选择的商品。

下面是购物车的constructor代码:

class Cart
{
    private $items;

    public function __construct($items)
    {
        $this->items = $items;
    }
    //other functions...
}

这里是AppServiceProvider

class AppServiceProvider extends ServiceProvider
{
//boot

public function register()
{        
    $this->app->bind(Cart::class, function () {
        return new Cart(session('cart'));
    });
}

如前所述,服务提供商无法访问 session('cart')

因此,我直接将 session('cart') 放入 Cart 的构造函数中。

class Cart
{
    private $items;

    public function __construct()
    {
        $this->items = session('cart');
    }
}

这种方式,Cart 总是依赖于 session... 但是,采用这种方法,无法通过 Service provider 来解决 Cart 的依赖关系(即 session),因为 Service provider 无法访问 session(如前所述)。采用这种方法,必须使用 new 关键字来实例化 Cart

class SomeController extends Controller
{
    private $cart;

    public function __construct(Cart $cart)
    {
        $this->cart = $cart;
    }

    public index()
    {
        $this->cart;
        //This will get null in its $items property,
        //because Service Providers can't access session

        $cart = new Cart();
        //This can get items from session()
    }
}

使用 new Cart() 并不是非常理想。我希望将 Cart 作为依赖项注入到控制器中。

除了直接将 session 放入构造函数之外,是否有其他方法可以将其用作类的依赖项?

非常感谢您的建议。

1个回答

5

在我的看来,注入Session是一个相当常见的用例,但奇怪的是文档对此没有充分的说明。

我对Laravel 5.8的session进行了一些尝试,可能有一种解决方案适用于您。似乎您可以使用Illuminate\Session\Store类进行类型提示并使用该类来检索数据。这将导致类似以下的代码:

namespace App\Test;

use Illuminate\Session\Store;

class Cart
{
    /**
     * @var \Illuminate\Session\Store
     */
    private $session;

    public function __construct(Store $session)
    {
        $this->session = $session;
    }

    public function getItems(): array
    {
        return $this->session->get('cart') ?? [];
    }

    public function addItem(string $item): void
    {
        $this->session->push('cart', $item);
    }
}

这个类被Laravel依赖容器自动解析。然而,如果你想自己处理,你的服务提供者会像这样:

    public function register()
    {
        $this->app->bind(Cart::class, function (Container $container) {
            return new Cart($container->get(Store::class));
        });
    }

我认为这件事情的难点在于,不能直接在服务提供者中访问会话(session)值,但是可以访问该服务,从而获得对这些值的访问权限。
你认为这个解决方案适合你的使用场景吗?

看起来很不错!我会尝试这种方法。谢谢你的建议! - Hiroki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接