Namespaces omitted for brevity...
I have written the following service provider and registered in config/app.php:
class OfferServiceProvider extends ServiceProvider
{
public function register()
{
$this->registerLossControlManager();
}
protected function registerLossControlManager()
{
$this->app->bind('LossControlInterface', 'LossControl');
}
}
Here is my LossControlInterface
interface LossControlInterface
{
/**
* @param int $demandId
* @param float $offerTotal
* @param float $productTotal
* @param null|int $partnerId
* @return mixed
*/
public function make($demandId, $offerTotal, $productTotal, $partnerId = null);
/**
* @return float
*/
public function getAcceptableLoss();
/**
* @return bool
*/
public function isAcceptable();
/**
* @return bool
*/
public function isUnacceptable();
/**
* @return null
*/
public function reject();
}
Now within the controller, I can inject the LossController as follows:
use LossControlInterface as LossControl;
class HomeController extends BaseController {
public function __construct(LossControl $lossControl)
{
$this->lossControl = $lossControl;
}
public function getLossThresholds()
{
$lossControl = $this->lossControl->make(985, 1000, null);
var_dump('Acceptable Loss: ' . $lossControl->getAcceptableLoss());
var_dump('Actual Loss: ' . $lossControl->calculateLoss());
var_dump('Acceptable? ' . $lossControl->isAcceptable());
}
}
However if I try to dependency inject the LossControlInterface from within a custom class called by a command:
[2014-09-02 13:09:52] development.ERROR: exception 'ErrorException' with message 'Argument 11 passed to Offer::__construct() must be an instance of LossControlInterface, none given, called in /home/vagrant/Code/.../ProcessOffer.php on line 44 and defined' in /home/vagrant/Code/.../Offer.php:79
It appears as though I am unable to dependency inject the interface into a custom class, but I can when dependency injecting into a controller.
Any thoughts on what Im doing wrong or have omitted to get the automatic resolution working?
In laravel 5.4 (https://github.com/laravel/framework/pull/18271) you need to use the new makeWith method of the IoC container.
if you still use 5.3 or below, the above answers will work.
The IoC is automatic within controllers, and you don't see the injection because Laravel handles the construction of controllers for you. When creating any other custom class by using the
new
keyword, you will still need to send in all of the parameters needed to it's constructor:You can hide this, to a degree, by funneling creation of your custom class through a service provider:
Then just have the IoC make it whenever you need it:
In your case, you can change your code to look like this:
A perhaps cleaner approach could be to create a service provider and an
OfferFactory
which gets injected into your controller. The controller can then request the factory to create the offer whenever it needs one:This has the benefit of completely decoupling your controller from the logic behind the creation of the offer, yet allowing you to have a spot to add any amount of complexity necessary to the process of creating offers.
In Laravel 5.2 the simplest solution for your particular problem would be to replace
with
or even shorter
which will use Laravel Container to take care of dependencies.
If however you want to pass additional parameters to the
Offer
constructor it is necessary to bind it in your service providerAnd voila, now you can write