【问题标题】:how to use variables and import files in symfony yaml config component如何在 symfony yaml 配置组件中使用变量和导入文件
【发布时间】:2015-03-10 18:17:38
【问题描述】:

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

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

我要导入配置文件:

imports:
  - { resource: otherfile.yml }

或声明变量:

myvar: value
othervar: %myvar%

【问题讨论】:

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

标签: php symfony configuration yaml


【解决方案1】:

Symfony Config 组件没有内置此功能。在配置文件中定义和解析导入和参数是 DependencyInjection 组件的一部分,即其 FileLoader 类 (Symfony\Component\DependencyInjection\Loader\FileLoader)。

如果您不想将整个 DependencyInjection 组件添加为依赖项,最好的方法是简单地扩展 Config 组件自己的 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 类,看看它是如何在那里完成的(忽略所有资源注册的东西)。

【讨论】:

    【解决方案2】:

    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);
        }
    }
    

    【讨论】:

      【解决方案3】:

      好的,这里有一些未经测试的代码:

      <?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 并直接访问数组

      【讨论】:

      • 很高兴知道这些类使用什么 use 语句
      猜你喜欢
      • 2018-11-21
      • 1970-01-01
      • 2021-08-21
      • 2016-11-19
      • 2023-03-06
      • 2017-11-01
      • 2011-02-02
      • 2022-11-21
      相关资源
      最近更新 更多