如何将Symfony配置树绑定到对象

时间:2014-05-31 00:31:00

标签: symfony

我如何将Symfony配置树绑定到类而不是返回数组?

使用Symfony\Component\Config\Definition\Processor返回一个数组。

在我的情况下,我希望将配置绑定到一个类,这样我就可以使用方法来组合部分数据。

以下是我的用例的一个简单示例。我希望配置绑定到一个类,所以我可以使用一个方法将table.name和table.version连接在一起(我的实际用例更复杂,但这是一个简单的例子)

config.yml

  db:
    table:
      name: some_table
      version: v2

ConfigurationInterface

class DBConfiguration implements ConfigurationInterface
{
    /**
     * {@inheritDoc}
     */
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder();
        $rootNode = $treeBuilder->root('db');

        $rootNode
            ->children()
                ->arrayNode('table')
                    ->children()
                        ->scalarNode('name')->isRequired()->end()
                        ->scalarNode('version')->end()
                    ->end()
                ->end()
        ;

        return $treeBuilder;
    }
}

我希望将配置绑定到

class DB
{

    public $table;

    public function __construct()
    {
        $this->table = new Table();
    }

}


class Table
{

    public $name;
    public $version;

    /**
     * @return string
     * Calculate the full table name.
     */
    public function getTableName()
    {
        return $this->name.'-'.$this->version;
    }

}

2 个答案:

答案 0 :(得分:2)

Symfony Config组件不支持该功能。

但是,在Symfony项目中,这通常是在container compile phase完成的。在您的包的Extension类中,您将可以以数组形式访问包的配置树。

然后,您可以获取此数组并将其分配给将在其中创建配置对象的服务容器中定义的服务。

这正是DoctrineBundle的配置类的构建方式:

  1. Abstract services (for the configuration and the factory) are defined in dbal.xml

  2. When loading DoctrineBundle's extension, an instance of the abstract config service is created for each defined connection.

  3. An instance of the abstract factory service is created for each defined connection.

  4. The options array is then passed to the abstract factory service along with the configuration

  5. When creating an instance, the factory then does the necessary transformations

答案 1 :(得分:1)

据我所知,Symfony没有本机支持,但是,您可以自己实现它。您可以使用负责反序列化的Symfony Serializer Component子集,但我认为这将是一种过度杀伤力。特别是因为我没有看到任何PublicPropertyDenormalizer,只有GetSetMethodNormalizer(这也是非规范化)。因此,您必须使自己的配置对象具有get/set方法或滚动PublicPropertyDenormalizer。可能,但它看起来像是一种矫枉过正,并没有多大帮助:

Symfony Serializer Component

$array = [
    'field1' => 'F1',
    'subobject' => [
        'subfield1' => 'SF1',
    ],
];

class MyConfigObject implements Symfony\Component\Serializer\Normalizer\DenormalizableInterface
{
    private $field1;

    private $subobject;

    public function getField1()
    {
        return $this->field1;
    }

    public function setField1($field1)
    {
        $this->field1 = $field1;
    }

    public function getSubobject()
    {
        return $this->subobject;
    }

    public function setSubobject(SubObject $subobject)
    {
        $this->subobject = $subobject;
    }

    public function denormalize(\Symfony\Component\Serializer\Normalizer\DenormalizerInterface $denormalizer, $data, $format = null, array $context = array())
    {
        $obj = new static();
        $obj->setField1($data['field1']);
        $obj->setSubobject($denormalizer->denormalize($data['subobject'], 'SubObject'));

        return $obj;
    }
}

class SubObject
{
    private $subfield1;

    public function getSubfield1()
    {
        return $this->subfield1;
    }

    public function setSubfield1($subfield1)
    {
        $this->subfield1 = $subfield1;
    }
}

$normalizer = new \Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer();

$obj = (new MyConfigObject())->denormalize($normalizer, $array);    

Native PHP Way

Imo这比上面容易得多,因为Symfony Serializer并没有真正做到这一点。

$array = [
    'field1' => 'F1',
    'subobject' => [
        'subfield1' => 'SF1',
    ],
];

trait Denormalizable
{
    public function fromArray($array)
    {
        foreach ($array as $property => $value) {
            if (is_array($value)) {
                if ($this->$property instanceof ArrayDenormalizableInterface) {
                    $this->$property->fromArray($value);    
                } else {
                    $this->$property = $value;
                }
            } else {
                $this->$property = $value;
            }
        }
    }
}

interface ArrayDenormalizableInterface
{
    public function fromArray($array);
}

class MyConfigObject implements ArrayDenormalizableInterface
{
    use Denormalizable;

    public $field1;

    public $subobject;

    public function __construct()
    {
        $this->subobject = new SubObject();
    }
}

class SubObject implements ArrayDenormalizableInterface
{
    use Denormalizable;

    public $subfield1;
}

$myConf = new MyConfigObject();
$myConf->fromArray($array);

无论您选择哪种方式,现在只需从symfony处理器返回数组并将其转换为您需要的配置对象。