eb491d9435b2d461701d017288817b63b7312d9c
[yaffs-website] / vendor / symfony / dependency-injection / Tests / Dumper / PhpDumperTest.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\DependencyInjection\Tests\Dumper;
13
14 use DummyProxyDumper;
15 use PHPUnit\Framework\TestCase;
16 use Symfony\Component\Config\FileLocator;
17 use Symfony\Component\DependencyInjection\ContainerBuilder;
18 use Symfony\Component\DependencyInjection\ContainerInterface;
19 use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
20 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
21 use Symfony\Component\DependencyInjection\Reference;
22 use Symfony\Component\DependencyInjection\Definition;
23 use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
24 use Symfony\Component\DependencyInjection\Variable;
25 use Symfony\Component\ExpressionLanguage\Expression;
26
27 require_once __DIR__.'/../Fixtures/includes/classes.php';
28
29 class PhpDumperTest extends TestCase
30 {
31     protected static $fixturesPath;
32
33     public static function setUpBeforeClass()
34     {
35         self::$fixturesPath = realpath(__DIR__.'/../Fixtures/');
36     }
37
38     public function testDump()
39     {
40         $dumper = new PhpDumper(new ContainerBuilder());
41
42         $this->assertStringEqualsFile(self::$fixturesPath.'/php/services1.php', $dumper->dump(), '->dump() dumps an empty container as an empty PHP class');
43         $this->assertStringEqualsFile(self::$fixturesPath.'/php/services1-1.php', $dumper->dump(array('class' => 'Container', 'base_class' => 'AbstractContainer', 'namespace' => 'Symfony\Component\DependencyInjection\Dump')), '->dump() takes a class and a base_class options');
44     }
45
46     public function testDumpOptimizationString()
47     {
48         $definition = new Definition();
49         $definition->setClass('stdClass');
50         $definition->addArgument(array(
51             'only dot' => '.',
52             'concatenation as value' => '.\'\'.',
53             'concatenation from the start value' => '\'\'.',
54             '.' => 'dot as a key',
55             '.\'\'.' => 'concatenation as a key',
56             '\'\'.' => 'concatenation from the start key',
57             'optimize concatenation' => 'string1%some_string%string2',
58             'optimize concatenation with empty string' => 'string1%empty_value%string2',
59             'optimize concatenation from the start' => '%empty_value%start',
60             'optimize concatenation at the end' => 'end%empty_value%',
61         ));
62
63         $container = new ContainerBuilder();
64         $container->setResourceTracking(false);
65         $container->setDefinition('test', $definition);
66         $container->setParameter('empty_value', '');
67         $container->setParameter('some_string', '-');
68         $container->compile();
69
70         $dumper = new PhpDumper($container);
71         $this->assertStringEqualsFile(self::$fixturesPath.'/php/services10.php', $dumper->dump(), '->dump() dumps an empty container as an empty PHP class');
72     }
73
74     public function testDumpRelativeDir()
75     {
76         $definition = new Definition();
77         $definition->setClass('stdClass');
78         $definition->addArgument('%foo%');
79         $definition->addArgument(array('%foo%' => '%buz%/'));
80
81         $container = new ContainerBuilder();
82         $container->setDefinition('test', $definition);
83         $container->setParameter('foo', 'wiz'.dirname(__DIR__));
84         $container->setParameter('bar', __DIR__);
85         $container->setParameter('baz', '%bar%/PhpDumperTest.php');
86         $container->setParameter('buz', dirname(dirname(__DIR__)));
87         $container->compile();
88
89         $dumper = new PhpDumper($container);
90         $this->assertStringEqualsFile(self::$fixturesPath.'/php/services12.php', $dumper->dump(array('file' => __FILE__)), '->dump() dumps __DIR__ relative strings');
91     }
92
93     /**
94      * @dataProvider provideInvalidParameters
95      * @expectedException \InvalidArgumentException
96      */
97     public function testExportParameters($parameters)
98     {
99         $dumper = new PhpDumper(new ContainerBuilder(new ParameterBag($parameters)));
100         $dumper->dump();
101     }
102
103     public function provideInvalidParameters()
104     {
105         return array(
106             array(array('foo' => new Definition('stdClass'))),
107             array(array('foo' => new Expression('service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")'))),
108             array(array('foo' => new Reference('foo'))),
109             array(array('foo' => new Variable('foo'))),
110         );
111     }
112
113     public function testAddParameters()
114     {
115         $container = include self::$fixturesPath.'/containers/container8.php';
116         $dumper = new PhpDumper($container);
117         $this->assertStringEqualsFile(self::$fixturesPath.'/php/services8.php', $dumper->dump(), '->dump() dumps parameters');
118     }
119
120     public function testAddService()
121     {
122         // without compilation
123         $container = include self::$fixturesPath.'/containers/container9.php';
124         $dumper = new PhpDumper($container);
125         $this->assertStringEqualsFile(self::$fixturesPath.'/php/services9.php', str_replace(str_replace('\\', '\\\\', self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), '%path%', $dumper->dump()), '->dump() dumps services');
126
127         // with compilation
128         $container = include self::$fixturesPath.'/containers/container9.php';
129         $container->compile();
130         $dumper = new PhpDumper($container);
131         $this->assertStringEqualsFile(self::$fixturesPath.'/php/services9_compiled.php', str_replace(str_replace('\\', '\\\\', self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), '%path%', $dumper->dump()), '->dump() dumps services');
132
133         $dumper = new PhpDumper($container = new ContainerBuilder());
134         $container->register('foo', 'FooClass')->addArgument(new \stdClass());
135         try {
136             $dumper->dump();
137             $this->fail('->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources');
138         } catch (\Exception $e) {
139             $this->assertInstanceOf('\Symfony\Component\DependencyInjection\Exception\RuntimeException', $e, '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources');
140             $this->assertEquals('Unable to dump a service container if a parameter is an object or a resource.', $e->getMessage(), '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources');
141         }
142     }
143
144     public function testServicesWithAnonymousFactories()
145     {
146         $container = include self::$fixturesPath.'/containers/container19.php';
147         $dumper = new PhpDumper($container);
148
149         $this->assertStringEqualsFile(self::$fixturesPath.'/php/services19.php', $dumper->dump(), '->dump() dumps services with anonymous factories');
150     }
151
152     public function testAddServiceIdWithUnsupportedCharacters()
153     {
154         $class = 'Symfony_DI_PhpDumper_Test_Unsupported_Characters';
155         $container = new ContainerBuilder();
156         $container->register('bar$', 'FooClass');
157         $container->register('bar$!', 'FooClass');
158         $dumper = new PhpDumper($container);
159         eval('?>'.$dumper->dump(array('class' => $class)));
160
161         $this->assertTrue(method_exists($class, 'getBarService'));
162         $this->assertTrue(method_exists($class, 'getBar2Service'));
163     }
164
165     public function testConflictingServiceIds()
166     {
167         $class = 'Symfony_DI_PhpDumper_Test_Conflicting_Service_Ids';
168         $container = new ContainerBuilder();
169         $container->register('foo_bar', 'FooClass');
170         $container->register('foobar', 'FooClass');
171         $dumper = new PhpDumper($container);
172         eval('?>'.$dumper->dump(array('class' => $class)));
173
174         $this->assertTrue(method_exists($class, 'getFooBarService'));
175         $this->assertTrue(method_exists($class, 'getFoobar2Service'));
176     }
177
178     public function testConflictingMethodsWithParent()
179     {
180         $class = 'Symfony_DI_PhpDumper_Test_Conflicting_Method_With_Parent';
181         $container = new ContainerBuilder();
182         $container->register('bar', 'FooClass');
183         $container->register('foo_bar', 'FooClass');
184         $dumper = new PhpDumper($container);
185         eval('?>'.$dumper->dump(array(
186             'class' => $class,
187             'base_class' => 'Symfony\Component\DependencyInjection\Tests\Fixtures\containers\CustomContainer',
188         )));
189
190         $this->assertTrue(method_exists($class, 'getBar2Service'));
191         $this->assertTrue(method_exists($class, 'getFoobar2Service'));
192     }
193
194     /**
195      * @dataProvider provideInvalidFactories
196      * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
197      * @expectedExceptionMessage Cannot dump definition
198      */
199     public function testInvalidFactories($factory)
200     {
201         $container = new ContainerBuilder();
202         $def = new Definition('stdClass');
203         $def->setFactory($factory);
204         $container->setDefinition('bar', $def);
205         $dumper = new PhpDumper($container);
206         $dumper->dump();
207     }
208
209     public function provideInvalidFactories()
210     {
211         return array(
212             array(array('', 'method')),
213             array(array('class', '')),
214             array(array('...', 'method')),
215             array(array('class', '...')),
216         );
217     }
218
219     public function testAliases()
220     {
221         $container = include self::$fixturesPath.'/containers/container9.php';
222         $container->compile();
223         $dumper = new PhpDumper($container);
224         eval('?>'.$dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Aliases')));
225
226         $container = new \Symfony_DI_PhpDumper_Test_Aliases();
227         $container->set('foo', $foo = new \stdClass());
228         $this->assertSame($foo, $container->get('foo'));
229         $this->assertSame($foo, $container->get('alias_for_foo'));
230         $this->assertSame($foo, $container->get('alias_for_alias'));
231     }
232
233     public function testFrozenContainerWithoutAliases()
234     {
235         $container = new ContainerBuilder();
236         $container->compile();
237
238         $dumper = new PhpDumper($container);
239         eval('?>'.$dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Frozen_No_Aliases')));
240
241         $container = new \Symfony_DI_PhpDumper_Test_Frozen_No_Aliases();
242         $this->assertFalse($container->has('foo'));
243     }
244
245     public function testOverrideServiceWhenUsingADumpedContainer()
246     {
247         require_once self::$fixturesPath.'/php/services9.php';
248         require_once self::$fixturesPath.'/includes/foo.php';
249
250         $container = new \ProjectServiceContainer();
251         $container->set('bar', $bar = new \stdClass());
252         $container->setParameter('foo_bar', 'foo_bar');
253
254         $this->assertSame($bar, $container->get('bar'), '->set() overrides an already defined service');
255     }
256
257     public function testOverrideServiceWhenUsingADumpedContainerAndServiceIsUsedFromAnotherOne()
258     {
259         require_once self::$fixturesPath.'/php/services9.php';
260         require_once self::$fixturesPath.'/includes/foo.php';
261         require_once self::$fixturesPath.'/includes/classes.php';
262
263         $container = new \ProjectServiceContainer();
264         $container->set('bar', $bar = new \stdClass());
265
266         $this->assertSame($bar, $container->get('foo')->bar, '->set() overrides an already defined service');
267     }
268
269     /**
270      * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
271      */
272     public function testCircularReference()
273     {
274         $container = new ContainerBuilder();
275         $container->register('foo', 'stdClass')->addArgument(new Reference('bar'));
276         $container->register('bar', 'stdClass')->setPublic(false)->addMethodCall('setA', array(new Reference('baz')));
277         $container->register('baz', 'stdClass')->addMethodCall('setA', array(new Reference('foo')));
278         $container->compile();
279
280         $dumper = new PhpDumper($container);
281         $dumper->dump();
282     }
283
284     public function testDumpAutowireData()
285     {
286         $container = include self::$fixturesPath.'/containers/container24.php';
287         $dumper = new PhpDumper($container);
288
289         $this->assertStringEqualsFile(self::$fixturesPath.'/php/services24.php', $dumper->dump());
290     }
291
292     public function testEnvParameter()
293     {
294         $container = new ContainerBuilder();
295         $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
296         $loader->load('services26.yml');
297         $container->compile();
298         $dumper = new PhpDumper($container);
299
300         $this->assertStringEqualsFile(self::$fixturesPath.'/php/services26.php', $dumper->dump(), '->dump() dumps inline definitions which reference service_container');
301     }
302
303     /**
304      * @expectedException \Symfony\Component\DependencyInjection\Exception\EnvParameterException
305      * @expectedExceptionMessage Environment variables "FOO" are never used. Please, check your container's configuration.
306      */
307     public function testUnusedEnvParameter()
308     {
309         $container = new ContainerBuilder();
310         $container->getParameter('env(FOO)');
311         $container->compile();
312         $dumper = new PhpDumper($container);
313         $dumper->dump();
314     }
315
316     public function testInlinedDefinitionReferencingServiceContainer()
317     {
318         $container = new ContainerBuilder();
319         $container->register('foo', 'stdClass')->addMethodCall('add', array(new Reference('service_container')))->setPublic(false);
320         $container->register('bar', 'stdClass')->addArgument(new Reference('foo'));
321         $container->compile();
322
323         $dumper = new PhpDumper($container);
324         $this->assertStringEqualsFile(self::$fixturesPath.'/php/services13.php', $dumper->dump(), '->dump() dumps inline definitions which reference service_container');
325     }
326
327     public function testInitializePropertiesBeforeMethodCalls()
328     {
329         require_once self::$fixturesPath.'/includes/classes.php';
330
331         $container = new ContainerBuilder();
332         $container->register('foo', 'stdClass');
333         $container->register('bar', 'MethodCallClass')
334             ->setProperty('simple', 'bar')
335             ->setProperty('complex', new Reference('foo'))
336             ->addMethodCall('callMe');
337         $container->compile();
338
339         $dumper = new PhpDumper($container);
340         eval('?>'.$dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Properties_Before_Method_Calls')));
341
342         $container = new \Symfony_DI_PhpDumper_Test_Properties_Before_Method_Calls();
343         $this->assertTrue($container->get('bar')->callPassed(), '->dump() initializes properties before method calls');
344     }
345
346     public function testCircularReferenceAllowanceForLazyServices()
347     {
348         $container = new ContainerBuilder();
349         $container->register('foo', 'stdClass')->addArgument(new Reference('bar'));
350         $container->register('bar', 'stdClass')->setLazy(true)->addArgument(new Reference('foo'));
351         $container->compile();
352
353         $dumper = new PhpDumper($container);
354         $dumper->dump();
355
356         $this->addToAssertionCount(1);
357     }
358
359     public function testCircularReferenceAllowanceForInlinedDefinitionsForLazyServices()
360     {
361         /*
362          *   test graph:
363          *              [connection] -> [event_manager] --> [entity_manager](lazy)
364          *                                                           |
365          *                                                           --(call)- addEventListener ("@lazy_service")
366          *
367          *              [lazy_service](lazy) -> [entity_manager](lazy)
368          *
369          */
370
371         $container = new ContainerBuilder();
372
373         $eventManagerDefinition = new Definition('stdClass');
374
375         $connectionDefinition = $container->register('connection', 'stdClass');
376         $connectionDefinition->addArgument($eventManagerDefinition);
377
378         $container->register('entity_manager', 'stdClass')
379             ->setLazy(true)
380             ->addArgument(new Reference('connection'));
381
382         $lazyServiceDefinition = $container->register('lazy_service', 'stdClass');
383         $lazyServiceDefinition->setLazy(true);
384         $lazyServiceDefinition->addArgument(new Reference('entity_manager'));
385
386         $eventManagerDefinition->addMethodCall('addEventListener', array(new Reference('lazy_service')));
387
388         $container->compile();
389
390         $dumper = new PhpDumper($container);
391
392         $dumper->setProxyDumper(new DummyProxyDumper());
393         $dumper->dump();
394
395         $this->addToAssertionCount(1);
396     }
397
398     public function testDumpContainerBuilderWithFrozenConstructorIncludingPrivateServices()
399     {
400         $container = new ContainerBuilder();
401         $container->register('foo_service', 'stdClass')->setArguments(array(new Reference('baz_service')));
402         $container->register('bar_service', 'stdClass')->setArguments(array(new Reference('baz_service')));
403         $container->register('baz_service', 'stdClass')->setPublic(false);
404         $container->compile();
405
406         $dumper = new PhpDumper($container);
407
408         $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_private_frozen.php', $dumper->dump());
409     }
410
411     public function testPrivateWithIgnoreOnInvalidReference()
412     {
413         require_once self::$fixturesPath.'/includes/classes.php';
414
415         $container = new ContainerBuilder();
416         $container->register('not_invalid', 'BazClass')
417             ->setPublic(false);
418         $container->register('bar', 'BarClass')
419             ->addMethodCall('setBaz', array(new Reference('not_invalid', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)));
420
421         $dumper = new PhpDumper($container);
422         eval('?>'.$dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Private_With_Ignore_On_Invalid_Reference')));
423
424         $container = new \Symfony_DI_PhpDumper_Test_Private_With_Ignore_On_Invalid_Reference();
425         $this->assertInstanceOf('BazClass', $container->get('bar')->getBaz());
426     }
427
428     public function testExpressionReferencingPrivateService()
429     {
430         $container = new ContainerBuilder();
431         $container->register('private_bar', 'stdClass')
432             ->setPublic(false);
433         $container->register('private_foo', 'stdClass')
434             ->setPublic(false);
435         $container->register('public_foo', 'stdClass')
436             ->addArgument(new Expression('service("private_foo")'));
437
438         $container->compile();
439         $dumper = new PhpDumper($container);
440
441         $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_private_in_expression.php', $dumper->dump());
442     }
443
444     public function testDumpHandlesLiteralClassWithRootNamespace()
445     {
446         $container = new ContainerBuilder();
447         $container->register('foo', '\\stdClass');
448
449         $dumper = new PhpDumper($container);
450         eval('?>'.$dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Literal_Class_With_Root_Namespace')));
451
452         $container = new \Symfony_DI_PhpDumper_Test_Literal_Class_With_Root_Namespace();
453
454         $this->assertInstanceOf('stdClass', $container->get('foo'));
455     }
456
457     /**
458      * This test checks the trigger of a deprecation note and should not be removed in major releases.
459      *
460      * @group legacy
461      * @expectedDeprecation The "foo" service is deprecated. You should stop using it, as it will soon be removed.
462      */
463     public function testPrivateServiceTriggersDeprecation()
464     {
465         $container = new ContainerBuilder();
466         $container->register('foo', 'stdClass')
467             ->setPublic(false)
468             ->setDeprecated(true);
469         $container->register('bar', 'stdClass')
470             ->setPublic(true)
471             ->setProperty('foo', new Reference('foo'));
472
473         $container->compile();
474
475         $dumper = new PhpDumper($container);
476         eval('?>'.$dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Private_Service_Triggers_Deprecation')));
477
478         $container = new \Symfony_DI_PhpDumper_Test_Private_Service_Triggers_Deprecation();
479
480         $container->get('bar');
481     }
482 }