Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I dynamically set a parameter in Symfony2?

I'm trying to dynamically set a parameter in Symfony2 (that I cannot statically set in my parameters.yml file). My approach is to use an EventListener:

namespace Acme\AcmeBundle\EventListener;

use Symfony\Component\DependencyInjection\Container;

class AcmeListener
{
    private $container;

    public function __construct(Container $container)
    {
        $this->container = $container;
    }

    public function onKernelRequest()
    {
        // Dynamically fetch $bar
        $bar = fetch('foobar');

        // Set parameter
        $this->container->setParameter('foo', $bar);
    }
}

And my service definition in config.yml looks like this:

service:
    kernel.listener.acme_listener:
        class: Acme\AcmeBundle\EventListener\AcmeListener
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
        arguments: [ '@service_container' ]

The problem is, I get an exception:

LogicException: Impossible to call set() on a frozen ParameterBag.

How can I work around this exception or do you see another way to dynamically set a parameter?

like image 585
Gottlieb Notschnabel Avatar asked Apr 18 '14 15:04

Gottlieb Notschnabel


2 Answers

The container parameters rule is that:

You can only set a parameter before the container is compiled

How to remedy the problem depends on your needs with the premise that the container is not thought to have dynamic parameters.

  1. create you custom dynamic "options" service and inject it in other services, in this way you can also manage your parameters in database (like wordpress wp_options), but i don't know a bundle that do this. For existing services (ex. mailer) you can use configurators.

  2. invalidate the cache when parameters changes here an easy method so when you reload the page the container is rebuilt. If the parameters change frequently risks to reload the cache frequently and this becomes a problem if you have large loads.

if you choose the second option you need to set the parameters before it is filled in the container, so you can:

  • export in a custom yaml file loaded in app/config/config.yml when parameters changes before you clear the cache, in this way you can get the data from other services
  • load parameters in a bundle extension here the cookbook, in this way you can't access to other services to get the data, the extension can access only to the containerbuilder

I suggest, however, option 1 (options service and configurators) because (I repeat) the container is not thought to have dynamic parameters but it offers the ability to have custom dynamic service configurators that use data from any source.

like image 120
Marino Di Clemente Avatar answered Nov 14 '22 08:11

Marino Di Clemente


I had the problem on a list of URLs starting by %base_url% when I wanted to do a failover system.

I finally replaced %base_url% by #base_url# and did a manual placeholders resolution in a service.

$tries = array (
        $this->container->getParameter('base_url'),
        $this->container->getParameter('base_url_failover'),
);

foreach ($tries as $try)
{
    $url = str_replace('#base_url#', $try, $unresolvedUrl);

    // whatever
}
like image 1
Alain Tiemblo Avatar answered Nov 14 '22 09:11

Alain Tiemblo