Skip to content

Instantly share code, notes, and snippets.

@nicolas-grekas
Created April 16, 2019 14:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nicolas-grekas/bfdd3c17b40d5be2eb9b36a181e66df4 to your computer and use it in GitHub Desktop.
Save nicolas-grekas/bfdd3c17b40d5be2eb9b36a181e66df4 to your computer and use it in GitHub Desktop.
From Yaml to PHP-DSL
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Dumper;
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\Yaml\Tag\TaggedValue;
use Symfony\Component\Yaml\Yaml;
/**
* @author Guilhem Niot <guilhem.niot@gmail.com>
*/
class YamlToDslConverter
{
private $uses = array();
/**
* Transforms a Yaml config file into a DSL file.
*
* @param string $yaml
*
* @return string
*/
public function transform($yaml)
{
$config = Yaml::parse(file_get_contents($file), Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS);
$header = <<<PHP
<?php
namespace Symfony\Component\DependencyInjection\Loader\Config;
PHP;
if (null === $config) {
return $header;
}
$code = '';
$previous = null;
foreach ($config as $key => $value) {
switch ($key) {
case 'imports':
$code .= $this->dumpImports($value);
break;
case 'parameters':
$code .= $this->dumpParameters($value);
break;
case 'services':
$code .= $this->dumpServices($value);
break;
default:
if (in_array($previous, array('imports', 'parameters', 'services', null))) {
$code .= "\n";
}
$code .= sprintf("config(%s, %s)\n", $this->dumpValue($key, false), $this->dumpValue($value, false));
break;
}
$previous = $key;
}
}
private function dumpImports(array $imports)
{
if (!$imports) {
return '';
}
$code = '';
foreach ($imports as $import) {
if (!is_array($import)) {
$import = array('resource' => $import);
}
$code .= sprintf("\nimport(%s", $this->dumpValue($import['resource']));
if (isset($import['type']) || isset($import['ignore_errors'])) {
$code .= sprintf(', %s', $this->dumpValue(isset($import['type']) ? $import['type'] : null);
}
if (isset($import['ignore_errors'])) {
$code .= sprintf(', %s', $this->dumpValue((bool) $import['ignore_errors']));
}
$code .= ');'
}
return $code."\n";
}
private function dumpParameters(array $parameters)
{
if (!$parameters) {
return '';
}
$code = "\nparameters()";
foreach ($parameters as $key => $value) {
$code .= sprintf("\n ->add(%s, %s)", $this->dumpValue($key), $this->dumpValue($value));
}
return $code."\n;\n";
}
private function dumpServices(array $services)
{
if (!$services) {
return '';
}
$code = "\nservices()";
foreach ($services as $id => $definition) {
$code .= sprintf("\n ->add(%s, %s)", $this->dumpValue($key), $this->dumpValue($value));
}
return $code."\n;\n";
}
/**
* Dumps values.
*
* @param mixed $value
* @param bool $interpolate
*
* @return string
*
* @throws RuntimeException
*/
private function dumpValue($value, $interpolate = true)
{
if (is_array($value)) {
$code = array();
if (array_keys($value) === range(0, count($value))) {
foreach ($value as $k => $v) {
$code[] = $this->dumpValue($v, $interpolate);
}
} else {
foreach ($value as $k => $v) {
$code[] = sprintf('%s => %s', $this->dumpValue($k, false), $this->dumpValue($v, $interpolate));
}
}
return sprintf('array(%s)', implode(', ', $code));
} elseif ($interpolate && $value instanceof TaggedValue) {
if ('iterator' === $value->getTag()) {
return sprintf('iter(%s)', $this->dumpValue($value->getValue()));
}
if ('service' === $value->getTag()) {
$definition = $value->getValue();
$code = sprintf('service(%s)', isset($definition['class']) ? $this->dumpValue($definition['class']) : '';
}
throw new RuntimeException(sprintf('Unsupported tag "%s".', $value->getTag()));
} elseif ($interpolate && $value instanceof Definition) {
$code = sprintf('service(%s)', null !== $value->getClass() ? $this->dumpValue($value->getClass()) : '');
$arguments = array();
foreach ($value->getArguments() as $argument) {
$arguments[] = $this->dumpValue($argument);
}
$code .= sprintf('->with(%s)', implode(', ', $arguments));
if (null !== $value->getFactory()) {
$code .= sprintf('->factory(%s)', $this->dumpValue($value->getFactory()));
}
if ($value->isAutowired()) {
$code .= '->autowire()';
}
if ($value->getTags()) {
foreach ($value->getTags() as $name => $tags) {
foreach ($tags as $attributes) {
$code .= sprintf('->tag(%s%s)', $this->dumpValue($name), ', '.$this->dumpValue($attributes));
}
}
}
if ($value->getFile()) {
$code .= sprintf('->file(%s)', $this->dumpValue($value->getFile()));
}
if ($value->isLazy()) {
$code .= '->lazy()';
}
return $code;
} elseif ($interpolate && is_string($value) && $value && '@' === $value[0]) {
if (isset($value[1])) {
if ('?' === $value[1]) {
return sprintf('ref(%s)->ignoreOnInvalid()', $this->dumpValue(substr($value, 2)));
}
if ('=' === $value[1]) {
return sprintf('expr(%s)', $this->dumpValue(substr($value, 2)));
}
if ('@' === $value[1]) {
return var_export(substr($value, 1), true);
}
}
return sprintf('ref(%s)', $this->dumpValue(substr($value, 1)));
} elseif (is_object($value) || is_resource($value)) {
throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
}
$export = var_export($value, true);
if ('NULL' === $export) {
return 'null';
}
return $export;
}
/**
* Escapes arguments.
*
* @param array $arguments
*
* @return array
*/
private function escape(array $arguments)
{
$args = array();
foreach ($arguments as $k => $v) {
if (is_array($v)) {
$args[$k] = $this->escape($v);
} elseif (is_string($v)) {
$args[$k] = str_replace('%', '%%', $v);
} else {
$args[$k] = $v;
}
}
return $args;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment