4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\DependencyInjection\Tests\Loader;
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\DependencyInjection\ContainerBuilder;
16 use Symfony\Component\DependencyInjection\Reference;
17 use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
18 use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
19 use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
20 use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
21 use Symfony\Component\Config\Loader\LoaderResolver;
22 use Symfony\Component\Config\FileLocator;
23 use Symfony\Component\ExpressionLanguage\Expression;
25 class YamlFileLoaderTest extends TestCase
27 protected static $fixturesPath;
29 public static function setUpBeforeClass()
31 self::$fixturesPath = realpath(__DIR__.'/../Fixtures/');
32 require_once self::$fixturesPath.'/includes/foo.php';
33 require_once self::$fixturesPath.'/includes/ProjectExtension.php';
37 * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
38 * @expectedExceptionMessageRegExp /The file ".+" does not exist./
40 public function testLoadUnExistFile()
42 $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/ini'));
43 $r = new \ReflectionObject($loader);
44 $m = $r->getMethod('loadFile');
45 $m->setAccessible(true);
47 $m->invoke($loader, 'foo.yml');
51 * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
52 * @expectedExceptionMessageRegExp /The file ".+" does not contain valid YAML./
54 public function testLoadInvalidYamlFile()
56 $path = self::$fixturesPath.'/ini';
57 $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator($path));
58 $r = new \ReflectionObject($loader);
59 $m = $r->getMethod('loadFile');
60 $m->setAccessible(true);
62 $m->invoke($loader, $path.'/parameters.ini');
66 * @dataProvider provideInvalidFiles
67 * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
69 public function testLoadInvalidFile($file)
71 $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml'));
73 $loader->load($file.'.yml');
76 public function provideInvalidFiles()
79 array('bad_parameters'),
82 array('bad_services'),
91 public function testLoadParameters()
93 $container = new ContainerBuilder();
94 $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
95 $loader->load('services2.yml');
96 $this->assertEquals(array('foo' => 'bar', 'mixedcase' => array('MixedCaseKey' => 'value'), 'values' => array(true, false, 0, 1000.3), 'bar' => 'foo', 'escape' => '@escapeme', 'foo_bar' => new Reference('foo_bar')), $container->getParameterBag()->all(), '->load() converts YAML keys to lowercase');
99 public function testLoadImports()
101 $container = new ContainerBuilder();
102 $resolver = new LoaderResolver(array(
103 new IniFileLoader($container, new FileLocator(self::$fixturesPath.'/ini')),
104 new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')),
105 new PhpFileLoader($container, new FileLocator(self::$fixturesPath.'/php')),
106 $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')),
108 $loader->setResolver($resolver);
109 $loader->load('services4.yml');
111 $actual = $container->getParameterBag()->all();
112 $expected = array('foo' => 'bar', 'values' => array(true, false), 'bar' => '%foo%', 'escape' => '@escapeme', 'foo_bar' => new Reference('foo_bar'), 'mixedcase' => array('MixedCaseKey' => 'value'), 'imported_from_ini' => true, 'imported_from_xml' => true);
113 $this->assertEquals(array_keys($expected), array_keys($actual), '->load() imports and merges imported files');
115 // Bad import throws no exception due to ignore_errors value.
116 $loader->load('services4_bad_import.yml');
122 public function testLegacyLoadServices()
124 $container = new ContainerBuilder();
125 $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
126 $loader->load('legacy-services6.yml');
127 $services = $container->getDefinitions();
128 $this->assertEquals('FooClass', $services['constructor']->getClass());
129 $this->assertEquals('getInstance', $services['constructor']->getFactoryMethod());
130 $this->assertEquals('BazClass', $services['factory_service']->getClass());
131 $this->assertEquals('baz_factory', $services['factory_service']->getFactoryService());
132 $this->assertEquals('getInstance', $services['factory_service']->getFactoryMethod());
133 $this->assertEquals('container', $services['scope.container']->getScope());
134 $this->assertEquals('custom', $services['scope.custom']->getScope());
135 $this->assertEquals('prototype', $services['scope.prototype']->getScope());
136 $this->assertTrue($services['request']->isSynthetic(), '->load() parses the synthetic flag');
137 $this->assertTrue($services['request']->isSynchronized(), '->load() parses the synchronized flag');
138 $this->assertTrue($services['request']->isLazy(), '->load() parses the lazy flag');
139 $this->assertNull($services['request']->getDecoratedService());
142 public function testLoadServices()
144 $container = new ContainerBuilder();
145 $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
146 $loader->load('services6.yml');
147 $services = $container->getDefinitions();
148 $this->assertTrue(isset($services['foo']), '->load() parses service elements');
149 $this->assertFalse($services['not_shared']->isShared(), '->load() parses the shared flag');
150 $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Definition', $services['foo'], '->load() converts service element to Definition instances');
151 $this->assertEquals('FooClass', $services['foo']->getClass(), '->load() parses the class attribute');
152 $this->assertEquals('%path%/foo.php', $services['file']->getFile(), '->load() parses the file tag');
153 $this->assertEquals(array('foo', new Reference('foo'), array(true, false)), $services['arguments']->getArguments(), '->load() parses the argument tags');
154 $this->assertEquals('sc_configure', $services['configurator1']->getConfigurator(), '->load() parses the configurator tag');
155 $this->assertEquals(array(new Reference('baz'), 'configure'), $services['configurator2']->getConfigurator(), '->load() parses the configurator tag');
156 $this->assertEquals(array('BazClass', 'configureStatic'), $services['configurator3']->getConfigurator(), '->load() parses the configurator tag');
157 $this->assertEquals(array(array('setBar', array()), array('setBar', array()), array('setBar', array(new Expression('service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")')))), $services['method_call1']->getMethodCalls(), '->load() parses the method_call tag');
158 $this->assertEquals(array(array('setBar', array('foo', new Reference('foo'), array(true, false)))), $services['method_call2']->getMethodCalls(), '->load() parses the method_call tag');
159 $this->assertEquals('factory', $services['new_factory1']->getFactory(), '->load() parses the factory tag');
160 $this->assertEquals(array(new Reference('baz'), 'getClass'), $services['new_factory2']->getFactory(), '->load() parses the factory tag');
161 $this->assertEquals(array('BazClass', 'getInstance'), $services['new_factory3']->getFactory(), '->load() parses the factory tag');
163 $aliases = $container->getAliases();
164 $this->assertTrue(isset($aliases['alias_for_foo']), '->load() parses aliases');
165 $this->assertEquals('foo', (string) $aliases['alias_for_foo'], '->load() parses aliases');
166 $this->assertTrue($aliases['alias_for_foo']->isPublic());
167 $this->assertTrue(isset($aliases['another_alias_for_foo']));
168 $this->assertEquals('foo', (string) $aliases['another_alias_for_foo']);
169 $this->assertFalse($aliases['another_alias_for_foo']->isPublic());
171 $this->assertEquals(array('decorated', null, 0), $services['decorator_service']->getDecoratedService());
172 $this->assertEquals(array('decorated', 'decorated.pif-pouf', 0), $services['decorator_service_with_name']->getDecoratedService());
173 $this->assertEquals(array('decorated', 'decorated.pif-pouf', 5), $services['decorator_service_with_name_and_priority']->getDecoratedService());
176 public function testLoadFactoryShortSyntax()
178 $container = new ContainerBuilder();
179 $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
180 $loader->load('services14.yml');
181 $services = $container->getDefinitions();
183 $this->assertEquals(array(new Reference('baz'), 'getClass'), $services['factory']->getFactory(), '->load() parses the factory tag with service:method');
184 $this->assertEquals(array('FooBacFactory', 'createFooBar'), $services['factory_with_static_call']->getFactory(), '->load() parses the factory tag with Class::method');
187 public function testExtensions()
189 $container = new ContainerBuilder();
190 $container->registerExtension(new \ProjectExtension());
191 $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
192 $loader->load('services10.yml');
193 $container->compile();
194 $services = $container->getDefinitions();
195 $parameters = $container->getParameterBag()->all();
197 $this->assertTrue(isset($services['project.service.bar']), '->load() parses extension elements');
198 $this->assertTrue(isset($parameters['project.parameter.bar']), '->load() parses extension elements');
200 $this->assertEquals('BAR', $services['project.service.foo']->getClass(), '->load() parses extension elements');
201 $this->assertEquals('BAR', $parameters['project.parameter.foo'], '->load() parses extension elements');
204 $loader->load('services11.yml');
205 $this->fail('->load() throws an InvalidArgumentException if the tag is not valid');
206 } catch (\Exception $e) {
207 $this->assertInstanceOf('\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the tag is not valid');
208 $this->assertStringStartsWith('There is no extension able to load the configuration for "foobarfoobar" (in', $e->getMessage(), '->load() throws an InvalidArgumentException if the tag is not valid');
212 public function testSupports()
214 $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator());
216 $this->assertTrue($loader->supports('foo.yml'), '->supports() returns true if the resource is loadable');
217 $this->assertTrue($loader->supports('foo.yaml'), '->supports() returns true if the resource is loadable');
218 $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
221 public function testNonArrayTagsThrowsException()
223 $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml'));
225 $loader->load('badtag1.yml');
226 $this->fail('->load() should throw an exception when the tags key of a service is not an array');
227 } catch (\Exception $e) {
228 $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the tags key is not an array');
229 $this->assertStringStartsWith('Parameter "tags" must be an array for service', $e->getMessage(), '->load() throws an InvalidArgumentException if the tags key is not an array');
234 * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
235 * @expectedExceptionMessage A "tags" entry must be an array for service
237 public function testNonArrayTagThrowsException()
239 $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml'));
240 $loader->load('badtag4.yml');
243 public function testTagWithoutNameThrowsException()
245 $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml'));
247 $loader->load('badtag2.yml');
248 $this->fail('->load() should throw an exception when a tag is missing the name key');
249 } catch (\Exception $e) {
250 $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if a tag is missing the name key');
251 $this->assertStringStartsWith('A "tags" entry is missing a "name" key for service ', $e->getMessage(), '->load() throws an InvalidArgumentException if a tag is missing the name key');
255 public function testTagWithAttributeArrayThrowsException()
257 $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml'));
259 $loader->load('badtag3.yml');
260 $this->fail('->load() should throw an exception when a tag-attribute is not a scalar');
261 } catch (\Exception $e) {
262 $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if a tag-attribute is not a scalar');
263 $this->assertStringStartsWith('A "tags" attribute must be of a scalar-type for service "foo_service", tag "foo", attribute "bar"', $e->getMessage(), '->load() throws an InvalidArgumentException if a tag-attribute is not a scalar');
267 public function testLoadYamlOnlyWithKeys()
269 $container = new ContainerBuilder();
270 $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
271 $loader->load('services21.yml');
273 $definition = $container->getDefinition('manager');
274 $this->assertEquals(array(array('setLogger', array(new Reference('logger'))), array('setClass', array('User'))), $definition->getMethodCalls());
275 $this->assertEquals(array(true), $definition->getArguments());
276 $this->assertEquals(array('manager' => array(array('alias' => 'user'))), $definition->getTags());
280 * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
281 * @expectedExceptionMessageRegExp /The tag name for service ".+" in .+ must be a non-empty string/
283 public function testTagWithEmptyNameThrowsException()
285 $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml'));
286 $loader->load('tag_name_empty_string.yml');
290 * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
291 * @expectedExceptionMessageREgExp /The tag name for service "\.+" must be a non-empty string/
293 public function testTagWithNonStringNameThrowsException()
295 $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml'));
296 $loader->load('tag_name_no_string.yml');
300 * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
302 public function testTypesNotArray()
304 $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml'));
305 $loader->load('bad_types1.yml');
309 * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
311 public function testTypeNotString()
313 $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml'));
314 $loader->load('bad_types2.yml');
317 public function testTypes()
319 $container = new ContainerBuilder();
320 $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
321 $loader->load('services22.yml');
323 $this->assertEquals(array('Foo', 'Bar'), $container->getDefinition('foo_service')->getAutowiringTypes());
324 $this->assertEquals(array('Foo'), $container->getDefinition('baz_service')->getAutowiringTypes());
327 public function testAutowire()
329 $container = new ContainerBuilder();
330 $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
331 $loader->load('services23.yml');
333 $this->assertTrue($container->getDefinition('bar_service')->isAutowired());
337 * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
338 * @expectedExceptionMessage The value of the "decorates" option for the "bar" service must be the id of the service without the "@" prefix (replace "@foo" with "foo").
340 public function testDecoratedServicesWithWrongSyntaxThrowsException()
342 $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml'));
343 $loader->load('bad_decorates.yml');