How to implement Dependency Injection in Laravel Livewire

iamkirillart

Kirill

Posted on March 26, 2023

How to implement Dependency Injection in Laravel Livewire

I like to use Dependency Injection (DI) in my code. It helps me to keep my code clean and reduces code coupling.

What is Dependency Injection

Dependency Injection is a design pattern that allows for the separation of concerns by removing the responsibility of creating objects and their dependencies from the class that uses them. Instead, these dependencies are provided or injected into the class by a third-party or a container.

Here's an example in PHP:

class UserService {
    private $userRepository;

    public function __construct(UserRepository $userRepository) {
        $this->userRepository = $userRepository;
    }

    public function getUsers() {
        return $this->userRepository->findAll();
    }
}

class UserRepository {
    public function findAll() {
        // fetch users from the database
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, the UserService requires a UserRepository object to fetch users from the database. Instead of creating the UserRepository object inside the UserService, we inject it via the constructor. This allows for better separation of concerns and makes the UserService more flexible, as we can easily swap out the UserRepository implementation without changing the UserService code. You can read more about how it works in Laravel in documentation.

How to use DI with Livewire

When we use Livewire components, we can’t use the __construct method inside it because Livewire needs $id for a component.

I started to research and found this thread on GitHub. Some developers recommend using the mount() method like this:

use Livewire\Component;
use Psr\Log\LoggerInterface;

class Foo extends Component
{
    protected LoggerInterface $logger;

    public function mount(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public function render()
    {
        $this->logger->info('component rendered');
        return view('livewire.foo');
    }

    public function action()
    {
        $this->logger->info('action triggered');
    }
}
Enter fullscreen mode Exit fullscreen mode

The problem with mount() DI is that it doesn't work in some cases. For example, when you click on the button and call action(), your $this->logger will be empty. This happens because the mount() method isn't called when the user interacts with the component.

The good news for us is that in version 2.6 of Livewire developers added boot() hook. This hook will be called every time you use your component. Here's how you can use DI inside your Livewire component:

class YourComponent extends Livewire\Component
{
    private SomeService $someService;
    private OneMoreService $oneMoreService;

    public function boot(
        SomeService $someService,
        OneMoreService $oneMoreService
    )
    {
        $this->someService = $someService;
        $this->oneMoreService = $oneMoreService;
    }
}
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
iamkirillart
Kirill

Posted on March 26, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related