2015-12-19 2 views
10

Я использую Twig_Environment для рендеринга html-писем для отправки. У меня есть класс NotificationService, который используется другими службами для отправки этих писем.Twig_Environment в классе обслуживания приводит к DIC RuntimeExtension только при unittesting в Symfony 2.8

В нормальном использовании, все работает, но с обновлением до 2.8 UnitTest завершаться: Symfony\Component\DependencyInjection\Exception\RuntimeException: You have requested a synthetic service ("kernel"). The DIC does not know how to construct this service

я отладил StackTrace и проблема, как представляется, Twig_Environment (который использует file_locator который впрыскивает kernel)

/** 
* Notification Service Class 
* 
* @DI\Service("app.service.notification") 
*/ 
class NotificationService extends Generic 
{ 
    /** 
    * @var \Twig_Environment 
    */ 
    protected $twig; 

    /** 
    * @var \Swift_Mailer 
    */ 
    protected $swiftMailer; 

    /** 
    * @var string 
    */ 
    protected $mailTemplate = 'VendorAdminBundle:Email:system2.html.twig'; 

    /** 
    * @param \Swift_Mailer  $swiftMailer 
    * @param \Twig_Environment $twig 
    * 
    * @DI\InjectParams({ 
    *  "swiftMailer" = @DI\Inject("mailer"), 
    *  "twig" = @DI\Inject("twig") 
    * }) 
    */ 
    public function __construct(\Swift_Mailer $swiftMailer, \Twig_Environment $twig) 
    { 
     $this->twig   = $twig; 
     $this->swiftMailer = $swiftMailer; 
    } 

    /** 
    * Send notification mail to Manager 
    * @param UserEntity $manager 
    * @param array  $contacts 
    */ 
    public function notifyManager(UserEntity $manager, array $contacts) 
    { 
     $subject = 'Lorem Ipsum'; 
     $templateFile = "AppBundle:Email:notifyManager.html.twig"; 
     $templateContent = $this->twig->loadTemplate($templateFile); 
     $body = $templateContent->render(array(
      'user'  => $manager, 
      'contacts' => $contacts, 
      'subject' => $subject, 
     )); 

     $this->sendMail($body, $subject, $manager); 
    } 
} 

Любые указатели о том, как это решить?

EDIT: (по запросу)

class NotificationTest extends DoctrineTestCase 
{ 
    /** 
    * @var \App\Service\Notification 
    */ 
    protected $service; 

    public function setUp() 
    { 
     $this->markTestSkipped('Problem with twig env'); 

     $this->loadFixturesFromDirectory(__DIR__ . '/DataFixtures'); 
     $this->loginUser('admin', $this->getUser(1)); 
     $this->service = $this->container->get('neos.service.notification'); // <-- exception thrown here 
    } 

    [test methods] 
} 

EDIT2:

/** 
* Class DoctrineTestCase. 
* 
* This is the base class to load doctrine fixtures using the symfony configuration 
*/ 
class DoctrineTestCase extends TestCase 
{ 
    /** 
    * @var \Symfony\Component\DependencyInjection\Container 
    */ 
    protected $container; 

    /** 
    * @var \Doctrine\ORM\EntityManager 
    */ 
    protected $em; 

    /** 
    * @var string 
    */ 
    protected $environment = 'test'; 

    /** 
    * @var bool 
    */ 
    protected $debug = true; 

    /** 
    * @var string 
    */ 
    protected $entityManagerServiceId = 'doctrine.orm.entity_manager'; 

    /** 
    * Constructor. 
    * 
    * @param string|null $name  Test name 
    * @param array  $data  Test data 
    * @param string  $dataName Data name 
    */ 
    public function __construct($name = null, array $data = array(), $dataName = '') 
    { 
     parent::__construct($name, $data, $dataName); 

     if (!static::$kernel) { 
      static::$kernel = self::createKernel(array(
       'environment' => $this->environment, 
       'debug' => $this->debug, 
      )); 
      static::$kernel->boot(); 
      static::$kernel->getContainer()->set('kernel', static::$kernel); //<--- Added - but doesnt help 
     } 

     $this->container = static::$kernel->getContainer(); 
     $this->em = $this->getEntityManager(); 
    } 

    /** 
    * Executes fixtures. 
    * 
    * @param \Doctrine\Common\DataFixtures\Loader $loader 
    */ 
    protected function executeFixtures(Loader $loader) 
    { 
     $purger = new ORMPurger(); 
     $executor = new ORMExecutor($this->em, $purger); 
     $executor->execute($loader->getFixtures()); 
    } 

    /** 
    * Load and execute fixtures from a directory. 
    * 
    * @param string $directory 
    */ 
    protected function loadFixturesFromDirectory($directory) 
    { 
     $loader = new ContainerAwareLoader($this->container); 
     $loader->loadFromDirectory($directory); 
     $this->executeFixtures($loader); 
    } 

    /** 
    * Returns the doctrine orm entity manager. 
    * 
    * @return object 
    */ 
    protected function getEntityManager() 
    { 
     return $this->container->get($this->entityManagerServiceId); 
    } 
} 

EDIT3: Адресности на ядро, похоже, изменилась иногда в прошлом. см http://symfony.com/doc/master/cookbook/testing/doctrine.html

я изменил мой конструктор из:

public function __construct($name = null, array $data = array(), $dataName = '') 
{ 
    parent::__construct($name, $data, $dataName); 

    if (!static::$kernel) { 
     static::$kernel = self::createKernel(array(
      'environment' => $this->environment, 
      'debug' => $this->debug, 
     )); 
     static::$kernel->boot(); 
     static::$kernel->getContainer()->set('kernel', static::$kernel); //<--- Added - but doesnt help 
    } 

    $this->container = static::$kernel->getContainer(); 
    $this->em = $this->getEntityManager(); 
} 

к:

public function __construct($name = null, array $data = [], $dataName = '') 
{ 
    parent::__construct($name, $data, $dataName); 

    self::bootKernel(); 

    $this->container = static::$kernel->getContainer(); 
    $this->em = $this->getEntityManager(); 
} 

но несчастливо оно не исправить RuntimeException, когда тесты используют Twig_Env.

+1

Возможно, эта страница будет полезной [http://symfony.com/doc/2.8/components/dependency_injection/synthetic_services.html]. –

+0

но shoudnt AppKernel установил экземпляр ядра? unittests проходят через те же классы начальной загрузки. – Rufinus

+0

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

ответ

8

Вы не должны загружать ядро ​​в конструктор тестового примера. Таким образом, это будет завершение работы после выполнения первого теста (см. https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php#L186-L189). Вы должны скорее загрузить ядро ​​в методе setUp() тестового примера.

+0

, пожалуйста, отредактируйте ваш ответ в соответствии с вашим комментарием (у вас есть неточная ссылка в вашем ответе) –

+0

благодарит за заметки – xabbuh

+0

Спасибо xabbuh. Именно наша проблема. Так просто просто не загружать ядро ​​в 'setUpBeforeClass()', а в 'setUp()' Method. – Wulf