Service Providers & Dependency Injection In Laravel Explained With Examples.

Service Providers & Dependency Injection In Laravel Explained With Examples.

In this tutorial, we will explain everything about Service Providers in Laravel and dependency injection,

How to create and register a service provider, and how to use it in your Laravel application, and the register and boot methods and the Service Container of Laravel. I explain using Laravel 10.

You can make great Laravel applications without even knowing what service providers are, but once you know them, you will regret that you have wasted so much time and resources and could code your app better.

Dependency Injection In Laravel

Let me show what you do with the service providers, let’s say you want to create a class as a service that does something special and you want to call this class in some controllers. what you will do is.

namespace App\Service;


class MyService
{
    public function greeting()
    {
        echo "hello";
    }
}

You will create an instance of the class every time you use it. It will be something like the below code.

Use App\Services\MyService ;
 //controller function
 public function index()
  {
    $myservice =  new MyService();
     return $myservice->greeting();
  }

But What if this class takes parameters as objects?

class Huge{
    public function __construct(
        FooService $fooService,
        BarService $barService,
    ) {

    }
    public function imHuge()
    {
        echo "I'm huge";
    }

}

You have to create instances of $fooService and $barService, every time you want a new instance of the Huge class. During the request life cycle, you might have many instances so you will repeat the code, and that makes the code hard to read and maintain in addition to wasting your server memory and making your application slow. so here comes the Laravel Service Provider to solve all these problems and perform Dependency injection.

Use App\Services\MyService;
//controller function
 public function index(MyService $myservice)
  {
     return $myservice->greeting();
  }

Service providers make it easy to inject dependencies into your classes. As you can see in the example above we called the class as a function argument and Laravel instantiates the class and creates an object automatically for us using its powerful tool for managing class dependencies, The Laravel service container. and the same thing goes for the Huge class.

Use App\Services\Huge;
//controller function
 public function index(Huge $huge)
  {
     return $huge->imHuge();
  }

Looks good! Let’s see how can we achieve that.

Laravel Service Container

From the Laravel 10 documentation ” 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.” as we did in the examples above. and we use the Service providers to tell the service container about our classes to add them in its container.

Creating Service Providers with Real Project Example.

Let’s create a service provider to register a class that can check if the user has permission or not and throw AuthorizationException. This is a real project example. I’m using this package Laravel-permission.

First, I have the authorization checking class as the below

<?php 
namespace App\Helpers;
use Auth;
class AuthorizationCheck{

    public function checkPermission($permission){

        if(!Auth::user()->can($permission)){
            throw new \Illuminate\Auth\Access\AuthorizationException(__('unauthorised'));
        }
        
    }
}
?>

The class called AuthorizationCheck. It has a single method called checkPermission(), which takes a permission name as input and throws an AuthorizationException if the user does not have that permission.

Let’s create a Laravel service provider called AuthorizationCheckServiceProvider to register the AuthorizationCheck class as a singleton in the Laravel service container. This means that there will only ever be one instance of the AuthorizationCheck class in your Laravel application, and that instance can be accessed from anywhere in your application using the Laravel dependency injection container.

The Artisan CLI can generate a new provider via the make:provider command:

php artisan make:provider AuthorizationCheckServiceProvider

Laravel creates our class in app\Providers\AuthorizationCheckServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Helpers\AuthorizationCheck;
use Illuminate\Contracts\Foundation\Application;
class AuthorizationCheckServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     */
    public function register(): void
    {
        $this->app->singleton(AuthorizationCheck::class, function (Application $app) {
            return new AuthorizationCheck();
        });
    }

    /**
     * Bootstrap services.
     */
    public function boot(): void
    {
        //
    }
}

The register() method of a Laravel service provider is used to register services with the Laravel application. In our case, the register() method is registering the AuthorizationCheck class as a singleton.

The singleton() method takes two arguments: the class name of the service to be registered and a closure that returns an instance of the service. The closure is passed the Laravel application instance as its argument.

In this case, the closure simply returns a new instance of the AuthorizationCheck class.

All service providers are registered in the config/app.php configuration file. By default, a set of Laravel core service providers are registered in the providers array and we need to add our class as well.

'providers' => ServiceProvider::defaultProviders()->merge([
      //
        App\Providers\AuthorizationCheckServiceProvider::class,

 ])->toArray(),

