Symfony2中基于区域设置的参数值

I have a Symfony2 app, with multiple locale and every domain has his own domain name (means the locale is not prefixed or appended after the domain) like "shoes.com" and "schue.de".

To perform this, I'm using the jms_i18n_routing bundle, which takes care of setting the right locale.

My problems comes when I want to integrate for example, Facebook login with hwi_ouath bundle, where I have to set the "app id" and "app secret" in my config.yml, but the apps are also locale specific (as from now on in Facebook you can create only 1 redirect URL) so I should change the parameter values somewhere, but at container compilation time, I don't have access to the Request object, to check for the locale and later I can't change the parameter values.

Any idea how to solve this problem?

You can do that with factory service.

<service id="facebook.factory" class="Acme\Facebook\Factory">
    <argument type="service" id="request_stack"/>
    <argument>%facebook_credentials%</argument>
</service>
<service id="facebook" class="Facebook"
         factory-service="facebook.factory" factory-method="create"/>

<!-- use "facebook" where you need it -->

And create factory, something like this:

namespace Acme\Facebook;

class Factory
{
    //...

    public function __construct($requestStack, $credentials)
    {
        $this->requestStack = $requestStack;
        $this->credentials = $credentials;
    }

    public function create()
    {
        $r = $requestStack->getCurrentRequest();
        // throw if $r is null
        $c = $this->credentials[$r->getHost()];
        return new Facebook($c);
    }
}

Just keep in mind that facebook service will be created just once. Assuming hostname/locale does not change in single request, this should be ok. If it can change, inject factory itself and call create when you need it. Of course, in this case you could save already created Facebook objects for each locale and reuse them.

Unfortunatelly, you will have to redefine the services, as the bundle configures service with single set of parameters, which is not acceptable in your situation. So, bundle integration will probably not work out of the box, but you can still use all the classes it provides.

At the end I used this solution, maybe someone needs something like this:

In the AppKernel I made a server variable with the current http host:

class AppKernel extends Kernel
{
   /**
    * @inheritdoc
    */
   public function __construct($environment, $debug)
   {
       parent::__construct($environment, $debug);
       if ($hostEnv = $this->getHostEnv()) {
           $_SERVER['SYMFONY__HOST'] = $hostEnv;
       }
   }
  ...
   private function getHostEnv()
   {
       if (!empty($_SERVER['HTTP_HOST'])) {
           return $_SERVER['HTTP_HOST'];
       }

       return null;
   }
   public function registerContainerConfiguration(LoaderInterface $loader)
   {
       $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
       $loader->load(__DIR__.'/config/parameters.php');
   }
}

With the SYMFONY__% server variable you can create automatically parameters.

Then parameter.php:

<?php

require_once('PlasticConfig.php');

if (!empty($container)) {
    $plasticConfig = new PlasticConfig($container);
    $container = $plasticConfig->load();
}

Then PlasticConfig.php:

<?php

use \Symfony\Component\DependencyInjection\ContainerInterface;

class PlasticConfig {

    /**
     * @var Symfony\Component\DependencyInjection\ContainerInterface
     */
    protected $container;

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

    public function load()
    {
        /** 
         * this was defined in the constructor of AppKernel 
         * at console command there is no HTTP_HOST variable
         */
        if (!$this->container->hasParameter('host')) {
            return $this->container;
        }

        $host = $this->container->getParameter('host');
        //Magic can be done here, important is, that you return your container instance here

        return $this->container;
    }
} 

In my parameters.yml I have some parameters, with the names host_de, host_en ... and I will iterate through all the parameters and if I find a match with the current host then I have the locale from the parameter name. After that I just need to set the facebook parameters also from the parameters.yml, where I have parameters like: facebook.de.app_id: XY and facebook.en.app_id: ZS.

config.yml

imports:
    - { resource: parameters.php } #add this import

hwi_ouath bundle:
    # put this in the right place
    app_id: %facebook.app_id%
    app_secret: %facebook.secret%

parameters.php

<?php

$lang = 'en';

if ('schue.de' === $_SERVER['HTTP_HOST']) {
    $lang = 'de';
} // elseif (...

$container->setParameter('facebook.app_id', $container->getParameter('facebook.'.$lang.'.app_id'));
$container->setParameter('facebook.secret', $container->getParameter('facebook.'.$lang.'.secret'));