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);
然而,通过构造函数或方法注入将服务注入模型可能不是一个好的做法,请考虑以不需要这样做的方式设计系统,而是将模型注入一项服务。
让我们看一个例子(为了切入正题,只是一个虚拟的例子!)。
- 假设我们有购物篮和订单模型,我们想向购物篮添加订单
- 并且我们有一个折扣服务,可以根据订单计算折扣
- 每次用户向购物篮添加订单时,我们都需要计算新的折扣并将其设置在购物篮中
一种方法是:
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;
}
}
- 在第一个方法中,篮子正在做出是否有折扣的决定,但这不是篮子所关心的
- 在第一种方法中,购物篮取决于折扣服务,但在现实世界中,您不需要折扣服务即可拥有购物篮
我有一个名为 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);
然而,通过构造函数或方法注入将服务注入模型可能不是一个好的做法,请考虑以不需要这样做的方式设计系统,而是将模型注入一项服务。
让我们看一个例子(为了切入正题,只是一个虚拟的例子!)。
- 假设我们有购物篮和订单模型,我们想向购物篮添加订单
- 并且我们有一个折扣服务,可以根据订单计算折扣
- 每次用户向购物篮添加订单时,我们都需要计算新的折扣并将其设置在购物篮中
一种方法是:
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;
}
}
- 在第一个方法中,篮子正在做出是否有折扣的决定,但这不是篮子所关心的
- 在第一种方法中,购物篮取决于折扣服务,但在现实世界中,您不需要折扣服务即可拥有购物篮