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);
Related
I just created a symfony DI extension , where I'm trying to append some form theme configuration to my app/config.yml.
1) My Extension class:
class ELFinderFieldTypeExtension 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('form_themes.yml');
}
...
2) My form_themes.yml
twig:
form_themes:
- 'ELFinderFieldTypeBundle:elfinder:elfinder_widget.html.twig'
Unfortunately, It's not the right way to load a twig config, that's way I'm getting kind of:
There is no extension able to load the configuration for "twig" (in
/var/www/html/..../DependencyInjection/../Resources/config/form_themes.yml).
Looked for namespace "twig", found none
Anyone have any idea would be voted and appreciated.
I found an easy solution, ally I need is to append my config after implementing PrependExtensionInterface Interface:
public function prepend(ContainerBuilder $container)
{
$configFile = \sprintf('%s%s', __DIR__, '/../Resources/config/form_themes.yml');
$this->prependYamlConfigFile($container, 'twig', $configFile);
}
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.
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.
I'm currently trying to find a solid solution to change the dependencies of a Symfony2 service dynamically. In detail: I have a Services which uses a HTTP-Driver to communicate with an external API.
class myAwesomeService
{
private $httpDriver;
public function __construct(
HTTDriverInterface $httpDriver
) {
$this->httpDriver = $httpDriver;
}
public function transmitData($data)
{
$this->httpDriver->dispatch($data);
}
}
While running the Behat tests on the CI, I'd like to use a httpMockDriver instead of the real driver because the external API might be down, slow or even broken and I don't want to break the build.
At the moment I'm doing something like this:
<?php
namespace MyAwesome\TestBundle\DependencyInjection;
class MyAwesomeTestExtension 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'));
$environment = //get environment
if ($environment == 'test') {
$loader->load('services_mock.yml');
} else {
$loader->load('services.yml');
}
}
}
This works for now, but will break for sure. So, is there a more elegant/solid way to change the HTTPDriver dynamically?
I finally found a solution that looks solid to me. As of Symfony 2.4 you can use the expression syntax: Using the Expression Language
So I configured my service this way.
service.yml
parameters:
httpDriver.class: HTTP\Driver\Driver
httpMockDriver.class: HTTP\Driver\MockDriver
myAwesomeService.class: My\Awesome\Service
service:
myAwesomeService:
class: "%myAwesomeService.class%"
arguments:
- "#=service('service_container').get('kernel.environment') == 'test'? service('httpMockDriver) : service('httpDriver)"
This works for me.
I have successfully installed the sncRedisBundle and used the predis element of it within a controller, using:
$this->container->get('snc_redis.default');
I want to do the same within an extension:
class MyExtension extends Extension
{
/**
* {#inheritDoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$redis = $container->get('snc_redis.default');
}
}
But I get:
The service definition "snc_redis.default" does not exist.
Is this a scoping issue? How do I access redis from within an Extension?
Thanks!
services:
site:
class: Emlaktown\AppBundle\Site\Site
arguments: [%api_url%, "#request_stack", "#service_container"]
....
use Symfony\Component\DependencyInjection\Container;
....
public function __construct($apiUrl, RequestStack $requestStack, Container $container)
{
$this->client = new Client($apiUrl);
$this->redis = $container->get('snc_redis.cache');
$request = $requestStack->getCurrentRequest();
$this->client->setDefaultOption('Accept-Language', $request->getLocale());
}