Laravel Service Provider Example

Making sense of Laravel Service Providers and Service Containers

I’ve read the service provider docs several times and I was always left with a vague understanding. Maybe a new explanation will be helpful? Here goes.

10,000 foot view

Laravel’s service providers are a little more than, but very much concerned with the concept of dependency injection. Here’s a non-academic description of dependency injection:

Dependency injection is sticking a required value in the parameter of a constructor or a setter method.

If a dependency that you’re injecting is simple has no dependencies of itself, this is no problem. But sometimes, your dependencies need a more hands-on approach to their instantiation.

The service container is where you would put the rules for making an instance of class that is being auto-loaded.

The service provider is a place where you can put the service container code.

The Service Provider does some other stuff too.

An example

Here’s a class that takes in a dependency.

1
2
3
4
5
6
7
8
9
use App\Services\FaceService;
class MyController extends Controller
{
public function __construct(FaceService $faceService)
{
$this->faceService = $faceService;
}
}

In the above code we have a class whose constructor expects a FaceService object. Our use statement above shows where it’s located. Because Laravel is awesome, it will autoload the FaceService class.

In many cases, this works great, but if we try to use our code, we will see this error: Unresolvable dependency resolving [Parameter #0 [ <required> $apiKey ]] in class App\Services\FaceService

Why?

The FaceService has specific dependencies of its own. This is why we need to use the Service Container.

Here’s the constructor of the face service.

1
2
3
4
public function __construct($apiKey)
{
$this->apiKey = $apiKey;
}

So our dependency is an api key. It could be anything… another object… whatever. But if we inject this FaceServcice depency into our controller, we need to ensure that the FaceService is able to be instantiated correctly.

That’s where the Service Container comes into play.

The Service Container helps us set up our dependency

Here, we take advantage of the service container:

1
2
3
4
5
use App\Services\FaceService;
$this->app->bind('App\Services\FaceService', function ($app) {
return new FaceService(env('FACE_API_KEY'));
});

The above code says that when App\Services\FaceService is going to be auto-loaded…. do stuff. In our case, we want to instantiate a new FaceService object with our API key.

Since the first parameter in the bind method is a string, you can’t use the short version of the classname. You gotta send the whole path a la App\Services\FaceService.

Now by binding to the service container, Laravel knows how to auto-load FaceService.

This code lives in the Service Provider

You saw the Service Container code above but I didn’t say where to put it. It goes in a Service Provider. And specifically, it goes into the register mehod.

You can create a new Service Provider by copying an existing one or using php artisan make:provider ProviderName

1
2
3
4
5
6
7
8
9
10
11
12
<?php
use App\Services\FaceService;
class FaceServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('App\Services\FaceService', function ($app) {
return new FaceService(env('MS_FACE_API_KEY1'));
});
}
}

The above code contains our code that binds to the service containe, it’s wrapped nicely inside the register method.

Finally, tell Laravel about the provider

The final thing we need to do is tell Laravel about the Service Provider. To do that we need to add to the providers array in config/app.php. Like so: App\Providers\FaceServiceProvider::class,

That’s it.

Conclusion

We now can see that the Service Container lets us define rules for how classes are auto-loaded during the dependency injection process. The Service Container code lives inside the Service Provider class, which must be registered in config/app.php

The Service Provider does more than just do this type of registration, but this is a good starting point.

avatar

Dev Blog