¿Cómo leo los ajustes de configuración de Symfony2 config.yml?

191

He agregado una configuración a mi archivo config.yml como tal:

app.config:
    contact_email: somebody@gmail.com
    ...

Por mi vida, no puedo entender cómo leerlo en una variable. Intenté algo como esto en uno de mis controladores:

$recipient =
$this->container->getParameter('contact_email');

Pero recibo un error que dice:

Se debe definir el parámetro "contact_email".

He borrado mi caché, también busqué en todas partes en la documentación del sitio recargado de Symfony2, pero no puedo encontrar cómo hacerlo.

Probablemente demasiado cansado para resolver esto ahora. ¿Alguien puede ayudarme con esto?

josef.van.niekerk
fuente

Respuestas:

194

En lugar de definir contact_emaildentro app.config, defínalo en una parametersentrada:

parameters:
    contact_email: somebody@gmail.com

Debería encontrar que la llamada que está haciendo dentro de su controlador ahora funciona.

Douglas Greenshields
fuente
44
¿Cómo funcionaría esto con los entornos de desarrollo / producción? Entonces, para las pruebas, quiero que los correos electrónicos se envíen a un correo electrónico de prueba y la producción recibiría otro correo electrónico
Phill Pafford,
2
@Phill: si está utilizando el swiftmailer estándar en su symfony2, puede usar la siguiente configuración en su config_dev.yml: swiftmailer: delivery_address: [email protected] puede encontrar más información en el libro de cocina de Symfony2
Pierre
44
¿Debo inyectar clase de contenedor en todas partes (controlador, entidad, clase) cuando uso esta instrucción $ this-> container-> getParameter ('contact_email'); ? ¿O hay una manera más sencilla de hacerlo sin inyectar la clase contenedor?
webblover
1
Según esta solución, ¿cómo puedo acceder a las propiedades anidadas?
Ousmane
1
@webblover Simplemente inserte el parámetro usando la %parameter_name%notación - (en YAML)
MauganRa
173

Si bien la solución de mover el contact_emailto parameters.ymles fácil, como se propone en otras respuestas, eso puede saturar fácilmente su archivo de parámetros si maneja muchos paquetes o si maneja bloques de configuración anidados.

  • Primero, responderé estrictamente la pregunta.
  • Más adelante, daré un enfoque para obtener esas configuraciones de los servicios sin pasar nunca por un espacio común como parámetros.

PRIMER ENFOQUE: Bloque de configuración separado, obteniéndolo como parámetro

Con una extensión ( más sobre extensiones aquí ) puede mantener esto fácilmente "separado" en diferentes bloques en el config.ymly luego inyectarlo como un parámetro que se puede obtener del controlador.

Dentro de su clase de Extensión dentro del DependencyInjectiondirectorio escriba esto:

class MyNiceProjectExtension extends Extension
{
    public function load( array $configs, ContainerBuilder $container )
    {
        // The next 2 lines are pretty common to all Extension templates.
        $configuration = new Configuration();
        $processedConfig = $this->processConfiguration( $configuration, $configs );

        // This is the KEY TO YOUR ANSWER
        $container->setParameter( 'my_nice_project.contact_email', $processedConfig[ 'contact_email' ] );

        // Other stuff like loading services.yml
    }

Luego, en su config.yml, config_dev.yml y así puede configurar

my_nice_project:
    contact_email: someone@example.com

Para poder procesar eso config.ymldentro de tu MyNiceBundleExtensiontambién necesitarás una Configurationclase en el mismo espacio de nombres:

class Configuration implements ConfigurationInterface
{
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder();
        $rootNode = $treeBuilder->root( 'my_nice_project' );

        $rootNode->children()->scalarNode( 'contact_email' )->end();

        return $treeBuilder;
    }
}

Luego puede obtener la configuración de su controlador, como lo deseaba en su pregunta original, pero manteniendo la parameters.ymllimpieza y configurándola config.ymlen secciones separadas:

$recipient = $this->container->getParameter( 'my_nice_project.contact_email' );

SEGUNDO ENFOQUE: Bloque de configuración separado, inyectando la configuración en un servicio

Para los lectores que buscan algo similar, pero para obtener la configuración de un servicio, existe una forma aún mejor que nunca abarrota el espacio común de "parámetros" e incluso no necesita containerque se pase al servicio (pasar el contenedor completo es práctica para evitar).

Este truco anterior todavía "se inyecta" en el espacio de parámetros de su configuración.

Sin embargo, después de cargar su definición del servicio, puede agregar una llamada a un método como, por ejemplo, setConfig()que inyecta ese bloque solo al servicio.

Por ejemplo, en la clase de extensión:

class MyNiceProjectExtension extends Extension
{
    public function load( array $configs, ContainerBuilder $container )
    {
        $configuration = new Configuration();
        $processedConfig = $this->processConfiguration( $configuration, $configs );

        // Do not add a paramater now, just continue reading the services.
        $loader = new YamlFileLoader( $container, new FileLocator( __DIR__ . '/../Resources/config' ) );
        $loader->load( 'services.yml' );

        // Once the services definition are read, get your service and add a method call to setConfig()
        $sillyServiceDefintion = $container->getDefinition( 'my.niceproject.sillymanager' );
        $sillyServiceDefintion->addMethodCall( 'setConfig', array( $processedConfig[ 'contact_email' ] ) );
    }
}

Luego, en su services.yml, defina su servicio como de costumbre, sin ningún cambio absoluto:

services:
    my.niceproject.sillymanager:
        class: My\NiceProjectBundle\Model\SillyManager
        arguments: []

