‪TYPO3CMS  10.4
ServiceProviderCompilationPassTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Prophecy\Argument;
21 use Psr\Container\ContainerInterface;
22 use Psr\Log\NullLogger;
23 use Symfony\Component\DependencyInjection\ContainerBuilder;
24 use Symfony\Component\DependencyInjection\Definition;
32 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
33 
34 class ‪ServiceProviderCompilationPassTest extends UnitTestCase
35 {
36  protected function ‪getServiceProviderRegistry(array $serviceProviders)
37  {
38  $serviceProviderRegistryProphecy = $this->prophesize(ServiceProviderRegistry::class);
39  $serviceProviderRegistryProphecy->getIterator()->will(function () use ($serviceProviders): \Generator {
40  foreach ($serviceProviders as $id => $serviceProvider) {
41  yield (string)$id => new $serviceProvider();
42  }
43  });
44 
45  foreach ($serviceProviders as $id => $serviceProvider) {
46  $packageKey = (string)$id;
47 
48  $instance = new $serviceProvider();
49  $factories = $instance->getFactories();
50  $extensions = $instance->getExtensions();
51 
52  $serviceProviderRegistryProphecy->getFactories($id)->willReturn($factories);
53  $serviceProviderRegistryProphecy->getExtensions($id)->willReturn($extensions);
54 
55  foreach ($factories as $serviceName => $factory) {
56  $serviceProviderRegistryProphecy->createService($packageKey, $serviceName, Argument::type(ContainerInterface::class))->will(function (‪$args) use ($factory) {
57  return $factory(‪$args[2]);
58  });
59  }
60  foreach ($extensions as $serviceName => $extension) {
61  $serviceProviderRegistryProphecy->extendService($packageKey, $serviceName, Argument::type(ContainerInterface::class), Argument::cetera())->will(function (‪$args) use ($extension) {
62  return $extension(‪$args[2], ‪$args[3] ?? null);
63  });
64  }
65  }
66 
67  return $serviceProviderRegistryProphecy->reveal();
68  }
69 
70  protected function ‪getContainer(array $serviceProviders, callable $configure = null)
71  {
72  static $id = 0;
73 
74  $registry = $this->‪getServiceProviderRegistry($serviceProviders);
75  $registryServiceName = 'service_provider_registry_' . ++$id;
76 
77  $container = new ContainerBuilder();
78  if ($configure !== null) {
79  $configure($container);
80  }
81  $logger = new Definition(NullLogger::class);
82  $logger->setPublic(true);
83  $container->setDefinition('logger', $logger);
84 
85  $container->addCompilerPass(new ‪ServiceProviderCompilationPass($registry, $registryServiceName));
86  $container->compile();
87  $container->set($registryServiceName, $registry);
88 
89  return $container;
90  }
91 
92  public function ‪testSimpleServiceProvider()
93  {
94  $container = $this->‪getContainer([
95  TestServiceProvider::class
96  ]);
97 
98  $serviceA = $container->get('serviceA');
99  $serviceD = $container->get('serviceD');
100 
101  self::assertInstanceOf(\stdClass::class, $serviceA);
102  self::assertInstanceOf(\stdClass::class, $serviceD);
103  self::assertEquals(42, $container->get('function'));
104  }
105 
107  {
108  $container = $this->‪getContainer([
109  TestServiceProvider::class,
110  TestServiceProviderOverride::class,
111  TestServiceProviderOverride2::class
112  ]);
113 
114  $serviceA = $container->get('serviceA');
115  $serviceC = $container->get('serviceC');
116 
117  self::assertInstanceOf(\stdClass::class, $serviceA);
118  self::assertEquals('foo', $serviceA->newProperty);
119  self::assertEquals('bar', $serviceA->newProperty2);
120  self::assertEquals('localhost', $serviceC->serviceB->parameter);
121  }
122 
124  {
125  $container = $this->‪getContainer([
126  TestServiceProvider::class,
127  TestServiceProviderFactoryOverride::class,
128  ]);
129 
130  $serviceA = $container->get('serviceA');
131 
132  self::assertInstanceOf(\stdClass::class, $serviceA);
133  self::assertEquals('remotehost', $serviceA->serviceB->parameter);
134  }
135 
137  {
138  $container = $this->‪getContainer(
139  [
140  TestServiceProvider::class,
141  TestServiceProviderFactoryOverride::class,
142  ],
143  function (ContainerBuilder $container) {
144  $definition = new Definition('stdClass');
145  // property should be overridden by service provider
146  $definition->setProperty('parameter', 'remotehost');
147  // property should not be "deleted" by service provider
148  $definition->setProperty('symfony_defined_parameter', 'foobar');
149  $container->setDefinition('serviceB', $definition);
150  }
151  );
152 
153  $serviceA = $container->get('serviceA');
154 
155  self::assertInstanceOf(\stdClass::class, $serviceA);
156  self::assertEquals('remotehost', $serviceA->serviceB->parameter);
157  self::assertEquals('foobar', $serviceA->serviceB->symfony_defined_parameter);
158  }
159 
161  {
162  $container = $this->‪getContainer(
163  [
164  TestServiceProvider::class,
165  TestServiceProviderFactoryOverride::class,
166  ],
167  function (ContainerBuilder $container) {
168  $definition = new Definition('stdClass');
169  // property should be overridden by service provider
170  $definition->setProperty('parameter', 'remotehost');
171  // property should not be "deleted" by service provider
172  $definition->setProperty('symfony_defined_parameter', 'foobar');
173  $definition->setAutowired(true);
174  $container->setDefinition('serviceB', $definition);
175  }
176  );
177 
178  $serviceA = $container->get('serviceA');
179 
180  self::assertInstanceOf(\stdClass::class, $serviceA);
181  self::assertEquals('remotehost', $serviceA->serviceB->parameter);
182  self::assertEquals('foobar', $serviceA->serviceB->symfony_defined_parameter);
183  self::assertFalse($container->getDefinition('serviceB')->isAutowired());
184  }
185 
187  {
188  $this->expectException(\Exception::class);
189  $this->expectExceptionMessage('A registered extension for the service "serviceA" requires the service to be available, which is missing.');
190 
191  $container = $this->‪getContainer([
192  TestServiceProviderOverride::class,
193  ]);
194  }
195 
197  {
198  $this->expectException(\TypeError::class);
199 
200  $registry = new ‪ServiceProviderRegistry([
201  new class() implements ‪ServiceProviderInterface {
202  public function getFactories()
203  {
204  return [
205  'invalid' => 2
206  ];
207  }
208  public function getExtensions()
209  {
210  return [];
211  }
212  }
213  ]);
214  $container = new ContainerBuilder();
215  $registryServiceName = 'service_provider_registry_test';
216  $container->addCompilerPass(new ‪ServiceProviderCompilationPass($registry, $registryServiceName));
217  $container->compile();
218  }
219 }
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\Fixtures\TestServiceProviderOverride2
Definition: TestServiceProviderOverride2.php:24
‪TYPO3\CMS\Core\DependencyInjection\ServiceProviderCompilationPass
Definition: ServiceProviderCompilationPass.php:29
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\ServiceProviderCompilationPassTest\getServiceProviderRegistry
‪getServiceProviderRegistry(array $serviceProviders)
Definition: ServiceProviderCompilationPassTest.php:36
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\Fixtures\TestServiceProvider
Definition: TestServiceProvider.php:29
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\ServiceProviderCompilationPassTest\testServiceProviderFactoryOverridesForSymfonyDefinedServices
‪testServiceProviderFactoryOverridesForSymfonyDefinedServices()
Definition: ServiceProviderCompilationPassTest.php:136
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\ServiceProviderCompilationPassTest\testExceptionForNonNullableExtensionArgument
‪testExceptionForNonNullableExtensionArgument()
Definition: ServiceProviderCompilationPassTest.php:186
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\Fixtures\TestServiceProviderFactoryOverride
Definition: TestServiceProviderFactoryOverride.php:24
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\ServiceProviderCompilationPassTest\testServiceProviderOverrides
‪testServiceProviderOverrides()
Definition: ServiceProviderCompilationPassTest.php:106
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection
Definition: FailsafeContainerTest.php:18
‪TYPO3\CMS\Core\DependencyInjection\ServiceProviderRegistry
Definition: ServiceProviderRegistry.php:31
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\ServiceProviderCompilationPassTest\testSimpleServiceProvider
‪testSimpleServiceProvider()
Definition: ServiceProviderCompilationPassTest.php:92
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\ServiceProviderCompilationPassTest\getContainer
‪getContainer(array $serviceProviders, callable $configure=null)
Definition: ServiceProviderCompilationPassTest.php:70
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\ServiceProviderCompilationPassTest\testServiceProviderFactoryOverrides
‪testServiceProviderFactoryOverrides()
Definition: ServiceProviderCompilationPassTest.php:123
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\ServiceProviderCompilationPassTest\testServiceProviderFactoryOverrideResetsAutowiring
‪testServiceProviderFactoryOverrideResetsAutowiring()
Definition: ServiceProviderCompilationPassTest.php:160
‪$args
‪$args
Definition: validateRstFiles.php:214
‪TYPO3\CMS\Core\DependencyInjection\ServiceProviderInterface
Definition: ServiceProviderInterface.php:24
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\Fixtures\TestServiceProviderOverride
Definition: TestServiceProviderOverride.php:24
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\ServiceProviderCompilationPassTest
Definition: ServiceProviderCompilationPassTest.php:35
‪TYPO3\CMS\Core\Tests\Unit\DependencyInjection\ServiceProviderCompilationPassTest\testExceptionForInvalidFactories
‪testExceptionForInvalidFactories()
Definition: ServiceProviderCompilationPassTest.php:196