How to avoid service container in factory models

后端 未结 2 691
夕颜
夕颜 2020-12-11 09:51

I\'m using Symfony 4 for a project, and I have a question regarding factories.

Assume that I have a strategy depending on a kind of string.

I\'d like to crea

2条回答
  •  -上瘾入骨i
    2020-12-11 10:30

    A Symfony Service Locator can be used to avoid the need to inject the complete container. The locator acts like a container but only has access to a limited number of services.

    It takes a bit of magic to configure everything. In your case, you only want the locator to access services implementing the Doing interface.

    Start with the locator which will inherit get/has methods like all containers:

    use Symfony\Component\DependencyInjection\ServiceLocator;
    
    class DoingLocator extends ServiceLocator
    {
        protected $services = [
            'bar' => 'app.service.bar',
            'baz' => 'app.service.baz'
        ];
        public function locate($string) {
            return $this->get($this->services[$string]);
        }
    }
    

    Now comes the magic. You actually could configure this manually in services.yaml per the documentation but it is more fun to do it automatically.

    Start by making your Kernel class a compiler pass:

    # src/Kernel.php
    use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
    class Kernel extends BaseKernel implements CompilerPassInterface
    

    Next, automatically tag all services that implement the Doing interface:

    # Kernel.php
    protected function build(ContainerBuilder $container)
    {
        $container->registerForAutoconfiguration(Doing::class)
            ->addTag('doing');
    }
    

    Finally, add a compiler pass to build your locator service:

    # Kernel.php
    public function process(ContainerBuilder $container)
    {
        $doingLocatorIds = [];
        foreach ($container->findTaggedServiceIds('doing') as $id => $tags) {
            $doingLocatorIds[$id] = new Reference($id);
        }
        $doingLocator = $container->getDefinition(DoingLocator::class);
        $doingLocator->setArguments([$doingLocatorIds]);
    }
    

    And presto. You are done. You can now inject your DoingLocator (aka MyServiceFactory) and all should be well.

提交回复
热议问题