Search code examples
symfonysymfony4

using service into service depending on configuration in thrid-party bundle


I am busy to port my third-party bundle from symfony 3 to symfony 4. I have my own service inside this bundle. Let's call it MyService:

use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Security\Core\User\UserCheckerInterface;

class MyService
{
    private $params;
    private $userChecker;

    function __construct( ParameterBagInterface $params,
                          UserCheckerInterface  $userChecker )
    {
        $this->params = $params;
        $this->userChecker = $userChecker;
    }

    // ...
}

I have problems with the second injection 'UserCheckerInterface' which must inject another container service depending on my bundle configuration.

MyBundle/DependencyInjection/Configuration.php:

class Configuration implements ConfigurationInterface
{
    /**
     * {@inheritdoc}
     */
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder();
        $rootNode = $treeBuilder->root('fbeen_user');

        $rootNode
            ->children()
                ->scalarNode('user_checker')->defaultValue('@security.user_checker.main')->end()
            ->end()
        ;

        return $treeBuilder;
    }

}

And finally inside my bundle the services.yaml:

services:
    _defaults:
        bind:
            $userChecker: '@security.user_checker.main'

    my_bundle.my_service:
        class: MyCompany\MyBundle\Service\MyService
        arguments: ['@parameter_bag'] 
        public: true

This works but if i move the _defaults: bind section from the bundle's service.yaml to the main service.yaml outside the third-party bundle than it doesn't. This means that anyone which uses my third-party bundle still cannot use another userChecker. I tried something like:

services:
    _defaults:
        bind:
            $userChecker: '@%mycompany_mybundle.user_checker%'

but it gives a string as result instead of an instance. Somebody have a clue for me?


Solution

  • You must configure your service in Extension class

    <?php
    
    namespace MyBundle\DependencyInjection;
    
    use Symfony\Component\DependencyInjection\ContainerBuilder;
    use Symfony\Component\Config\FileLocator;
    use Symfony\Component\HttpKernel\DependencyInjection\Extension;
    use Symfony\Component\DependencyInjection\Loader;
    use Symfony\Component\DependencyInjection\Reference;
    
    class MyBundleExtension extends Extension 
    {
        public function load(array $configs, ContainerBuilder $container)
        {
            $configuration = new Configuration();
            $config = $this->processConfiguration($configuration, $configs);
    
            $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
            $loader->load('services.yml');
    
            $definition = $container->getDefinition('my_bundle.my_service');
            $definition->replaceArgument(1, new Reference($config["user_checker"]));
        }
    }