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\Alias; Chris@14: use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; Chris@14: use Symfony\Component\DependencyInjection\Argument\IteratorArgument; Chris@14: use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; Chris@14: use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; Chris@0: use Symfony\Component\DependencyInjection\ContainerInterface; Chris@0: use Symfony\Component\DependencyInjection\Definition; Chris@17: use Symfony\Component\DependencyInjection\Exception\RuntimeException; Chris@0: use Symfony\Component\DependencyInjection\Parameter; Chris@0: use Symfony\Component\DependencyInjection\Reference; Chris@0: use Symfony\Component\ExpressionLanguage\Expression; Chris@17: use Symfony\Component\Yaml\Dumper as YmlDumper; Chris@17: use Symfony\Component\Yaml\Parser; Chris@17: use Symfony\Component\Yaml\Tag\TaggedValue; Chris@17: use Symfony\Component\Yaml\Yaml; Chris@0: Chris@0: /** Chris@0: * YamlDumper dumps a service container as a YAML string. Chris@0: * Chris@0: * @author Fabien Potencier Chris@0: */ Chris@0: class YamlDumper extends Dumper Chris@0: { Chris@0: private $dumper; Chris@0: Chris@0: /** Chris@0: * Dumps the service container as an YAML string. Chris@0: * Chris@0: * @return string A YAML string representing of the service container Chris@0: */ Chris@17: public function dump(array $options = []) Chris@0: { Chris@0: if (!class_exists('Symfony\Component\Yaml\Dumper')) { Chris@0: throw new RuntimeException('Unable to dump the container as the Symfony Yaml Component is not installed.'); Chris@0: } Chris@0: Chris@0: if (null === $this->dumper) { Chris@0: $this->dumper = new YmlDumper(); Chris@0: } Chris@0: Chris@0: return $this->container->resolveEnvPlaceholders($this->addParameters()."\n".$this->addServices()); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Adds a service. Chris@0: * Chris@0: * @param string $id Chris@0: * @param Definition $definition Chris@0: * Chris@0: * @return string Chris@0: */ Chris@14: private function addService($id, Definition $definition) Chris@0: { Chris@0: $code = " $id:\n"; 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: $code .= sprintf(" class: %s\n", $this->dumper->dump($class)); Chris@0: } Chris@0: Chris@14: if (!$definition->isPrivate()) { Chris@14: $code .= sprintf(" public: %s\n", $definition->isPublic() ? 'true' : 'false'); Chris@0: } Chris@0: Chris@0: $tagsCode = ''; Chris@0: foreach ($definition->getTags() as $name => $tags) { Chris@0: foreach ($tags as $attributes) { Chris@17: $att = []; Chris@0: foreach ($attributes as $key => $value) { Chris@0: $att[] = sprintf('%s: %s', $this->dumper->dump($key), $this->dumper->dump($value)); Chris@0: } Chris@0: $att = $att ? ', '.implode(', ', $att) : ''; Chris@0: Chris@0: $tagsCode .= sprintf(" - { name: %s%s }\n", $this->dumper->dump($name), $att); Chris@0: } Chris@0: } Chris@0: if ($tagsCode) { Chris@0: $code .= " tags:\n".$tagsCode; Chris@0: } Chris@0: Chris@0: if ($definition->getFile()) { Chris@0: $code .= sprintf(" file: %s\n", $this->dumper->dump($definition->getFile())); Chris@0: } Chris@0: Chris@0: if ($definition->isSynthetic()) { Chris@0: $code .= " synthetic: true\n"; Chris@0: } Chris@0: Chris@0: if ($definition->isDeprecated()) { Chris@17: $code .= sprintf(" deprecated: %s\n", $this->dumper->dump($definition->getDeprecationMessage('%service_id%'))); Chris@0: } Chris@0: Chris@0: if ($definition->isAutowired()) { Chris@0: $code .= " autowire: true\n"; Chris@0: } Chris@0: Chris@0: $autowiringTypesCode = ''; Chris@14: foreach ($definition->getAutowiringTypes(false) as $autowiringType) { Chris@0: $autowiringTypesCode .= sprintf(" - %s\n", $this->dumper->dump($autowiringType)); Chris@0: } Chris@0: if ($autowiringTypesCode) { Chris@0: $code .= sprintf(" autowiring_types:\n%s", $autowiringTypesCode); Chris@0: } Chris@0: Chris@14: if ($definition->isAutoconfigured()) { Chris@14: $code .= " autoconfigure: true\n"; Chris@14: } Chris@14: Chris@14: if ($definition->isAbstract()) { Chris@14: $code .= " abstract: true\n"; Chris@14: } Chris@14: Chris@0: if ($definition->isLazy()) { Chris@0: $code .= " lazy: true\n"; Chris@0: } Chris@0: Chris@0: if ($definition->getArguments()) { Chris@0: $code .= sprintf(" arguments: %s\n", $this->dumper->dump($this->dumpValue($definition->getArguments()), 0)); Chris@0: } Chris@0: Chris@0: if ($definition->getProperties()) { Chris@0: $code .= sprintf(" properties: %s\n", $this->dumper->dump($this->dumpValue($definition->getProperties()), 0)); Chris@0: } Chris@0: Chris@0: if ($definition->getMethodCalls()) { Chris@0: $code .= sprintf(" calls:\n%s\n", $this->dumper->dump($this->dumpValue($definition->getMethodCalls()), 1, 12)); Chris@0: } Chris@0: Chris@0: if (!$definition->isShared()) { Chris@0: $code .= " shared: false\n"; Chris@0: } Chris@0: Chris@0: if (null !== $decorated = $definition->getDecoratedService()) { Chris@0: list($decorated, $renamedId, $priority) = $decorated; Chris@0: $code .= sprintf(" decorates: %s\n", $decorated); Chris@0: if (null !== $renamedId) { Chris@0: $code .= sprintf(" decoration_inner_name: %s\n", $renamedId); Chris@0: } Chris@0: if (0 !== $priority) { Chris@0: $code .= sprintf(" decoration_priority: %s\n", $priority); Chris@0: } Chris@0: } Chris@0: Chris@0: if ($callable = $definition->getFactory()) { Chris@0: $code .= sprintf(" factory: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0)); Chris@0: } Chris@0: Chris@0: if ($callable = $definition->getConfigurator()) { Chris@0: $code .= sprintf(" configurator: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0)); Chris@0: } Chris@0: Chris@0: return $code; 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: * Chris@0: * @return string Chris@0: */ Chris@14: private function addServiceAlias($alias, Alias $id) Chris@0: { Chris@14: if ($id->isPrivate()) { Chris@0: return sprintf(" %s: '@%s'\n", $alias, $id); Chris@0: } Chris@0: Chris@14: return sprintf(" %s:\n alias: %s\n public: %s\n", $alias, $id, $id->isPublic() ? 'true' : 'false'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Adds services. Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: private function addServices() Chris@0: { Chris@0: if (!$this->container->getDefinitions()) { Chris@0: return ''; Chris@0: } Chris@0: Chris@0: $code = "services:\n"; Chris@0: foreach ($this->container->getDefinitions() as $id => $definition) { Chris@0: $code .= $this->addService($id, $definition); 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: $code .= $this->addServiceAlias($alias, $id); Chris@0: } Chris@0: Chris@0: return $code; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Adds parameters. Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: private function addParameters() Chris@0: { Chris@0: if (!$this->container->getParameterBag()->all()) { Chris@0: return ''; Chris@0: } Chris@0: Chris@14: $parameters = $this->prepareParameters($this->container->getParameterBag()->all(), $this->container->isCompiled()); Chris@0: Chris@17: return $this->dumper->dump(['parameters' => $parameters], 2); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Dumps callable to YAML format. Chris@0: * Chris@0: * @param callable $callable Chris@0: * Chris@0: * @return callable Chris@0: */ Chris@0: private function dumpCallable($callable) Chris@0: { Chris@17: if (\is_array($callable)) { Chris@0: if ($callable[0] instanceof Reference) { Chris@17: $callable = [$this->getServiceCall((string) $callable[0], $callable[0]), $callable[1]]; Chris@0: } else { Chris@17: $callable = [$callable[0], $callable[1]]; Chris@0: } Chris@0: } Chris@0: Chris@0: return $callable; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Dumps the value to YAML format. Chris@0: * Chris@0: * @param mixed $value Chris@0: * Chris@0: * @return mixed Chris@0: * Chris@0: * @throws RuntimeException When trying to dump object or resource Chris@0: */ Chris@0: private function dumpValue($value) Chris@0: { Chris@14: if ($value instanceof ServiceClosureArgument) { Chris@14: $value = $value->getValues()[0]; Chris@14: } Chris@14: if ($value instanceof ArgumentInterface) { Chris@14: if ($value instanceof TaggedIteratorArgument) { Chris@14: return new TaggedValue('tagged', $value->getTag()); Chris@14: } Chris@14: if ($value instanceof IteratorArgument) { Chris@14: $tag = 'iterator'; Chris@14: } else { Chris@17: throw new RuntimeException(sprintf('Unspecified Yaml tag for type "%s".', \get_class($value))); Chris@14: } Chris@14: Chris@14: return new TaggedValue($tag, $this->dumpValue($value->getValues())); Chris@14: } Chris@14: Chris@17: if (\is_array($value)) { Chris@17: $code = []; Chris@0: foreach ($value as $k => $v) { Chris@0: $code[$k] = $this->dumpValue($v); Chris@0: } Chris@0: Chris@0: return $code; Chris@0: } elseif ($value instanceof Reference) { Chris@0: return $this->getServiceCall((string) $value, $value); Chris@0: } elseif ($value instanceof Parameter) { Chris@0: return $this->getParameterCall((string) $value); Chris@0: } elseif ($value instanceof Expression) { Chris@0: return $this->getExpressionCall((string) $value); Chris@14: } elseif ($value instanceof Definition) { Chris@14: return new TaggedValue('service', (new Parser())->parse("_:\n".$this->addService('_', $value), Yaml::PARSE_CUSTOM_TAGS)['_']['_']); Chris@17: } elseif (\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: } Chris@0: Chris@0: return $value; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the service call. Chris@0: * Chris@0: * @param string $id Chris@0: * @param Reference $reference Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: private function getServiceCall($id, Reference $reference = null) Chris@0: { Chris@14: if (null !== $reference) { Chris@14: switch ($reference->getInvalidBehavior()) { Chris@14: case ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE: break; Chris@14: case ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE: return sprintf('@!%s', $id); Chris@14: default: return sprintf('@?%s', $id); Chris@14: } Chris@0: } Chris@0: Chris@0: return sprintf('@%s', $id); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets parameter call. Chris@0: * Chris@0: * @param string $id Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: private function getParameterCall($id) Chris@0: { Chris@0: return sprintf('%%%s%%', $id); Chris@0: } Chris@0: Chris@0: private function getExpressionCall($expression) Chris@0: { Chris@0: return sprintf('@=%s', $expression); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Prepares parameters. Chris@0: * Chris@0: * @param array $parameters Chris@0: * @param bool $escape Chris@0: * Chris@0: * @return array Chris@0: */ Chris@0: private function prepareParameters(array $parameters, $escape = true) Chris@0: { Chris@17: $filtered = []; Chris@0: foreach ($parameters as $key => $value) { Chris@17: if (\is_array($value)) { Chris@0: $value = $this->prepareParameters($value, $escape); Chris@17: } elseif ($value instanceof Reference || \is_string($value) && 0 === strpos($value, '@')) { Chris@0: $value = '@'.$value; Chris@0: } Chris@0: Chris@0: $filtered[$key] = $value; Chris@0: } Chris@0: Chris@0: return $escape ? $this->escape($filtered) : $filtered; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Escapes arguments. Chris@0: * Chris@0: * @return array Chris@0: */ Chris@0: private function escape(array $arguments) Chris@0: { Chris@17: $args = []; Chris@0: foreach ($arguments as $k => $v) { Chris@17: if (\is_array($v)) { Chris@0: $args[$k] = $this->escape($v); Chris@17: } 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: }