gremo
gremo

Reputation: 48477

How to dynamically append sections to Symfony 2 configuration?

my_bundle:
    algorithm: blowfish # One of 'md5', 'blowfish', 'sha256', 'sha512'

This configuration is done by this configuration tree:

// Algorithms and constants to check
$algorithms = array(
    'md5'      => 'CRYPT_MD5',
    'blowfish' => 'CRYPT_BLOWFISH',
    'sha256'   => 'CRYPT_SHA256',
    'sha512'   => 'CRYPT_SHA512',
);

$rootNode
    ->children()
        ->scalarNode('algorithm')
            ->isRequired()
            ->beforeNormalization()
                ->ifString()
                ->then(function($v) { return strtolower($v); })
            ->end()
            ->validate()
                ->ifNotInArray(array_keys($algorithms))
                ->thenInvalid('invalid algorithm.')
            ->end()
            ->validate()
                ->ifTrue(function($v) use($algorithms) {
                    return 1 != @constant($algorithms[$v]);
                })
                ->thenInvalid('algorithm %s is not supported by this system.')
            ->end()
        ->end()
    ->end();

Since each algorithm requires different parameters, how can I dynamically add them as children of the root node, base on the selected algorithm?

For example, if algorithm is "blowfish" there should be a scalar node named "cost", while if "sha512" a scalar node "rounds", each with different validation rules.

EDIT: what I really need is figure out the current algorithm (how to do with $rootNode?) and than call on of:

$rootNode->append($this->getBlowfishParamsNode());
$rootNode->append($this->getSha256ParamsNode());
$rootNode->append($this->getSha512ParamsNode());

EDIT: possible configurations I'd like to accomplish:

my_bundle:
    algorithm: blowfish
    cost: 15

Another:

my_bundle:
    algorithm: sha512
    rounds: 50000

And another:

my_bundle:
    algorithm: md5

Upvotes: 15

Views: 1874

Answers (2)

Mick
Mick

Reputation: 31959

You could check (using ifTrue()) if the value of algorithm is md5. If this is the case, you unset the blowfish, sha256, sha513 keys in the array containing the raw config values.

You can then use a similar logic if algorithm is blowfish, sha256 or sha513.


$rootNode->
    ->beforeNormalization()
        //...
        ->ifTrue(function($v) {
            // $v contains the raw configuration values
            return 'md5' === $v['algorithm'];
        })
        ->then(function($v) {
            unset($v['blowfish']);
            unset($v['sha256']);
            unset($v['sha512']);
            return $v;
        })
        ->end()
        // ...do same logic for the others
    ->end();

You'd have to use something like this:

my_bundle:
    algorithm: blowfish
    md5: #your params
    blowfish: #will be unset if algorithm is md5 for example
    sha256: #will be unset if algorithm is md5 for example
    sha512: #will be unset if algorithm is md5 for example

As you mention, you can then append all of them:

$rootNode->append($this->getMd5ParamsNode());
$rootNode->append($this->getBlowfishParamsNode());
$rootNode->append($this->getSha256ParamsNode());
$rootNode->append($this->getSha512ParamsNode());

EDIT

There is also a thenUnset() function.

EDIT

Doctrine's way of doing it might be of interest here.

Upvotes: 3

Gonza
Gonza

Reputation: 360

Gremo, maybe im on the wrong track here. BTW, thanks for your reply on my question.

Its just an opinion maybe its just a silly answer... well here we go.

For your answer i know that you already know/understand how a bundle extension works.

Maybe you can define the 4 empty params needed as seen on configuring-services-and-setting-parameters

...you'll set this parameter in your extension class, based on the incoming configuration values...

Then you can have specific checks on the tree (like if algorithm is 'blowfish' then cost is required)

$rootNode->
    ->beforeNormalization()
        ->ifTrue(function($v) {
            // $v contains the raw configuration values
            // if 'algorithm' blowfish -> cost isRequired
            // or as you said on your question you can call
            // ->append($this->addBlowfishParametersNode())
        })
        ->then(function($v) {
            // maybe some unsetting, but not needed
        })
        ->end()
    ->children()
        // ...
    ->end()
;

Check "Appending Sections"

public function addBlowfishParametersNode()
{
    $builder = new TreeBuilder();
    $node = $builder->root('parameters');

    $node
        ->isRequired()
        ->requiresAtLeastOneElement()
        ...
        ...

Upvotes: 0

Related Questions