/dmCorePlugin/lib/vendor/sfService/sfServiceContainerDumperGraphviz.php

https://github.com/xdade/diem · PHP · 222 lines · 152 code · 34 blank · 36 comment · 7 complexity · d692921ac40cc10f54ba9ba2fd07a195 MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of the symfony framework.
  4. *
  5. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  6. *
  7. * This source file is subject to the MIT license that is bundled
  8. * with this source code in the file LICENSE.
  9. */
  10. /**
  11. * sfServiceContainerDumperGraphviz dumps a service container as a graphviz file.
  12. *
  13. * You can convert the generated dot file with the dot utility (http://www.graphviz.org/):
  14. *
  15. * dot -Tpng container.dot > foo.png
  16. *
  17. * @package symfony
  18. * @subpackage dependency_injection
  19. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  20. * @version SVN: $Id$
  21. */
  22. class sfServiceContainerDumperGraphviz extends sfServiceContainerDumper
  23. {
  24. protected $nodes, $edges;
  25. /**
  26. * Dumps the service container as a graphviz graph.
  27. *
  28. * Available options:
  29. *
  30. * * graph: The default options for the whole graph
  31. * * node: The default options for nodes
  32. * * edge: The default options for edges
  33. * * node.instance: The default options for services that are defined directly by object instances
  34. * * node.definition: The default options for services that are defined via service definition instances
  35. * * node.missing: The default options for missing services
  36. *
  37. * @param array $options An array of options
  38. *
  39. * @return string The dot representation of the service container
  40. */
  41. public function dump(array $options = array())
  42. {
  43. $this->options = array(
  44. 'graph' => array('ratio' => 'compress'),
  45. 'node' => array('fontsize' => 11, 'fontname' => 'Arial', 'shape' => 'record'),
  46. 'edge' => array('fontsize' => 9, 'fontname' => 'Arial', 'color' => 'grey', 'arrowhead' => 'open', 'arrowsize' => 0.5),
  47. 'node.instance' => array('fillcolor' => '#9999ff', 'style' => 'filled'),
  48. 'node.definition' => array('fillcolor' => '#eeeeee'),
  49. 'node.missing' => array('fillcolor' => '#ff9999', 'style' => 'filled'),
  50. );
  51. foreach (array('graph', 'node', 'edge', 'node.instance', 'node.definition', 'node.missing') as $key)
  52. {
  53. if (isset($options[$key]))
  54. {
  55. $this->options[$key] = array_merge($this->options[$key], $options[$key]);
  56. }
  57. }
  58. $this->nodes = $this->findNodes();
  59. $this->edges = array();
  60. foreach ($this->container->getServiceDefinitions() as $id => $definition)
  61. {
  62. $this->edges[$id] = $this->findEdges($id, $definition->getArguments(), true, '');
  63. foreach ($definition->getMethodCalls() as $call)
  64. {
  65. $this->edges[$id] = array_merge(
  66. $this->edges[$id],
  67. $this->findEdges($id, $call[1], false, $call[0].'()')
  68. );
  69. }
  70. }
  71. return $this->startDot().$this->addNodes().$this->addEdges().$this->endDot();
  72. }
  73. protected function addNodes()
  74. {
  75. $code = '';
  76. foreach ($this->nodes as $id => $node)
  77. {
  78. $aliases = $this->getAliases($id);
  79. $code .= sprintf(" node_%s [label=\"%s\\n%s\\n\", shape=%s%s];\n", $this->dotize($id), $id.($aliases ? ' ('.implode(', ', $aliases).')' : ''), $node['class'], $this->options['node']['shape'], $this->addAttributes($node['attributes']));
  80. }
  81. return $code;
  82. }
  83. protected function addEdges()
  84. {
  85. $code = '';
  86. foreach ($this->edges as $id => $edges)
  87. {
  88. foreach ($edges as $edge)
  89. {
  90. $code .= sprintf(" node_%s -> node_%s [label=\"%s\" style=\"%s\"];\n", $this->dotize($id), $this->dotize($edge['to']), $edge['name'], $edge['required'] ? 'filled' : 'dashed');
  91. }
  92. }
  93. return $code;
  94. }
  95. protected function findEdges($id, $arguments, $required, $name)
  96. {
  97. $edges = array();
  98. foreach ($arguments as $argument)
  99. {
  100. if ($argument instanceof sfServiceReference)
  101. {
  102. if (!$this->container->hasService((string) $argument))
  103. {
  104. $this->nodes[(string) $argument] = array('name' => $name, 'required' => $required, 'class' => '', 'attributes' => $this->options['node.missing']);
  105. }
  106. $edges[] = array('name' => $name, 'required' => $required, 'to' => $argument);
  107. }
  108. elseif (is_array($argument))
  109. {
  110. $edges = array_merge($edges, $this->findEdges($id, $argument, $required, $name));
  111. }
  112. }
  113. return $edges;
  114. }
  115. protected function findNodes()
  116. {
  117. $nodes = array();
  118. $container = clone $this->container;
  119. foreach ($container->getServiceDefinitions() as $id => $definition)
  120. {
  121. $nodes[$id] = array('class' => $this->getValue($definition->getClass()), 'attributes' => array_merge($this->options['node.definition'], array('style' => $definition->isShared() ? 'filled' : 'dotted')));
  122. $container->setServiceDefinition($id, new sfServiceDefinition('stdClass'));
  123. }
  124. foreach ($container as $id => $service)
  125. {
  126. if (in_array($id, array_keys($container->getAliases())))
  127. {
  128. continue;
  129. }
  130. if (!$container->hasServiceDefinition($id))
  131. {
  132. $nodes[$id] = array('class' => get_class($service), 'attributes' => $this->options['node.instance']);
  133. }
  134. }
  135. return $nodes;
  136. }
  137. protected function getValue($value, $default = '')
  138. {
  139. return $this->container->resolveValue($value);
  140. }
  141. protected function startDot()
  142. {
  143. $parameters = var_export($this->container->getParameters(), true);
  144. return sprintf("digraph sc {\n %s\n node [%s];\n edge [%s];\n\n",
  145. $this->addOptions($this->options['graph']),
  146. $this->addOptions($this->options['node']),
  147. $this->addOptions($this->options['edge'])
  148. );
  149. }
  150. protected function endDot()
  151. {
  152. return "}\n";
  153. }
  154. protected function addAttributes($attributes)
  155. {
  156. $code = array();
  157. foreach ($attributes as $k => $v)
  158. {
  159. $code[] = sprintf('%s="%s"', $k, $v);
  160. }
  161. return $code ? ', '.implode(', ', $code) : '';
  162. }
  163. protected function addOptions($options)
  164. {
  165. $code = array();
  166. foreach ($options as $k => $v)
  167. {
  168. $code[] = sprintf('%s="%s"', $k, $v);
  169. }
  170. return implode(' ', $code);
  171. }
  172. protected function dotize($id)
  173. {
  174. return strtolower(preg_replace('/[^\w]/i', '_', $id));
  175. }
  176. protected function getAliases($id)
  177. {
  178. $aliases = array();
  179. foreach ($this->container->getAliases() as $alias => $origin)
  180. {
  181. if ($id == $origin)
  182. {
  183. $aliases[] = $alias;
  184. }
  185. }
  186. return $aliases;
  187. }
  188. }