I have an Eloquent Model called Surface which is dependent on a ZipCodeRepository object:
class Surface extends Model{
public function __construct(ZipCodeRepositoryInterface $zipCode){...}
and an Address object that hasMany surfaces.
class Address extends Model{
public surfaces() { return $this->hasMany('App/Surface'); }
}
My issue is when I call $address->surfaces
I get the following error:
Argument 1 passed to App\Surface::__construct() must be an instance of App\Repositories\ZipCodeRepositoryInterface, none given
I thought the IoC would automatically inject that.
In Laravel, dependency injection is the process of injecting class dependencies into a class through a constructor or setter method. This allows your code to look clean and run faster. Dependency injection involves the use of a Laravel service container, a container that is used to manage class dependencies.
The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection. Dependency injection is a fancy phrase that essentially means this: class dependencies are "injected" into the class via the constructor or, in some cases, "setter" methods.
The singleton pattern is used to restrict the instantiation of a class to a single object, which can be useful when only one object is required across the system. … The first call will instantiate the object while any subsequent will only return the instantiated object.
The Laravel inversion of control container is a powerful tool for managing class dependencies. Dependency injection is a method of removing hard-coded class dependencies. Instead, the dependencies are injected at run-time, allowing for greater flexibility as dependency implementations may be swapped easily.
However it might not be a good practice to inject services into your models either by constructor or method injection, think about designing the system in such a way that you do not need to do that and instead maybe inject the model into a service.
Let's see an example(just a dummy example in order to get to the point!).
one approach is:
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;
}
}
In this approach we injected discount service into Basket model
Another better approach would be like this:
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;
}
}
In Laravel 5.7 you can use the global resolve(...)
method. I don't think the global App
is defined in more recent version of Laravel.
$myService = resolve(ServiceName::class);
Resolving in Laravel docs
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With