Php 如何在symfony yaml配置组件中使用变量和导入文件

Php 如何在symfony yaml配置组件中使用变量和导入文件,php,symfony,configuration,yaml,Php,Symfony,Configuration,Yaml,我在项目中使用symfony的config组件,我需要在yml配置文件的各个部分中使用相同的值 有人知道如何使用config组件重现symfony configuration.yml的行为吗 我想导入配置文件: imports: - { resource: otherfile.yml } 或声明变量: myvar: value othervar: %myvar% 好的,下面是一些未经测试的代码: <?php // parse yaml to an array $parser = n

我在项目中使用symfony的config组件,我需要在yml配置文件的各个部分中使用相同的值

有人知道如何使用config组件重现symfony configuration.yml的行为吗

我想导入配置文件:

imports:
  - { resource: otherfile.yml }
或声明变量:

myvar: value
othervar: %myvar%

好的,下面是一些未经测试的代码:

<?php
// parse yaml to an array
$parser = new \Symfony\Component\Yaml\Parser();
$configs = $parser->parse(\file_get_contents('config.yml'));

// your config tree
$configuration = new Configuration();

// processor reading the config from the array according to the Configuration NodeTree
$processor = new Processor();
$result = $processor->processConfiguration($configuration, $configs);

// you can be 100% sure, that your $result array has the attributes you set in Configuration

处理器应该为您验证配置并引发异常。但是您也可以直接解析YAML并访问数组

好的,下面是一些未经测试的代码:

<?php
// parse yaml to an array
$parser = new \Symfony\Component\Yaml\Parser();
$configs = $parser->parse(\file_get_contents('config.yml'));

// your config tree
$configuration = new Configuration();

// processor reading the config from the array according to the Configuration NodeTree
$processor = new Processor();
$result = $processor->processConfiguration($configuration, $configs);

// you can be 100% sure, that your $result array has the attributes you set in Configuration

处理器应该为您验证配置并引发异常。但是您也可以只解析YAML并直接访问阵列

Symfony配置组件没有内置此功能。定义和解析配置文件中的导入和参数是DependencyInjection组件的一部分,即其文件加载程序类Symfony\component\DependencyInjection\Loader\FileLoader

如果不想将整个DependencyInjection组件添加为依赖项,那么最好的方法是简单地扩展配置组件自己的FileLoader类,重写load方法,读入配置,查找imports子元素,并在其中引用的文件路径上调用$this->import。 然后读取parameters键下的所有内容,迭代所有配置键,并用它们的值替换以前找到的任何参数

例如:

public function load($resource, $type = null)
{
  // ...
  // Load your config data as usual. It's assumed that
  // the configuration is now a multidimensional array
  // named $content
  // Load the imports:
  if (isset($content['imports'])) {
      foreach ($content['imports'] as $import) {
          $extraContent = $this->import($import['resource']);
          $content = array_replace_recursive($extraContent, $content);
      }
  }
  // Store the parameters:
  if (isset($content['parameters'])) {
      foreach ($content['parameters'] as $param) {
          foreach ($param as $key => $value) {
              $this->_parameters[$key] = $value;
          }
      }
  }
  // iterate over all configuration keys and substitute
  // placeholders with parameter values:
  array_walk_recursive(
      $content,
      function(&$val, $key) {
          $matches = null;
          preg_match('/\%(.*?)\%/', $val, $matches);
          $param = isset($matches[1]) ? $matches[1] : false;
          if ($param) {
              if (isset($this->_parameters[$param])) {
                  $val = str_replace("%$param%", $this->_parameters[$param], $val);
              }
          }
      }
  );    
  // And you're done. From here on, proceed as usual
  // (like, validate content against a ConfigurationInterface
  // implementation
  // ...
}
请注意:示例代码非常简短,不包含错误检查,也没有以这种简短的形式进行过测试——但它确实包含了所有必要的步骤,我希望它能为您指明正确的方向


还建议查看Symfony\Component\DependencyInjection\Loader\FileLoader类,看看它是如何完成的,忽略所有资源注册内容。

Symfony配置组件没有内置此功能。定义和解析配置文件中的导入和参数是DependencyInjection组件的一部分,即其文件加载程序类Symfony\component\DependencyInjection\Loader\FileLoader

如果不想将整个DependencyInjection组件添加为依赖项,那么最好的方法是简单地扩展配置组件自己的FileLoader类,重写load方法,读入配置,查找imports子元素,并在其中引用的文件路径上调用$this->import。 然后读取parameters键下的所有内容,迭代所有配置键,并用它们的值替换以前找到的任何参数

例如:

