Как заставить Symfony DI и PHP-DI работать вместе?

Некоторое время назад у меня была проблема с автопроводкой для Controller s. Наконец я решил это, отключив DIC Symfony. Это было нормально для этого случая. Но теперь мне это нужно для использования Symfony's EventDispatcher и прикрепление Listener к этому. Так что теперь я должен найти чистое решение вместо обходного пути.

Соответствующие места для настройки DI приложения: services.yaml, Kernel.php, routes.yaml (для контроллеров) и common.php (файл со списком зависимостей). Я сделал конфигурации во всех этих файлах (см. Код ниже). Но я получаю ошибку:

RuntimeException

Не удается автоматически подключить службу "App\Interop\Website\Controller\IndexController": аргумент "$fooService" метода "__construct()" ссылается на интерфейс "App\Services\Dummy\External\FooServiceInterface", но такой службы не существует. Возможно, вам следует использовать псевдоним этого интерфейса для одной из этих существующих служб: "App\Services\Dummy\External\FooAService", "App\Services\Dummy\External\FooBService". Вы создали класс, который реализует этот интерфейс?

Значит для меня: откат к контейнеру PHP-DI не работает. Теперь я отладил это и вижу - это не может работать таким образом. Когда мы посмотрим на DI\Bridge\Symfony\Kernel#initializeContainer(...) Посмотрим, что сначала

parent::initializeContainer();

позвонить и только после этого:

$rootContainer = $this->getContainer();
$rootContainer->setFallbackContainer($this->getPHPDIContainer());

Таким образом, Symfony DIC пытается инициализироваться. Откат еще не установлен. Сбой инициализации, потому что некоторые зависимости (необходимые в этом случае для IndexController - но это не специфическая проблема контроллера) не может быть найден / загружен в / из services.yaml и запасного варианта там нет. Но если это так, мост PHP-DI вообще не будет работать ни для кого (за исключением некоторых особых случаев, когда каждый интерфейс имеет только одну реализацию).

Я на самом деле уверен, что это проблема 8-го уровня. Что я делаю не так и как заставить его работать (теперь чисто и правильно)?


структура проекта

проект-структура

services.yaml

parameters:

services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: false

    App\:
        resource: '../src/*'
        exclude: '../src/Base/{Entity,Enums,Exceptions,Messages,Migrations,Repository,Utils},Kernel.php'

    App\Interop\Website\Controller\:
        resource: '../src/Interop/Website/Controller'
        tags: ['controller.service_arguments']

App\Kernel

namespace App;

use DI\Bridge\Symfony\Kernel as PhpDIBridgeSymfonyKernel;

class Kernel extends PhpDIBridgeSymfonyKernel
{

    ...
    // default stuff
    ...

    protected function buildPHPDIContainer(PhpDiContainerBuilder $builder)
    {
        $builder->addDefinitions($this->getProjectDir() . '/config/dependencies/common.php');
        return $builder->build();
    }

    /*
    I've not overridden the initializeContainer(). Is it correct?
    Anyway, according to the docu (http://php-di.org/doc/frameworks/symfony2.html) it isn't needed.
    */

}

/config/routes.yaml

index:
    pattern: /
    defaults: App\Interop\Website\Controller\IndexController:indexAction
my:
    pattern: /my
    defaults: App\Interop\Website\Controller\MyController:processUserMessageAction

/config/dependencies/common.php

use ...

$commonDependencies = [
    FooServiceInterface::class => DI\autowire(FooBService::class),
    BarServiceInterface::class => DI\autowire(BarService::class),
    NameConverterInterface::class => DI\autowire(CamelCaseToSnakeCaseNameConverter::class),
    EntityManagerInterface::class => function () {
        $config = new Configuration();
        $config->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader()));
        $config->setProxyDir(__DIR__ . '/../../var/cache/' . getenv('APP_ENV') . '/doctrine/orm/Proxies');
        $config->setProxyNamespace('Proxies');
        $connectionParams = [
            'url' => getenv('DATABASE_URL'),
        ];
        $connection = DriverManager::getConnection($connectionParams, $config);
        return EntityManager::create($connection, $config);
    },
    StateManagingServiceInterface::class => DI\autowire(StateManagingService::class),
];

$commonLocalDependenciesPath = __DIR__ . DIRECTORY_SEPARATOR . 'common.local.php';
$commonLocalDependencies = file_exists($commonLocalDependenciesPath) ? require $commonLocalDependenciesPath : [];

$mergedDefinitions = array_merge($commonDependencies, $commonLocalDependencies);

return $mergedDefinitions;

0 ответов

Другие вопросы по тегам