Bogdan  Dubyk Bogdan Dubyk - 3 months ago 22
PHP Question

Laravel service provider explanation

I'm not much familiar with Laravel Service provider and I have a question about it.

Example: I have three classes SystemProfiler, SurveyProfiler and OfferProfiler which implements ProfilerInterface. And also I have ProfilerService class which inject ProfilerInterface in the constructor. I need to create different ProfilerService services with injection of each of that profilers.

ProfilerService:

class ProfilerService {

$this->profiler;

function __construct(ProfilerInterface $profiler) {
$this->profiler = profiler;
}
}


I know how to do that in symfony2 framework:

system_profiler:
class: App\MyBundle\Profiles\SystemProfiler

survey_profiler:
class: App\MyBundle\Profiles\SurveyProfiler

offer_profiler:
class: App\MyBundle\Profiles\OfferProfiler

system_profile_service:
class: App\MyBundle\Services\ProfilerService
arguments:
- system_profiler

survey_profile_service:
class: App\MyBundle\Services\ProfilerService
arguments:
- survey_profiler

offer_profile_service:
class: App\MyBundle\Services\ProfilerService
arguments:
- offer_profiler


and then just call
$this->container->get()
with alias of ProfilerService realization

But Laravel documentation said that "there is no need to bind classes into the container if they do not depend on any interfaces.". And ProfilerService not depend on interface. So I can bind each profiler to interface like so:

$this->app->bind('App\MyBundle\Contracts\ProfilerInterface','App\MyBundle\Profiles\SystemProfiler');


or

$this->app->bind('App\MyBundle\Contracts\ProfilerInterface','App\MyBundle\Profiles\SurveyProfiler');


or

$this->app->bind('App\MyBundle\Contracts\ProfilerInterface','App\MyBundle\Profiles\OfferProfiler');


but how I should bind which of the Profilers should be injected to the ProfilerService and when???

I would appreciate any help and explanations

Answer

Here it goes (read the docs):

// ServiceProvider
public function register()
{
    // Simple binding
    $this->app->bind('some_service.one', \App\ImplOne::class);
    $this->app->bind('some_service.two', \App\ImplTwo::class);

    // Aliasing interface - container will inject some_service.one
    // whenever interface is required...
    $this->app->alias('some_service.one', \App\SomeInterface::class);

    // ...except for the Contextual Binding:
    $this->app->when(\App\DependantTwo::class)
              ->needs(\App\SomeInterface::class)
              ->give('some_service.two');
}

USAGE:

$ php artisan tinker

// Aliases
>>> app('some_service.one')
=> App\ImplOne {#669}
>>> app('some_service.two')
=> App\ImplTwo {#671}

// Aliased interface
>>> app('App\SomeInterface')
=> App\ImplOne {#677}
>>> app('App\DependantOne')->dependency
=> App\ImplOne {#677}

// Contextual
>>> app('App\DependantTwo')->dependency
=> App\ImplOne {#676}

Given this setup:

namespace App;

class ImplOne implements SomeInterface {}

class ImplTwo implements SomeInterface {}

class DependantOne
{
    public function __construct(SomeInterface $dependency)
    {
        $this->dependency = $dependency;
    }
}

class DependantTwo
{
    public function __construct(SomeInterface $dependency)
    {
        $this->dependency = $dependency;
    }
}
Comments