Getting errors when validating Symfony2 semantic configuration - php

I'm trying to write a semantic configuration of the bundle in Symfony2. I have prepared a configuration file using YAML (spu.yml):
spu:
modules:
spu-module:
reuqires: []
path: modules/spu-module.js
Then I'm loading it in Extension file (DependencyInjection/spuExtension.php):
namespace Gig\SpuBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
class spuExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration( $configuration, $configs );
$loader = new Loader\YamlFileLoader( $container, new FileLocator( __DIR__ . '/../Resources/config' ) );
$loader->load( 'services.yml' );
$loader->load( 'spu.yml' );
}
}
And configuration class ()DependencyInjection/Configuration.php) for this extension is:
namespace Gig\SpuBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root( 'spu' );
$rootNode
->children()
->arrayNode('modules')
->isRequired()
->prototype('array')
->end()
->end();
return $treeBuilder;
}
}
When validating the config I get an error:
[Symfony\Component\Config\Definition\Exception\InvalidConfigurationException]
The child node "modules" at path "spu" must be configured.
What am I doing wrong?

You must include this in your main app/config/config.yml file
imports:
- { resource: parameters.yml }
- { resource: security.yml }
- { resource: spu.yml }
If you want to have default parameters, set them in DependencyInjection/Configuration.php
This can be something like this.
$rootNode
->children()
->arrayNode('modules')
->isRequired()
->addDefaultsIfNotSet()
->prototype('array')
->children()
->arrayNode('reuqires')->end()
->scalarNode('path')->defaultValue('modules/spu-module.js')->end()
->end()
->end()
->end()
->end();

The best way to do this is to let the users define the configuration for your bundle in the config.yml file. There is no need for a special file.
You can keep the configuration which you have in your Configuration class but you will have to modify your spuExtension class.
The way Symfony works you will have to read the values from the config.yml for your bundle in the spuExtension class and then set them as parameters. Then you will have easy access to these values by using the container's getParameter method.
This is how your config.yml will look
spu:
modules:
spu-module:
reuqires: []
path: modules/spu-module.js
Then in your spuExtension class you can get these values specified by doing:
class spuExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration( $configuration, $configs );
$loader = new Loader\YamlFileLoader( $container, new FileLocator( __DIR__ . '/../Resources/config' ) );
$loader->load( 'services.yml' );
$container->setParameter('modules', $configs[0]);
}
}
This will make it easy for you to use the container in an controller to get a parameter.
The $configs variable in the spuExtension will contain all the configuration that is listed under your root. Which in this case is spu.
The way Symfony works you first have to load the configuration in your bundle's extension class and then set this as a parameter, this seems redundant but it's a best practice and it was intended to work like this.

Ok, I did it different way.
public function load(array $configs, ContainerBuilder $container)
{
$loader = new Loader\YamlFileLoader( $container, new FileLocator( __DIR__ . '/../Resources/config' ) );
$loader->load( 'services.yml' );
$loader->load( 'spu.yml' );
$spuConfig = Yaml::parse(__DIR__ . '/../Resources/config/spu.yml');
$configs = array_merge($configs, $spuConfig);
$configuration = new Configuration();
$config = $this->processConfiguration( $configuration, $configs );
}
And now I'm getting what I wanted. I can validate params in Configuration class.

Related

Loading configuration resource to Symfony

Since I'm running out of ideas (and stackoverflow threads): I need an additional app configuration, located under /etc/appname/config.yml (client requirement).
My configuration file:
foo: 'bar'
I'm loading this file within my `app/config/config.yml:
imports:
- { resource: /etc/appname/config.yml }
The error:
There is no extension able to load the configuration for "foo"
I've already implemented a Configuration class:
<?php
namespace AppBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('');
$rootNode
->children()
->scalarNode('foo')->defaultValue('')->end()
->end()
;
return $treeBuilder;
}
}
But it still doesn't work. If I load the config via the load method
public function load(array $configs, ContainerBuilder $container)
{
$loader = new YamlFileLoader(
$container,
new FileLocator('/etc/frsereportergui')
);
$loader->load('config.yml');
}
I get the same error.
Anyone got an idea?

