Как заставить 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;