How can I dynamically set a parameter in Symfony2?

2019-02-16 13:57发布

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?

3条回答
看我几分像从前
2楼-- · 2019-02-16 14:19

I think we can add parameters as simple class functions to a service.

This is my controller function.

   /**
     * @Route("/products/checkService")
     * @Template()
     */
    public function checkServiceAction() {            
        $paypal = $this->get('Paypal');
        return new Response($paypal->chkVal('dsdd'));
    }

This is my service

<?php

namespace Eagle\ShopBundle\Services;

use Symfony\Component\HttpFoundation\Response;

class Paypal {      
    public function __construct($var) {
        $this->paypalCongig = $var;
    }

    public function getVal() {
        return $this->paypalCongig;
   }

    public function chkVal($var) {
        return $var;
   }
}
查看更多
时光不老,我们不散
3楼-- · 2019-02-16 14:21

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.

查看更多
We Are One
4楼-- · 2019-02-16 14:30

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
}
查看更多
登录 后发表回答