Let’s use our class in a controller.

<?php
//
use App\Helpers\AuthorizationCheck;

class CategoryController extends Controller
{
 public function __construct(public AuthorizationCheck $authorizationCheck){
  }
//
 public function show(Category $category)
  {
        $this->authorizationCheck->checkPermission('categories view');
        return new CategoryResource($category);
   }

}

This Laravel controller called CategoryController. It has a constructor that injects the AuthorizationCheck class as a dependency. This means that the CategoryController class can use the AuthorizationCheck class to check if the currently authenticated user has the necessary permissions to access the controller’s methods.

The show() method first checks if the user has the categories view permission. If the user does not have the permission, the AuthorizationException will be thrown and the user will not be able to view the category.

If the user does have the categories view permission, the show() method will return a new CategoryResource instance, which is a Laravel resource that can be used to serialize the category data into a JSON response.

Service Providers Example for boot method

Let’s create a Laravel service provider called ViewDataServiceProvider that shares the application’s locale and direction with all views.

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View;
class ViewDataServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap services.
     */
    public function boot(): void
    {
           //sharing app lang data and direction

           $locale = app()->getLocale() ;
           $dir = $localeDirs[$locale]; // rtl or ltr
           View::share('locale',$locale);
           View::share('dir', $dir);

    }
}

ViewDataServiceProvider class shares the application’s locale and direction with all views.

This is done by calling the View::share() method twice. The first time, the locale variable is shared with the views. The second time, the dir variable is shared with the views.

The locale variable is the current locale of the application. The dir variable is the direction of the application, which is either ltr (left-to-right) or rtl (right-to-left).

Sharing the locale and direction with all views makes it easy to localize your application and support both left-to-right and right-to-left languages.

Here we use the boot method because The boot() method in a Laravel service provider is used to perform any actions that need to be taken before the application is ready to be used.

We use our variables in the blade as if it comes from a controller.

<!-- view blade -->
<main class="content" dir="{{$dir}}">
 <div class="container-fluid p-0" dir="{{$dir}}">
    @yield('content')
 </div>
</main>

The boot() method is called after all service providers have been registered. This ensures that all services have been registered before any other bootstrapping code is executed.

For example, the boot() method can be used to:

  • Register event listeners
  • Register middleware
  • Bind services to the Laravel service container
  • Publish configuration files
  • Publish assets

That’s how can we use Laravel service providers,

Service Providers in The Request Life Cycle of Laravel

The Service Providers come in the third stage of the Laravel request life cycle. The HTTP kernel will load Service Providers, one of the most important kernel bootstrapping, every feature provided by Laravel framework will be bootstrap by Service Providers such as database connections, mailer services, and caching services, queue, validation, and routing components all the application’s dependencies. All of the service providers for the application are configured in the config/app.php configuration file’s providers array.

When a service provider is loaded, it executes two methods: register() and boot(). The register() method is responsible for loading or registering the dependencies that the service provider provides. The boot() method is responsible for performing any additional tasks that the service provider needs to do.

Laravel documentation: Request Lifecycle

What are the benefits of using service providers in Laravel?

There are many benefits to using service providers in Laravel

Dependency injection: Service providers make it easy to inject dependencies into your classes. This makes your code more loosely coupled and easier to test.

Centralized configuration: Service providers provide a centralized place to configure your application’s dependencies. This makes it easy to manage your dependencies and makes your code more maintainable.

Flexibility: Service providers are flexible and can be used to load any type of dependency. This makes them a powerful tool for extending the functionality of Laravel.

Efficiency: Service providers are loaded only when they are needed, which can improve the performance of your application.

Reusability: Service providers can be reused in multiple applications, which can save you time and effort.

Write better: service providers are a powerful tool that can help you to write better, more maintainable, and more efficient Laravel applications.

Laravel documentation: Service Providers

Conclusion

Service providers are a powerful feature in Laravel that allow you to customize and extend the framework. Service providers can be used to register services, bind classes to the service container, publish configuration files and assets, and bootstrap the application.

Service providers are registered in the config/app.php file. When Laravel starts up, it loads all of the registered service providers and calls their register() and boot() methods.

I hope that was useful information for you, thank you.