5 * Contains \Drupal\Tests\Component\DependencyInjection\ContainerTest.
8 namespace Drupal\Tests\Component\DependencyInjection;
10 use Drupal\Component\Utility\Crypt;
11 use Symfony\Component\DependencyInjection\ContainerInterface;
12 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
13 use Symfony\Component\DependencyInjection\Exception\LogicException;
14 use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
15 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
16 use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
17 use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
18 use Prophecy\Argument;
21 * @coversDefaultClass \Drupal\Component\DependencyInjection\Container
22 * @group DependencyInjection
24 class ContainerTest extends \PHPUnit_Framework_TestCase {
27 * The tested container.
29 * @var \Symfony\Component\DependencyInjection\ContainerInterface
34 * The container definition used for the test.
38 protected $containerDefinition;
41 * The container class to be tested.
45 protected $containerClass;
48 * Whether the container uses the machine-optimized format or not.
52 protected $machineFormat;
57 protected function setUp() {
58 $this->machineFormat = TRUE;
59 $this->containerClass = '\Drupal\Component\DependencyInjection\Container';
60 $this->containerDefinition = $this->getMockContainerDefinition();
61 $this->container = new $this->containerClass($this->containerDefinition);
65 * Tests that passing a non-supported format throws an InvalidArgumentException.
67 * @covers ::__construct
69 public function testConstruct() {
70 $container_definition = $this->getMockContainerDefinition();
71 $container_definition['machine_format'] = !$this->machineFormat;
72 $this->setExpectedException(InvalidArgumentException::class);
73 $container = new $this->containerClass($container_definition);
77 * Tests that Container::getParameter() works properly.
79 * @covers ::getParameter
81 public function testGetParameter() {
82 $this->assertEquals($this->containerDefinition['parameters']['some_config'], $this->container->getParameter('some_config'), 'Container parameter matches for %some_config%.');
83 $this->assertEquals($this->containerDefinition['parameters']['some_other_config'], $this->container->getParameter('some_other_config'), 'Container parameter matches for %some_other_config%.');
87 * Tests that Container::getParameter() works properly for non-existing
90 * @covers ::getParameter
91 * @covers ::getParameterAlternatives
92 * @covers ::getAlternatives
94 public function testGetParameterIfNotFound() {
95 $this->setExpectedException(ParameterNotFoundException::class);
96 $this->container->getParameter('parameter_that_does_not_exist');
100 * Tests that Container::getParameter() works properly for NULL parameters.
102 * @covers ::getParameter
104 public function testGetParameterIfNotFoundBecauseNull() {
105 $this->setExpectedException(ParameterNotFoundException::class);
106 $this->container->getParameter(NULL);
110 * Tests that Container::hasParameter() works properly.
112 * @covers ::hasParameter
114 public function testHasParameter() {
115 $this->assertTrue($this->container->hasParameter('some_config'), 'Container parameters include %some_config%.');
116 $this->assertFalse($this->container->hasParameter('some_config_not_exists'), 'Container parameters do not include %some_config_not_exists%.');
120 * Tests that Container::setParameter() in an unfrozen case works properly.
122 * @covers ::setParameter
124 public function testSetParameterWithUnfrozenContainer() {
125 $container_definition = $this->containerDefinition;
126 $container_definition['frozen'] = FALSE;
127 $this->container = new $this->containerClass($container_definition);
128 $this->container->setParameter('some_config', 'new_value');
129 $this->assertEquals('new_value', $this->container->getParameter('some_config'), 'Container parameters can be set.');
133 * Tests that Container::setParameter() in a frozen case works properly.
135 * @covers ::setParameter
137 public function testSetParameterWithFrozenContainer() {
138 $this->container = new $this->containerClass($this->containerDefinition);
139 $this->setExpectedException(LogicException::class);
140 $this->container->setParameter('some_config', 'new_value');
144 * Tests that Container::get() works properly.
147 * @covers ::createService
149 public function testGet() {
150 $container = $this->container->get('service_container');
151 $this->assertSame($this->container, $container, 'Container can be retrieved from itself.');
153 // Retrieve services of the container.
154 $other_service_class = $this->containerDefinition['services']['other.service']['class'];
155 $other_service = $this->container->get('other.service');
156 $this->assertInstanceOf($other_service_class, $other_service, 'other.service has the right class.');
158 $some_parameter = $this->containerDefinition['parameters']['some_config'];
159 $some_other_parameter = $this->containerDefinition['parameters']['some_other_config'];
161 $service = $this->container->get('service.provider');
163 $this->assertEquals($other_service, $service->getSomeOtherService(), '@other.service was injected via constructor.');
164 $this->assertEquals($some_parameter, $service->getSomeParameter(), '%some_config% was injected via constructor.');
165 $this->assertEquals($this->container, $service->getContainer(), 'Container was injected via setter injection.');
166 $this->assertEquals($some_other_parameter, $service->getSomeOtherParameter(), '%some_other_config% was injected via setter injection.');
167 $this->assertEquals($service->_someProperty, 'foo', 'Service has added properties.');
171 * Tests that Container::get() for non-shared services works properly.
174 * @covers ::createService
176 public function testGetForNonSharedService() {
177 $service = $this->container->get('non_shared_service');
178 $service2 = $this->container->get('non_shared_service');
180 $this->assertNotSame($service, $service2, 'Non shared services are always re-instantiated.');
184 * Tests that Container::get() works properly for class from parameters.
187 * @covers ::createService
189 public function testGetForClassFromParameter() {
190 $container_definition = $this->containerDefinition;
191 $container_definition['frozen'] = FALSE;
192 $container = new $this->containerClass($container_definition);
194 $other_service_class = $this->containerDefinition['parameters']['some_parameter_class'];
195 $other_service = $container->get('other.service_class_from_parameter');
196 $this->assertInstanceOf($other_service_class, $other_service, 'other.service_class_from_parameter has the right class.');
200 * Tests that Container::set() works properly.
204 public function testSet() {
205 $this->assertNull($this->container->get('new_id', ContainerInterface::NULL_ON_INVALID_REFERENCE));
206 $mock_service = new MockService();
207 $this->container->set('new_id', $mock_service);
209 $this->assertSame($mock_service, $this->container->get('new_id'), 'A manual set service works as expected.');
213 * Tests that Container::has() works properly.
217 public function testHas() {
218 $this->assertTrue($this->container->has('other.service'));
219 $this->assertFalse($this->container->has('another.service'));
221 // Set the service manually, ensure that its also respected.
222 $mock_service = new MockService();
223 $this->container->set('another.service', $mock_service);
224 $this->assertTrue($this->container->has('another.service'));
228 * Tests that Container::has() for aliased services works properly.
232 public function testHasForAliasedService() {
233 $service = $this->container->has('service.provider');
234 $aliased_service = $this->container->has('service.provider_alias');
235 $this->assertSame($service, $aliased_service);
239 * Tests that Container::get() for circular dependencies works properly.
241 * @covers ::createService
243 public function testGetForCircularServices() {
244 $this->setExpectedException(ServiceCircularReferenceException::class);
245 $this->container->get('circular_dependency');
249 * Tests that Container::get() for non-existent services works properly.
252 * @covers ::createService
253 * @covers ::getAlternatives
254 * @covers ::getServiceAlternatives
256 public function testGetForNonExistantService() {
257 $this->setExpectedException(ServiceNotFoundException::class);
258 $this->container->get('service_not_exists');
262 * Tests that Container::get() for a serialized definition works properly.
265 * @covers ::createService
267 public function testGetForSerializedServiceDefinition() {
268 $container_definition = $this->containerDefinition;
269 $container_definition['services']['other.service'] = serialize($container_definition['services']['other.service']);
270 $container = new $this->containerClass($container_definition);
272 // Retrieve services of the container.
273 $other_service_class = $this->containerDefinition['services']['other.service']['class'];
274 $other_service = $container->get('other.service');
275 $this->assertInstanceOf($other_service_class, $other_service, 'other.service has the right class.');
277 $service = $container->get('service.provider');
278 $this->assertEquals($other_service, $service->getSomeOtherService(), '@other.service was injected via constructor.');
282 * Tests that Container::get() for non-existent parameters works properly.
285 * @covers ::createService
286 * @covers ::resolveServicesAndParameters
288 public function testGetForNonExistantParameterDependency() {
289 $service = $this->container->get('service_parameter_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE);
290 $this->assertNull($service, 'Service is NULL.');
294 * Tests Container::get() with an exception due to missing parameter on the second call.
297 * @covers ::createService
298 * @covers ::resolveServicesAndParameters
300 public function testGetForParameterDependencyWithExceptionOnSecondCall() {
301 $service = $this->container->get('service_parameter_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE);
302 $this->assertNull($service, 'Service is NULL.');
304 // Reset the service.
305 $this->container->set('service_parameter_not_exists', NULL);
306 $this->setExpectedException(InvalidArgumentException::class);
307 $this->container->get('service_parameter_not_exists');
311 * Tests that Container::get() for non-existent parameters works properly.
314 * @covers ::createService
315 * @covers ::resolveServicesAndParameters
317 public function testGetForNonExistantParameterDependencyWithException() {
318 $this->setExpectedException(InvalidArgumentException::class);
319 $this->container->get('service_parameter_not_exists');
323 * Tests that Container::get() for non-existent dependencies works properly.
326 * @covers ::createService
327 * @covers ::resolveServicesAndParameters
329 public function testGetForNonExistantServiceDependency() {
330 $service = $this->container->get('service_dependency_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE);
331 $this->assertNull($service, 'Service is NULL.');
335 * Tests that Container::get() for non-existent dependencies works properly.
338 * @covers ::createService
339 * @covers ::resolveServicesAndParameters
340 * @covers ::getAlternatives
342 public function testGetForNonExistantServiceDependencyWithException() {
343 $this->setExpectedException(ServiceNotFoundException::class);
344 $this->container->get('service_dependency_not_exists');
348 * Tests that Container::get() for non-existent services works properly.
351 * @covers ::createService
353 public function testGetForNonExistantServiceWhenUsingNull() {
354 $this->assertNull($this->container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does not throw exception.');
358 * Tests that Container::get() for NULL service works properly.
360 * @covers ::createService
362 public function testGetForNonExistantNULLService() {
363 $this->setExpectedException(ServiceNotFoundException::class);
364 $this->container->get(NULL);
368 * Tests multiple Container::get() calls for non-existing dependencies work.
371 * @covers ::createService
373 public function testGetForNonExistantServiceMultipleTimes() {
374 $container = new $this->containerClass();
376 $this->assertNull($container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does not throw exception.');
377 $this->assertNull($container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does not throw exception on second call.');
381 * Tests multiple Container::get() calls with exception on the second time.
384 * @covers ::createService
385 * @covers ::getAlternatives
387 public function testGetForNonExistantServiceWithExceptionOnSecondCall() {
388 $this->assertNull($this->container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does nto throw exception.');
389 $this->setExpectedException(ServiceNotFoundException::class);
390 $this->container->get('service_not_exists');
394 * Tests that Container::get() for aliased services works properly.
397 * @covers ::createService
399 public function testGetForAliasedService() {
400 $service = $this->container->get('service.provider');
401 $aliased_service = $this->container->get('service.provider_alias');
402 $this->assertSame($service, $aliased_service);
406 * Tests that Container::get() for synthetic services works - if defined.
409 * @covers ::createService
411 public function testGetForSyntheticService() {
412 $synthetic_service = new \stdClass();
413 $this->container->set('synthetic', $synthetic_service);
414 $test_service = $this->container->get('synthetic');
415 $this->assertSame($synthetic_service, $test_service);
419 * Tests that Container::get() for synthetic services throws an Exception if not defined.
422 * @covers ::createService
424 public function testGetForSyntheticServiceWithException() {
425 $this->setExpectedException(RuntimeException::class);
426 $this->container->get('synthetic');
430 * Tests that Container::get() for services with file includes works.
433 * @covers ::createService
435 public function testGetWithFileInclude() {
436 $file_service = $this->container->get('container_test_file_service_test');
437 $this->assertTrue(function_exists('container_test_file_service_test_service_function'));
438 $this->assertEquals('Hello Container', container_test_file_service_test_service_function());
442 * Tests that Container::get() for various arguments lengths works.
445 * @covers ::createService
446 * @covers ::resolveServicesAndParameters
448 public function testGetForInstantiationWithVariousArgumentLengths() {
450 for ($i = 0; $i < 12; $i++) {
451 $instantiation_service = $this->container->get('service_test_instantiation_' . $i);
452 $this->assertEquals($args, $instantiation_service->getArguments());
453 $args[] = 'arg_' . $i;
458 * Tests that Container::get() for wrong factories works correctly.
461 * @covers ::createService
463 public function testGetForWrongFactory() {
464 $this->setExpectedException(RuntimeException::class);
465 $this->container->get('wrong_factory');
469 * Tests Container::get() for factories via services (Symfony 2.7.0).
472 * @covers ::createService
474 public function testGetForFactoryService() {
475 $factory_service = $this->container->get('factory_service');
476 $factory_service_class = $this->container->getParameter('factory_service_class');
477 $this->assertInstanceOf($factory_service_class, $factory_service);
481 * Tests that Container::get() for factories via class works (Symfony 2.7.0).
484 * @covers ::createService
486 public function testGetForFactoryClass() {
487 $service = $this->container->get('service.provider');
488 $factory_service = $this->container->get('factory_class');
490 $this->assertInstanceOf(get_class($service), $factory_service);
491 $this->assertEquals('bar', $factory_service->getSomeParameter(), 'Correct parameter was passed via the factory class instantiation.');
492 $this->assertEquals($this->container, $factory_service->getContainer(), 'Container was injected via setter injection.');
496 * Tests that Container::get() for configurable services throws an Exception.
499 * @covers ::createService
501 public function testGetForConfiguratorWithException() {
502 $this->setExpectedException(InvalidArgumentException::class);
503 $this->container->get('configurable_service_exception');
507 * Tests that Container::get() for configurable services works.
510 * @covers ::createService
512 public function testGetForConfigurator() {
513 $container = $this->container;
515 // Setup a configurator.
516 $configurator = $this->prophesize('\Drupal\Tests\Component\DependencyInjection\MockConfiguratorInterface');
517 $configurator->configureService(Argument::type('object'))
519 ->will(function($args) use ($container) {
520 $args[0]->setContainer($container);
522 $container->set('configurator', $configurator->reveal());
524 // Test that the configurator worked.
525 $service = $container->get('configurable_service');
526 $this->assertSame($container, $service->getContainer(), 'Container was injected via configurator.');
530 * Tests that private services work correctly.
533 * @covers ::createService
534 * @covers ::resolveServicesAndParameters
536 public function testResolveServicesAndParametersForPrivateService() {
537 $service = $this->container->get('service_using_private');
538 $private_service = $service->getSomeOtherService();
539 $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.');
541 // Test that sharing the same private services works.
542 $service = $this->container->get('another_service_using_private');
543 $another_private_service = $service->getSomeOtherService();
544 $this->assertNotSame($private_service, $another_private_service, 'Private service is not shared.');
545 $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.');
549 * Tests that private service sharing works correctly.
552 * @covers ::createService
553 * @covers ::resolveServicesAndParameters
555 public function testResolveServicesAndParametersForSharedPrivateService() {
556 $service = $this->container->get('service_using_shared_private');
557 $private_service = $service->getSomeOtherService();
558 $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.');
560 // Test that sharing the same private services works.
561 $service = $this->container->get('another_service_using_shared_private');
562 $same_private_service = $service->getSomeOtherService();
563 $this->assertSame($private_service, $same_private_service, 'Private service is shared.');
564 $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.');
568 * Tests that services with an array of arguments work correctly.
571 * @covers ::createService
572 * @covers ::resolveServicesAndParameters
574 public function testResolveServicesAndParametersForArgumentsUsingDeepArray() {
575 $service = $this->container->get('service_using_array');
576 $other_service = $this->container->get('other.service');
577 $this->assertEquals($other_service, $service->getSomeOtherService(), '@other.service was injected via constructor.');
581 * Tests that services that are optional work correctly.
584 * @covers ::createService
585 * @covers ::resolveServicesAndParameters
587 public function testResolveServicesAndParametersForOptionalServiceDependencies() {
588 $service = $this->container->get('service_with_optional_dependency');
589 $this->assertNull($service->getSomeOtherService(), 'other service was NULL was expected.');
593 * Tests that an invalid argument throw an Exception.
596 * @covers ::createService
597 * @covers ::resolveServicesAndParameters
599 public function testResolveServicesAndParametersForInvalidArgument() {
600 $this->setExpectedException(InvalidArgumentException::class);
601 $this->container->get('invalid_argument_service');
605 * Tests that invalid arguments throw an Exception.
608 * @covers ::createService
609 * @covers ::resolveServicesAndParameters
611 public function testResolveServicesAndParametersForInvalidArguments() {
612 // In case the machine-optimized format is not used, we need to simulate the
614 $this->setExpectedException(InvalidArgumentException::class);
615 if (!$this->machineFormat) {
616 throw new InvalidArgumentException('Simulating the test failure.');
618 $this->container->get('invalid_arguments_service');
622 * Tests that a parameter that points to a service works correctly.
625 * @covers ::createService
626 * @covers ::resolveServicesAndParameters
628 public function testResolveServicesAndParametersForServiceInstantiatedFromParameter() {
629 $service = $this->container->get('service.provider');
630 $test_service = $this->container->get('service_with_parameter_service');
631 $this->assertSame($service, $test_service->getSomeOtherService(), 'Service was passed via parameter.');
635 * Tests that Container::initialized works correctly.
637 * @covers ::initialized
639 public function testInitialized() {
640 $this->assertFalse($this->container->initialized('late.service'), 'Late service is not initialized.');
641 $this->container->get('late.service');
642 $this->assertTrue($this->container->initialized('late.service'), 'Late service is initialized after it was retrieved once.');
646 * Tests that Container::initialized works correctly for aliases.
648 * @covers ::initialized
650 public function testInitializedForAliases() {
651 $this->assertFalse($this->container->initialized('late.service_alias'), 'Late service is not initialized.');
652 $this->container->get('late.service');
653 $this->assertTrue($this->container->initialized('late.service_alias'), 'Late service is initialized after it was retrieved once.');
657 * Tests that unsupported methods throw an Exception.
659 * @covers ::enterScope
660 * @covers ::leaveScope
663 * @covers ::isScopeActive
665 * @dataProvider scopeExceptionTestProvider
667 public function testScopeFunctionsWithException($method, $argument) {
673 $this->setExpectedException(\BadMethodCallException::class);
674 $callable($argument);
678 * Data provider for scopeExceptionTestProvider().
681 * Returns per data set an array with:
682 * - method name to call
685 public function scopeExceptionTestProvider() {
686 $scope = $this->prophesize('\Symfony\Component\DependencyInjection\ScopeInterface')->reveal();
688 ['enterScope', 'test_scope'],
689 ['leaveScope', 'test_scope'],
690 ['hasScope', 'test_scope'],
691 ['isScopeActive', 'test_scope'],
692 ['addScope', $scope],
697 * Tests that Container::getServiceIds() works properly.
699 * @covers ::getServiceIds
701 public function testGetServiceIds() {
702 $service_definition_keys = array_keys($this->containerDefinition['services']);
703 $this->assertEquals($service_definition_keys, $this->container->getServiceIds(), 'Retrieved service IDs match definition.');
705 $mock_service = new MockService();
706 $this->container->set('bar', $mock_service);
707 $this->container->set('service.provider', $mock_service);
708 $service_definition_keys[] = 'bar';
710 $this->assertEquals($service_definition_keys, $this->container->getServiceIds(), 'Retrieved service IDs match definition after setting new services.');
714 * Gets a mock container definition.
717 * Associated array with parameters and services.
719 protected function getMockContainerDefinition() {
720 $fake_service = new \stdClass();
722 $parameters['some_parameter_class'] = get_class($fake_service);
723 $parameters['some_private_config'] = 'really_private_lama';
724 $parameters['some_config'] = 'foo';
725 $parameters['some_other_config'] = 'lama';
726 $parameters['factory_service_class'] = get_class($fake_service);
727 // Also test alias resolving.
728 $parameters['service_from_parameter'] = $this->getServiceCall('service.provider_alias');
731 $services['service_container'] = [
732 'class' => '\Drupal\service_container\DependencyInjection\Container',
734 $services['other.service'] = [
735 'class' => get_class($fake_service),
738 $services['non_shared_service'] = [
739 'class' => get_class($fake_service),
743 $services['other.service_class_from_parameter'] = [
744 'class' => $this->getParameterCall('some_parameter_class'),
746 $services['late.service'] = [
747 'class' => get_class($fake_service),
749 $services['service.provider'] = [
750 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
751 'arguments' => $this->getCollection([
752 $this->getServiceCall('other.service'),
753 $this->getParameterCall('some_config'),
755 'properties' => $this->getCollection(['_someProperty' => 'foo']),
757 ['setContainer', $this->getCollection([
758 $this->getServiceCall('service_container'),
760 ['setOtherConfigParameter', $this->getCollection([
761 $this->getParameterCall('some_other_config'),
767 // Test private services.
769 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
770 'arguments' => $this->getCollection([
771 $this->getServiceCall('other.service'),
772 $this->getParameterCall('some_private_config'),
777 $services['service_using_private'] = [
778 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
779 'arguments' => $this->getCollection([
780 $this->getPrivateServiceCall(NULL, $private_service),
781 $this->getParameterCall('some_config'),
784 $services['another_service_using_private'] = [
785 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
786 'arguments' => $this->getCollection([
787 $this->getPrivateServiceCall(NULL, $private_service),
788 $this->getParameterCall('some_config'),
792 // Test shared private services.
793 $id = 'private_service_shared_1';
795 $services['service_using_shared_private'] = [
796 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
797 'arguments' => $this->getCollection([
798 $this->getPrivateServiceCall($id, $private_service, TRUE),
799 $this->getParameterCall('some_config'),
802 $services['another_service_using_shared_private'] = [
803 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
804 'arguments' => $this->getCollection([
805 $this->getPrivateServiceCall($id, $private_service, TRUE),
806 $this->getParameterCall('some_config'),
810 // Tests service with invalid argument.
811 $services['invalid_argument_service'] = [
812 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
813 'arguments' => $this->getCollection([
814 1, // Test passing non-strings, too.
821 $services['invalid_arguments_service'] = [
822 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
823 'arguments' => (object) [
828 // Test service that needs deep-traversal.
829 $services['service_using_array'] = [
830 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
831 'arguments' => $this->getCollection([
832 $this->getCollection([
833 $this->getServiceCall('other.service'),
835 $this->getParameterCall('some_private_config'),
839 $services['service_with_optional_dependency'] = [
840 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
841 'arguments' => $this->getCollection([
842 $this->getServiceCall('service.does_not_exist', ContainerInterface::NULL_ON_INVALID_REFERENCE),
843 $this->getParameterCall('some_private_config'),
848 $services['factory_service'] = [
849 'class' => '\Drupal\service_container\ServiceContainer\ControllerInterface',
851 $this->getServiceCall('service.provider'),
854 'arguments' => $this->getCollection([
855 $this->getParameterCall('factory_service_class'),
858 $services['factory_class'] = [
859 'class' => '\Drupal\service_container\ServiceContainer\ControllerInterface',
860 'factory' => '\Drupal\Tests\Component\DependencyInjection\MockService::getFactoryMethod',
862 '\Drupal\Tests\Component\DependencyInjection\MockService',
866 ['setContainer', $this->getCollection([
867 $this->getServiceCall('service_container'),
872 $services['wrong_factory'] = [
873 'class' => '\Drupal\service_container\ServiceContainer\ControllerInterface',
874 'factory' => (object) ['I am not a factory, but I pretend to be.'],
877 $services['circular_dependency'] = [
878 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
879 'arguments' => $this->getCollection([
880 $this->getServiceCall('circular_dependency'),
883 $services['synthetic'] = [
886 // The file could have been named as a .php file. The reason it is a .data
887 // file is that SimpleTest tries to load it. SimpleTest does not like such
888 // fixtures and hence we use a neutral name like .data.
889 $services['container_test_file_service_test'] = [
890 'class' => '\stdClass',
891 'file' => __DIR__ . '/Fixture/container_test_file_service_test_service_function.data',
894 // Test multiple arguments.
896 for ($i = 0; $i < 12; $i++) {
897 $services['service_test_instantiation_' . $i] = [
898 'class' => '\Drupal\Tests\Component\DependencyInjection\MockInstantiationService',
899 // Also test a collection that does not need resolving.
900 'arguments' => $this->getCollection($args, FALSE),
902 $args[] = 'arg_' . $i;
905 $services['service_parameter_not_exists'] = [
906 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
907 'arguments' => $this->getCollection([
908 $this->getServiceCall('service.provider'),
909 $this->getParameterCall('not_exists'),
912 $services['service_dependency_not_exists'] = [
913 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
914 'arguments' => $this->getCollection([
915 $this->getServiceCall('service_not_exists'),
916 $this->getParameterCall('some_config'),
920 $services['service_with_parameter_service'] = [
921 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
922 'arguments' => $this->getCollection([
923 $this->getParameterCall('service_from_parameter'),
924 // Also test deep collections that don't need resolving.
925 $this->getCollection([
931 // To ensure getAlternatives() finds something.
932 $services['service_not_exists_similar'] = [
936 // Test configurator.
937 $services['configurator'] = [
940 $services['configurable_service'] = [
941 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
944 $this->getServiceCall('configurator'),
948 $services['configurable_service_exception'] = [
949 'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
951 'configurator' => 'configurator_service_test_does_not_exist',
955 $aliases['service.provider_alias'] = 'service.provider';
956 $aliases['late.service_alias'] = 'late.service';
959 'aliases' => $aliases,
960 'parameters' => $parameters,
961 'services' => $services,
963 'machine_format' => $this->machineFormat,
968 * Helper function to return a service definition.
970 protected function getServiceCall($id, $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
974 'invalidBehavior' => $invalid_behavior,
979 * Helper function to return a service definition.
981 protected function getParameterCall($name) {
983 'type' => 'parameter',
989 * Helper function to return a private service definition.
991 protected function getPrivateServiceCall($id, $service_definition, $shared = FALSE) {
993 $hash = Crypt::hashBase64(serialize($service_definition));
994 $id = 'private__' . $hash;
997 'type' => 'private_service',
999 'value' => $service_definition,
1000 'shared' => $shared,
1005 * Helper function to return a machine-optimized collection.
1007 protected function getCollection($collection, $resolve = TRUE) {
1009 'type' => 'collection',
1010 'value' => $collection,
1011 'resolve' => $resolve,
1018 * Helper interface to test Container::get() with configurator.
1020 * @group DependencyInjection
1022 interface MockConfiguratorInterface {
1025 * Configures a service.
1027 * @param object $service
1028 * The service to configure.
1030 public function configureService($service);
1036 * Helper class to test Container::get() method for varying number of parameters.
1038 * @group DependencyInjection
1040 class MockInstantiationService {
1045 protected $arguments;
1048 * Construct a mock instantiation service.
1050 public function __construct() {
1051 $this->arguments = func_get_args();
1055 * Return arguments injected into the service.
1058 * Return the passed arguments.
1060 public function getArguments() {
1061 return $this->arguments;
1068 * Helper class to test Container::get() method.
1070 * @group DependencyInjection
1075 * @var ContainerInterface
1077 protected $container;
1082 protected $someOtherService;
1087 protected $someParameter;
1092 protected $someOtherParameter;
1095 * Constructs a MockService object.
1097 * @param object $some_other_service
1098 * (optional) Another injected service.
1099 * @param string $some_parameter
1100 * (optional) An injected parameter.
1102 public function __construct($some_other_service = NULL, $some_parameter = NULL) {
1103 if (is_array($some_other_service)) {
1104 $some_other_service = $some_other_service[0];
1106 $this->someOtherService = $some_other_service;
1107 $this->someParameter = $some_parameter;
1111 * Sets the container object.
1113 * @param ContainerInterface $container
1114 * The container to inject via setter injection.
1116 public function setContainer(ContainerInterface $container) {
1117 $this->container = $container;
1121 * Gets the container object.
1123 * @return ContainerInterface
1124 * The internally set container.
1126 public function getContainer() {
1127 return $this->container;
1131 * Gets the someOtherService object.
1134 * The injected service.
1136 public function getSomeOtherService() {
1137 return $this->someOtherService;
1141 * Gets the someParameter property.
1144 * The injected parameter.
1146 public function getSomeParameter() {
1147 return $this->someParameter;
1151 * Sets the someOtherParameter property.
1153 * @param string $some_other_parameter
1154 * The setter injected parameter.
1156 public function setOtherConfigParameter($some_other_parameter) {
1157 $this->someOtherParameter = $some_other_parameter;
1161 * Gets the someOtherParameter property.
1164 * The injected parameter.
1166 public function getSomeOtherParameter() {
1167 return $this->someOtherParameter;
1171 * Provides a factory method to get a service.
1173 * @param string $class
1174 * The class name of the class to instantiate
1175 * @param array $arguments
1176 * (optional) Arguments to pass to the new class.
1179 * The instantiated service object.
1181 public static function getFactoryMethod($class, $arguments = []) {
1182 $r = new \ReflectionClass($class);
1183 $service = ($r->getConstructor() === NULL) ? $r->newInstance() : $r->newInstanceArgs($arguments);