2015-06-03 7 views
1

ПреамбулаSymfony2: инъекции зависимостей зависят от запроса

Моего приложение Symfony2 будет доступны из нескольких ДВОЙ. В зависимости от TLD я хочу использовать другую почтовую программу swiftmailer. Однако я не смог динамически вводить правильную почтовую программу, несмотря на множество подходов (фабрика услуг, передача компилятора, расширение DI, «динамический псевдоним»).

Это привело к фундаментальной реализации: Зависимости инъецируют перед тем компилируется контейнер, запрос доступен после того, как контейнер собран. Следовательно, нет никакого способа сделать зависимую инъекцию зависимой от запроса (и, следовательно, все вышеупомянутые подходы не удались).

Проблема

Мне сказали, что никогда не тянуть зависимостей, но всегда вводить их.

Чтобы проиллюстрировать это далее:

У меня

  • three swiftmailers: mailer_en, mailer_de, mailer_ie и
  • три области: domain.co.uk, domain.de и domain.ie

и хотите ввести правильный swiftmailer в custom mailer service for FOSUserBundle (или в любую другую службу, которая требует swiftmailer).

Вопрос

Как придать правильную зависимость, если я не знаю, пока запрос не доступен?

У меня было две идеи, но не уверен, о том, как подходят они:

  1. Должен ли я вводить какой-то «мэйлеру Provider»? Все еще вид тянущих зависимостей, не так ли?
  2. Могу ли я использовать какой-то прокси-класс, переадресовывая взаимодействие с правильным почтовым сервером?

Или я полностью не в том направлении?

ответ

1

Внедрение запроса is covered in the documentation. Это, как говорится, я думаю, что вы получите наибольший удар за доллар by using a factory.

+0

Спасибо, Питер, не знаю, как я пропустил это ... – Jonny

1

Для дальнейшего использования, здесь реализация Peter's answer:

Custom mailer for FOSUserBundle конфигурации:

# app/config/config.yml 

fos_user: 
    # ... 
    service: 
     mailer: acme.mailer 

и

# src/Acme/UserBundle/config/services.xml 

<service id="acme.mailer.factory" class="Acme\UserBundle\Service\TwigSwiftMailerFactory" public="false"> 
    <call method="setContainer"> 
     <argument type="service" id="service_container" /> 
    </call> 
</service> 

<service id="acme.mailer" class="TwigSwiftMailer"> 
    <factory service="propeo_user.mailer.factory" method="createTwigSwiftMailer" /> 
    <argument type="service" id="acme.mailer_name_provider" /> 
    <argument type="service" id="router" /> 
    <argument type="service" id="twig" /> 
    <argument type="collection"> 
     <argument key="template" type="collection"> 
      <argument key="confirmation">%fos_user.registration.confirmation.template%</argument> 
      <argument key="resetting">%fos_user.resetting.email.template%</argument> 
     </argument> 
    </argument> 
</service> 

, а также фабрика классов:

# Acme/UserBundle/Service/TwigSwiftMailerFactory 

class TwigSwiftMailerFactory extends ContainerAware 
{ 
    private function getContainer() 
    { 
     if(!($this->container instanceof ContainerInterface)) { 
      throw new \RuntimeException('Container is missing'); 
     } 
     return $this->container; 
    } 

    public function createTwigSwiftMailer(MailerNameProvider $mailerNameProvider, UrlGeneratorInterface $router, \Twig_Environment $twig, array $parameters) 
    { 
     $container = $this->getContainer(); 
     $name = $mailerNameProvider->getMailerName(); // returns mailer name, e.g. mailer_en 

     $mailer = $container->get(
      sprintf('swiftmailer.mailer.%s', $name ? $name : 'default') 
     ); 

     $parameters['from_email']['confirmation'] = 
      $parameters['from_email']['resetting'] = 
       $container->getParameter(
        sprintf('swiftmailer.mailer.%s.sender_address', $name ? $name : 'default') 
       ) 
     ; 

     return new TwigSwiftMailer($mailer, $router, $twig, $parameters); 
    } 
}