doe_doe_doe liked a comment+100 XP
2mos ago
From your last snippet, you can use the container to instantiate the service class, without pre-configuring a locator
use Illuminate\Contracts\Container\Container;
class MessageHandler
{
public function __construct(
// 1. Inject the container
private readonly Container $container,
) {}
public function handle(MessageInterface $message) {
$voodooClass = $this->getVoodooAttributeClass($message);
// 2. resolve the service from the container
$voodooService = $this->container->make($voodooClass);
$voodooService->doVoodoo($message);
}
}
If you don't want to inject the container, use the gloabl helper:
class MessageHandler
{
public function handle(MessageInterface $message) {
$voodooClass = $this->getVoodooAttributeClass($message);
// Use the global helper to resolve the service
$voodooService = app($voodooClass);
$voodooService->doVoodoo($message);
}
}
doe_doe_doe wrote a reply+100 XP
3mos ago
doe_doe_doe started a new conversation+100 XP
3mos ago
Hi,
I'm relativly new to Laravel and currently I'm searching, which is the best way to design my app.
Let's say I have a MessageInterface and I have about 50x different implementations of this interface. And now I want to build different VoodooServices for these messages. Each message implementation could have a different VoodooService.
In Symfony there would be a nice solution for this: Service locator. I didn't find something similar in Laravel. What would be a good and flexible solution in Laravel?
In Symfony this would look like this:
Message class with attribute:
#[VoodooAttribute(FooVoodooService::class)]
class FooMessage() implements MessageInterface {
...
}
VoodooInterface
#[AutoconfigureTag('voodoo')]
interface VoodooInterface {
...
}
Voodoo service
class FooVoodooService implements VoodooInterface {
public function doVoodoo(MessageInterface $message): void {
...
}
}
Service Locator
class VoodooLocator extends AbstractLocator {
public function __construct(
#[AutowireLocator('voodoo')]
ServiceLocator $services
) {
parent::__construct($services);
}
...
MessageHandler
class MessageHandler {
public function __constructor(
private VoodooLocator $voodooLocator,
)
public function handle(MessageInterface $message) {
$voodooClass = $this->getVoodooAttributeClass($message);
$voodooService = $this->voodooLocator->getService($voodooClass);
$voodooService->doVoodoo($message);
}
}
So I have different message classes, where I can assign different voodoo services with an attribute. An easy and flexible design. Then I have a voodoo interface and a service locator. This locator contains all services, which have this voodoo interface. Then in the message handler I read out the voodoo class from the attribute, get the service from the locator and then do voodoo.
Service locators are considered an anti-pattern. But for me, the typical arguments against a service locator don't apply here, because this VoodooLocator contains only implementations of the VoodooInterface - not the whole container.
Now I search for a good and flexible solution in Laravel? Any tips?