1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the Symfony package. |
5
|
|
|
* |
6
|
|
|
* (c) Fabien Potencier <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Symfony\Component\DependencyInjection\Dumper; |
13
|
|
|
|
14
|
|
|
use Symfony\Component\DependencyInjection\ContainerInterface; |
15
|
|
|
use Symfony\Component\DependencyInjection\Parameter; |
16
|
|
|
use Symfony\Component\DependencyInjection\Reference; |
17
|
|
|
use Symfony\Component\DependencyInjection\Definition; |
18
|
|
|
use Symfony\Component\DependencyInjection\Alias; |
19
|
|
|
use Symfony\Component\DependencyInjection\Exception\RuntimeException; |
20
|
|
|
use Symfony\Component\ExpressionLanguage\Expression; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* XmlDumper dumps a service container as an XML string. |
24
|
|
|
* |
25
|
|
|
* @author Fabien Potencier <[email protected]> |
26
|
|
|
* @author Martin Hasoň <[email protected]> |
27
|
|
|
* |
28
|
|
|
* @api |
29
|
|
|
*/ |
30
|
|
|
class XmlDumper extends Dumper |
31
|
|
|
{ |
32
|
|
|
/** |
33
|
|
|
* @var \DOMDocument |
34
|
|
|
*/ |
35
|
|
|
private $document; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* Dumps the service container as an XML string. |
39
|
|
|
* |
40
|
|
|
* @param array $options An array of options |
41
|
|
|
* |
42
|
|
|
* @return string An xml string representing of the service container |
43
|
|
|
* |
44
|
|
|
* @api |
45
|
|
|
*/ |
46
|
|
|
public function dump(array $options = array()) |
47
|
|
|
{ |
48
|
|
|
$this->document = new \DOMDocument('1.0', 'utf-8'); |
49
|
|
|
$this->document->formatOutput = true; |
50
|
|
|
|
51
|
|
|
$container = $this->document->createElementNS('http://symfony.com/schema/dic/services', 'container'); |
52
|
|
|
$container->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); |
53
|
|
|
$container->setAttribute('xsi:schemaLocation', 'http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd'); |
54
|
|
|
|
55
|
|
|
$this->addParameters($container); |
56
|
|
|
$this->addServices($container); |
57
|
|
|
|
58
|
|
|
$this->document->appendChild($container); |
59
|
|
|
$xml = $this->document->saveXML(); |
60
|
|
|
$this->document = null; |
61
|
|
|
|
62
|
|
|
return $xml; |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Adds parameters. |
67
|
|
|
* |
68
|
|
|
* @param \DOMElement $parent |
69
|
|
|
*/ |
70
|
|
|
private function addParameters(\DOMElement $parent) |
71
|
|
|
{ |
72
|
|
|
$data = $this->container->getParameterBag()->all(); |
73
|
|
|
if (!$data) { |
|
|
|
|
74
|
|
|
return; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
if ($this->container->isFrozen()) { |
78
|
|
|
$data = $this->escape($data); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
$parameters = $this->document->createElement('parameters'); |
82
|
|
|
$parent->appendChild($parameters); |
83
|
|
|
$this->convertParameters($data, 'parameter', $parameters); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Adds method calls. |
88
|
|
|
* |
89
|
|
|
* @param array $methodcalls |
90
|
|
|
* @param \DOMElement $parent |
91
|
|
|
*/ |
92
|
|
|
private function addMethodCalls(array $methodcalls, \DOMElement $parent) |
93
|
|
|
{ |
94
|
|
|
foreach ($methodcalls as $methodcall) { |
95
|
|
|
$call = $this->document->createElement('call'); |
96
|
|
|
$call->setAttribute('method', $methodcall[0]); |
97
|
|
|
if (count($methodcall[1])) { |
98
|
|
|
$this->convertParameters($methodcall[1], 'argument', $call); |
99
|
|
|
} |
100
|
|
|
$parent->appendChild($call); |
101
|
|
|
} |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* Adds a service. |
106
|
|
|
* |
107
|
|
|
* @param Definition $definition |
108
|
|
|
* @param string $id |
109
|
|
|
* @param \DOMElement $parent |
110
|
|
|
*/ |
111
|
|
|
private function addService($definition, $id, \DOMElement $parent) |
112
|
|
|
{ |
113
|
|
|
$service = $this->document->createElement('service'); |
114
|
|
|
if (null !== $id) { |
115
|
|
|
$service->setAttribute('id', $id); |
116
|
|
|
} |
117
|
|
|
if ($definition->getClass()) { |
|
|
|
|
118
|
|
|
$service->setAttribute('class', $definition->getClass()); |
119
|
|
|
} |
120
|
|
|
if ($definition->getFactoryMethod(false)) { |
|
|
|
|
121
|
|
|
$service->setAttribute('factory-method', $definition->getFactoryMethod(false)); |
|
|
|
|
122
|
|
|
} |
123
|
|
|
if ($definition->getFactoryClass(false)) { |
|
|
|
|
124
|
|
|
$service->setAttribute('factory-class', $definition->getFactoryClass(false)); |
|
|
|
|
125
|
|
|
} |
126
|
|
|
if ($definition->getFactoryService(false)) { |
|
|
|
|
127
|
|
|
$service->setAttribute('factory-service', $definition->getFactoryService(false)); |
|
|
|
|
128
|
|
|
} |
129
|
|
|
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) { |
130
|
|
|
$service->setAttribute('scope', $scope); |
131
|
|
|
} |
132
|
|
|
if (!$definition->isPublic()) { |
133
|
|
|
$service->setAttribute('public', 'false'); |
134
|
|
|
} |
135
|
|
|
if ($definition->isSynthetic()) { |
136
|
|
|
$service->setAttribute('synthetic', 'true'); |
137
|
|
|
} |
138
|
|
|
if ($definition->isSynchronized(false)) { |
|
|
|
|
139
|
|
|
$service->setAttribute('synchronized', 'true'); |
140
|
|
|
} |
141
|
|
|
if ($definition->isLazy()) { |
142
|
|
|
$service->setAttribute('lazy', 'true'); |
143
|
|
|
} |
144
|
|
|
if (null !== $decorated = $definition->getDecoratedService()) { |
145
|
|
|
list($decorated, $renamedId) = $decorated; |
146
|
|
|
$service->setAttribute('decorates', $decorated); |
147
|
|
|
if (null !== $renamedId) { |
148
|
|
|
$service->setAttribute('decoration-inner-name', $renamedId); |
149
|
|
|
} |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
foreach ($definition->getTags() as $name => $tags) { |
153
|
|
|
foreach ($tags as $attributes) { |
154
|
|
|
$tag = $this->document->createElement('tag'); |
155
|
|
|
$tag->setAttribute('name', $name); |
156
|
|
|
foreach ($attributes as $key => $value) { |
157
|
|
|
$tag->setAttribute($key, $value); |
158
|
|
|
} |
159
|
|
|
$service->appendChild($tag); |
160
|
|
|
} |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
if ($definition->getFile()) { |
|
|
|
|
164
|
|
|
$file = $this->document->createElement('file'); |
165
|
|
|
$file->appendChild($this->document->createTextNode($definition->getFile())); |
166
|
|
|
$service->appendChild($file); |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
if ($parameters = $definition->getArguments()) { |
170
|
|
|
$this->convertParameters($parameters, 'argument', $service); |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
if ($parameters = $definition->getProperties()) { |
174
|
|
|
$this->convertParameters($parameters, 'property', $service, 'name'); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
$this->addMethodCalls($definition->getMethodCalls(), $service); |
178
|
|
|
|
179
|
|
View Code Duplication |
if ($callable = $definition->getFactory()) { |
|
|
|
|
180
|
|
|
$factory = $this->document->createElement('factory'); |
181
|
|
|
|
182
|
|
|
if (is_array($callable) && $callable[0] instanceof Definition) { |
183
|
|
|
$this->addService($callable[0], null, $factory); |
184
|
|
|
$factory->setAttribute('method', $callable[1]); |
185
|
|
|
} elseif (is_array($callable)) { |
186
|
|
|
$factory->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]); |
187
|
|
|
$factory->setAttribute('method', $callable[1]); |
188
|
|
|
} else { |
189
|
|
|
$factory->setAttribute('function', $callable); |
190
|
|
|
} |
191
|
|
|
$service->appendChild($factory); |
192
|
|
|
} |
193
|
|
|
|
194
|
|
View Code Duplication |
if ($callable = $definition->getConfigurator()) { |
|
|
|
|
195
|
|
|
$configurator = $this->document->createElement('configurator'); |
196
|
|
|
|
197
|
|
|
if (is_array($callable) && $callable[0] instanceof Definition) { |
198
|
|
|
$this->addService($callable[0], null, $configurator); |
199
|
|
|
$configurator->setAttribute('method', $callable[1]); |
200
|
|
|
} elseif (is_array($callable)) { |
201
|
|
|
$configurator->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]); |
202
|
|
|
$configurator->setAttribute('method', $callable[1]); |
203
|
|
|
} else { |
204
|
|
|
$configurator->setAttribute('function', $callable); |
205
|
|
|
} |
206
|
|
|
$service->appendChild($configurator); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
$parent->appendChild($service); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* Adds a service alias. |
214
|
|
|
* |
215
|
|
|
* @param string $alias |
216
|
|
|
* @param Alias $id |
217
|
|
|
* @param \DOMElement $parent |
218
|
|
|
*/ |
219
|
|
|
private function addServiceAlias($alias, Alias $id, \DOMElement $parent) |
220
|
|
|
{ |
221
|
|
|
$service = $this->document->createElement('service'); |
222
|
|
|
$service->setAttribute('id', $alias); |
223
|
|
|
$service->setAttribute('alias', $id); |
224
|
|
|
if (!$id->isPublic()) { |
225
|
|
|
$service->setAttribute('public', 'false'); |
226
|
|
|
} |
227
|
|
|
$parent->appendChild($service); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* Adds services. |
232
|
|
|
* |
233
|
|
|
* @param \DOMElement $parent |
234
|
|
|
*/ |
235
|
|
|
private function addServices(\DOMElement $parent) |
236
|
|
|
{ |
237
|
|
|
$definitions = $this->container->getDefinitions(); |
238
|
|
|
if (!$definitions) { |
|
|
|
|
239
|
|
|
return; |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
$services = $this->document->createElement('services'); |
243
|
|
|
foreach ($definitions as $id => $definition) { |
244
|
|
|
$this->addService($definition, $id, $services); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
$aliases = $this->container->getAliases(); |
248
|
|
View Code Duplication |
foreach ($aliases as $alias => $id) { |
|
|
|
|
249
|
|
|
while (isset($aliases[(string) $id])) { |
250
|
|
|
$id = $aliases[(string) $id]; |
251
|
|
|
} |
252
|
|
|
$this->addServiceAlias($alias, $id, $services); |
253
|
|
|
} |
254
|
|
|
$parent->appendChild($services); |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* Converts parameters. |
259
|
|
|
* |
260
|
|
|
* @param array $parameters |
261
|
|
|
* @param string $type |
262
|
|
|
* @param \DOMElement $parent |
263
|
|
|
* @param string $keyAttribute |
264
|
|
|
*/ |
265
|
|
|
private function convertParameters($parameters, $type, \DOMElement $parent, $keyAttribute = 'key') |
266
|
|
|
{ |
267
|
|
|
$withKeys = array_keys($parameters) !== range(0, count($parameters) - 1); |
268
|
|
|
foreach ($parameters as $key => $value) { |
269
|
|
|
$element = $this->document->createElement($type); |
270
|
|
|
if ($withKeys) { |
271
|
|
|
$element->setAttribute($keyAttribute, $key); |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
if (is_array($value)) { |
275
|
|
|
$element->setAttribute('type', 'collection'); |
276
|
|
|
$this->convertParameters($value, $type, $element, 'key'); |
277
|
|
|
} elseif ($value instanceof Reference) { |
278
|
|
|
$element->setAttribute('type', 'service'); |
279
|
|
|
$element->setAttribute('id', (string) $value); |
280
|
|
|
$behaviour = $value->getInvalidBehavior(); |
281
|
|
|
if ($behaviour == ContainerInterface::NULL_ON_INVALID_REFERENCE) { |
282
|
|
|
$element->setAttribute('on-invalid', 'null'); |
283
|
|
|
} elseif ($behaviour == ContainerInterface::IGNORE_ON_INVALID_REFERENCE) { |
284
|
|
|
$element->setAttribute('on-invalid', 'ignore'); |
285
|
|
|
} |
286
|
|
|
if (!$value->isStrict()) { |
287
|
|
|
$element->setAttribute('strict', 'false'); |
288
|
|
|
} |
289
|
|
|
} elseif ($value instanceof Definition) { |
290
|
|
|
$element->setAttribute('type', 'service'); |
291
|
|
|
$this->addService($value, null, $element); |
292
|
|
|
} elseif ($value instanceof Expression) { |
|
|
|
|
293
|
|
|
$element->setAttribute('type', 'expression'); |
294
|
|
|
$text = $this->document->createTextNode(self::phpToXml((string) $value)); |
295
|
|
|
$element->appendChild($text); |
296
|
|
|
} else { |
297
|
|
|
if (in_array($value, array('null', 'true', 'false'), true)) { |
298
|
|
|
$element->setAttribute('type', 'string'); |
299
|
|
|
} |
300
|
|
|
$text = $this->document->createTextNode(self::phpToXml($value)); |
301
|
|
|
$element->appendChild($text); |
302
|
|
|
} |
303
|
|
|
$parent->appendChild($element); |
304
|
|
|
} |
305
|
|
|
} |
306
|
|
|
|
307
|
|
|
/** |
308
|
|
|
* Escapes arguments. |
309
|
|
|
* |
310
|
|
|
* @param array $arguments |
311
|
|
|
* |
312
|
|
|
* @return array |
313
|
|
|
*/ |
314
|
|
View Code Duplication |
private function escape($arguments) |
315
|
|
|
{ |
316
|
|
|
$args = array(); |
317
|
|
|
foreach ($arguments as $k => $v) { |
318
|
|
|
if (is_array($v)) { |
319
|
|
|
$args[$k] = $this->escape($v); |
320
|
|
|
} elseif (is_string($v)) { |
321
|
|
|
$args[$k] = str_replace('%', '%%', $v); |
322
|
|
|
} else { |
323
|
|
|
$args[$k] = $v; |
324
|
|
|
} |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
return $args; |
328
|
|
|
} |
329
|
|
|
|
330
|
|
|
/** |
331
|
|
|
* Converts php types to xml types. |
332
|
|
|
* |
333
|
|
|
* @param mixed $value Value to convert |
334
|
|
|
* |
335
|
|
|
* @return string |
336
|
|
|
* |
337
|
|
|
* @throws RuntimeException When trying to dump object or resource |
338
|
|
|
*/ |
339
|
|
|
public static function phpToXml($value) |
340
|
|
|
{ |
341
|
|
|
switch (true) { |
342
|
|
|
case null === $value: |
343
|
|
|
return 'null'; |
344
|
|
|
case true === $value: |
345
|
|
|
return 'true'; |
346
|
|
|
case false === $value: |
347
|
|
|
return 'false'; |
348
|
|
|
case $value instanceof Parameter: |
349
|
|
|
return '%'.$value.'%'; |
350
|
|
|
case is_object($value) || is_resource($value): |
351
|
|
|
throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.'); |
352
|
|
|
default: |
353
|
|
|
return (string) $value; |
354
|
|
|
} |
355
|
|
|
} |
356
|
|
|
} |
357
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.