Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\DependencyInjection\Dumper; Chris@0: Chris@0: use Symfony\Component\DependencyInjection\ContainerInterface; Chris@0: use Symfony\Component\DependencyInjection\Parameter; Chris@0: use Symfony\Component\DependencyInjection\Reference; Chris@0: use Symfony\Component\DependencyInjection\Definition; Chris@0: use Symfony\Component\DependencyInjection\Alias; Chris@0: use Symfony\Component\DependencyInjection\Exception\RuntimeException; Chris@0: use Symfony\Component\ExpressionLanguage\Expression; Chris@0: Chris@0: /** Chris@0: * XmlDumper dumps a service container as an XML string. Chris@0: * Chris@0: * @author Fabien Potencier Chris@0: * @author Martin HasoĊˆ Chris@0: */ Chris@0: class XmlDumper extends Dumper Chris@0: { Chris@0: /** Chris@0: * @var \DOMDocument Chris@0: */ Chris@0: private $document; Chris@0: Chris@0: /** Chris@0: * Dumps the service container as an XML string. Chris@0: * Chris@0: * @param array $options An array of options Chris@0: * Chris@0: * @return string An xml string representing of the service container Chris@0: */ Chris@0: public function dump(array $options = array()) Chris@0: { Chris@0: $this->document = new \DOMDocument('1.0', 'utf-8'); Chris@0: $this->document->formatOutput = true; Chris@0: Chris@0: $container = $this->document->createElementNS('http://symfony.com/schema/dic/services', 'container'); Chris@0: $container->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); Chris@0: $container->setAttribute('xsi:schemaLocation', 'http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd'); Chris@0: Chris@0: $this->addParameters($container); Chris@0: $this->addServices($container); Chris@0: Chris@0: $this->document->appendChild($container); Chris@0: $xml = $this->document->saveXML(); Chris@0: $this->document = null; Chris@0: Chris@0: return $this->container->resolveEnvPlaceholders($xml); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Adds parameters. Chris@0: * Chris@0: * @param \DOMElement $parent Chris@0: */ Chris@0: private function addParameters(\DOMElement $parent) Chris@0: { Chris@0: $data = $this->container->getParameterBag()->all(); Chris@0: if (!$data) { Chris@0: return; Chris@0: } Chris@0: Chris@0: if ($this->container->isFrozen()) { Chris@0: $data = $this->escape($data); Chris@0: } Chris@0: Chris@0: $parameters = $this->document->createElement('parameters'); Chris@0: $parent->appendChild($parameters); Chris@0: $this->convertParameters($data, 'parameter', $parameters); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Adds method calls. Chris@0: * Chris@0: * @param array $methodcalls Chris@0: * @param \DOMElement $parent Chris@0: */ Chris@0: private function addMethodCalls(array $methodcalls, \DOMElement $parent) Chris@0: { Chris@0: foreach ($methodcalls as $methodcall) { Chris@0: $call = $this->document->createElement('call'); Chris@0: $call->setAttribute('method', $methodcall[0]); Chris@0: if (count($methodcall[1])) { Chris@0: $this->convertParameters($methodcall[1], 'argument', $call); Chris@0: } Chris@0: $parent->appendChild($call); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Adds a service. Chris@0: * Chris@0: * @param Definition $definition Chris@0: * @param string $id Chris@0: * @param \DOMElement $parent Chris@0: */ Chris@0: private function addService($definition, $id, \DOMElement $parent) Chris@0: { Chris@0: $service = $this->document->createElement('service'); Chris@0: if (null !== $id) { Chris@0: $service->setAttribute('id', $id); Chris@0: } Chris@0: if ($class = $definition->getClass()) { Chris@0: if ('\\' === substr($class, 0, 1)) { Chris@0: $class = substr($class, 1); Chris@0: } Chris@0: Chris@0: $service->setAttribute('class', $class); Chris@0: } Chris@0: if (!$definition->isShared()) { Chris@0: $service->setAttribute('shared', 'false'); Chris@0: } Chris@0: if (!$definition->isPublic()) { Chris@0: $service->setAttribute('public', 'false'); Chris@0: } Chris@0: if ($definition->isSynthetic()) { Chris@0: $service->setAttribute('synthetic', 'true'); Chris@0: } Chris@0: if ($definition->isLazy()) { Chris@0: $service->setAttribute('lazy', 'true'); Chris@0: } Chris@0: if (null !== $decorated = $definition->getDecoratedService()) { Chris@0: list($decorated, $renamedId, $priority) = $decorated; Chris@0: $service->setAttribute('decorates', $decorated); Chris@0: if (null !== $renamedId) { Chris@0: $service->setAttribute('decoration-inner-name', $renamedId); Chris@0: } Chris@0: if (0 !== $priority) { Chris@0: $service->setAttribute('decoration-priority', $priority); Chris@0: } Chris@0: } Chris@0: Chris@0: foreach ($definition->getTags() as $name => $tags) { Chris@0: foreach ($tags as $attributes) { Chris@0: $tag = $this->document->createElement('tag'); Chris@0: $tag->setAttribute('name', $name); Chris@0: foreach ($attributes as $key => $value) { Chris@0: $tag->setAttribute($key, $value); Chris@0: } Chris@0: $service->appendChild($tag); Chris@0: } Chris@0: } Chris@0: Chris@0: if ($definition->getFile()) { Chris@0: $file = $this->document->createElement('file'); Chris@0: $file->appendChild($this->document->createTextNode($definition->getFile())); Chris@0: $service->appendChild($file); Chris@0: } Chris@0: Chris@0: if ($parameters = $definition->getArguments()) { Chris@0: $this->convertParameters($parameters, 'argument', $service); Chris@0: } Chris@0: Chris@0: if ($parameters = $definition->getProperties()) { Chris@0: $this->convertParameters($parameters, 'property', $service, 'name'); Chris@0: } Chris@0: Chris@0: $this->addMethodCalls($definition->getMethodCalls(), $service); Chris@0: Chris@0: if ($callable = $definition->getFactory()) { Chris@0: $factory = $this->document->createElement('factory'); Chris@0: Chris@0: if (is_array($callable) && $callable[0] instanceof Definition) { Chris@0: $this->addService($callable[0], null, $factory); Chris@0: $factory->setAttribute('method', $callable[1]); Chris@0: } elseif (is_array($callable)) { Chris@0: $factory->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]); Chris@0: $factory->setAttribute('method', $callable[1]); Chris@0: } else { Chris@0: $factory->setAttribute('function', $callable); Chris@0: } Chris@0: $service->appendChild($factory); Chris@0: } Chris@0: Chris@0: if ($definition->isDeprecated()) { Chris@0: $deprecated = $this->document->createElement('deprecated'); Chris@0: $deprecated->appendChild($this->document->createTextNode($definition->getDeprecationMessage('%service_id%'))); Chris@0: Chris@0: $service->appendChild($deprecated); Chris@0: } Chris@0: Chris@0: if ($definition->isAutowired()) { Chris@0: $service->setAttribute('autowire', 'true'); Chris@0: } Chris@0: Chris@0: foreach ($definition->getAutowiringTypes() as $autowiringTypeValue) { Chris@0: $autowiringType = $this->document->createElement('autowiring-type'); Chris@0: $autowiringType->appendChild($this->document->createTextNode($autowiringTypeValue)); Chris@0: Chris@0: $service->appendChild($autowiringType); Chris@0: } Chris@0: Chris@0: if ($callable = $definition->getConfigurator()) { Chris@0: $configurator = $this->document->createElement('configurator'); Chris@0: Chris@0: if (is_array($callable) && $callable[0] instanceof Definition) { Chris@0: $this->addService($callable[0], null, $configurator); Chris@0: $configurator->setAttribute('method', $callable[1]); Chris@0: } elseif (is_array($callable)) { Chris@0: $configurator->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]); Chris@0: $configurator->setAttribute('method', $callable[1]); Chris@0: } else { Chris@0: $configurator->setAttribute('function', $callable); Chris@0: } Chris@0: $service->appendChild($configurator); Chris@0: } Chris@0: Chris@0: $parent->appendChild($service); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Adds a service alias. Chris@0: * Chris@0: * @param string $alias Chris@0: * @param Alias $id Chris@0: * @param \DOMElement $parent Chris@0: */ Chris@0: private function addServiceAlias($alias, Alias $id, \DOMElement $parent) Chris@0: { Chris@0: $service = $this->document->createElement('service'); Chris@0: $service->setAttribute('id', $alias); Chris@0: $service->setAttribute('alias', $id); Chris@0: if (!$id->isPublic()) { Chris@0: $service->setAttribute('public', 'false'); Chris@0: } Chris@0: $parent->appendChild($service); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Adds services. Chris@0: * Chris@0: * @param \DOMElement $parent Chris@0: */ Chris@0: private function addServices(\DOMElement $parent) Chris@0: { Chris@0: $definitions = $this->container->getDefinitions(); Chris@0: if (!$definitions) { Chris@0: return; Chris@0: } Chris@0: Chris@0: $services = $this->document->createElement('services'); Chris@0: foreach ($definitions as $id => $definition) { Chris@0: $this->addService($definition, $id, $services); Chris@0: } Chris@0: Chris@0: $aliases = $this->container->getAliases(); Chris@0: foreach ($aliases as $alias => $id) { Chris@0: while (isset($aliases[(string) $id])) { Chris@0: $id = $aliases[(string) $id]; Chris@0: } Chris@0: $this->addServiceAlias($alias, $id, $services); Chris@0: } Chris@0: $parent->appendChild($services); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Converts parameters. Chris@0: * Chris@0: * @param array $parameters Chris@0: * @param string $type Chris@0: * @param \DOMElement $parent Chris@0: * @param string $keyAttribute Chris@0: */ Chris@0: private function convertParameters(array $parameters, $type, \DOMElement $parent, $keyAttribute = 'key') Chris@0: { Chris@0: $withKeys = array_keys($parameters) !== range(0, count($parameters) - 1); Chris@0: foreach ($parameters as $key => $value) { Chris@0: $element = $this->document->createElement($type); Chris@0: if ($withKeys) { Chris@0: $element->setAttribute($keyAttribute, $key); Chris@0: } Chris@0: Chris@0: if (is_array($value)) { Chris@0: $element->setAttribute('type', 'collection'); Chris@0: $this->convertParameters($value, $type, $element, 'key'); Chris@0: } elseif ($value instanceof Reference) { Chris@0: $element->setAttribute('type', 'service'); Chris@0: $element->setAttribute('id', (string) $value); Chris@0: $behaviour = $value->getInvalidBehavior(); Chris@0: if ($behaviour == ContainerInterface::NULL_ON_INVALID_REFERENCE) { Chris@0: $element->setAttribute('on-invalid', 'null'); Chris@0: } elseif ($behaviour == ContainerInterface::IGNORE_ON_INVALID_REFERENCE) { Chris@0: $element->setAttribute('on-invalid', 'ignore'); Chris@0: } Chris@0: } elseif ($value instanceof Definition) { Chris@0: $element->setAttribute('type', 'service'); Chris@0: $this->addService($value, null, $element); Chris@0: } elseif ($value instanceof Expression) { Chris@0: $element->setAttribute('type', 'expression'); Chris@0: $text = $this->document->createTextNode(self::phpToXml((string) $value)); Chris@0: $element->appendChild($text); Chris@0: } else { Chris@0: if (in_array($value, array('null', 'true', 'false'), true)) { Chris@0: $element->setAttribute('type', 'string'); Chris@0: } Chris@0: $text = $this->document->createTextNode(self::phpToXml($value)); Chris@0: $element->appendChild($text); Chris@0: } Chris@0: $parent->appendChild($element); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Escapes arguments. Chris@0: * Chris@0: * @param array $arguments Chris@0: * Chris@0: * @return array Chris@0: */ Chris@0: private function escape(array $arguments) Chris@0: { Chris@0: $args = array(); Chris@0: foreach ($arguments as $k => $v) { Chris@0: if (is_array($v)) { Chris@0: $args[$k] = $this->escape($v); Chris@0: } elseif (is_string($v)) { Chris@0: $args[$k] = str_replace('%', '%%', $v); Chris@0: } else { Chris@0: $args[$k] = $v; Chris@0: } Chris@0: } Chris@0: Chris@0: return $args; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Converts php types to xml types. Chris@0: * Chris@0: * @param mixed $value Value to convert Chris@0: * Chris@0: * @return string Chris@0: * Chris@0: * @throws RuntimeException When trying to dump object or resource Chris@0: */ Chris@0: public static function phpToXml($value) Chris@0: { Chris@0: switch (true) { Chris@0: case null === $value: Chris@0: return 'null'; Chris@0: case true === $value: Chris@0: return 'true'; Chris@0: case false === $value: Chris@0: return 'false'; Chris@0: case $value instanceof Parameter: Chris@0: return '%'.$value.'%'; Chris@0: case is_object($value) || is_resource($value): Chris@0: throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.'); Chris@0: default: Chris@0: return (string) $value; Chris@0: } Chris@0: } Chris@0: }