YamlDumper.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\DependencyInjection\Dumper;
  11. use Symfony\Component\Yaml\Dumper as YmlDumper;
  12. use Symfony\Component\DependencyInjection\Alias;
  13. use Symfony\Component\DependencyInjection\ContainerInterface;
  14. use Symfony\Component\DependencyInjection\Definition;
  15. use Symfony\Component\DependencyInjection\Parameter;
  16. use Symfony\Component\DependencyInjection\Reference;
  17. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  18. use Symfony\Component\DependencyInjection\ContainerBuilder;
  19. /**
  20. * YamlDumper dumps a service container as a YAML string.
  21. *
  22. * @author Fabien Potencier <fabien@symfony.com>
  23. *
  24. * @api
  25. */
  26. class YamlDumper extends Dumper
  27. {
  28. private $dumper;
  29. /**
  30. * Constructor.
  31. *
  32. * @param ContainerBuilder $container The service container to dump
  33. *
  34. * @api
  35. */
  36. public function __construct(ContainerBuilder $container)
  37. {
  38. parent::__construct($container);
  39. $this->dumper = new YmlDumper();
  40. }
  41. /**
  42. * Dumps the service container as an YAML string.
  43. *
  44. * @param array $options An array of options
  45. *
  46. * @return string A YAML string representing of the service container
  47. *
  48. * @api
  49. */
  50. public function dump(array $options = array())
  51. {
  52. return $this->addParameters()."\n".$this->addServices();
  53. }
  54. /**
  55. * Adds a service
  56. *
  57. * @param string $id
  58. * @param Definition $definition
  59. *
  60. * @return string
  61. */
  62. private function addService($id, $definition)
  63. {
  64. $code = " $id:\n";
  65. if ($definition->getClass()) {
  66. $code .= sprintf(" class: %s\n", $definition->getClass());
  67. }
  68. $tagsCode = '';
  69. foreach ($definition->getTags() as $name => $tags) {
  70. foreach ($tags as $attributes) {
  71. $att = array();
  72. foreach ($attributes as $key => $value) {
  73. $att[] = sprintf('%s: %s', $this->dumper->dump($key), $this->dumper->dump($value));
  74. }
  75. $att = $att ? ', '.implode(' ', $att) : '';
  76. $tagsCode .= sprintf(" - { name: %s%s }\n", $this->dumper->dump($name), $att);
  77. }
  78. }
  79. if ($tagsCode) {
  80. $code .= " tags:\n".$tagsCode;
  81. }
  82. if ($definition->getFile()) {
  83. $code .= sprintf(" file: %s\n", $definition->getFile());
  84. }
  85. if ($definition->isSynthetic()) {
  86. $code .= sprintf(" synthetic: true\n");
  87. }
  88. if ($definition->isSynchronized()) {
  89. $code .= sprintf(" synchronized: true\n");
  90. }
  91. if ($definition->getFactoryClass()) {
  92. $code .= sprintf(" factory_class: %s\n", $definition->getFactoryClass());
  93. }
  94. if ($definition->isLazy()) {
  95. $code .= sprintf(" lazy: true\n");
  96. }
  97. if ($definition->getFactoryMethod()) {
  98. $code .= sprintf(" factory_method: %s\n", $definition->getFactoryMethod());
  99. }
  100. if ($definition->getFactoryService()) {
  101. $code .= sprintf(" factory_service: %s\n", $definition->getFactoryService());
  102. }
  103. if ($definition->getArguments()) {
  104. $code .= sprintf(" arguments: %s\n", $this->dumper->dump($this->dumpValue($definition->getArguments()), 0));
  105. }
  106. if ($definition->getProperties()) {
  107. $code .= sprintf(" properties: %s\n", $this->dumper->dump($this->dumpValue($definition->getProperties()), 0));
  108. }
  109. if ($definition->getMethodCalls()) {
  110. $code .= sprintf(" calls:\n%s\n", $this->dumper->dump($this->dumpValue($definition->getMethodCalls()), 1, 12));
  111. }
  112. if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) {
  113. $code .= sprintf(" scope: %s\n", $scope);
  114. }
  115. if ($callable = $definition->getConfigurator()) {
  116. if (is_array($callable)) {
  117. if ($callable[0] instanceof Reference) {
  118. $callable = array($this->getServiceCall((string) $callable[0], $callable[0]), $callable[1]);
  119. } else {
  120. $callable = array($callable[0], $callable[1]);
  121. }
  122. }
  123. $code .= sprintf(" configurator: %s\n", $this->dumper->dump($callable, 0));
  124. }
  125. return $code;
  126. }
  127. /**
  128. * Adds a service alias
  129. *
  130. * @param string $alias
  131. * @param Alias $id
  132. *
  133. * @return string
  134. */
  135. private function addServiceAlias($alias, $id)
  136. {
  137. if ($id->isPublic()) {
  138. return sprintf(" %s: @%s\n", $alias, $id);
  139. } else {
  140. return sprintf(" %s:\n alias: %s\n public: false", $alias, $id);
  141. }
  142. }
  143. /**
  144. * Adds services
  145. *
  146. * @return string
  147. */
  148. private function addServices()
  149. {
  150. if (!$this->container->getDefinitions()) {
  151. return '';
  152. }
  153. $code = "services:\n";
  154. foreach ($this->container->getDefinitions() as $id => $definition) {
  155. $code .= $this->addService($id, $definition);
  156. }
  157. $aliases = $this->container->getAliases();
  158. foreach ($aliases as $alias => $id) {
  159. while (isset($aliases[(string) $id])) {
  160. $id = $aliases[(string) $id];
  161. }
  162. $code .= $this->addServiceAlias($alias, $id);
  163. }
  164. return $code;
  165. }
  166. /**
  167. * Adds parameters
  168. *
  169. * @return string
  170. */
  171. private function addParameters()
  172. {
  173. if (!$this->container->getParameterBag()->all()) {
  174. return '';
  175. }
  176. $parameters = $this->prepareParameters($this->container->getParameterBag()->all(), $this->container->isFrozen());
  177. return $this->dumper->dump(array('parameters' => $parameters), 2);
  178. }
  179. /**
  180. * Dumps the value to YAML format
  181. *
  182. * @param mixed $value
  183. *
  184. * @return mixed
  185. *
  186. * @throws RuntimeException When trying to dump object or resource
  187. */
  188. private function dumpValue($value)
  189. {
  190. if (is_array($value)) {
  191. $code = array();
  192. foreach ($value as $k => $v) {
  193. $code[$k] = $this->dumpValue($v);
  194. }
  195. return $code;
  196. } elseif ($value instanceof Reference) {
  197. return $this->getServiceCall((string) $value, $value);
  198. } elseif ($value instanceof Parameter) {
  199. return $this->getParameterCall((string) $value);
  200. } elseif (is_object($value) || is_resource($value)) {
  201. throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
  202. }
  203. return $value;
  204. }
  205. /**
  206. * Gets the service call.
  207. *
  208. * @param string $id
  209. * @param Reference $reference
  210. *
  211. * @return string
  212. */
  213. private function getServiceCall($id, Reference $reference = null)
  214. {
  215. if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
  216. return sprintf('@?%s', $id);
  217. }
  218. return sprintf('@%s', $id);
  219. }
  220. /**
  221. * Gets parameter call.
  222. *
  223. * @param string $id
  224. *
  225. * @return string
  226. */
  227. private function getParameterCall($id)
  228. {
  229. return sprintf('%%%s%%', $id);
  230. }
  231. /**
  232. * Prepares parameters.
  233. *
  234. * @param array $parameters
  235. * @param Boolean $escape
  236. *
  237. * @return array
  238. */
  239. private function prepareParameters($parameters, $escape = true)
  240. {
  241. $filtered = array();
  242. foreach ($parameters as $key => $value) {
  243. if (is_array($value)) {
  244. $value = $this->prepareParameters($value, $escape);
  245. } elseif ($value instanceof Reference || is_string($value) && 0 === strpos($value, '@')) {
  246. $value = '@'.$value;
  247. }
  248. $filtered[$key] = $value;
  249. }
  250. return $escape ? $this->escape($filtered) : $filtered;
  251. }
  252. /**
  253. * Escapes arguments
  254. *
  255. * @param array $arguments
  256. *
  257. * @return array
  258. */
  259. private function escape($arguments)
  260. {
  261. $args = array();
  262. foreach ($arguments as $k => $v) {
  263. if (is_array($v)) {
  264. $args[$k] = $this->escape($v);
  265. } elseif (is_string($v)) {
  266. $args[$k] = str_replace('%', '%%', $v);
  267. } else {
  268. $args[$k] = $v;
  269. }
  270. }
  271. return $args;
  272. }
  273. }