ResolveInstanceofConditionalsPassTest.php 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\DependencyInjection\Tests\Compiler;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Component\DependencyInjection\ChildDefinition;
  13. use Symfony\Component\DependencyInjection\Compiler\ResolveInstanceofConditionalsPass;
  14. use Symfony\Component\DependencyInjection\Compiler\ResolveDefinitionTemplatesPass;
  15. use Symfony\Component\DependencyInjection\ContainerBuilder;
  16. class ResolveInstanceofConditionalsPassTest extends TestCase
  17. {
  18. public function testProcess()
  19. {
  20. $container = new ContainerBuilder();
  21. $def = $container->register('foo', self::class)->addTag('tag')->setAutowired(true)->setChanges(array());
  22. $def->setInstanceofConditionals(array(
  23. parent::class => (new ChildDefinition(''))->setProperty('foo', 'bar')->addTag('baz', array('attr' => 123)),
  24. ));
  25. (new ResolveInstanceofConditionalsPass())->process($container);
  26. $parent = 'instanceof.'.parent::class.'.0.foo';
  27. $def = $container->getDefinition('foo');
  28. $this->assertEmpty($def->getInstanceofConditionals());
  29. $this->assertInstanceOf(ChildDefinition::class, $def);
  30. $this->assertTrue($def->isAutowired());
  31. $this->assertSame($parent, $def->getParent());
  32. $this->assertSame(array('tag' => array(array()), 'baz' => array(array('attr' => 123))), $def->getTags());
  33. $parent = $container->getDefinition($parent);
  34. $this->assertSame(array('foo' => 'bar'), $parent->getProperties());
  35. $this->assertSame(array(), $parent->getTags());
  36. }
  37. public function testProcessInheritance()
  38. {
  39. $container = new ContainerBuilder();
  40. $def = $container
  41. ->register('parent', parent::class)
  42. ->addMethodCall('foo', array('foo'));
  43. $def->setInstanceofConditionals(array(
  44. parent::class => (new ChildDefinition(''))->addMethodCall('foo', array('bar')),
  45. ));
  46. $def = (new ChildDefinition('parent'))->setClass(self::class);
  47. $container->setDefinition('child', $def);
  48. (new ResolveInstanceofConditionalsPass())->process($container);
  49. (new ResolveDefinitionTemplatesPass())->process($container);
  50. $expected = array(
  51. array('foo', array('bar')),
  52. array('foo', array('foo')),
  53. );
  54. $this->assertSame($expected, $container->getDefinition('parent')->getMethodCalls());
  55. $this->assertSame($expected, $container->getDefinition('child')->getMethodCalls());
  56. }
  57. public function testProcessDoesReplaceShared()
  58. {
  59. $container = new ContainerBuilder();
  60. $def = $container->register('foo', 'stdClass');
  61. $def->setInstanceofConditionals(array(
  62. 'stdClass' => (new ChildDefinition(''))->setShared(false),
  63. ));
  64. (new ResolveInstanceofConditionalsPass())->process($container);
  65. $def = $container->getDefinition('foo');
  66. $this->assertFalse($def->isShared());
  67. }
  68. public function testProcessHandlesMultipleInheritance()
  69. {
  70. $container = new ContainerBuilder();
  71. $def = $container->register('foo', self::class)->setShared(true);
  72. $def->setInstanceofConditionals(array(
  73. parent::class => (new ChildDefinition(''))->setLazy(true)->setShared(false),
  74. self::class => (new ChildDefinition(''))->setAutowired(true),
  75. ));
  76. (new ResolveInstanceofConditionalsPass())->process($container);
  77. (new ResolveDefinitionTemplatesPass())->process($container);
  78. $def = $container->getDefinition('foo');
  79. $this->assertTrue($def->isAutowired());
  80. $this->assertTrue($def->isLazy());
  81. $this->assertTrue($def->isShared());
  82. }
  83. public function testProcessUsesAutoconfiguredInstanceof()
  84. {
  85. $container = new ContainerBuilder();
  86. $def = $container->register('normal_service', self::class);
  87. $def->setInstanceofConditionals(array(
  88. parent::class => (new ChildDefinition(''))
  89. ->addTag('local_instanceof_tag')
  90. ->setFactory('locally_set_factory'),
  91. ));
  92. $def->setAutoconfigured(true);
  93. $container->registerForAutoconfiguration(parent::class)
  94. ->addTag('autoconfigured_tag')
  95. ->setAutowired(true)
  96. ->setFactory('autoconfigured_factory');
  97. (new ResolveInstanceofConditionalsPass())->process($container);
  98. (new ResolveDefinitionTemplatesPass())->process($container);
  99. $def = $container->getDefinition('normal_service');
  100. // autowired thanks to the autoconfigured instanceof
  101. $this->assertTrue($def->isAutowired());
  102. // factory from the specific instanceof overrides global one
  103. $this->assertEquals('locally_set_factory', $def->getFactory());
  104. // tags are merged, the locally set one is first
  105. $this->assertSame(array('local_instanceof_tag' => array(array()), 'autoconfigured_tag' => array(array())), $def->getTags());
  106. }
  107. public function testAutoconfigureInstanceofDoesNotDuplicateTags()
  108. {
  109. $container = new ContainerBuilder();
  110. $def = $container->register('normal_service', self::class);
  111. $def
  112. ->addTag('duplicated_tag')
  113. ->addTag('duplicated_tag', array('and_attributes' => 1))
  114. ;
  115. $def->setInstanceofConditionals(array(
  116. parent::class => (new ChildDefinition(''))->addTag('duplicated_tag'),
  117. ));
  118. $def->setAutoconfigured(true);
  119. $container->registerForAutoconfiguration(parent::class)
  120. ->addTag('duplicated_tag', array('and_attributes' => 1))
  121. ;
  122. (new ResolveInstanceofConditionalsPass())->process($container);
  123. (new ResolveDefinitionTemplatesPass())->process($container);
  124. $def = $container->getDefinition('normal_service');
  125. $this->assertSame(array('duplicated_tag' => array(array(), array('and_attributes' => 1))), $def->getTags());
  126. }
  127. public function testProcessDoesNotUseAutoconfiguredInstanceofIfNotEnabled()
  128. {
  129. $container = new ContainerBuilder();
  130. $def = $container->register('normal_service', self::class);
  131. $def->setInstanceofConditionals(array(
  132. parent::class => (new ChildDefinition(''))
  133. ->addTag('foo_tag'),
  134. ));
  135. $container->registerForAutoconfiguration(parent::class)
  136. ->setAutowired(true);
  137. (new ResolveInstanceofConditionalsPass())->process($container);
  138. (new ResolveDefinitionTemplatesPass())->process($container);
  139. $def = $container->getDefinition('normal_service');
  140. $this->assertFalse($def->isAutowired());
  141. }
  142. /**
  143. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  144. * @expectedExceptionMessage "App\FakeInterface" is set as an "instanceof" conditional, but it does not exist.
  145. */
  146. public function testBadInterfaceThrowsException()
  147. {
  148. $container = new ContainerBuilder();
  149. $def = $container->register('normal_service', self::class);
  150. $def->setInstanceofConditionals(array(
  151. 'App\\FakeInterface' => (new ChildDefinition(''))
  152. ->addTag('foo_tag'),
  153. ));
  154. (new ResolveInstanceofConditionalsPass())->process($container);
  155. }
  156. public function testBadInterfaceForAutomaticInstanceofIsOk()
  157. {
  158. $container = new ContainerBuilder();
  159. $container->register('normal_service', self::class)
  160. ->setAutoconfigured(true);
  161. $container->registerForAutoconfiguration('App\\FakeInterface')
  162. ->setAutowired(true);
  163. (new ResolveInstanceofConditionalsPass())->process($container);
  164. $this->assertTrue($container->hasDefinition('normal_service'));
  165. }
  166. /**
  167. * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
  168. * @expectedExceptionMessage Autoconfigured instanceof for type "PHPUnit\Framework\TestCase" defines method calls but these are not supported and should be removed.
  169. */
  170. public function testProcessThrowsExceptionForAutoconfiguredCalls()
  171. {
  172. $container = new ContainerBuilder();
  173. $container->registerForAutoconfiguration(parent::class)
  174. ->addMethodCall('setFoo');
  175. (new ResolveInstanceofConditionalsPass())->process($container);
  176. }
  177. /**
  178. * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
  179. * @expectedExceptionMessage Autoconfigured instanceof for type "PHPUnit\Framework\TestCase" defines arguments but these are not supported and should be removed.
  180. */
  181. public function testProcessThrowsExceptionForArguments()
  182. {
  183. $container = new ContainerBuilder();
  184. $container->registerForAutoconfiguration(parent::class)
  185. ->addArgument('bar');
  186. (new ResolveInstanceofConditionalsPass())->process($container);
  187. }
  188. public function testMergeReset()
  189. {
  190. $container = new ContainerBuilder();
  191. $container
  192. ->register('bar', self::class)
  193. ->addArgument('a')
  194. ->addMethodCall('setB')
  195. ->setDecoratedService('foo')
  196. ->addTag('t')
  197. ->setInstanceofConditionals(array(
  198. parent::class => (new ChildDefinition(''))->addTag('bar'),
  199. ))
  200. ;
  201. (new ResolveInstanceofConditionalsPass())->process($container);
  202. $abstract = $container->getDefinition('abstract.instanceof.bar');
  203. $this->assertEmpty($abstract->getArguments());
  204. $this->assertEmpty($abstract->getMethodCalls());
  205. $this->assertNull($abstract->getDecoratedService());
  206. $this->assertEmpty($abstract->getTags());
  207. $this->assertTrue($abstract->isAbstract());
  208. }
  209. }