Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
GraphvizDumper.php
001 <?php
002
003 /*
004 * This file is part of the Symfony package.
005 *
006 * (c) Fabien Potencier <fabien@symfony.com>
007 *
008 * For the full copyright and license information, please view the LICENSE
009 * file that was distributed with this source code.
010 */
011
012 namespace Symfony\Component\DependencyInjection\Dumper;
013
014 use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
015 use Symfony\Component\DependencyInjection\ContainerBuilder;
016 use Symfony\Component\DependencyInjection\Definition;
017 use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
018 use Symfony\Component\DependencyInjection\Parameter;
019 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
020 use Symfony\Component\DependencyInjection\Reference;
021
022 /**
023 * GraphvizDumper dumps a service container as a graphviz file.
024 *
025 * You can convert the generated dot file with the dot utility (http://www.graphviz.org/):
026 *
027 * dot -Tpng container.dot > foo.png
028 *
029 * @author Fabien Potencier <fabien@symfony.com>
030 */
031 class GraphvizDumper extends Dumper
032 {
033 private $nodes;
034 private $edges;
035 // All values should be strings
036 private $options = [
037 'graph' => ['ratio' => 'compress'],
038 'node' => ['fontsize' => '11', 'fontname' => 'Arial', 'shape' => 'record'],
039 'edge' => ['fontsize' => '9', 'fontname' => 'Arial', 'color' => 'grey', 'arrowhead' => 'open', 'arrowsize' => '0.5'],
040 'node.instance' => ['fillcolor' => '#9999ff', 'style' => 'filled'],
041 'node.definition' => ['fillcolor' => '#eeeeee'],
042 'node.missing' => ['fillcolor' => '#ff9999', 'style' => 'filled'],
043 ];
044
045 /**
046 * Dumps the service container as a graphviz graph.
047 *
048 * Available options:
049 *
050 * * graph: The default options for the whole graph
051 * * node: The default options for nodes
052 * * edge: The default options for edges
053 * * node.instance: The default options for services that are defined directly by object instances
054 * * node.definition: The default options for services that are defined via service definition instances
055 * * node.missing: The default options for missing services
056 *
057 * @return string The dot representation of the service container
058 */
059 public function dump(array $options = [])
060 {
061 foreach (['graph', 'node', 'edge', 'node.instance', 'node.definition', 'node.missing'] as $key) {
062 if (isset($options[$key])) {
063 $this->options[$key] = array_merge($this->options[$key], $options[$key]);
064 }
065 }
066
067 $this->nodes = $this->findNodes();
068
069 $this->edges = [];
070 foreach ($this->container->getDefinitions() as $id => $definition) {
071 $this->edges[$id] = array_merge(
072 $this->findEdges($id, $definition->getArguments(), true, ''),
073 $this->findEdges($id, $definition->getProperties(), false, '')
074 );
075
076 foreach ($definition->getMethodCalls() as $call) {
077 $this->edges[$id] = array_merge(
078 $this->edges[$id],
079 $this->findEdges($id, $call[1], false, $call[0].'()')
080 );
081 }
082 }
083
084 return $this->container->resolveEnvPlaceholders($this->startDot().$this->addNodes().$this->addEdges().$this->endDot(), '__ENV_%s__');
085 }
086
087 /**
088 * Returns all nodes.
089 *
090 * @return string A string representation of all nodes
091 */
092 private function addNodes()
093 {
094 $code = '';
095 foreach ($this->nodes as $id => $node) {
096 $aliases = $this->getAliases($id);
097
098 $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']));
099 }
100
101 return $code;
102 }
103
104 /**
105 * Returns all edges.
106 *
107 * @return string A string representation of all edges
108 */
109 private function addEdges()
110 {
111 $code = '';
112 foreach ($this->edges as $id => $edges) {
113 foreach ($edges as $edge) {
114 $code .= sprintf(" node_%s -> node_%s [label=\"%s\" style=\"%s\"%s];\n", $this->dotize($id), $this->dotize($edge['to']), $edge['name'], $edge['required'] ? 'filled' : 'dashed', $edge['lazy'] ? ' color="#9999ff"' : '');
115 }
116 }
117
118 return $code;
119 }
120
121 /**
122 * Finds all edges belonging to a specific service id.
123 *
124 * @param string $id The service id used to find edges
125 * @param array $arguments An array of arguments
126 * @param bool $required
127 * @param string $name
128 *
129 * @return array An array of edges
130 */
131 private function findEdges($id, array $arguments, $required, $name, $lazy = false)
132 {
133 $edges = [];
134 foreach ($arguments as $argument) {
135 if ($argument instanceof Parameter) {
136 $argument = $this->container->hasParameter($argument) ? $this->container->getParameter($argument) : null;
137 } elseif (\is_string($argument) && preg_match('/^%([^%]+)%$/', $argument, $match)) {
138 $argument = $this->container->hasParameter($match[1]) ? $this->container->getParameter($match[1]) : null;
139 }
140
141 if ($argument instanceof Reference) {
142 $lazyEdge = $lazy;
143
144 if (!$this->container->has((string) $argument)) {
145 $this->nodes[(string) $argument] = ['name' => $name, 'required' => $required, 'class' => '', 'attributes' => $this->options['node.missing']];
146 } elseif ('service_container' !== (string) $argument) {
147 $lazyEdge = $lazy || $this->container->getDefinition((string) $argument)->isLazy();
148 }
149
150 $edges[] = ['name' => $name, 'required' => $required, 'to' => $argument, 'lazy' => $lazyEdge];
151 } elseif ($argument instanceof ArgumentInterface) {
152 $edges = array_merge($edges, $this->findEdges($id, $argument->getValues(), $required, $name, true));
153 } elseif ($argument instanceof Definition) {
154 $edges = array_merge($edges,
155 $this->findEdges($id, $argument->getArguments(), $required, ''),
156 $this->findEdges($id, $argument->getProperties(), false, '')
157 );
158 foreach ($argument->getMethodCalls() as $call) {
159 $edges = array_merge($edges, $this->findEdges($id, $call[1], false, $call[0].'()'));
160 }
161 } elseif (\is_array($argument)) {
162 $edges = array_merge($edges, $this->findEdges($id, $argument, $required, $name, $lazy));
163 }
164 }
165
166 return $edges;
167 }
168
169 /**
170 * Finds all nodes.
171 *
172 * @return array An array of all nodes
173 */
174 private function findNodes()
175 {
176 $nodes = [];
177
178 $container = $this->cloneContainer();
179
180 foreach ($container->getDefinitions() as $id => $definition) {
181 $class = $definition->getClass();
182
183 if ('\\' === substr($class, 0, 1)) {
184 $class = substr($class, 1);
185 }
186
187 try {
188 $class = $this->container->getParameterBag()->resolveValue($class);
189 } catch (ParameterNotFoundException $e) {
190 }
191
192 $nodes[$id] = ['class' => str_replace('\\', '\\\\', $class), 'attributes' => array_merge($this->options['node.definition'], ['style' => $definition->isShared() ? 'filled' : 'dotted'])];
193 $container->setDefinition($id, new Definition('stdClass'));
194 }
195
196 foreach ($container->getServiceIds() as $id) {
197 if (\array_key_exists($id, $container->getAliases())) {
198 continue;
199 }
200
201 if (!$container->hasDefinition($id)) {
202 $nodes[$id] = ['class' => str_replace('\\', '\\\\', \get_class($container->get($id))), 'attributes' => $this->options['node.instance']];
203 }
204 }
205
206 return $nodes;
207 }
208
209 private function cloneContainer()
210 {
211 $parameterBag = new ParameterBag($this->container->getParameterBag()->all());
212
213 $container = new ContainerBuilder($parameterBag);
214 $container->setDefinitions($this->container->getDefinitions());
215 $container->setAliases($this->container->getAliases());
216 $container->setResources($this->container->getResources());
217 foreach ($this->container->getExtensions() as $extension) {
218 $container->registerExtension($extension);
219 }
220
221 return $container;
222 }
223
224 /**
225 * Returns the start dot.
226 *
227 * @return string The string representation of a start dot
228 */
229 private function startDot()
230 {
231 return sprintf("digraph sc {\n %s\n node [%s];\n edge [%s];\n\n",
232 $this->addOptions($this->options['graph']),
233 $this->addOptions($this->options['node']),
234 $this->addOptions($this->options['edge'])
235 );
236 }
237
238 /**
239 * Returns the end dot.
240 *
241 * @return string
242 */
243 private function endDot()
244 {
245 return "}\n";
246 }
247
248 /**
249 * Adds attributes.
250 *
251 * @param array $attributes An array of attributes
252 *
253 * @return string A comma separated list of attributes
254 */
255 private function addAttributes(array $attributes)
256 {
257 $code = [];
258 foreach ($attributes as $k => $v) {
259 $code[] = sprintf('%s="%s"', $k, $v);
260 }
261
262 return $code ? ', '.implode(', ', $code) : '';
263 }
264
265 /**
266 * Adds options.
267 *
268 * @param array $options An array of options
269 *
270 * @return string A space separated list of options
271 */
272 private function addOptions(array $options)
273 {
274 $code = [];
275 foreach ($options as $k => $v) {
276 $code[] = sprintf('%s="%s"', $k, $v);
277 }
278
279 return implode(' ', $code);
280 }
281
282 /**
283 * Dotizes an identifier.
284 *
285 * @param string $id The identifier to dotize
286 *
287 * @return string A dotized string
288 */
289 private function dotize($id)
290 {
291 return strtolower(preg_replace('/\W/i', '_', $id));
292 }
293
294 /**
295 * Compiles an array of aliases for a specified service id.
296 *
297 * @param string $id A service id
298 *
299 * @return array An array of aliases
300 */
301 private function getAliases($id)
302 {
303 $aliases = [];
304 foreach ($this->container->getAliases() as $alias => $origin) {
305 if ($id == $origin) {
306 $aliases[] = $alias;
307 }
308 }
309
310 return $aliases;
311 }
312 }
313