5 * Contains \Drupal\Tests\Component\DependencyInjection\ContainerTest.
8 namespace Drupal\Tests\Component\DependencyInjection;
10 use Drupal\Component\Utility\Crypt;
11 use PHPUnit\Framework\TestCase;
12 use Symfony\Component\DependencyInjection\ContainerInterface;
13 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
14 use Symfony\Component\DependencyInjection\Exception\LogicException;
15 use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
16 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
17 use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
18 use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
19 use Prophecy\Argument;
22 * @coversDefaultClass \Drupal\Component\DependencyInjection\Container
23 * @group DependencyInjection
25 class ContainerTest extends TestCase {
28 * The tested container.
30 * @var \Symfony\Component\DependencyInjection\ContainerInterface
35 * The container definition used for the test.
39 protected $containerDefinition;
42 * The container class to be tested.
46 protected $containerClass;
49 * Whether the container uses the machine-optimized format or not.
53 protected $machineFormat;
58 protected function setUp() {
59 $this->machineFormat = TRUE;
60 $this->containerClass = '\Drupal\Component\DependencyInjection\Container';
61 $this->containerDefinition = $this->getMockContainerDefinition();
62 $this->container = new $this->containerClass($this->containerDefinition);
66 * Tests that passing a non-supported format throws an InvalidArgumentException.
68 * @covers ::__construct
70 public function testConstruct() {
71 $container_definition = $this->getMockContainerDefinition();
72 $container_definition['machine_format'] = !$this->machineFormat;
73 if (method_exists($this, 'expectException')) {
74 $this->expectException(InvalidArgumentException::class);
77 $this->setExpectedException(InvalidArgumentException::class);
79 $container = new $this->containerClass($container_definition);
83 * Tests that Container::getParameter() works properly.
85 * @covers ::getParameter
87 public function testGetParameter() {
88 $this->assertEquals($this->containerDefinition['parameters']['some_config'], $this->container->getParameter('some_config'), 'Container parameter matches for %some_config%.');
89 $this->assertEquals($this->containerDefinition['parameters']['some_other_config'], $this->container->getParameter('some_other_config'), 'Container parameter matches for %some_other_config%.');
93 * Tests that Container::getParameter() works properly for non-existing
96 * @covers ::getParameter
97 * @covers ::getParameterAlternatives
98 * @covers ::getAlternatives
100 public function testGetParameterIfNotFound() {
101 if (method_exists($this, 'expectException')) {
102 $this->expectException(ParameterNotFoundException::class);
105 $this->setExpectedException(ParameterNotFoundException::class);
107 $this->container->getParameter('parameter_that_does_not_exist');
111 * Tests that Container::getParameter() works properly for NULL parameters.
113 * @covers ::getParameter
115 public function testGetParameterIfNotFoundBecauseNull() {
116 if (method_exists($this, 'expectException')) {
117 $this->expectException(ParameterNotFoundException::class);
120 $this->setExpectedException(ParameterNotFoundException::class);
122 $this->container->getParameter(NULL);
126 * Tests that Container::hasParameter() works properly.
128 * @covers ::hasParameter
130 public function testHasParameter() {
131 $this->assertTrue($this->container->hasParameter('some_config'), 'Container parameters include %some_config%.');
132 $this->assertFalse($this->container->hasParameter('some_config_not_exists'), 'Container parameters do not include %some_config_not_exists%.');
136 * Tests that Container::setParameter() in an unfrozen case works properly.
138 * @covers ::setParameter
140 public function testSetParameterWithUnfrozenContainer() {
141 $container_definition = $this->containerDefinition;
142 $container_definition['frozen'] = FALSE;
143 $this->container = new $this->containerClass($container_definition);
144 $this->container->setParameter('some_config', 'new_value');
145 $this->assertEquals('new_value', $this->container->getParameter('some_config'), 'Container parameters can be set.');
149 * Tests that Container::setParameter() in a frozen case works properly.
151 * @covers ::setParameter
153 public function testSetParameterWithFrozenContainer() {
154 $this->container = new $this->containerClass($this->containerDefinition);
155 if (method_exists($this, 'expectException')) {
156 $this->expectException(LogicException::class);
159 $this->setExpectedException(LogicException::class);
161 $this->container->setParameter('some_config', 'new_value');
165 * Tests that Container::get() works properly.
168 * @covers ::createService
170 public function testGet() {
171 $container = $this->container->get('service_container');
172 $this->assertSame($this->container, $container, 'Container can be retrieved from itself.');
174 // Retrieve services of the container.
175 $other_service_class = $this->containerDefinition['services']['other.service']['class'];
176 $other_service = $this->container->get('other.service');
177 $this->assertInstanceOf($other_service_class, $other_service, 'other.service has the right class.');
179 $some_parameter = $this->containerDefinition['parameters']['some_config'];
180 $some_other_parameter = $this->containerDefinition['parameters']['some_other_config'];
182 $service = $this->container->get('service.provider');
184 $this->assertEquals($other_service, $service->getSomeOtherService(), '@other.service was injected via constructor.');
185 $this->assertEquals($some_parameter, $service->getSomeParameter(), '%some_config% was injected via constructor.');
186 $this->assertEquals($this->container, $service->getContainer(), 'Container was injected via setter injection.');
187 $this->assertEquals($some_other_parameter, $service->getSomeOtherParameter(), '%some_other_config% was injected via setter injection.');
188 $this->assertEquals($service->_someProperty, 'foo', 'Service has added properties.');
192 * Tests that Container::get() for non-shared services works properly.
195 * @covers ::createService
197 public function testGetForNonSharedService() {
198 $service = $this->container->get('non_shared_service');
199 $service2 = $this->container->get('non_shared_service');
201 $this->assertNotSame($service, $service2, 'Non shared services are always re-instantiated.');
205 * Tests that Container::get() works properly for class from parameters.
208 * @covers ::createService
210 public function testGetForClassFromParameter() {
211 $container_definition = $this->containerDefinition;
212 $container_definition['frozen'] = FALSE;
213 $container = new $this->containerClass($container_definition);
215 $other_service_class = $this->containerDefinition['parameters']['some_parameter_class'];
216 $other_service = $container->get('other.service_class_from_parameter');
217 $this->assertInstanceOf($other_service_class, $other_service, 'other.service_class_from_parameter has the right class.');
221 * Tests that Container::set() works properly.
225 public function testSet() {
226 $this->assertNull($this->container->get('new_id', ContainerInterface::NULL_ON_INVALID_REFERENCE));
227 $mock_service = new MockService();
228 $this->container->set('new_id', $mock_service);
230 $this->assertSame($mock_service, $this->container->get('new_id'), 'A manual set service works as expected.');
234 * Tests that Container::has() works properly.
238 public function testHas() {
239 $this->assertTrue($this->container->has('other.service'));
240 $this->assertFalse($this->container->has('another.service'));
242 // Set the service manually, ensure that its also respected.
243 $mock_service = new MockService();
244 $this->container->set('another.service', $mock_service);
245 $this->assertTrue($this->container->has('another.service'));
249 * Tests that Container::has() for aliased services works properly.
253 public function testHasForAliasedService() {
254 $service = $this->container->has('service.provider');
255 $aliased_service = $this->container->has('service.provider_alias');
256 $this->assertSame($service, $aliased_service);
260 * Tests that Container::get() for circular dependencies works properly.
262 * @covers ::createService
264 public function testGetForCircularServices() {
265 if (method_exists($this, 'expectException')) {
266 $this->expectException(ServiceCircularReferenceException::class);
269 $this->setExpectedException(ServiceCircularReferenceException::class);
271 $this->container->get('circular_dependency');
275 * Tests that Container::get() for non-existent services works properly.
278 * @covers ::createService
279 * @covers ::getAlternatives
280 * @covers ::getServiceAlternatives
282 public function testGetForNonExistantService() {
283 if (method_exists($this, 'expectException')) {
284 $this->expectException(ServiceNotFoundException::class);
287 $this->setExpectedException(ServiceNotFoundException::class);
289 $this->container->get('service_not_exists');
293 * Tests that Container::get() for a serialized definition works properly.
296 * @covers ::createService
298 public function testGetForSerializedServiceDefinition() {
299 $container_definition = $this->containerDefinition;
300 $container_definition['services']['other.service'] = serialize($container_definition['services']['other.service']);
301 $container = new $this->containerClass($container_definition);
303 // Retrieve services of the container.
304 $other_service_class = $this->containerDefinition['services']['other.service']['class'];
305 $other_service = $container->get('other.service');
306 $this->assertInstanceOf($other_service_class, $other_service, 'other.service has the right class.');
308 $service = $container->get('service.provider');
309 $this->assertEquals($other_service, $service->getSomeOtherService(), '@other.service was injected via constructor.');
313 * Tests that Container::get() for non-existent parameters works properly.
316 * @covers ::createService
317 * @covers ::resolveServicesAndParameters
319 public function testGetForNonExistantParameterDependency() {
320 $service = $this->container->get('service_parameter_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE);
321 $this->assertNull($service, 'Service is NULL.');
325 * Tests Container::get() with an exception due to missing parameter on the second call.
328 * @covers ::createService
329 * @covers ::resolveServicesAndParameters
331 public function testGetForParameterDependencyWithExceptionOnSecondCall() {
332 $service = $this->container->get('service_parameter_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE);
333 $this->assertNull($service, 'Service is NULL.');
335 // Reset the service.
336 $this->container->set('service_parameter_not_exists', NULL);
337 if (method_exists($this, 'expectException')) {
338 $this->expectException(InvalidArgumentException::class);
341 $this->setExpectedException(InvalidArgumentException::class);
343 $this->container->get('service_parameter_not_exists');
347 * Tests that Container::get() for non-existent parameters works properly.
350 * @covers ::createService
351 * @covers ::resolveServicesAndParameters
353 public function testGetForNonExistantParameterDependencyWithException() {
354 if (method_exists($this, 'expectException')) {
355 $this->expectException(InvalidArgumentException::class);
358 $this->setExpectedException(InvalidArgumentException::class);
360 $this->container->get('service_parameter_not_exists');
364 * Tests that Container::get() for non-existent dependencies works properly.
367 * @covers ::createService
368 * @covers ::resolveServicesAndParameters
370 public function testGetForNonExistantServiceDependency() {
371 $service = $this->container->get('service_dependency_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE);
372 $this->assertNull($service, 'Service is NULL.');
376 * Tests that Container::get() for non-existent dependencies works properly.
379 * @covers ::createService
380 * @covers ::resolveServicesAndParameters
381 * @covers ::getAlternatives
383 public function testGetForNonExistantServiceDependencyWithException() {
384 if (method_exists($this, 'expectException')) {
385 $this->expectException(ServiceNotFoundException::class);
388 $this->setExpectedException(ServiceNotFoundException::class);
390 $this->container->get('service_dependency_not_exists');
394 * Tests that Container::get() for non-existent services works properly.
397 * @covers ::createService
399 public function testGetForNonExistantServiceWhenUsingNull() {
400 $this->assertNull($this->container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does not throw exception.');
404 * Tests that Container::get() for NULL service works properly.
406 * @covers ::createService
408 public function testGetForNonExistantNULLService() {
409 if (method_exists($this, 'expectException')) {
410 $this->expectException(ServiceNotFoundException::class);
413 $this->setExpectedException(ServiceNotFoundException::class);
415 $this->container->get(NULL);
419 * Tests multiple Container::get() calls for non-existing dependencies work.
422 * @covers ::createService
424 public function testGetForNonExistantServiceMultipleTimes() {
425 $container = new $this->containerClass();
427 $this->assertNull($container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does not throw exception.');
428 $this->assertNull($container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does not throw exception on second call.');
432 * Tests multiple Container::get() calls with exception on the second time.
435 * @covers ::createService
436 * @covers ::getAlternatives
438 public function testGetForNonExistantServiceWithExceptionOnSecondCall() {
439 $this->assertNull($this->container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does nto throw exception.');
440 if (method_exists($this, 'expectException')) {
441 $this->expectException(ServiceNotFoundException::class);
444 $this->setExpectedException(ServiceNotFoundException::class);
446 $this->container->get('service_not_exists');
450 * Tests that Container::get() for aliased services works properly.
453 * @covers ::createService
455 public function testGetForAliasedService() {
456 $service = $this->container->get('service.provider');
457 $aliased_service = $this->container->get('service.provider_alias');
458 $this->assertSame($service, $aliased_service);
462 * Tests that Container::get() for synthetic services works - if defined.
465 * @covers ::createService
467 public function testGetForSyntheticService() {
468 $synthetic_service = new \stdClass();
469 $this->container->set('synthetic', $synthetic_service);
470 $test_service = $this->container->get('synthetic');
471 $this->assertSame($synthetic_service, $test_service);
475 * Tests that Container::get() for synthetic services throws an Exception if not defined.
478 * @covers ::createService
480 public function testGetForSyntheticServiceWithException() {
481 if (method_exists($this, 'expectException')) {
482 $this->expectException(RuntimeException::class);
485 $this->setExpectedException(RuntimeException::class);
487 $this->container->get('synthetic');
491 * Tests that Container::get() for services with file includes works.
494 * @covers ::createService
496 public function testGetWithFileInclude() {
497 $file_service = $this->container->get('container_test_file_service_test');
498 $this->assertTrue(function_exists('container_test_file_service_test_service_function'));
499 $this->assertEquals('Hello Container', container_test_file_service_test_service_function());
503 * Tests that Container::get() for various arguments lengths works.
506 * @covers ::createService
507 * @covers ::resolveServicesAndParameters
509 public function testGetForInstantiationWithVariousArgumentLengths() {
511 for ($i = 0; $i < 12; $i++) {
512 $instantiation_service = $this->container->get('service_test_instantiation_' . $i);
513 $this->assertEquals($args, $instantiation_service->getArguments());
514 $args[] = 'arg_' . $i;
519 * Tests that Container::get() for wrong factories works correctly.
522 * @covers ::createService
524 public function testGetForWrongFactory() {
525 if (method_exists($this, 'expectException')) {
526 $this->expectException(RuntimeException::class);
529 $this->setExpectedException(RuntimeException::class);
531 $this->container->get('wrong_factory');
535 * Tests Container::get() for factories via services (Symfony 2.7.0).
538 * @covers ::createService
540 public function testGetForFactoryService() {
541 $factory_service = $this->container->get('factory_service');
542 $factory_service_class = $this->container->getParameter('factory_service_class');
543 $this->assertInstanceOf($factory_service_class, $factory_service);
547 * Tests that Container::get() for factories via class works (Symfony 2.7.0).
550 * @covers ::createService
552 public function testGetForFactoryClass() {
553 $service = $this->container->get('service.provider');
554 $factory_service = $this->container->get('factory_class');
556 $this->assertInstanceOf(get_class($service), $factory_service);
557 $this->assertEquals('bar', $factory_service->getSomeParameter(), 'Correct parameter was passed via the factory class instantiation.');
558 $this->assertEquals($this->container, $factory_service->getContainer(), 'Container was injected via setter injection.');
562 * Tests that Container::get() for configurable services throws an Exception.
565 * @covers ::createService
567 public function testGetForConfiguratorWithException() {
568 if (method_exists($this, 'expectException')) {
569 $this->expectException(InvalidArgumentException::class);
572 $this->setExpectedException(InvalidArgumentException::class);
574 $this->container->get('configurable_service_exception');
578 * Tests that Container::get() for configurable services works.
581 * @covers ::createService
583 public function testGetForConfigurator() {
584 $container = $this->container;
586 // Setup a configurator.
587 $configurator = $this->prophesize('\Drupal\Tests\Component\DependencyInjection\MockConfiguratorInterface');
588 $configurator->configureService(Argument::type('object'))
590 ->will(function ($args) use ($container) {
591 $args[0]->setContainer($container);
593 $container->set('configurator', $configurator->reveal());
595 // Test that the configurator worked.
596 $service = $container->get('configurable_service');
597 $this->assertSame($container, $service->getContainer(), 'Container was injected via configurator.');
601 * Tests that private services work correctly.
604 * @covers ::createService
605 * @covers ::resolveServicesAndParameters
607 public function testResolveServicesAndParametersForPrivateService() {
608 $service = $this->container->get('service_using_private');
609 $private_service = $service->getSomeOtherService();
610 $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.');
612 // Test that sharing the same private services works.
613 $service = $this->container->get('another_service_using_private');
614 $another_private_service = $service->getSomeOtherService();
615 $this->assertNotSame($private_service, $another_private_service, 'Private service is not shared.');
616 $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.');
620 * Tests that private service sharing works correctly.
623 * @covers ::createService
624 * @covers ::resolveServicesAndParameters
626 public function testResolveServicesAndParametersForSharedPrivateService() {
627 $service = $this->container->get('service_using_shared_private');
628 $private_service = $service->getSomeOtherService();
629 $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.');
631 // Test that sharing the same private services works.
632 $service = $this->container->get('another_service_using_shared_private');
633 $same_private_service = $service->getSomeOtherService();
634 $this->assertSame($private_service, $same_private_service, 'Private service is shared.');
635 $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.');
639 * Tests that services with an array of arguments work correctly.
642 * @covers ::createService
643 * @covers ::resolveServicesAndParameters
645 public function testResolveServicesAndParametersForArgumentsUsingDeepArray() {
646 $service = $this->container->get('service_using_array');
647 $other_service = $this->container->get('other.service');
648 $this->assertEquals($other_service, $service->getSomeOtherService(), '@other.service was injected via constructor.');
652 * Tests that services that are optional work correctly.
655 * @covers ::createService
656 * @covers ::resolveServicesAndParameters
658 public function testResolveServicesAndParametersForOptionalServiceDependencies() {
659 $service = $this->container->get('service_with_optional_dependency');
660 $this->assertNull($service->getSomeOtherService(), 'other service was NULL was expected.');
664 * Tests that an invalid argument throw an Exception.
667 * @covers ::createService
668 * @covers ::resolveServicesAndParameters
670 public function testResolveServicesAndParametersForInvalidArgument() {
671 if (method_exists($this, 'expectException')) {
672 $this->expectException(InvalidArgumentException::class);
675 $this->setExpectedException(InvalidArgumentException::class);
677 $this->container->get('invalid_argument_service');
681 * Tests that invalid arguments throw an Exception.
684 * @covers ::createService
685 * @covers ::resolveServicesAndParameters
687 public function testResolveServicesAndParametersForInvalidArguments() {
688 // In case the machine-optimized format is not used, we need to simulate the
690 if (method_exists($this, 'expectException')) {
691 $this->expectException(InvalidArgumentException::class);
694 $this->setExpectedException(InvalidArgumentException::class);
696 if (!$this->machineFormat) {
697 throw new InvalidArgumentException('Simulating the test failure.');
699 $this->container->get('invalid_arguments_service');
703 * Tests that a parameter that points to a service works correctly.
706 * @covers ::createService
707 * @covers ::resolveServicesAndParameters
709 public function testResolveServicesAndParametersForServiceInstantiatedFromParameter() {
710 $service = $this->container->get('service.provider');
711 $test_service = $this->container->get('service_with_parameter_service');
712 $this->assertSame($service, $test_service->getSomeOtherService(), 'Service was passed via parameter.');
716 * Tests that Container::initialized works correctly.
718 * @covers ::initialized
720 public function testInitialized() {
721 $this->assertFalse($this->container->initialized('late.service'), 'Late service is not initialized.');
722 $this->container->get('late.service');
723 $this->assertTrue($this->container->initialized('late.service'), 'Late service is initialized after it was retrieved once.');
727 * Tests that Container::initialized works correctly for aliases.
729 * @covers ::initialized
731 public function testInitializedForAliases() {
732 $this->assertFalse($this->container->initialized('late.service_alias'), 'Late service is not initialized.');
733 $this->container->get('late.service');
734 $this->assertTrue($this->container->initialized('late.service_alias'), 'Late service is initialized after it was retrieved once.');
738 * Tests that Container::getServiceIds() works properly.
740 * @covers ::getServiceIds
742 public function testGetServiceIds() {
743 $service_definition_keys = array_keys($this->containerDefinition['services']);
744 $this->assertEquals($service_definition_keys, $this->container->getServiceIds(), 'Retrieved service IDs match definition.');
746 $mock_service = new MockService();
747 $this->container->set('bar', $mock_service);
748 $this->container->set('service.provider', $mock_service);
749 $service_definition_keys[] = 'bar';
751 $this->assertEquals($service_definition_keys, $this->container->getServiceIds(), 'Retrieved service IDs match definition after setting new services.');
755 * Gets a mock container definition.
758 * Associated array with parameters and services.
760 protected function getMockContainerDefinition() {
761 $fake_service = new \stdClass();
763 $parameters['some_parameter_class'] = get_class($fake_service);
764 $parameters['some_private_config'] = 'really_private_lama';
765 $parameters['some_config'] = 'foo';
766 $parameters['some_other_config'] = 'lama';
767 $parameters['factory_service_class'] = get_class($fake_service);
768 // Also test alias resolving.
769 $parameters['service_from_parameter'] = $this->getServiceCall('service.provider_alias');
772 $services['service_container'] = [
773 'class' => '\Drupal\service_container\DependencyInjection\Container',
775 $services['other.service'] = [
776 'class' => get_class($fake_service),
779 $services['non_shared_service'] = [
780 'class' => get_class($fake_service),
784 $services['other.service_class_from_parameter'] = [
785 'class' => $this->getParameterCall('some_parameter_class'),
787 $services['late.service'] = [
788 'class' => get_class($fake_service),
790 $services['service.provider'] = [
791 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
792 'arguments' => $this->getCollection([
793 $this->getServiceCall('other.service'),
794 $this->getParameterCall('some_config'),
796 'properties' => $this->getCollection(['_someProperty' => 'foo']),
800 $this->getCollection([
801 $this->getServiceCall('service_container'),
805 'setOtherConfigParameter',
806 $this->getCollection([
807 $this->getParameterCall('some_other_config'),
814 // Test private services.
816 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
817 'arguments' => $this->getCollection([
818 $this->getServiceCall('other.service'),
819 $this->getParameterCall('some_private_config'),
824 $services['service_using_private'] = [
825 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
826 'arguments' => $this->getCollection([
827 $this->getPrivateServiceCall(NULL, $private_service),
828 $this->getParameterCall('some_config'),
831 $services['another_service_using_private'] = [
832 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
833 'arguments' => $this->getCollection([
834 $this->getPrivateServiceCall(NULL, $private_service),
835 $this->getParameterCall('some_config'),
839 // Test shared private services.
840 $id = 'private_service_shared_1';
842 $services['service_using_shared_private'] = [
843 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
844 'arguments' => $this->getCollection([
845 $this->getPrivateServiceCall($id, $private_service, TRUE),
846 $this->getParameterCall('some_config'),
849 $services['another_service_using_shared_private'] = [
850 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
851 'arguments' => $this->getCollection([
852 $this->getPrivateServiceCall($id, $private_service, TRUE),
853 $this->getParameterCall('some_config'),
857 // Tests service with invalid argument.
858 $services['invalid_argument_service'] = [
859 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
860 'arguments' => $this->getCollection([
861 // Test passing non-strings, too.
869 $services['invalid_arguments_service'] = [
870 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
871 'arguments' => (object) [
876 // Test service that needs deep-traversal.
877 $services['service_using_array'] = [
878 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
879 'arguments' => $this->getCollection([
880 $this->getCollection([
881 $this->getServiceCall('other.service'),
883 $this->getParameterCall('some_private_config'),
887 $services['service_with_optional_dependency'] = [
888 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
889 'arguments' => $this->getCollection([
890 $this->getServiceCall('service.does_not_exist', ContainerInterface::NULL_ON_INVALID_REFERENCE),
891 $this->getParameterCall('some_private_config'),
896 $services['factory_service'] = [
897 'class' => '\Drupal\service_container\ServiceContainer\ControllerInterface',
899 $this->getServiceCall('service.provider'),
902 'arguments' => $this->getCollection([
903 $this->getParameterCall('factory_service_class'),
906 $services['factory_class'] = [
907 'class' => '\Drupal\service_container\ServiceContainer\ControllerInterface',
908 'factory' => '\Drupal\Tests\Component\DependencyInjection\MockService::getFactoryMethod',
910 '\Drupal\Tests\Component\DependencyInjection\MockService',
916 $this->getCollection([
917 $this->getServiceCall('service_container'),
923 $services['wrong_factory'] = [
924 'class' => '\Drupal\service_container\ServiceContainer\ControllerInterface',
925 'factory' => (object) ['I am not a factory, but I pretend to be.'],
928 $services['circular_dependency'] = [
929 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
930 'arguments' => $this->getCollection([
931 $this->getServiceCall('circular_dependency'),
934 $services['synthetic'] = [
937 // The file could have been named as a .php file. The reason it is a .data
938 // file is that SimpleTest tries to load it. SimpleTest does not like such
939 // fixtures and hence we use a neutral name like .data.
940 $services['container_test_file_service_test'] = [
941 'class' => '\stdClass',
942 'file' => __DIR__ . '/Fixture/container_test_file_service_test_service_function.data',
945 // Test multiple arguments.
947 for ($i = 0; $i < 12; $i++) {
948 $services['service_test_instantiation_' . $i] = [
949 'class' => '\Drupal\Tests\Component\DependencyInjection\MockInstantiationService',
950 // Also test a collection that does not need resolving.
951 'arguments' => $this->getCollection($args, FALSE),
953 $args[] = 'arg_' . $i;
956 $services['service_parameter_not_exists'] = [
957 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
958 'arguments' => $this->getCollection([
959 $this->getServiceCall('service.provider'),
960 $this->getParameterCall('not_exists'),
963 $services['service_dependency_not_exists'] = [
964 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
965 'arguments' => $this->getCollection([
966 $this->getServiceCall('service_not_exists'),
967 $this->getParameterCall('some_config'),
971 $services['service_with_parameter_service'] = [
972 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
973 'arguments' => $this->getCollection([
974 $this->getParameterCall('service_from_parameter'),
975 // Also test deep collections that don't need resolving.
976 $this->getCollection([
982 // To ensure getAlternatives() finds something.
983 $services['service_not_exists_similar'] = [
987 // Test configurator.
988 $services['configurator'] = [
991 $services['configurable_service'] = [
992 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
995 $this->getServiceCall('configurator'),
999 $services['configurable_service_exception'] = [
1000 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
1002 'configurator' => 'configurator_service_test_does_not_exist',
1006 $aliases['service.provider_alias'] = 'service.provider';
1007 $aliases['late.service_alias'] = 'late.service';
1010 'aliases' => $aliases,
1011 'parameters' => $parameters,
1012 'services' => $services,
1014 'machine_format' => $this->machineFormat,
1019 * Helper function to return a service definition.
1021 protected function getServiceCall($id, $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
1023 'type' => 'service',
1025 'invalidBehavior' => $invalid_behavior,
1030 * Helper function to return a service definition.
1032 protected function getParameterCall($name) {
1034 'type' => 'parameter',
1040 * Helper function to return a private service definition.
1042 protected function getPrivateServiceCall($id, $service_definition, $shared = FALSE) {
1044 $hash = Crypt::hashBase64(serialize($service_definition));
1045 $id = 'private__' . $hash;
1048 'type' => 'private_service',
1050 'value' => $service_definition,
1051 'shared' => $shared,
1056 * Helper function to return a machine-optimized collection.
1058 protected function getCollection($collection, $resolve = TRUE) {
1060 'type' => 'collection',
1061 'value' => $collection,
1062 'resolve' => $resolve,
1069 * Helper interface to test Container::get() with configurator.
1071 * @group DependencyInjection
1073 interface MockConfiguratorInterface {
1076 * Configures a service.
1078 * @param object $service
1079 * The service to configure.
1081 public function configureService($service);
1087 * Helper class to test Container::get() method for varying number of parameters.
1089 * @group DependencyInjection
1091 class MockInstantiationService {
1096 protected $arguments;
1099 * Construct a mock instantiation service.
1101 public function __construct() {
1102 $this->arguments = func_get_args();
1106 * Return arguments injected into the service.
1109 * Return the passed arguments.
1111 public function getArguments() {
1112 return $this->arguments;
1119 * Helper class to test Container::get() method.
1121 * @group DependencyInjection
1126 * @var \Symfony\Component\DependencyInjection\ContainerInterface
1128 protected $container;
1133 protected $someOtherService;
1138 protected $someParameter;
1143 protected $someOtherParameter;
1146 * Constructs a MockService object.
1148 * @param object $some_other_service
1149 * (optional) Another injected service.
1150 * @param string $some_parameter
1151 * (optional) An injected parameter.
1153 public function __construct($some_other_service = NULL, $some_parameter = NULL) {
1154 if (is_array($some_other_service)) {
1155 $some_other_service = $some_other_service[0];
1157 $this->someOtherService = $some_other_service;
1158 $this->someParameter = $some_parameter;
1162 * Sets the container object.
1164 * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
1165 * The container to inject via setter injection.
1167 public function setContainer(ContainerInterface $container) {
1168 $this->container = $container;
1172 * Gets the container object.
1174 * @return \Symfony\Component\DependencyInjection\ContainerInterface
1175 * The internally set container.
1177 public function getContainer() {
1178 return $this->container;
1182 * Gets the someOtherService object.
1185 * The injected service.
1187 public function getSomeOtherService() {
1188 return $this->someOtherService;
1192 * Gets the someParameter property.
1195 * The injected parameter.
1197 public function getSomeParameter() {
1198 return $this->someParameter;
1202 * Sets the someOtherParameter property.
1204 * @param string $some_other_parameter
1205 * The setter injected parameter.
1207 public function setOtherConfigParameter($some_other_parameter) {
1208 $this->someOtherParameter = $some_other_parameter;
1212 * Gets the someOtherParameter property.
1215 * The injected parameter.
1217 public function getSomeOtherParameter() {
1218 return $this->someOtherParameter;
1222 * Provides a factory method to get a service.
1224 * @param string $class
1225 * The class name of the class to instantiate
1226 * @param array $arguments
1227 * (optional) Arguments to pass to the new class.
1230 * The instantiated service object.
1232 public static function getFactoryMethod($class, $arguments = []) {
1233 $r = new \ReflectionClass($class);
1234 $service = ($r->getConstructor() === NULL) ? $r->newInstance() : $r->newInstanceArgs($arguments);