public function load($resource, $type = null)
{
  // ...
  // Load your config data as usual. It's assumed that
  // the configuration is now a multidimensional array
  // named $content
  // Load the imports:
  if (isset($content['imports'])) {
      foreach ($content['imports'] as $import) {
          $extraContent = $this->import($import['resource']);
          $content = array_replace_recursive($extraContent, $content);
      }
  }
  // Store the parameters:
  if (isset($content['parameters'])) {
      foreach ($content['parameters'] as $param) {
          foreach ($param as $key => $value) {
              $this->_parameters[$key] = $value;
          }
      }
  }
  // iterate over all configuration keys and substitute
  // placeholders with parameter values:
  array_walk_recursive(
      $content,
      function(&$val, $key) {
          $matches = null;
          preg_match('/\%(.*?)\%/', $val, $matches);
          $param = isset($matches[1]) ? $matches[1] : false;
          if ($param) {
              if (isset($this->_parameters[$param])) {
                  $val = str_replace("%$param%", $this->_parameters[$param], $val);
              }
          }
      }
  );    
  // And you're done. From here on, proceed as usual
  // (like, validate content against a ConfigurationInterface
  // implementation
  // ...
}
请注意:示例代码非常简短,不包含错误检查,也没有以这种简短的形式进行过测试——但它确实包含了所有必要的步骤,我希望它能为您指明正确的方向


还建议查看Symfony\Component\DependencyInjection\Loader\FileLoader类,看看它是如何完成的,忽略所有资源注册的内容。

一点Markus Wolff代码:

class FileLoader extends \Symfony\Component\Config\Loader\FileLoader
{
    private $_parameters;

    public function addParameter($k, $v)
    {
        $this->_parameters[$k] = $v;
    }

    public function load($resource, $type = null)
    {
        $resource = $this->getLocator()->locate($resource, null, true);
        $content = \Symfony\Component\Yaml\Yaml::parse(file_get_contents($resource));

        if (isset($content['imports'])) {
            foreach ($content['imports'] as $import) {
                $extraContent = $this->import($import['resource']);
                $content = array_replace_recursive($extraContent, $content);
            }
        }

        if (isset($content['parameters'])) {
            foreach ($content['parameters'] as $key => $value) {
                $this->_parameters[$key] = $value;
            }
        }

        array_walk_recursive(
            $content,
            function (&$val) {
                $matches = null;
                preg_match_all('/\%(.*?)\%/', $val, $matches, PREG_SET_ORDER, 0);
                if ($matches) {
                    foreach ($matches as $match) {
                        if ($param = isset($match[1]) ? $match[1] : false) {
                            if (isset($this->_parameters[$param])) {
                                $val = str_replace("%$param%", $this->_parameters[$param], $val);
                            }
                        }
                    }
                }
            }
        );

        return $content;
    }

    public function supports($resource, $type = null)
    {
        return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION);
    }
}

对Markus Wolff代码的一点修改:

class FileLoader extends \Symfony\Component\Config\Loader\FileLoader
{
    private $_parameters;

    public function addParameter($k, $v)
    {
        $this->_parameters[$k] = $v;
    }

    public function load($resource, $type = null)
    {
        $resource = $this->getLocator()->locate($resource, null, true);
        $content = \Symfony\Component\Yaml\Yaml::parse(file_get_contents($resource));

        if (isset($content['imports'])) {
            foreach ($content['imports'] as $import) {
                $extraContent = $this->import($import['resource']);
                $content = array_replace_recursive($extraContent, $content);
            }
        }

        if (isset($content['parameters'])) {
            foreach ($content['parameters'] as $key => $value) {
                $this->_parameters[$key] = $value;
            }
        }

        array_walk_recursive(
            $content,
            function (&$val) {
                $matches = null;
                preg_match_all('/\%(.*?)\%/', $val, $matches, PREG_SET_ORDER, 0);
                if ($matches) {
                    foreach ($matches as $match) {
                        if ($param = isset($match[1]) ? $match[1] : false) {
                            if (isset($this->_parameters[$param])) {
                                $val = str_replace("%$param%", $this->_parameters[$param], $val);
                            }
                        }
                    }
                }
            }
        );

        return $content;
    }

    public function supports($resource, $type = null)
    {
        return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION);
    }
}

复制对你意味着什么?如果要重用标量值,可以使用参数。如果你想重用一组设置,只需为它创建一个配置,让symfony解析它并将它交给一个带有一些getter的服务。我只使用symfony的config和yaml组件,而不是整个框架。因此,我想知道如何在加载symfony配置文件时重现symfony内核的行为。这不会发生在内核本身,而是在每个Bundle的DependencyInjection文件夹中,*Extension.php加载生成NodeTree.ok的配置对象,那么,有没有一个symfony组件可以在symfony项目之外允许这种良好的行为呢?复制对您意味着什么?如果要重用标量值,可以使用参数。如果你想重用一组设置,只需为它创建一个配置,让symfony解析它并将它交给一个带有一些getter的服务。我只使用symfony的config和yaml组件,而不是整个框架。因此,我想知道如何在加载symfony配置文件时重现symfony内核的行为。这不会发生在内核本身,而是在每个Bundle的DependencyInjection文件夹中,*Extension.php加载生成NodeTree.ok的配置对象,那么,有没有一个symfony组件可以在symfony项目之外允许这种良好的行为呢?如果知道这些类使用什么use语句会很好,如果知道这些类使用什么use语句会很好