I am creating a Symfony 6 bundle that provides a service that depends on the utilizing application to implement a provided interface as a service. This bundle provides a service called MyBundleService. It also provides an interface called MyBundleManagerInterface that is expected to be implemented as a service by any utilizing applications.
How to auto-inject the service that utilizing applications implement into the MyBundleService service that my bundle provides?
Here is some simplified code to illustrate:
First is the interface:
/** MyBundleManagerInterface.php **/
namespace MyCompany\MyBundle\Interface;
interface MyBundleManagerInterface
{
public function processRequest(\Symfony\Component\HttpFoundation\Request $request): void;
}
Now, let say an application implements MyBundleManagerInterface as a service:
namespace App\Service;
use MyCompany\MyBundle\Interface\MyBundleManagerInterface;
class ManagerService implements MyBundleManagerInterface {
public function processRequest(\Symfony\Component\HttpFoundation\Request $request): void
{
//do something
}
}
The service MyBundleService inside my bundle seems to not be able to get the MyBundleManagerInterface implementation, which is the service ManagerService from the application.
/** MyBundleService.php **/
// the bundle has been configured to autowire all classes inside this namespace
namespace MyCompany\MyBundle\Service;
use MyCompany\MyBundle\Interface\MyBundleManagerInterface;
class MyBundleService
{
public function __construct(protected ?MyBundleManagerInterface $manager)
{
// the injected $manager seems to be NULL here
}
#[Required]
public function setManager(?MyBundleManagerInterface $manager)
{
// this Required-attributed method is called, yet the $manager parameter is NULL
$this->manager = $manager;
}
}
What did I miss? Is there a way to tell Symfony dependency injection that the ManagerService from the application can be injected into MyBundleService? Or is it not possible for a bundle to use services from applications?
The problem is that Symfony doesn't know which class to implement because you can implement the interface more than one times. To know wich class to autowire you must set an alias to the interface.
https://symfony.com/doc/current/service_container/autowiring.html#working-with-interfaces
For this use case I prefer to use tagged services. Then you can use more than one implementation and avoid requiring changes to the services.yaml file.