Внедрение зависимостей Symfony внедряет все классы типа в качестве параметров - PullRequest
0 голосов
/ 07 января 2019

Как я могу указать контейнеру DI вводить все сервисы определенного типа в другой сервис? Я хотел бы избежать регистрации всех этих сервисов вручную в качестве аргумента.

Как это можно автоматизировать?

class A {

    /**
     * @var ISomeInterface[]
     */
    private $implementations;


    public function __construct(ISomeInterface ...$implementations)
    {
        $this->implementations = $implementations;
    }

}

interface ISomeInterface {}

1 Ответ

0 голосов
/ 07 января 2019

Это может дать вам общее представление. Это скорее псевдокод, поэтому не копируйте и не вставляйте его. Symfony позволяет вам настраивать DI для ваших сервисов через ContainerBuilder - в 3.4 мы делаем это в классе * Extension. В своем приложении вы можете делать это везде, где у вас есть доступ к конструктору контейнеров. Если вы знаете, какие сервисы вам нужно внедрить, вы можете получить их в качестве справочного, в противном случае вы можете просмотреть определения и найти сервисы, которые соответствуют вашим критериям, то есть желаемому интерфейсу.

// Symfony 3.4

- `*Extension.php` class, usually found in DependencyInjection folder of a bundle

class BundleExtension extends Extension
{
    /**
     * @param array $configs
     * @param ContainerBuilder $container
     * @throws \Exception
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); // Your services
                $loader->load('services.yml');

                $configuration = new Configuration();
                $config = $this->processConfiguration($configuration, $configs);

        $implementations = [];

         // Get your implementations

        $implementations[] = ...;


        // You can either loop through config, get them as references (new Reference() ...), compare to interface predicate

        $aService = (new Definition(A:class)) // This is the crucial part
                        ->setArgument(0, $implementations);

        $container->setDefinition(A::class, $aService);

    }
}

Вы можете использовать $container->setArguments([/*your arguments*/]) для добавления аргументов в ваш сервис.

// Symfony 4.2

// Kernel.php ...
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
    {
        $container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php'));
        $container->setParameter('container.dumper.inline_class_loader', true);
        $confDir = $this->getProjectDir().'/config';


        $arguments = [];
        $services = [1, '2', 3, 4, 'def', 'abc']; // Your services

        foreach ($services as $item) {
            if (gettype($item) === 'string') { // Check if they pass your criteria, this is just an example
                $arguments[] = $item;
            }
        }

        $aService = (new Definition(A::class, $arguments)); // Service definition
        $container->setDefinition(A::class, $aService); // Inject it to a container

        $loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob');
        $loader->load($confDir.'/{packages}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob');
        $loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob');
        $loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob');
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...