3

In my Configuration.php I have a structure as following:

public function getConfigTreeBuilder()
{
  $treeBuilder = new TreeBuilder();
  $rootNode = $treeBuilder->root('my_bundle');

  $rootNode
    ->children()
      ->scalarNode('class')->cannotBeEmpty()->end()
      ->arrayNode('social_network')
        ->children()
          ->arrayNode('facebook')
            ->validate()
              ->ifTrue(function($node) {

                // my logic to validate if the 'class' specified implements my trait

              })
              ->thenInvalid('You must use XXXXXX trait in your class.')
            ->end()
            ->children()
              ->scalarNode('app_id')->isRequired()->cannotBeEmpty()->end()
              ->scalarNode('secret')->isRequired()->cannotBeEmpty()->end()
            ->end()
          ->end()
        ->end()
      ->end()
    ->end();

    return $treeBuilder;
}

I need to check if the specified class implement a specific trait part of my bundle.

How can I read the value of the class within the function($node) ?

0

2 Answers 2

2

This is an interesting question so I decided to experiment and see how it could be done. Usually, one would only put more general validation, which is why I guess you can't directly do it within the getConfigTreeBuilder function. Or at least I couldn't find a way. You can try doing function($node) use($rootNode) but you can't get the value of the node. So even if you try to do $rootNode->getNode('class') within the scope of your anonymous function, you wouldn't be able to get the actual value.

What you could do, on the other hand, is to go to your Extension class (located in DependencyInjection dir) and do the validation there. Something like this should do the work:

public function load(array $configs, ContainerBuilder $container)
{
    $configuration = new Configuration();
    $config = $this->processConfiguration($configuration, $configs);

    $class = $config['class'];

    // Apply your logic here...
    if(!$this->checkForTrait($class, 'myTrait')) {
        throw new \ErrorException("The class ".$class." should implement myTrait!");
    }

    $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
    $loader->load('services.yml');
}

private function checkForTrait($class, $trait)
{
    $class = new \ReflectionClass($class);
    $traits = $class->getTraitNames(); // returns an array of all trait names being currently used in that class.
    return in_array($trait, $traits);
}

I don't know if this is considered as "best practice", so if anybody has a better solution, please point it out :)

Sign up to request clarification or add additional context in comments.

Comments

0

All you have to do is to call validate() method inside scalarNode('class') node. Take a look:

public function getConfigTreeBuilder()
{
    $treeBuilder = new TreeBuilder();
    $rootNode = $treeBuilder->root('my_bundle');

    $rootNode
        ->children()
            ->scalarNode('class')
                ->cannotBeEmpty()
                ->validate()
                    ->ifTrue(function ($value) {
                        // my logic to validate if the 'class' specified implements my trait

                        $reflection = new \ReflectionClass($value);
                        $traitsNames = $reflection->getTraitNames();

                        return false === \in_array('myTrait', $traitsNames, true);
                    })
                    ->thenInvalid('You must use XXXXXX trait in your class.')
                ->end()
            ->end()
            ->arrayNode('social_network')
                ->children()
                    ->arrayNode('facebook')
                        ->children()
                            ->scalarNode('app_id')->isRequired()->cannotBeEmpty()->end()
                            ->scalarNode('secret')->isRequired()->cannotBeEmpty()->end()
                        ->end()
                    ->end()
                ->end()
            ->end()
        ->end()
    ;

    return $treeBuilder;
}

In this way validation is done per the scalar class node. The $value is value of class node, so it's name of your class.

The rest:

$reflection = new \ReflectionClass($value);
$traitsNames = $reflection->getTraitNames();

return false === \in_array('myTrait', $traitsNames, true);

it's just a piece of php code that verifies if the trait is implemented.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.