There is no extension able to load the configuration for ... Looked for namespace "...", found none

Introduction
I know. There are a thousands of post on this exact topic, but somehow I still can't manage to fix this issue. I'm always getting the error
There is no extension able to load the configuration for "first" (in /var/www/app/src/tzfrs/SpotifyBundle/DependencyInjection/../Resources/config/settings.yml). Looked for namespace "first", found none
Purpose
I created a bundle and want to have custom configuration options, but since they are bigger than a usual file, I don't want to put it in the config.yml, but in my own file.
Description
My project structure for the bundle looks like this /src/tzfrs/SpotifyBundle
Inside the bundle I have created the files
./TzfrsSpotifyBundle.php
./DependencyInjection/Configuration.php
./DependencyInjection/TzfrsSpotifyExtension.php
./Resources/config/settings.yml
I have, of course, registered the Bundle in the AppKernel, and everything works fine so far with the bundle, except for the new config I want to add
Contents of TzfrsSpotifyBundle
<?php
namespace tzfrs\SpotifyBundle;
use tzfrs\SpotifyBundle\DependencyInjection\TzfrsSpotifyExtension;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class TzfrsSpotifyBundle extends Bundle
{
}
Contents of /DependencyInjection/Configuration.php (minimized to relevant info only)
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('first');
$rootNode
->children()
->booleanNode('secondary')->defaultTrue()->end()
->end();
return $treeBuilder;
}
Contents of ./DependencyInjection/TzfrsSpotifyExtension.php (minimized to relevant info only)
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('settings.yml');
}
Contents of ./Resources/config/settings.yml
first:
secondary: false
Ideas
If any more questions come up or suggestions that won't work, I'll update this section with the info
What I tried was the same this post here suggested https://stackoverflow.com/a/36051719/2823419 but it didn't work. I got the same error.
Then I tried this answer https://stackoverflow.com/a/35505189 meaning naming the root element like my bundle. Still the same error
Make sure you have everything spelled correctly and that your extension class is actually being called. If you don't name the extension just right then it won't be loaded. I just tested this and it works fine:
cerad_spotify:
first:
secondary: false
class CeradSpotifyBundle extends Bundle
{
}
namespace Cerad\SpotifyBundle\DependencyInjection;
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('cerad_spotify');
$rootNode
->children()
->arrayNode('first')
->children()
->booleanNode('secondary')->end()
->end()
->end() // first
->end()
;
return $treeBuilder;
}
}
namespace Cerad\SpotifyBundle\DependencyInjection;
class CeradSpotifyExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
VarDumper::dump($config);
}
}

Symfony 2 loading custom configuration file

