Following the advice posted at Loading custom config file for app in symfony2 I stucked into namespace issue.
In \src\AppBundle\DependencyInjection I have two files:
AppExtension.php:
<?php
namespace AppBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\Validator\Tests\Fixtures\Entity;
use AppBundle\DependencyInjection\Configuration;
/**
* This is the class that loads and manages your bundle configuration
*/
class AppExtension extends Extension
{
/**
* {#inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$container->setParameter('kh', $config['kh']);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('general.yml'); # another file of yours
}
}
and Configuration.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('kh');
$rootNode
->children()
->arrayNode('tags')
->prototype('array')
->children()
->scalarNode('name')->isRequired()->end();
->scalarNode('role')->isRequired()->end();
->scalarNode('priority')->isRequired()->end();
->scalarNode('label')->isRequired()->end();
->end();
->end();
->end();
return $treeBuilder;
}
}
It seems that I make some kind of mistake naming the files as executing:
php app/console cache:clear --env=prod
results in:
PHP Fatal error: Class 'AppBundle\DependencyInjection\Configuration' not found in /var/www/dev.investmentopportunities.pl/src/AppBundle/DependencyInjection/AppExtension.php on line 22
[2015-08-02 10:39:36] php.EMERGENCY: Fatal Error: Class 'AppBundle\DependencyInjection\Configuration' not found {"type":1,"file":"/var/www/dev.investmentopportunities.pl/src/AppBundle/DependencyInjection/AppExtension.php","line":22,"level":6143,"stack":[]}
Unluckily I have a problem with finding the error on my own. I have tried to rename files but still the error occurs. Could you please advice what am I doing wrong?
UPDATE 1:
As sugested by #San Thapa I have tried also to remove "use" command. This results in:
PHP Fatal error: Class 'AppBundle\DependencyInjection\Configuration' not found in /var/www/dev.investmentopportunities.pl/src/AppBundle/DependencyInjection/AppExtension.php on line 21
[2015-08-02 12:05:27] php.EMERGENCY: Fatal Error: Class 'AppBundle\DependencyInjection\Configuration' not found {"type":1,"file":"/var/www/dev.investmentopportunities.pl/src/AppBundle/DependencyInjection/AppExtension.php","line":21,"level":6143,"stack":[]}
[Symfony\Component\Debug\Exception\ClassNotFoundException]
Attempted to load class "Configuration" from namespace "AppBundle\Dependenc
yInjection".
Did you forget a "use" statement for e.g. "Symfony\Bundle\TwigBundle\Depend
encyInjection\Configuration", "Symfony\Bundle\DebugBundle\DependencyInjecti
on\Configuration", "Symfony\Bundle\WebProfilerBundle\DependencyInjection\Co
nfiguration", "Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestB
undle\DependencyInjection\Configuration", "Symfony\Bundle\FrameworkBundle\D
ependencyInjection\Configuration", "Genemu\Bundle\FormBundle\DependencyInje
ction\Configuration", "Doctrine\ORM\Configuration", "Doctrine\DBAL\Configur
ation", "Doctrine\Bundle\DoctrineCacheBundle\DependencyInjection\Configurat
ion", "Symfony\Bundle\SwiftmailerBundle\DependencyInjection\Configuration",
"Symfony\Bundle\MonologBundle\DependencyInjection\Configuration", "Symfony
\Bundle\AsseticBundle\DependencyInjection\Configuration", "Sensio\Bundle\Fr
ameworkExtraBundle\DependencyInjection\Configuration", "PUGX\AutocompleterB
undle\DependencyInjection\Configuration", "Knp\Bundle\PaginatorBundle\Depen
dencyInjection\Configuration", "FOS\UserBundle\DependencyInjection\Configur
ation" or "Doctrine\Bundle\DoctrineBundle\DependencyInjection\Configuration
"?
What seems a bit strange acessing the webpage from browser does not result in any error.
Just added to first line of Configuration.php:
<?php
and also remove semicolons:
$rootNode
->children()
->arrayNode('tags')
->prototype('array')
->children()
->scalarNode('name')->isRequired()->end()
->scalarNode('role')->isRequired()->end()
->scalarNode('priority')->isRequired()->end()
->scalarNode('label')->isRequired()->end()
->end()
->end()
->end();
I'm not sure about structure... Maybe you forgot add one more end()...
Related
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?
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);
}
}
For a few hours now I've been struggling to do the most simple thing you can imagine and it just won't work. I've read tons of stackoverflow questions, read the complete Symfony documentation on configuration files and with every article or other piece of information I read, it gets harder and harder to understand.
Details
I've created my own Bundle. Lets call it HappyBundle. I've put this Bundle in my company's folder. So naturally I've got CompanyHappyBundle.
I want to make a configuration file specifically for this bundle as I want it to be reusable.
As I test i created the following:
# src/Company/HappyBundle/Resources/config/config.yml
company_happy:
import:
path: /tmp
Now, what I want is to be able to use this value in my Controller. I just don't know how. It throws me the following error:
[Symfony\Component\Config\Exception\FileLoaderLoadException]
There is no extension able to load the configuration for "company_happy" (in /home/user/symfony/src/Company/HappyBundle/Resources/config/config.yml).
Looked for namespace "company_happy", found "framework", "security", "twig", "monolog", "swiftmailer", "assetic", "doctrine", "sensio_framework_extra", "debug", "web_profiler", "sensio_distribution" in /home/user/symfony/src/Company/HappyBundle/Resources/config/config.yml (which is being imported from "/home/user/symfony/app/config/config.yml").
Update
In the config.yml I added the following:
#app/config/config.yml
imports:
- { resource: "#CompanyHappyBundle/Resources/config/config.yml" }
I've also made a Configuration class because I read somewhere this was required. I really do think this is alot of work to make just one config file.
namespace Company\HappyBundle\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('company_happy');
$rootNode
->children()
->arrayNode('import')
->children()
->scalarNode('attachments_path')->defaultValue('/tmp')->end()
->scalarNode('method')->defaultValue('ALL')->end()
->booleanNode('move_mail')->defaultValue(true)->end()
->booleanNode('mark_read')->defaultValue(true)->end()
->end()
->end()
;
return $treeBuilder;
}
}
What I am actually looking for are the steps and requirements needed to get this working. The thing with symfony is that it has a million ways to do this. The documentation doesn't just give a workflow.
Can someone please help me out?
I have solved my own issue but not without trouble. I'm not at all pleased with Symfony's configuration system.
Step one - Create your config file
Create a file named config.yml in src/<bundle name>/Resources/config/
yourbundle:
param_one: value_one
param_two: value_two
param_three: value_three
param_four: value_four
param_five:
subparam_one: subvalue_one
subparam_two: subvalue_two
subparam_three: subvalue_three
subparam_four: subvalue_four
Step two - Importing your configuration file
Go to app/config/config.yml and add:
#app/config/config.yml
imports:
- { resource: "#YourBundle/Resources/config/config.yml" }
Step three - Create a configuration class
Create a file named Configuration.php in src/<bundle name>/DependencyInjection/
namespace YourBundle\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('yourbundle');
$rootNode
->children()
->scalarNode('param_one')->defaultValue('value_one')->end()
->scalarNode('param_two')->defaultValue('value_two')->end()
->scalarNode('param_three')->defaultValue('value_three')->end()
->scalarNode('param_four')->defaultValue('value_four')->end()
->arrayNode('param_five')
->children()
->scalarNode('subparam_one')->defaultValue('subvalue_one')->end()
->scalarNode('subparam_two')->defaultValue('subvalue_two')->end()
->scalarNode('subparam_three')->defaultValue('subvalue_three')->end()
->scalarNode('subparam_four')->defaultValue('subvalue_four')->end()
->end()
->end()
;
return $treeBuilder;
}
}
Step four - Creating an extension
Last but not least, you'll have to create an extension. Create a file <yourbundle>Extension.php in src/<your bundle>/DependencyInjection/
namespace YourBundle\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
class YourbundleExtension extends Extension
{
/**
* #var ContainerBuilder
*/
protected $container;
/**
* {#inheritDoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$this->container = $container;
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
foreach ($config as $key => $value) {
$this->parseNode('yourbundle.'.$key, $value);
}
$container->setParameter('yourbundle', $config);
}
/**
* #param string $name
* #param mixed $value
*
* #throws \Exception
*/
protected function parseNode($name, $value)
{
if (is_string($value)) {
$this->set($name, $value);
return;
}
if (is_integer($value)) {
$this->set($name, $value);
return;
}
if (is_array($value)) {
foreach ($value as $newKey => $newValue) {
$this->parseNode($name.'.'.$newKey, $newValue);
}
return;
}
if (is_bool($value)) {
$this->set($name, $value);
return;
}
throw new \Exception(gettype($value).' not supported');
}
/**
* #param string $key
* #param mixed $value
*/
protected function set($key, $value)
{
$this->container->setParameter($key, $value);
}
}
All these steps are required just to be able to call a configuration parameter specific for your bundle.
If any of you know any way to do this easier, feel free to post an answer or comment.
A few notices:
In config.yml, you are trying to define import as array. It seems like symfony doesn't allow creating array elements in the root of your config, meaning that you have to nest arrays deeper down the tree. So you can not do:
company_happy:
import:
path: /tmp
another_import:
...
I am not sure this is exactly what you were trying to do, but you defined import as array, which makes me assume so.
On the other hand, you can do:
company_happy:
imports:
import:
path: /tmp
another_import:
...
Regarding no extension able to load the configuration error: Make sure your extension file is following naming convetions.It should be called CompanyHappyExtension.php with CompanyHappyExtension class defined inside.
I have created a sample CompanyHappyBundle bundle which is working fine on Symofny 3 (probably works on S2 as well). Feel free to clone/download it :)
The services.yml file is an added bonus, as you will most likely need it anyway.
src/Company/Bundle/HappyBundle/CompanyHappyBundle.php:
<?php
namespace Company\Bundle\HappyBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class CompanyHappyBundle extends Bundle
{
}
src/Company/Bundle/HappyBundle/DependencyInjection/CompanyHappyExtension.php
<?php
namespace Company\Bundle\HappyBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
class CompanyHappyExtension extends Extension implements ExtensionInterface
{
public function load(array $configs, ContainerBuilder $container)
{
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
$configuration = new Configuration();
$options = $this->processConfiguration($configuration, $configs);
// Do something with your options here
}
}
src/Company/Bundle/HappyBundle/DependencyInjection/Configuration.php
<?
namespace Company\Bundle\HappyBundle\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('company_happy');
$rootNode
->children()
->arrayNode('imports')
->prototype('array')
->children()
->scalarNode('path')->defaultValue('/tmp')->end()
->scalarNode('method')->defaultValue('ALL')->end()
->booleanNode('move_mail')->defaultValue(true)->end()
->booleanNode('mark_read')->defaultValue(true)->end()
->end()
->end()
->end()
;
return $treeBuilder;
}
}
src/Company/Bundle/HappyBundle/Resources/config/config.yml
company_happy:
imports:
import:
path: /tmp
src/Company/Bundle/HappyBundle/Resources/config/services.yml
# Define your services here
services:
you're almost done, you just need to configure your Bundle to use your config parameters, take a look at this answer.
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: ~
In the process of building a third party bundle for the Symfony2 framework I have run into a problem with allowing configuration to happen in the app/config.yml file. I want to do this so users of the bundle (mostly myself) won't have to go into the bundle to make configuration changes.
My bundle Configuration.php file reads:
<?php
namespace Ms2474\AuthNetBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
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('authorize_net');
$rootNode
->children()
->scalarNode('login_id')->defaultNull()->end()
->scalarNode('transaction_key')->defaultNull()->end()
->booleanNode('sandbox')->defaultValue(true)->end()
->scalarNode('log_file')->defaultValue(false)->end()
->end();
return $treeBuilder;
}
}
The bundle extension file (Ms2474AuthNetBundleExtension.php) reads:
<?php
namespace Ms2474\AuthNetBundle\DependencyInjection;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Definition\Processor;
class Ms2474AuthNetBundleExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$processor = new Processor();
$configuration = new Configuration();
$config = $processor->process($configuration->getConfigTree(), $configs);
if (null === $config['sandbox']) {
$config['sandbox'] = $container->getParameter('kernel.debug');
}
$container->setParameter('authorize_net.login_id', $config['login_id']);
$container->setParameter('authorize_net.transaction_key', $config['transaction_key']);
$container->setParameter('authorize_net.sandbox', $config['sandbox']);
if (isset($config['log_file'])) {
$container->setParameter('authorize_net.log_file', $config['log_file']);
}
$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
}
}
Now for the problem:
When I try to add the following to the app/config.yml file:
authorize_net:
login_id: 1234
transaction_key: 1234
sandbox: true
log_file: false
I get the following two errors:
InvalidArgumentException: There is no extension able to load the configuration for "authorize_net" (in /path/to/app/config/config.yml). Looked for namespace "authorize_net", found "framework", "security", "twig", "monolog", "swiftmailer", "assetic", "doctrine", "sensio_framework_extra", "jms_security_extra", "jms_aop", "fos_user", "jms_serializer", "fos_rest", "stof_doctrine_extensions", "vich_uploader", "gri_user", "gri_campaign", "gri_authorized_contact", "web_profiler", "sensio_distribution"
and:
FileLoaderLoadException: Cannot import resource "/path/to/app/config/config.yml" from "/path/to/app/config/config_dev.yml".
And the question:
What am I doing wrong here? I have looked through the documentation and also compared my code to other bundles such as the FOSUserBundle.
First, it should be called Ms2474AuthNetExtension, not Ms2474AuthNetBundleExtension.
Second, unless you've set up a custom namespace for the extension and loaded it manually, the configuration options should be under ms2474_auth_net, not authorize_net.