Y luego en tu SillyManagerclase, solo agrega el método:

class SillyManager
{
    private $contact_email;

    public function setConfig( $newConfigContactEmail )
    {
        $this->contact_email = $newConfigContactEmail;
    }
}

Tenga en cuenta que esto también funciona para matrices en lugar de valores escalares. Imagine que configura una cola de conejo y necesita host, usuario y contraseña:

my_nice_project:
    amqp:
        host: 192.168.33.55
        user: guest
        password: guest

Por supuesto, debe cambiar su árbol, pero luego puede hacer:

$sillyServiceDefintion->addMethodCall( 'setConfig', array( $processedConfig[ 'amqp' ] ) );

y luego en el servicio hacer:

class SillyManager
{
    private $host;
    private $user;
    private $password;

    public function setConfig( $config )
    {
        $this->host = $config[ 'host' ];
        $this->user = $config[ 'user' ];
        $this->password = $config[ 'password' ];
    }
}

¡Espero que esto ayude!

Xavi Montero
fuente
Si se pregunta qué es diferente entre el primer enfoque y la documentación, es que los valores de configuración se convierten en parámetros en el MyNiceProjectExtension->load()método con esta línea: $container->setParameter( 'my_nice_project.contact_email', $processedConfig[ 'contact_email' ]);. Gracias Xavi!
jxmallett
Respuesta perfecta, vergüenza, Symfony no te permite acceder a la configuración de la misma manera que a los parámetros.
Martin Lyne
Esta es una buena respuesta, pero expone la forma obtusa de Symfony de "configurar" una aplicación. ¿Cuál es el punto de tener archivos de configuración de entorno arbitrario cuando tiene que escribir e invocar servicios específicos para acceder a ellos? ¿Alguien en Symfony no se sentó allí y se dio cuenta de que 'Tal vez los desarrolladores realmente deseen proporcionar valores específicos del entorno en sus aplicaciones a los que puedan acceder'? Están siguiendo el patrón de diseño "STKTFANREO": "Ajuste las perillas en F'd y
quítelas
Tiene varias aplicaciones, especialmente en la implementación de pruebas automáticas paralelas, y especialmente cuando un equipo desarrolla un paquete que es principalmente modelo o lógica que es consumido por varios otros equipos en diferentes aplicaciones, por ejemplo, una aplicación que es un usuario front-end, otro que es un frente web de panel de administración y otro que es una API REST. Cada una de ellas es una aplicación diferente dispuesta a configurarse de manera diferente. Eso se multiplica por varios entornos (producción, preproducción, pruebas, desarrollo, etc.). Esto cede fácilmente en 12 o 15 configuraciones en una sola compañía.
Xavi Montero
@XaviMontero Seguí tus instrucciones SEGUNDO ENFOQUE: y cuando var_dump el $ this-> contact_email o agrego una salida () en la función setConfig () no sale. Parece que no se llama a
setConfig
35

Tengo que agregar a la respuesta de douglas, puede acceder a la configuración global, pero Symfony traduce algunos parámetros, por ejemplo:

# config.yml
... 
framework:
    session:
        domain: 'localhost'
...

son

$this->container->parameters['session.storage.options']['domain'];

Puede usar var_dump para buscar una clave o valor especificado.

Felipe Buccioni
fuente
17

Para poder exponer algunos parámetros de configuración para su paquete, debe consultar la documentación para hacerlo. Es bastante fácil de hacer :)

Aquí está el enlace: Cómo exponer una configuración semántica para un paquete

Nikola Petkanski
fuente
Honestamente, esta pregunta se hizo hace más de 2 años, en aquel entonces, el artículo anterior no existía.
josef.van.niekerk
10
Estoy de acuerdo con esa afirmación. He establecido la respuesta en caso de que alguien abra este artículo hoy en día. Gracias por la calificación negativa, me alegraste el día.
Nikola Petkanski
Mis disculpas, ahora que lo pienso, mi voto negativo no fue requerido. Aprecio tu contribución, traté de votar pero SO ya no lo permite. El enlace es de gran ayuda, ¡y estoy seguro de que otras personas se beneficiarán de él! ¿Quizás el administrador puede ayudarme a cambiar mi voto negativo?
josef.van.niekerk
Creo que puedes hacer clic nuevamente para deshacer.
Nikola Petkanski
No puede deshacer su voto más de X (5?) Minutos después de haberlo hecho o hasta que se
edite
3

Aprendí una manera fácil del ejemplo de código de http://tutorial.symblog.co.uk/

1) observe el ZendeskBlueFormBundle y la ubicación del archivo

# myproject/app/config/config.yml

imports:
    - { resource: parameters.yml }
    - { resource: security.yml }
    - { resource: @ZendeskBlueFormBundle/Resources/config/config.yml }

framework:

2) observe Zendesk_BlueForm.emails.contact_email y la ubicación del archivo

# myproject/src/Zendesk/BlueFormBundle/Resources/config/config.yml

parameters:
    # Zendesk contact email address
    Zendesk_BlueForm.emails.contact_email: dunnleaddress@gmail.com

3) observe cómo lo obtengo en $ client y la ubicación del archivo del controlador

# myproject/src/Zendesk/BlueFormBundle/Controller/PageController.php

    public function blueFormAction($name, $arg1, $arg2, $arg3, Request $request)
    {
    $client = new ZendeskAPI($this->container->getParameter("Zendesk_BlueForm.emails.contact_email"));
    ...
    }
Estiércol
fuente