I want to add a new configuration file in Bundle/Resources/config. I've tried following http://symfony.com/doc/current/cookbook/bundles/extension.html , but it doesn't work as it should and I get
There is no extension able to load the configuration for
"mailbroker_mail_details"
My files:
MailbrokerMailDetailsExtension.php
<?php
namespace Mailbroker\MailDetailsBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
class MailbrokerMailDetailsExtension extends Extension
{
/**
* {#inheritDoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
$loader->load('canonisers.yml');
}
public function getAlias()
{
return 'mailbroker_mail_details';
}
}
Configuration.php
<?php
namespace Mailbroker\MailDetailsBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
class Configuration implements ConfigurationInterface
{
/**
* {#inheritDoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('mailbroker_mail_details');
$rootNode
->children()
->scalarNode('abc')->end()
->end()
;
return $treeBuilder;
}
}
canonisers.yml
mailbroker_mail_details:
abc: 123
The Configuration is correct (when placed in app/config/config.yml it loads as it should), canonisers.yml is loaded correctly, but for some reason I can't make it work together. Thanks for your help!
Well, I have not tried it but you should be able to use the Yaml extension to load in the canonisers.yml file directly and add it to configs. Not recommended (bypasses the application caching stuff) but it might work:
use Symfony\Component\Yaml\Yaml;
class MailbrokerMailDetailsExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$file = __DIR__.'/../Resources/config/canonisers.yml';
$configs = array_merge($configs,Yaml::parse(file_get_contents($file));
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
....
Completely untested. You might need to add to app/config/config.yml
mailbroker_mail_details: ~
Just to get past the error message. Not sure.
Let me know if it works.
Ok, so #Iltar from #symfony irc channel pointed me to cookbook: http://symfony.com/doc/current/cookbook/bundles/prepend_extension.html
Long story short, PrependExtensionInterface with prepend method.
It was added since I last read through symfony book and cookbook, and it wasn't exactly googlable in this case, so I'll just leave the link here for other people.

How do I set default configuration value in Symfony2 correctly?

I've built a service which I'd like to be able to configure from a config file. I've been able to get it working as needed, but when I look at other bundles, don't see the same config setup as I've had to use. I feel like it's a hack.
What I need is to have a configuration value as optional, meaning if it isn't in the config.yml file it uses a default value. I've accomplished this by adding the following to my Configuration.php bundle file:
namespace ChrisJohnson00\ApiProfilerBundle\DependencyInjection;
...
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('chris_johnson00_api_profiler');
$rootNode
->children()
->scalarNode('warning_threshold')
->info('Changes the warning threshold time (ms). This is used to change the toolbar to yellow when the total response time is > this value')
->example("5000")
->defaultValue("5000")
->end()
->scalarNode('error_threshold')
->info('Changes the error threshold time (ms). This is used to change the toolbar to red when the total response time is > this value')
->example("10000")
->defaultValue("10000")
->end()
->end()
;
return $treeBuilder;
}
}
But this didn't work alone, I had to add the following to my bundle extension file's load function
namespace ChrisJohnson00\ApiProfilerBundle\DependencyInjection;
...
class ChrisJohnson00ApiProfilerExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$container->setParameter('chris_johnson00_api_profiler.warning_threshold', $config['warning_threshold']);
$container->setParameter('chris_johnson00_api_profiler.error_threshold', $config['error_threshold']);
$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.xml');
}
}
How can I configure my bundle's configuration parameters without the need for $container->setParameter(...) in my extension file?
Found a cookbook with the answers... I'm doing it correctly it seems.
http://symfony.com/doc/current/cookbook/bundles/extension.html

Exactly how does the defaultValue work in Symfony 2.0 NodeDefinition?

I'm trying to expose the semantic configuration within a bundle in Symfony 2.0 but I'm having trouble getting the defaultValue to work in the NodeDefinition class. I generated an empty bundle and created the necessary files for the Configuration to work and I am able to get the config value, but I want to set a defaultValue to configuration item. I use the defaultValue() method and remove the configuration item from my config.yml and then it shows up an empty array? Can anyone explain how the defaultValue() actually works, am I missing something?
<?php
// ./DependencyInjection/Configuration.php
namespace Test\Bundle\TestBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('test_bundle');
$rootNode
->children()
->scalarNode('foo')->defaultValue('bar')->end()
->end();
return $treeBuilder;
}
}
-
<?php
// ./DependencyInjection/TestBundleExtension.php
namespace Test\Bundle\TestBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
class TestBundleExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
var_dump($configs); // empty array
$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.xml');
}
}
So from the above Configuration class surely when the config item 'test_bundle.foo' is missing, it's value will be set to 'bar'... yes? Well that's what I thought but it doesn't.
Your root node is an array node. By default, if you dont set a key, default value is not applied. 2 examples on how to get your default value working:
Set the value as null:
# in the config.yml
test_bundle:
foo: ~
Tell your root node to use default values if not set:
// in your Configuration.php
$rootNode
->addDefaultsIfNotSet()
->children()
->scalarNode('foo')->defaultValue('bar')->end()
->end();
# in the config.yml
test_bundle: ~

Categories