Symfony - Get custom param in bundle controller - symfony

I'm running a website under Symfony 3.4.12 and I created my own custom bundle. I have a custom config file in Yaml :
# src/CompanyBundle//Resources/config/config.yml
company_bundle:
phone_number
... and it is launched this way :
<?php
# src/CompanyBundle/DependencyInjection/CompanyExtension.php
namespace CompanyBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
class CompanyExtension extends Extension
{
/**
* {#inheritDoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('config.yml');
}
}
?>
I would like to retrieve my custom parameters in my controller file, what is the best way to do it ? I tried this way, with no success :
$this->getParameter('company_bundle.phone_number')
Thanks.

You have to define your own DependencyInjection/Configuration.php: http://symfony.com/doc/3.4/bundles/configuration.html#processing-the-configs-array
Like that:
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('company_bundle');
$rootNode
->children()
->scalarNode('phone_number')
->end()
->end()
;
}
And then process it into your DependencyInjection/...Extension.php file. If you want to make this option as parameter you have to do it like that:
public function load(array $configs, ContainerBuilder $container)
{
// Some default code
$container->setParameter('company_bundle.phone_number', $config['phone_number']);
}
And then you can get this parameter in your controller like you do.

Related

get resolved parameters in a bundle extension class

I'm writing a Symfony bundle and I need to setup a service definition in my Extension class depending on the value of a configuration parameter.
An it works fine, as long as you don't try to use any expressions in the parameter value.
My extension class looks like this:
class MyBundleExtension extends Extension
{
/**
* {#inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
dd($config['custom_param']);
}
...
}
In my application, I set the parameter like this:
.env.local:
MY_BUNDLE_CUSTOM_PARAM=blah
config.yaml:
parameters:
my_bundle_custom_param: '%env(MY_BUNDLE_CUSTOM_PARAM)%'
my_bundle:
custom_param: '%my_bundle_custom_param%'
The problem is, that in the Extension class, this parameter is not yet resolved, so dd() shows this:
"env_de85db6c4d65707d_MY_BUNDLE_CUSTOM_PARAM_71f5c271abfed252c958c82c1e3fb8dc"
instead of the expected blah.
Is there any way to get the resolved value of the parameter in the Extension class?
You gave the correct answer in your comment:
/**
* #throws \Exception
*/
public function load(array $configs, ContainerBuilder $container): void
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$resolve = $container->resolveEnvPlaceholders($config, true);
$config['upload_path'] = \str_replace($_SERVER['DOCUMENT_ROOT'], '', $resolve['upload_directory']);
$container->setParameter("mybundle", $config);

How can I access config parameters defined in a custom extension?

I created a custom extension in my app for the sole purpose of being able to define config in yaml. I am unable to retrieve configuration params with ParameterBagInterface. What am I missing with the following approach?
config/packages/myapp.yaml
myapp:
foo:
bar: '%env(MYAPP_BAR)%'
I created a command to test if I could retrieve the config. When run, I get the error:
The parameter "myapp" must be defined.
class FooCommand extends Command
{
...
public function __construct(ParameterBagInterface $params, $name = '')
{
$this->params = $params;
parent::__construct();
}
...
protected function execute(InputInterface $input, OutputInterface $output): int
{
dd($this->params->get('myapp'));
...
I set all this up by creating the following files and modifying Kernel.php
src/DependencyInjection/Configuration.php
src/DependencyInjection/MyappExtension.php
Note that in the extension file below, the dd($config) prints everything defined in myapp.yaml.
src/DependencyInjection/MyappExtension.php
class MyappExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
// This dumps my config as an array
// dd($config);
}
}
src/DependencyInjection/Configuration.php
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('myapp');
$treeBuilder->getRootNode()
->children()
->arrayNode('foo')
->children()
->scalarNode('bar')->end()
->end()
->end()
->end();
return $treeBuilder;
}
src/Kernel.php (1 line modification)
...
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void
{
$container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php'));
$container->registerExtension(new MyappExtension());
...

symfony 4 configuration default value ( no file )

I'm trying to create a default configuration for my bundle. I created the bundle, bundle extension and configuration class. Inside the configuration class, I define a couple of keys with a default value. No yaml files are created. When I try to dump the configuration, I got the error:
"The extension with alias "foxtrot_alpha_users" does not have configuration."
But if I create the matching yaml file, and define at least one of the keys, the other key takes the default value as stated in the configuration class the value can be overridden.
Is it possible to define a default configuration with no yaml file at all?
Bundle class:
class UsersBundle extends Bundle
{
/**
* this is to have a custom alias
*
* #return void
*/
public function getContainerExtension()
{
return( new UsersExtension() );
}
}
Extension class:
class UsersExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
foreach($config as $key => $value)
{
$parameterKey = $this->getAlias().'.'.$key;
$container->setParameter($parameterKey, $value);
}
$container->setParameter('default_password', $config['default_password']);
}
/**
* customized alias
*
* #return string
*/
public function getAlias()
{
return('foxtrot_alpha_users');
}
Configuration class:
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('foxtrot_alpha_users');
$rootNode = $treeBuilder->getRootNode();
$this->addUserParameters( $rootNode );
return $treeBuilder;
}
private function addUserParameters( ArrayNodeDefinition $rootNode )
{
$rootNode
->addDefaultsIfNotSet()
->children()
->scalarNode('default_password')
->defaultValue('248')
->end()
->scalarNode('x')
->defaultValue('1')
->end()
->end()
;
return( $rootNode );
}

