简体   繁体   中英

Laravel dependency injection / IOC

I'm attempting to integrate to the Xero API - I'm using the following wrapper:

https://github.com/drawmyattention/xerolaravel

I'm able to access the API with the Facade methods but I would really like to resolve the dependencies and do it all properly, I'm still learning these bits.

I have followed the instructions, added:

DrawMyAttention\XeroLaravel\Providers\XeroServiceProvider::class

To my app.php & inside of my Controller I am attempting to resolve this (I think?)

I begin by doing the following:

use DrawMyAttention\XeroLaravel\Providers\XeroServiceProvider as Xero;
    private $xero;


public function __construct(XeroServiceProvider $xero)
{
    $this->xero = $xero;
}

And even that, produces the error:

 BindingResolutionException in Container.php line 828:
 Unresolvable dependency resolving [Parameter #0 [ <required> $app ]] 
 in class Illuminate\Support\ServiceProvider

I'm really sorry if this is a stupid question - I haven't dabbled much into this side of Laravel.

The service provider is only used to setup all the bindings and everything for the IOC. You add it inside your config/app.php , as you mentioned, and then you won't worry about it anymore. This is not the class you should be injecting.

Unfortunately, looking at the code, this package has not set itself up well for dependency injection. This is an example of one of the bindings inside the service provider:

$this->app->bind('XeroPrivate', function () use ($config) {
    return new \XeroPHP\Application\PrivateApplication($config);
});

With this binding, that means you can resolve a new PrivateApplication instance out of the IOC by calling $private = app('XeroPrivate'); . However, because PrivateApplication needs special construction (config passed in the constructor), this setup does not help you with dependency injection.

The binding is setup for XeroPrivate , however, this class doesn't exist, which means you can't type hint it to have it injected. You may have added XeroPrivate as an alias in your config/app.php file, which would bypass the issue of the XeroPrivate class not existing, however this would mean that the facade class is injected (which is what the alias points to), not the PrivateApplication class.

In order to be able to properly inject the PrivateApplication class, you will need to setup your own binding. You can create a new service provider, or just add this to your AppServiceProvider:

$this->app->bind('XeroPHP\Application\PrivateApplication', function ($app) {
    return $app['XeroPrivate'];
});

You will need to do the same thing for PublicApplication and PartnerApplication :

$this->app->bind('XeroPHP\Application\PublicApplication', function ($app) {
    return $app['XeroPublic'];
});

$this->app->bind('XeroPHP\Application\PartnerApplication', function ($app) {
    return $app['XeroPartner'];
});

With these bindings, you can safely inject any of the classes into your constructor, and they will be resolved properly:

use XeroPHP\Application\PrivateApplication;
use XeroPHP\Application\PublicApplication;
use XeroPHP\Application\PartnerApplication;

public function __construct(PrivateApplication $xeroPrivate, PublicApplication $xeroPublic, PartnerApplication $xeroPartner)
{
    $this->xeroPrivate = $xeroPrivate;
    $this->xeroPublic = $xeroPublic;
    $this->xeroPartner = $xeroPartner;
}

When the controller is instantiated, it will see that it needs a new XeroPHP\\Application\\PrivateApplication instance, and it will resolve this instance out of the IOC using the binding we created above (which in turn resolves the XeroPublic object out of the IOC). It will do the same for XeroPHP\\Application\\PublicApplication and XeroPHP\\Application\\PartnerApplication .

The rest of the classes don't require any special construction, so there is no need to create custom bindings for them. They can be injected as is:

use XeroPHP\Models\Accounting\Invoice;
use XeroPHP\Models\Accounting\Invoice\LineItem;
use XeroPHP\Models\Accounting\Contact;
use XeroPHP\Models\Accounting\BrandingTheme;
use XeroPHP\Models\Accounting\Attachment;

public function __construct(Invoice $xeroInvoice, LineItem $xeroLineItem, Contact $xeroContact, BrandingTheme $xeroBrandingTheme, Attachment $xeroAttachment)
{
    $this->xeroInvoice = $xeroInvoice;
    $this->xeroLineItem = $xeroLineItem;
    $this->xeroContact = $xeroContact;
    $this->xeroBrandingTheme = $xeroBrandingTheme;
    $this->xeroAttachment = $xeroAttachment;
}

When the controller is instantiated, it will see that it needs a new XeroPHP\\Models\\Accounting\\Invoice instance, but since there is no binding in the IOC for this class, it just new s up a new instance and injects that. It will do the same for the rest of the classes shown above.

Use the alias you've assigned:

use DrawMyAttention\XeroLaravel\Providers\XeroServiceProvider as Xero;

class Foo {

    private $xero;

    public function __construct(Xero $xero)
    {
        $this->xero = $xero;
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM