ContainerTest.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  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;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Component\DependencyInjection\Container;
  13. use Symfony\Component\DependencyInjection\ContainerInterface;
  14. use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
  15. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
  16. use Symfony\Component\DependencyInjection\Scope;
  17. class ContainerTest extends TestCase
  18. {
  19. public function testConstructor()
  20. {
  21. $sc = new Container();
  22. $this->assertSame($sc, $sc->get('service_container'), '__construct() automatically registers itself as a service');
  23. $sc = new Container(new ParameterBag(array('foo' => 'bar')));
  24. $this->assertEquals(array('foo' => 'bar'), $sc->getParameterBag()->all(), '__construct() takes an array of parameters as its first argument');
  25. }
  26. /**
  27. * @dataProvider dataForTestCamelize
  28. */
  29. public function testCamelize($id, $expected)
  30. {
  31. $this->assertEquals($expected, Container::camelize($id), sprintf('Container::camelize("%s")', $id));
  32. }
  33. public function dataForTestCamelize()
  34. {
  35. return array(
  36. array('foo_bar', 'FooBar'),
  37. array('foo.bar', 'Foo_Bar'),
  38. array('foo.bar_baz', 'Foo_BarBaz'),
  39. array('foo._bar', 'Foo_Bar'),
  40. array('foo_.bar', 'Foo_Bar'),
  41. array('_foo', 'Foo'),
  42. array('.foo', '_Foo'),
  43. array('foo_', 'Foo'),
  44. array('foo.', 'Foo_'),
  45. array('foo\bar', 'Foo_Bar'),
  46. );
  47. }
  48. /**
  49. * @dataProvider dataForTestUnderscore
  50. */
  51. public function testUnderscore($id, $expected)
  52. {
  53. $this->assertEquals($expected, Container::underscore($id), sprintf('Container::underscore("%s")', $id));
  54. }
  55. public function dataForTestUnderscore()
  56. {
  57. return array(
  58. array('FooBar', 'foo_bar'),
  59. array('Foo_Bar', 'foo.bar'),
  60. array('Foo_BarBaz', 'foo.bar_baz'),
  61. array('FooBar_BazQux', 'foo_bar.baz_qux'),
  62. array('_Foo', '.foo'),
  63. array('Foo_', 'foo.'),
  64. );
  65. }
  66. public function testCompile()
  67. {
  68. $sc = new Container(new ParameterBag(array('foo' => 'bar')));
  69. $this->assertFalse($sc->getParameterBag()->isResolved(), '->compile() resolves the parameter bag');
  70. $sc->compile();
  71. $this->assertTrue($sc->getParameterBag()->isResolved(), '->compile() resolves the parameter bag');
  72. $this->assertInstanceOf('Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag', $sc->getParameterBag(), '->compile() changes the parameter bag to a FrozenParameterBag instance');
  73. $this->assertEquals(array('foo' => 'bar'), $sc->getParameterBag()->all(), '->compile() copies the current parameters to the new parameter bag');
  74. }
  75. public function testIsFrozen()
  76. {
  77. $sc = new Container(new ParameterBag(array('foo' => 'bar')));
  78. $this->assertFalse($sc->isFrozen(), '->isFrozen() returns false if the parameters are not frozen');
  79. $sc->compile();
  80. $this->assertTrue($sc->isFrozen(), '->isFrozen() returns true if the parameters are frozen');
  81. }
  82. public function testGetParameterBag()
  83. {
  84. $sc = new Container();
  85. $this->assertEquals(array(), $sc->getParameterBag()->all(), '->getParameterBag() returns an empty array if no parameter has been defined');
  86. }
  87. public function testGetSetParameter()
  88. {
  89. $sc = new Container(new ParameterBag(array('foo' => 'bar')));
  90. $sc->setParameter('bar', 'foo');
  91. $this->assertEquals('foo', $sc->getParameter('bar'), '->setParameter() sets the value of a new parameter');
  92. $sc->setParameter('foo', 'baz');
  93. $this->assertEquals('baz', $sc->getParameter('foo'), '->setParameter() overrides previously set parameter');
  94. $sc->setParameter('Foo', 'baz1');
  95. $this->assertEquals('baz1', $sc->getParameter('foo'), '->setParameter() converts the key to lowercase');
  96. $this->assertEquals('baz1', $sc->getParameter('FOO'), '->getParameter() converts the key to lowercase');
  97. try {
  98. $sc->getParameter('baba');
  99. $this->fail('->getParameter() thrown an \InvalidArgumentException if the key does not exist');
  100. } catch (\Exception $e) {
  101. $this->assertInstanceOf('\InvalidArgumentException', $e, '->getParameter() thrown an \InvalidArgumentException if the key does not exist');
  102. $this->assertEquals('You have requested a non-existent parameter "baba".', $e->getMessage(), '->getParameter() thrown an \InvalidArgumentException if the key does not exist');
  103. }
  104. }
  105. public function testGetServiceIds()
  106. {
  107. $sc = new Container();
  108. $sc->set('foo', $obj = new \stdClass());
  109. $sc->set('bar', $obj = new \stdClass());
  110. $this->assertEquals(array('service_container', 'foo', 'bar'), $sc->getServiceIds(), '->getServiceIds() returns all defined service ids');
  111. $sc = new ProjectServiceContainer();
  112. $sc->set('foo', $obj = new \stdClass());
  113. $this->assertEquals(array('scoped', 'scoped_foo', 'scoped_synchronized_foo', 'inactive', 'bar', 'foo_bar', 'foo.baz', 'circular', 'throw_exception', 'throws_exception_on_service_configuration', 'service_container', 'foo'), $sc->getServiceIds(), '->getServiceIds() returns defined service ids by getXXXService() methods, followed by service ids defined by set()');
  114. }
  115. public function testSet()
  116. {
  117. $sc = new Container();
  118. $sc->set('._. \\o/', $foo = new \stdClass());
  119. $this->assertSame($foo, $sc->get('._. \\o/'), '->set() sets a service');
  120. }
  121. public function testSetWithNullResetTheService()
  122. {
  123. $sc = new Container();
  124. $sc->set('foo', null);
  125. $this->assertFalse($sc->has('foo'), '->set() with null service resets the service');
  126. }
  127. /**
  128. * @expectedException \InvalidArgumentException
  129. * @group legacy
  130. */
  131. public function testSetDoesNotAllowPrototypeScope()
  132. {
  133. $c = new Container();
  134. $c->set('foo', new \stdClass(), Container::SCOPE_PROTOTYPE);
  135. }
  136. /**
  137. * @expectedException \RuntimeException
  138. * @group legacy
  139. */
  140. public function testSetDoesNotAllowInactiveScope()
  141. {
  142. $c = new Container();
  143. $c->addScope(new Scope('foo'));
  144. $c->set('foo', new \stdClass(), 'foo');
  145. }
  146. /**
  147. * @group legacy
  148. */
  149. public function testSetAlsoSetsScopedService()
  150. {
  151. $c = new Container();
  152. $c->addScope(new Scope('foo'));
  153. $c->enterScope('foo');
  154. $c->set('foo', $foo = new \stdClass(), 'foo');
  155. $scoped = $this->getField($c, 'scopedServices');
  156. $this->assertArrayHasKey('foo', $scoped['foo'], '->set() sets a scoped service');
  157. $this->assertSame($foo, $scoped['foo']['foo'], '->set() sets a scoped service');
  158. }
  159. /**
  160. * @group legacy
  161. */
  162. public function testSetAlsoCallsSynchronizeService()
  163. {
  164. $c = new ProjectServiceContainer();
  165. $c->addScope(new Scope('foo'));
  166. $c->enterScope('foo');
  167. $c->set('scoped_synchronized_foo', $bar = new \stdClass(), 'foo');
  168. $this->assertTrue($c->synchronized, '->set() calls synchronize*Service() if it is defined for the service');
  169. }
  170. public function testSetReplacesAlias()
  171. {
  172. $c = new ProjectServiceContainer();
  173. $c->set('alias', $foo = new \stdClass());
  174. $this->assertSame($foo, $c->get('alias'), '->set() replaces an existing alias');
  175. }
  176. public function testGet()
  177. {
  178. $sc = new ProjectServiceContainer();
  179. $sc->set('foo', $foo = new \stdClass());
  180. $this->assertSame($foo, $sc->get('foo'), '->get() returns the service for the given id');
  181. $this->assertSame($foo, $sc->get('Foo'), '->get() returns the service for the given id, and converts id to lowercase');
  182. $this->assertSame($sc->__bar, $sc->get('bar'), '->get() returns the service for the given id');
  183. $this->assertSame($sc->__foo_bar, $sc->get('foo_bar'), '->get() returns the service if a get*Method() is defined');
  184. $this->assertSame($sc->__foo_baz, $sc->get('foo.baz'), '->get() returns the service if a get*Method() is defined');
  185. $this->assertSame($sc->__foo_baz, $sc->get('foo\\baz'), '->get() returns the service if a get*Method() is defined');
  186. $sc->set('bar', $bar = new \stdClass());
  187. $this->assertSame($bar, $sc->get('bar'), '->get() prefers to return a service defined with set() than one defined with a getXXXMethod()');
  188. try {
  189. $sc->get('');
  190. $this->fail('->get() throws a \InvalidArgumentException exception if the service is empty');
  191. } catch (\Exception $e) {
  192. $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws a ServiceNotFoundException exception if the service is empty');
  193. }
  194. $this->assertNull($sc->get('', ContainerInterface::NULL_ON_INVALID_REFERENCE), '->get() returns null if the service is empty');
  195. }
  196. public function testGetThrowServiceNotFoundException()
  197. {
  198. $sc = new ProjectServiceContainer();
  199. $sc->set('foo', $foo = new \stdClass());
  200. $sc->set('baz', $foo = new \stdClass());
  201. try {
  202. $sc->get('foo1');
  203. $this->fail('->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException if the key does not exist');
  204. } catch (\Exception $e) {
  205. $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException if the key does not exist');
  206. $this->assertEquals('You have requested a non-existent service "foo1". Did you mean this: "foo"?', $e->getMessage(), '->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException with some advices');
  207. }
  208. try {
  209. $sc->get('bag');
  210. $this->fail('->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException if the key does not exist');
  211. } catch (\Exception $e) {
  212. $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException if the key does not exist');
  213. $this->assertEquals('You have requested a non-existent service "bag". Did you mean one of these: "bar", "baz"?', $e->getMessage(), '->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException with some advices');
  214. }
  215. }
  216. public function testGetCircularReference()
  217. {
  218. $sc = new ProjectServiceContainer();
  219. try {
  220. $sc->get('circular');
  221. $this->fail('->get() throws a ServiceCircularReferenceException if it contains circular reference');
  222. } catch (\Exception $e) {
  223. $this->assertInstanceOf('\Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException', $e, '->get() throws a ServiceCircularReferenceException if it contains circular reference');
  224. $this->assertStringStartsWith('Circular reference detected for service "circular"', $e->getMessage(), '->get() throws a \LogicException if it contains circular reference');
  225. }
  226. }
  227. /**
  228. * @group legacy
  229. */
  230. public function testGetReturnsNullOnInactiveScope()
  231. {
  232. $sc = new ProjectServiceContainer();
  233. $this->assertNull($sc->get('inactive', ContainerInterface::NULL_ON_INVALID_REFERENCE));
  234. }
  235. /**
  236. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  237. * @expectedExceptionMessage You have requested a synthetic service ("request"). The DIC does not know how to construct this service.
  238. */
  239. public function testGetSyntheticServiceAlwaysThrows()
  240. {
  241. require_once __DIR__.'/Fixtures/php/services9.php';
  242. $container = new \ProjectServiceContainer();
  243. $container->get('request', ContainerInterface::NULL_ON_INVALID_REFERENCE);
  244. }
  245. public function testHas()
  246. {
  247. $sc = new ProjectServiceContainer();
  248. $sc->set('foo', new \stdClass());
  249. $this->assertFalse($sc->has('foo1'), '->has() returns false if the service does not exist');
  250. $this->assertTrue($sc->has('foo'), '->has() returns true if the service exists');
  251. $this->assertTrue($sc->has('bar'), '->has() returns true if a get*Method() is defined');
  252. $this->assertTrue($sc->has('foo_bar'), '->has() returns true if a get*Method() is defined');
  253. $this->assertTrue($sc->has('foo.baz'), '->has() returns true if a get*Method() is defined');
  254. $this->assertTrue($sc->has('foo\\baz'), '->has() returns true if a get*Method() is defined');
  255. }
  256. public function testInitialized()
  257. {
  258. $sc = new ProjectServiceContainer();
  259. $sc->set('foo', new \stdClass());
  260. $this->assertTrue($sc->initialized('foo'), '->initialized() returns true if service is loaded');
  261. $this->assertFalse($sc->initialized('foo1'), '->initialized() returns false if service is not loaded');
  262. $this->assertFalse($sc->initialized('bar'), '->initialized() returns false if a service is defined, but not currently loaded');
  263. $this->assertFalse($sc->initialized('alias'), '->initialized() returns false if an aliased service is not initialized');
  264. $sc->set('bar', new \stdClass());
  265. $this->assertTrue($sc->initialized('alias'), '->initialized() returns true for alias if aliased service is initialized');
  266. }
  267. public function testReset()
  268. {
  269. $c = new Container();
  270. $c->set('bar', new \stdClass());
  271. $c->reset();
  272. $this->assertNull($c->get('bar', ContainerInterface::NULL_ON_INVALID_REFERENCE));
  273. }
  274. /**
  275. * @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException
  276. * @expectedExceptionMessage Resetting the container is not allowed when a scope is active.
  277. * @group legacy
  278. */
  279. public function testCannotResetInActiveScope()
  280. {
  281. $c = new Container();
  282. $c->addScope(new Scope('foo'));
  283. $c->set('bar', new \stdClass());
  284. $c->enterScope('foo');
  285. $c->reset();
  286. }
  287. /**
  288. * @group legacy
  289. */
  290. public function testResetAfterLeavingScope()
  291. {
  292. $c = new Container();
  293. $c->addScope(new Scope('foo'));
  294. $c->set('bar', new \stdClass());
  295. $c->enterScope('foo');
  296. $c->leaveScope('foo');
  297. $c->reset();
  298. $this->assertNull($c->get('bar', ContainerInterface::NULL_ON_INVALID_REFERENCE));
  299. }
  300. /**
  301. * @group legacy
  302. */
  303. public function testEnterLeaveCurrentScope()
  304. {
  305. $container = new ProjectServiceContainer();
  306. $container->addScope(new Scope('foo'));
  307. $container->enterScope('foo');
  308. $container->set('foo', new \stdClass(), 'foo');
  309. $scoped1 = $container->get('scoped');
  310. $scopedFoo1 = $container->get('scoped_foo');
  311. $container->enterScope('foo');
  312. $container->set('foo', new \stdClass(), 'foo');
  313. $scoped2 = $container->get('scoped');
  314. $scoped3 = $container->get('SCOPED');
  315. $scopedFoo2 = $container->get('scoped_foo');
  316. $container->set('foo', null, 'foo');
  317. $container->leaveScope('foo');
  318. $scoped4 = $container->get('scoped');
  319. $scopedFoo3 = $container->get('scoped_foo');
  320. $this->assertNotSame($scoped1, $scoped2);
  321. $this->assertSame($scoped2, $scoped3);
  322. $this->assertSame($scoped1, $scoped4);
  323. $this->assertNotSame($scopedFoo1, $scopedFoo2);
  324. $this->assertSame($scopedFoo1, $scopedFoo3);
  325. }
  326. /**
  327. * @group legacy
  328. */
  329. public function testEnterLeaveScopeWithChildScopes()
  330. {
  331. $container = new Container();
  332. $container->addScope(new Scope('foo'));
  333. $container->addScope(new Scope('bar', 'foo'));
  334. $this->assertFalse($container->isScopeActive('foo'));
  335. $container->enterScope('foo');
  336. $container->enterScope('bar');
  337. $this->assertTrue($container->isScopeActive('foo'));
  338. $this->assertFalse($container->has('a'));
  339. $a = new \stdClass();
  340. $container->set('a', $a, 'bar');
  341. $scoped = $this->getField($container, 'scopedServices');
  342. $this->assertArrayHasKey('a', $scoped['bar']);
  343. $this->assertSame($a, $scoped['bar']['a']);
  344. $this->assertTrue($container->has('a'));
  345. $container->leaveScope('foo');
  346. $scoped = $this->getField($container, 'scopedServices');
  347. $this->assertArrayNotHasKey('bar', $scoped);
  348. $this->assertFalse($container->isScopeActive('foo'));
  349. $this->assertFalse($container->has('a'));
  350. }
  351. /**
  352. * @group legacy
  353. */
  354. public function testEnterScopeRecursivelyWithInactiveChildScopes()
  355. {
  356. $container = new Container();
  357. $container->addScope(new Scope('foo'));
  358. $container->addScope(new Scope('bar', 'foo'));
  359. $this->assertFalse($container->isScopeActive('foo'));
  360. $container->enterScope('foo');
  361. $this->assertTrue($container->isScopeActive('foo'));
  362. $this->assertFalse($container->isScopeActive('bar'));
  363. $this->assertFalse($container->has('a'));
  364. $a = new \stdClass();
  365. $container->set('a', $a, 'foo');
  366. $scoped = $this->getField($container, 'scopedServices');
  367. $this->assertArrayHasKey('a', $scoped['foo']);
  368. $this->assertSame($a, $scoped['foo']['a']);
  369. $this->assertTrue($container->has('a'));
  370. $container->enterScope('foo');
  371. $scoped = $this->getField($container, 'scopedServices');
  372. $this->assertArrayNotHasKey('a', $scoped);
  373. $this->assertTrue($container->isScopeActive('foo'));
  374. $this->assertFalse($container->isScopeActive('bar'));
  375. $this->assertFalse($container->has('a'));
  376. $container->enterScope('bar');
  377. $this->assertTrue($container->isScopeActive('bar'));
  378. $container->leaveScope('foo');
  379. $this->assertTrue($container->isScopeActive('foo'));
  380. $this->assertFalse($container->isScopeActive('bar'));
  381. $this->assertTrue($container->has('a'));
  382. }
  383. /**
  384. * @group legacy
  385. */
  386. public function testEnterChildScopeRecursively()
  387. {
  388. $container = new Container();
  389. $container->addScope(new Scope('foo'));
  390. $container->addScope(new Scope('bar', 'foo'));
  391. $container->enterScope('foo');
  392. $container->enterScope('bar');
  393. $this->assertTrue($container->isScopeActive('bar'));
  394. $this->assertFalse($container->has('a'));
  395. $a = new \stdClass();
  396. $container->set('a', $a, 'bar');
  397. $scoped = $this->getField($container, 'scopedServices');
  398. $this->assertArrayHasKey('a', $scoped['bar']);
  399. $this->assertSame($a, $scoped['bar']['a']);
  400. $this->assertTrue($container->has('a'));
  401. $container->enterScope('bar');
  402. $scoped = $this->getField($container, 'scopedServices');
  403. $this->assertArrayNotHasKey('a', $scoped);
  404. $this->assertTrue($container->isScopeActive('foo'));
  405. $this->assertTrue($container->isScopeActive('bar'));
  406. $this->assertFalse($container->has('a'));
  407. $container->leaveScope('bar');
  408. $this->assertTrue($container->isScopeActive('foo'));
  409. $this->assertTrue($container->isScopeActive('bar'));
  410. $this->assertTrue($container->has('a'));
  411. }
  412. /**
  413. * @expectedException \InvalidArgumentException
  414. * @group legacy
  415. */
  416. public function testEnterScopeNotAdded()
  417. {
  418. $container = new Container();
  419. $container->enterScope('foo');
  420. }
  421. /**
  422. * @expectedException \RuntimeException
  423. * @group legacy
  424. */
  425. public function testEnterScopeDoesNotAllowInactiveParentScope()
  426. {
  427. $container = new Container();
  428. $container->addScope(new Scope('foo'));
  429. $container->addScope(new Scope('bar', 'foo'));
  430. $container->enterScope('bar');
  431. }
  432. /**
  433. * @group legacy
  434. */
  435. public function testLeaveScopeNotActive()
  436. {
  437. $container = new Container();
  438. $container->addScope(new Scope('foo'));
  439. try {
  440. $container->leaveScope('foo');
  441. $this->fail('->leaveScope() throws a \LogicException if the scope is not active yet');
  442. } catch (\Exception $e) {
  443. $this->assertInstanceOf('\LogicException', $e, '->leaveScope() throws a \LogicException if the scope is not active yet');
  444. $this->assertEquals('The scope "foo" is not active.', $e->getMessage(), '->leaveScope() throws a \LogicException if the scope is not active yet');
  445. }
  446. try {
  447. $container->leaveScope('bar');
  448. $this->fail('->leaveScope() throws a \LogicException if the scope does not exist');
  449. } catch (\Exception $e) {
  450. $this->assertInstanceOf('\LogicException', $e, '->leaveScope() throws a \LogicException if the scope does not exist');
  451. $this->assertEquals('The scope "bar" is not active.', $e->getMessage(), '->leaveScope() throws a \LogicException if the scope does not exist');
  452. }
  453. }
  454. /**
  455. * @expectedException \InvalidArgumentException
  456. * @dataProvider getLegacyBuiltInScopes
  457. * @group legacy
  458. */
  459. public function testAddScopeDoesNotAllowBuiltInScopes($scope)
  460. {
  461. $container = new Container();
  462. $container->addScope(new Scope($scope));
  463. }
  464. /**
  465. * @expectedException \InvalidArgumentException
  466. * @group legacy
  467. */
  468. public function testAddScopeDoesNotAllowExistingScope()
  469. {
  470. $container = new Container();
  471. $container->addScope(new Scope('foo'));
  472. $container->addScope(new Scope('foo'));
  473. }
  474. /**
  475. * @expectedException \InvalidArgumentException
  476. * @dataProvider getLegacyInvalidParentScopes
  477. * @group legacy
  478. */
  479. public function testAddScopeDoesNotAllowInvalidParentScope($scope)
  480. {
  481. $c = new Container();
  482. $c->addScope(new Scope('foo', $scope));
  483. }
  484. /**
  485. * @group legacy
  486. */
  487. public function testAddScope()
  488. {
  489. $c = new Container();
  490. $c->addScope(new Scope('foo'));
  491. $c->addScope(new Scope('bar', 'foo'));
  492. $this->assertSame(array('foo' => 'container', 'bar' => 'foo'), $this->getField($c, 'scopes'));
  493. $this->assertSame(array('foo' => array('bar'), 'bar' => array()), $this->getField($c, 'scopeChildren'));
  494. $c->addScope(new Scope('baz', 'bar'));
  495. $this->assertSame(array('foo' => 'container', 'bar' => 'foo', 'baz' => 'bar'), $this->getField($c, 'scopes'));
  496. $this->assertSame(array('foo' => array('bar', 'baz'), 'bar' => array('baz'), 'baz' => array()), $this->getField($c, 'scopeChildren'));
  497. }
  498. /**
  499. * @group legacy
  500. */
  501. public function testHasScope()
  502. {
  503. $c = new Container();
  504. $this->assertFalse($c->hasScope('foo'));
  505. $c->addScope(new Scope('foo'));
  506. $this->assertTrue($c->hasScope('foo'));
  507. }
  508. /**
  509. * @expectedException \Exception
  510. * @expectedExceptionMessage Something went terribly wrong!
  511. */
  512. public function testGetThrowsException()
  513. {
  514. $c = new ProjectServiceContainer();
  515. try {
  516. $c->get('throw_exception');
  517. } catch (\Exception $e) {
  518. // Do nothing.
  519. }
  520. // Retry, to make sure that get*Service() will be called.
  521. $c->get('throw_exception');
  522. }
  523. public function testGetThrowsExceptionOnServiceConfiguration()
  524. {
  525. $c = new ProjectServiceContainer();
  526. try {
  527. $c->get('throws_exception_on_service_configuration');
  528. } catch (\Exception $e) {
  529. // Do nothing.
  530. }
  531. $this->assertFalse($c->initialized('throws_exception_on_service_configuration'));
  532. // Retry, to make sure that get*Service() will be called.
  533. try {
  534. $c->get('throws_exception_on_service_configuration');
  535. } catch (\Exception $e) {
  536. // Do nothing.
  537. }
  538. $this->assertFalse($c->initialized('throws_exception_on_service_configuration'));
  539. }
  540. /**
  541. * @group legacy
  542. */
  543. public function testIsScopeActive()
  544. {
  545. $c = new Container();
  546. $this->assertFalse($c->isScopeActive('foo'));
  547. $c->addScope(new Scope('foo'));
  548. $this->assertFalse($c->isScopeActive('foo'));
  549. $c->enterScope('foo');
  550. $this->assertTrue($c->isScopeActive('foo'));
  551. $c->leaveScope('foo');
  552. $this->assertFalse($c->isScopeActive('foo'));
  553. }
  554. public function getLegacyInvalidParentScopes()
  555. {
  556. return array(
  557. array(ContainerInterface::SCOPE_PROTOTYPE),
  558. array('bar'),
  559. );
  560. }
  561. public function getLegacyBuiltInScopes()
  562. {
  563. return array(
  564. array(ContainerInterface::SCOPE_CONTAINER),
  565. array(ContainerInterface::SCOPE_PROTOTYPE),
  566. );
  567. }
  568. protected function getField($obj, $field)
  569. {
  570. $reflection = new \ReflectionProperty($obj, $field);
  571. $reflection->setAccessible(true);
  572. return $reflection->getValue($obj);
  573. }
  574. public function testAlias()
  575. {
  576. $c = new ProjectServiceContainer();
  577. $this->assertTrue($c->has('alias'));
  578. $this->assertSame($c->get('alias'), $c->get('bar'));
  579. }
  580. public function testThatCloningIsNotSupported()
  581. {
  582. $class = new \ReflectionClass('Symfony\Component\DependencyInjection\Container');
  583. $clone = $class->getMethod('__clone');
  584. if (\PHP_VERSION_ID >= 50400) {
  585. $this->assertFalse($class->isCloneable());
  586. }
  587. $this->assertTrue($clone->isPrivate());
  588. }
  589. }
  590. class ProjectServiceContainer extends Container
  591. {
  592. public $__bar;
  593. public $__foo_bar;
  594. public $__foo_baz;
  595. public $synchronized;
  596. public function __construct()
  597. {
  598. parent::__construct();
  599. $this->__bar = new \stdClass();
  600. $this->__foo_bar = new \stdClass();
  601. $this->__foo_baz = new \stdClass();
  602. $this->synchronized = false;
  603. $this->aliases = array('alias' => 'bar');
  604. }
  605. protected function getScopedService()
  606. {
  607. if (!$this->isScopeActive('foo')) {
  608. throw new \RuntimeException('Invalid call');
  609. }
  610. return $this->services['scoped'] = $this->scopedServices['foo']['scoped'] = new \stdClass();
  611. }
  612. protected function getScopedFooService()
  613. {
  614. if (!$this->isScopeActive('foo')) {
  615. throw new \RuntimeException('invalid call');
  616. }
  617. return $this->services['scoped_foo'] = $this->scopedServices['foo']['scoped_foo'] = new \stdClass();
  618. }
  619. protected function getScopedSynchronizedFooService()
  620. {
  621. if (!$this->isScopeActive('foo')) {
  622. throw new \RuntimeException('invalid call');
  623. }
  624. return $this->services['scoped_bar'] = $this->scopedServices['foo']['scoped_bar'] = new \stdClass();
  625. }
  626. protected function synchronizeFooService()
  627. {
  628. // Typically get the service to pass it to a setter
  629. $this->get('foo');
  630. }
  631. protected function synchronizeScopedSynchronizedFooService()
  632. {
  633. $this->synchronized = true;
  634. }
  635. protected function getInactiveService()
  636. {
  637. throw new InactiveScopeException('request', 'request');
  638. }
  639. protected function getBarService()
  640. {
  641. return $this->__bar;
  642. }
  643. protected function getFooBarService()
  644. {
  645. return $this->__foo_bar;
  646. }
  647. protected function getFoo_BazService()
  648. {
  649. return $this->__foo_baz;
  650. }
  651. protected function getCircularService()
  652. {
  653. return $this->get('circular');
  654. }
  655. protected function getThrowExceptionService()
  656. {
  657. throw new \Exception('Something went terribly wrong!');
  658. }
  659. protected function getThrowsExceptionOnServiceConfigurationService()
  660. {
  661. $this->services['throws_exception_on_service_configuration'] = $instance = new \stdClass();
  662. throw new \Exception('Something was terribly wrong while trying to configure the service!');
  663. }
  664. }