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
}
}
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');
}
}
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;
}
}
Top comments (8)
This post explained exactly what i needed when i needed it! Thx so much!
Just for the record: this thing didn't change with Livewire 3; boot method is still the good way for injecting dependencies in a component 😄
Before I found your example I implemented like that:
But I like your example too. Thanks for sharing!
It's not DI
Its kinda. You specified that your component depends on some class, but the realization can be different depending on the environment and runtime.
But yes, your component started depend on
App
class and it brings some magic.How can I DI when a component A emits an event with a parameter array
$data
and on a component B which listens to that event, inject a DTO class ?(Component B)
public function showComp(MyDTO $data).
What if we use a computed property?
Honestly havent work with computed properties. Anyway
resolve()
is not about DI cause its magic method and your code now depends onresolve()
method.Did you find a solution?
The code I provided is working perfectly. I guess it is a better way to do this because computed properties cache data. so it makes things faster.