How to load, process and use custom parameters from Yaml configuration files in DI Extension class?

I'm trying to import a yaml configuration file in my App following the documentation provided here http://symfony.com/doc/current/bundles/extension.html but I always have the error message:
There is no extension able to load the configuration for "app"
My file is located here : config/packages/app.yaml and has the following structure :
app:
list:
model1:
prop1: value1
prop2: value2
model2:
...
As this is a simple App, all the files are in src/. So I have src/DependencyInjection/AppExtension.php
<?php
namespace App\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
class AppExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
}
}
And src/DependencyInjection/Configuration.php
<?php
namespace App\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('app');
// Node definition
$rootNode
->children()
->arrayNode('list')
->useAttributeAsKey('name')
->requiresAtLeastOneElement()
->prototype('array')
->children()
->requiresAtLeastOneElement()
->prototype('scalar')
->end()
->end()
->end()
->end()
->end();
return $treeBuilder;
}
}
I'm not able to access my parameters :(
Any idea?
If you want to load a custom configuration file to process it's parameters using an Extension class (like in Symfony bundle extension but without to create a bundle), to eventually "create" and add one or more of it to the "container" (before it will be compiled) you can register your Extension class manually in the configureContainer method contained in the Kernel.php file:
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
{
// to avoid the same error you need to put this line at the top
// if your file is stored under "$this->getProjectDir().'/config'" directory
$container->registerExtension(new YourAppExtensionClass());
// ----- rest of the code
}
Then you can use your params as usual registering a Compiler Pass.
Hope this helps.

Symfony prependExtensionConfig with data from a service

I try to prepend a config array to a different bundle using the prependExtensionConfig from my bundle. All works fine until $config is hardcoded.
My goal is to load the $config values using a service (from the db for example) and than prepend it to the other bundle.
The problem is that the services are not loaded at that moment.
I guess this is a limitation is symfony2.
Any ideas? thx
class MyExtension extends Extension implements PrependExtensionInterface
{
/**
* {#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');
}
public function prepend(ContainerBuilder $container)
{
$config = // load config from a service ...
$container->prependExtensionConfig('other_bundle', $config);
}
}
First of all you need to set up your config to take values from parameters section of Service container:
Setup config.yml:
# app/config/config.yml
namespace:
subnamespace:
param1: %param1%
param2: %param2%
Then you need to fill %param1% and %param2% parameters in container with values from database. To do that you need to declare your CompilerPass and add it to the container. After whole container will be loaded (in the compile time) you will have access to all services in it.
Just get the entity manager service and query for needed parameters and register them in container.
Define Compiler pass:
# src/Acme/YourBundle/DependencyInjection/Compiler/ParametersCompilerPass.php
class ParametersCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$em = $container->get('doctrine.orm.default_entity_manager');
$param1 = $em->getRepository('Acme:Params')->find(1);
$param2 = $em->getRepository('Acme:Params')->find(2);
$container->setParameter('param1', $param1);
$container->setParameter('param2', $param2);
}
}
In the bundle definition class you need to add compiler pass to your container
# src/Acme/YourBundle/AcmeYourBundle.php
class AcmeYourBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new ParametersCompilerPass(), PassConfig::TYPE_AFTER_REMOVING);
}
}
PassConfig::TYPE_AFTER_REMOVING means that this CompilerPass will be processed almost after all other compiler passes and in this moment you will already have every service injected.

Resources