Laravel5 对模型的依赖注入

Laravel5 dependency injection on Model

我有一个名为 Surface 的 Eloquent 模型,它依赖于 ZipCodeRepository 对象:

class Surface extends Model{
    public function __construct(ZipCodeRepositoryInterface $zipCode){...}

和一个具有多个表面的地址对象。

class Address extends Model{
    public surfaces() { return $this->hasMany('App/Surface'); }
}

我的问题是当我调用 $address->surfaces 时出现以下错误:

Argument 1 passed to App\Surface::__construct() must be an instance of App\Repositories\ZipCodeRepositoryInterface, none given

我以为 IoC 会自动注入那个。

感谢@svmm 引用 the question mentioned in the comments。我发现你不能在模型上使用依赖注入,因为你必须更改构造函数上的签名,这不适用于 Eloquent 框架。

我在重构代码时作为中间步骤所做的是在构造函数中使用 App::make 来创建对象,例如:

class Surface extends Model{
    public function __construct()
    {
        $this->zipCode = App::make('App\Repositories\ZipCodeRepositoryInterface');
    }

这样 IoC 仍会获取已实现的存储库。我只会这样做,直到我可以将函数拉入存储库以删除依赖项。

在Laravel 5.7中您可以使用全局resolve(...)方法。我不认为全局 App 是在 Laravel.

的更新版本中定义的
$myService = resolve(ServiceName::class);

Resolving in Laravel docs

然而,通过构造函数或方法注入将服务注入模型可能不是一个好的做法,请考虑以不需要这样做的方式设计系统,而是将模型注入一项服务。

让我们看一个例子(为了切入正题,只是一个虚拟的例子!)。

  • 假设我们有购物篮和订单模型,我们想向购物篮添加订单
  • 并且我们有一个折扣服务,可以根据订单计算折扣
  • 每次用户向购物篮添加订单时,我们都需要计算新的折扣并将其设置在购物篮中

一种方法是:

class OrderController
{
    function store(User $user, Order $order)
    {
        $basket = $user->getBasket();
        $basket->addOrder($order);
    }
}

class Basket
{
    private $discountService;

    public function __construct(DiscountService $discountService)
    {
        $this->discountService = $discountService;
    }

    function addOrder(Order $order)
    {
        $this->orders[] = $order;
        $discount = $this->discountService->calculateFor($this->orders);
        $this->discount = $discount;
    }
}

class DiscountService
{
    function calculateFor(array $orders) {
        // code for calculating discount;
        return $discount;
    }
}

在这种方法中,我们将折扣服务注入购物篮模型

另一种更好的方法是这样的:

class OrderController
{
    private $discountService;

    public function __construct(DiscountService $discountService)
    {
        $this->discountService = $discountService;
    }

    function store(User $user, Order $order)
    {
        $basket = $user->getBasket();
        $basket->addOrder($order);
        $this->discountService->setDiscount($basket);
    }
}

class Basket
{
    function addOrder(Order $order)
    {
        $this->orders[] = $order;
    }

    function getOrders()
    {
        return $this->orders;
    }

    function setDiscount(int $discount)
    {
        $this->discount = $discount;
    }
}

class DiscountService
{
    function setDiscount(Basket $basket) {
        $discount = $this->calculateFor($basket->getOrders());
        $basket->setDiscount($discount);
    }

    private function calculateFor(array $orders)
    {
        // code for calculating discount
        return $discount;
    }
}
  • 在第一个方法中,篮子正在做出是否有折扣的决定,但这不是篮子所关心的
  • 在第一种方法中,购物篮取决于折扣服务,但在现实世界中,您不需要折扣服务即可拥有购物篮