Slim Framework: как сломать циклическую инъекцию зависимостей?

Я использую Slim 4.5.0 с PHP-DI 6, и у меня проблема с циклической зависимостью.

Я знаю, как решить эту проблему с помощью сеттера, но в контексте SlimFramework я не могу заставить ничего работать.

Я хочу отправить сообщение в Slack Channel при возникновении ошибки.

LoggerInterface::class => function (ContainerInterface $c):Logger
{
  return new Logger($c->get(SlackService::class), $c->get("googleLogger"), (string)$c->get("RCQVersion"), $c->get('settings')['appSettings']['deploymentType'], $c->get('settings')['online']);
},

SecretManagerService::class => function (ContainerInterface $c):SecretManagerService
{
  return new SecretManagerService($c->get('settings'), $c->get(LoggerInterface::class));
},
SlackService::class =>function(ContainerInterface $c):SlackService
{
  $slackToken = $c->get(SecretManagerService::class)->getSecret(SecretManagerService::$SLACK_TOKEN);
  return new SlackService($slackToken, (string)$c->get("RCQVersion"), $c->get('settings')['appSettings']['deploymentType'], $c->get('settings')['online']);
},

Мне нужно предоставить SlackService моему пользовательскому Logger.

Я пытался использовать ключевое слово @Inject в моем классе Logger, чтобы установить Slack Service (и удалить его из конструктора):

  /**
   * @Inject
   * @var SlackService $slackService
   */
  private $slackService;

Или используйте функцию установки и @Inject (с именем класса и без него)

 /**
   * @Inject("RedCrossQuest\Service\SlackService")
   * @param SlackService $slackService
   */
  public function setSlackService(SlackService $slackService)
  {
    $this->slackService = $slackService;
  }

Но это не работает, хотя я чувствую, что это правильный путь.

Я уже использую @Inject для установки свойства в моем классе (строковое значение), и это работает хорошо, но здесь по некоторым причинам это не так.

Я не нашел здесь ничего, что могло бы помочь понять, почему это не сработает. https://php-di.org/doc/annotations.html

Каждый раз, когда возникает ошибка, я получаю сообщение об ошибке, говорящее, что slackService равен нулю Uncaught Error: Call to a member function postMessage() on null

Чего мне не хватает, чтобы заставить @Inject() работать?


person Thomas    schedule 12.08.2020    source источник
comment
Что такое googlelogger? Я не знаю, чего мне не хватает, но я не вижу циклической зависимости.   -  person Nima    schedule 12.08.2020
comment
Упс, исправлено. Logger требует Slack, Slack требует SecretManager, SecretManager требует Logger   -  person Thomas    schedule 12.08.2020
comment
Является ли SecretManager настраиваемым классом, который вы написали? Как и зачем он использует регистратор? Это конкретно нужно SlackService?   -  person Nima    schedule 13.08.2020
comment
Да, это класс, который я написал для извлечения секрета из Google Secret Manager. Slack Service нужен для получения своего API TOKEN. Вопрос здесь не в том, как функционально разорвать циклическую зависимость, а в том, как это сделать технически. Я пробовал @Inject и вводить Slack через сеттер вместо конструктора, но метод никогда не вызывается. я обновлю свой пост   -  person Thomas    schedule 13.08.2020
comment
Взгляните на эти проблемы 191 и 527 на github, а также этот ответ на SO.   -  person Nima    schedule 13.08.2020


Ответы (1)


Как указано Nima с билетами, циклические зависимости не могут быть решены с помощью установщика, если вы не используете Отложенная загрузка. Загвоздка в том, что для этого требуются прокси-библиотеки, которые имеют 3 дополнительные зависимости, что немного излишне для моего простого варианта использования. (также кажется, что в документации PHP-DI отсутствует шаг)

  • zendframework/zend-событийный менеджер (3.2.1)
  • zendframework/zend-код (3.4.1)
  • ocramius/прокси-менеджер (2.2.3)
  • ocramius/версии пакетов (1.5.1)

Чтобы обойти это, я вручную выполнил работу PHP-DI.

  • Я установил сеттер в моем Logger, чтобы установить SlackService после создания контейнера, и я не добавлял @Inject в комментарии над методом сеттера.
// Set up dependencies
$dependencies = require __DIR__ . '/../../src/dependencies.php';
$dependencies($containerBuilder);

// Build PHP-DI Container instance
$container = $containerBuilder->build();

$loggerInterface = $container->get(LoggerInterface::class);
$loggerInterface->setSlackService ($container->get(SlackService::class);


// Instantiate the app
AppFactory::setContainer($container);
$app = AppFactory::create();
person Thomas    schedule 14.08.2020