YamlFileLoader.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <?php
  2. namespace Symfony\Component\DependencyInjection\Loader;
  3. use Symfony\Component\DependencyInjection\ContainerInterface;
  4. use Symfony\Component\DependencyInjection\Definition;
  5. use Symfony\Component\DependencyInjection\Reference;
  6. use Symfony\Component\DependencyInjection\ContainerBuilder;
  7. use Symfony\Component\DependencyInjection\Resource\FileResource;
  8. use Symfony\Component\Yaml\Yaml;
  9. /*
  10. * This file is part of the Symfony framework.
  11. *
  12. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  13. *
  14. * This source file is subject to the MIT license that is bundled
  15. * with this source code in the file LICENSE.
  16. */
  17. /**
  18. * YamlFileLoader loads YAML files service definitions.
  19. *
  20. * The YAML format does not support anonymous services (cf. the XML loader).
  21. *
  22. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  23. */
  24. class YamlFileLoader extends FileLoader
  25. {
  26. /**
  27. * Loads a Yaml file.
  28. *
  29. * @param mixed $resource The resource
  30. */
  31. public function load($file)
  32. {
  33. $path = $this->findFile($file);
  34. $content = $this->loadFile($path);
  35. $this->container->addResource(new FileResource($path));
  36. if (!$content) {
  37. return;
  38. }
  39. // imports
  40. $this->parseImports($content, $file);
  41. // extensions
  42. $this->loadFromExtensions($content);
  43. // parameters
  44. if (isset($content['parameters'])) {
  45. foreach ($content['parameters'] as $key => $value) {
  46. $this->container->setParameter($key, $this->resolveServices($value));
  47. }
  48. }
  49. // services
  50. $this->parseDefinitions($content, $file);
  51. }
  52. /**
  53. * Returns true if this class supports the given resource.
  54. *
  55. * @param mixed $resource A resource
  56. *
  57. * @return Boolean true if this class supports the given resource, false otherwise
  58. */
  59. public function supports($resource)
  60. {
  61. return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION);
  62. }
  63. protected function parseImports($content, $file)
  64. {
  65. if (!isset($content['imports'])) {
  66. return;
  67. }
  68. foreach ($content['imports'] as $import) {
  69. $this->currentDir = dirname($file);
  70. $this->import($import['resource'], isset($import['ignore_errors']) ? (Boolean) $import['ignore_errors'] : false);
  71. }
  72. }
  73. protected function parseDefinitions($content, $file)
  74. {
  75. if (!isset($content['services'])) {
  76. return;
  77. }
  78. foreach ($content['services'] as $id => $service) {
  79. $this->parseDefinition($id, $service, $file);
  80. }
  81. }
  82. protected function parseDefinition($id, $service, $file)
  83. {
  84. if (is_string($service) && 0 === strpos($service, '@')) {
  85. $this->container->setAlias($id, substr($service, 1));
  86. return;
  87. }
  88. $definition = new Definition();
  89. if (isset($service['class'])) {
  90. $definition->setClass($service['class']);
  91. }
  92. if (isset($service['shared'])) {
  93. $definition->setShared($service['shared']);
  94. }
  95. if (isset($service['factory_method'])) {
  96. $definition->setFactoryMethod($service['factory_method']);
  97. }
  98. if (isset($service['factory_service'])) {
  99. $definition->setFactoryService($service['factory_service']);
  100. }
  101. if (isset($service['file'])) {
  102. $definition->setFile($service['file']);
  103. }
  104. if (isset($service['arguments'])) {
  105. $definition->setArguments($this->resolveServices($service['arguments']));
  106. }
  107. if (isset($service['configurator'])) {
  108. if (is_string($service['configurator'])) {
  109. $definition->setConfigurator($service['configurator']);
  110. } else {
  111. $definition->setConfigurator(array($this->resolveServices($service['configurator'][0]), $service['configurator'][1]));
  112. }
  113. }
  114. if (isset($service['calls'])) {
  115. foreach ($service['calls'] as $call) {
  116. $definition->addMethodCall($call[0], $this->resolveServices($call[1]));
  117. }
  118. }
  119. if (isset($service['tags'])) {
  120. foreach ($service['tags'] as $tag) {
  121. $name = $tag['name'];
  122. unset($tag['name']);
  123. $definition->addTag($name, $tag);
  124. }
  125. }
  126. $this->container->setDefinition($id, $definition);
  127. }
  128. protected function loadFile($file)
  129. {
  130. return $this->validate(Yaml::load($file), $file);
  131. }
  132. /**
  133. * @throws \InvalidArgumentException When service file is not valid
  134. */
  135. protected function validate($content, $file)
  136. {
  137. if (null === $content) {
  138. return $content;
  139. }
  140. if (!is_array($content)) {
  141. throw new \InvalidArgumentException(sprintf('The service file "%s" is not valid.', $file));
  142. }
  143. foreach (array_keys($content) as $key) {
  144. if (in_array($key, array('imports', 'parameters', 'services'))) {
  145. continue;
  146. }
  147. // can it be handled by an extension?
  148. if (false !== strpos($key, '.')) {
  149. list($namespace, $tag) = explode('.', $key);
  150. if (!$this->container->hasExtension($namespace)) {
  151. throw new \InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s" (in %s).', $key, $file));
  152. }
  153. continue;
  154. }
  155. throw new \InvalidArgumentException(sprintf('The "%s" tag is not valid (in %s).', $key, $file));
  156. }
  157. return $content;
  158. }
  159. protected function resolveServices($value)
  160. {
  161. if (is_array($value)) {
  162. $value = array_map(array($this, 'resolveServices'), $value);
  163. } else if (is_string($value) && 0 === strpos($value, '@@')) {
  164. $value = new Reference(substr($value, 2), ContainerInterface::IGNORE_ON_INVALID_REFERENCE);
  165. } else if (is_string($value) && 0 === strpos($value, '@')) {
  166. $value = new Reference(substr($value, 1));
  167. }
  168. return $value;
  169. }
  170. protected function loadFromExtensions($content)
  171. {
  172. foreach ($content as $key => $values) {
  173. if (in_array($key, array('imports', 'parameters', 'services'))) {
  174. continue;
  175. }
  176. list($namespace, $tag) = explode('.', $key);
  177. if (!is_array($values)) {
  178. $values = array();
  179. }
  180. $this->container->loadFromExtension($namespace, $tag, $values);
  181. }
  182. }
  183. }