Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force configuration reload in Symfony2

Tags:

symfony

I have a script which makes changes to the Symfony2 configuration and needs to be made aware of the new configuration before proceeding (specifically adding dbal connections). Is there a way to force the reload of the configuration during script execution?

like image 575
Eirik A. Johansen Avatar asked Apr 04 '13 14:04

Eirik A. Johansen


3 Answers

Update: You can't reload the configuration, but you can set the parameters on-the-fly, see second "Update" paragraph

It's not really possible in Symfony2 to do that.

In production mode, everything (even the configuration) is cached, so you have to clear the cache with

app/console cache:clear --env=prod --no-debug

(maybe followed by a app/console cache:warmup --env=prod --no-debug)

to reload the configuration. In development mode you could experiment with shutdown() followed by a boot() from Symfony\Component\HttpKernel\Kernel or maybe loadClassCache - but all of this is not really that what you want.

What exactly changes are made to the configuration files? Maybe you should use different files for different environments or consider any other method to get those changes (via a simple Webservice or even a static file read from within a Controller).

Update:

I figured out that you can set your container configuration parameter on-the-fly via

$container->setParameter('parameter', value);

Have a look at the Symfony2 documentation.

like image 77
akluth Avatar answered Oct 14 '22 02:10

akluth


My answer probably arrives very late but could be useful to someone else.

Symfony cache for "prod" environment is stored in "app/cache/prod/" folder and contains many things (Twig templates translated in PHP in "twig/" subfolder, annotations in "annotations/" subfolder, and... configuration parameters, app*ProjectContainer.php files, among many other things).

So what you can do is: when your configuration script changes parameters.yml, it can also delete appProdProjectContainer.php. The next user to hit your Symfony app will face a little longer response time, but the new configuration parameter will be taken into account and cached.

like image 43
David Guillot Avatar answered Oct 14 '22 03:10

David Guillot


Here is the partial solution, besides I used it in Symfony 3.2, but nevertheless this code is used to reload bundle configuration on the fly.

Firstly, you should inject container instance inside the service / controller where you want to use bundle instance which was reinitialized with other config:

/**
 * Service constructor.
 *
 * @param ContainerInterface $container
 */
public function __construct(ContainerInterface $container)
{
    $container = ReinitializedBundleExtension::updateContainerWithProdConfiguration($container);
}

Secondly, you should add a method to ReinitializedBundleExtension class which will update the container with reinitialized bundle instance and dependencies:

/**
 * Updates container with bundle services resolved with production configuration.
 *
 * @param ContainerInterface $oldContainer
 *
 * @return ContainerInterface $container
 */
public static function updateContainerWithProdConfiguration(ContainerInterface $oldContainer)
{
    $containerBuilder = new ContainerBuilder();

    // Copy external services used in the bundle.
    $logger = $oldContainer->get('logger');
    $containerBuilder->set('logger', $logger);

    // Load the production config files.
    $bundleResourcesPath = $oldContainer->get('kernel')->locateResource('@ReinitializedBundle/Resources/');
    $fileLocator = new FileLocator($bundleResourcesPath . '/config');
    $loader = new Loader\YamlFileLoader($containerBuilder, $fileLocator);
    $loader->setResolver(new LoaderResolver([$loader]));
    $loader->load($bundleResourcesPath . 'config/production/services.yml');

    // Resolving bundle services with prduction config.
    $containerBuilder->compile();
    $containerBuilder->resolveServices($containerBuilder->getDefinitions());

    // Merge resolved prod-configured services with old container.
    $serviceIds = $containerBuilder->getServiceIds();

    foreach ($serviceIds as $serviceId) {
        // Services which are not related to the bundle.
        if (strpos($serviceId, 'reinitialized_bundle_config_prefix') === false) {
            continue;
        }

        $oldContainer->set($serviceId, $containerBuilder->get($serviceId));
    }

    return $oldContainer;
}

PS: 1. All the ReinitializedBundle params and services are marked with 'reinitialized_bundle_config_prefix' prefix, so it's easy to recognize them in container, i.e:

reinitialized_bundle_config_prefix.service1 reinitialized_bundle_config_prefix.param1

  1. This is a solution for Yaml configs, so YamlFileLoader was used.
  2. ReinitializedBundle config filestructure:

.ReinitializedBundle └── Resources └── config ├── production | ├─── services.yml | └─── other stuff └── staging ├─── services.yml └─── other stuff

like image 1
Ivan Ovcharenko Avatar answered Oct 14 '22 01:10

Ivan Ovcharenko