Comment lire les paramètres de configuration depuis Symfony2 config.yml?

191

J'ai ajouté un paramètre à mon fichier config.yml en tant que tel:

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

Pour la vie de moi, je ne peux pas comprendre comment le lire dans une variable. J'ai essayé quelque chose comme ça dans l'un de mes contrôleurs:

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

Mais j'obtiens une erreur disant:

Le paramètre "contact_email" doit être défini.

J'ai vidé mon cache, j'ai également regardé partout dans la documentation du site rechargé Symfony2, mais je ne peux pas trouver comment faire cela.

Probablement trop fatigué pour comprendre cela maintenant. Quelqu'un peut-il aider avec ça?

josef.van.niekerk
la source

Réponses:

194

Plutôt que de définir à l' contact_emailintérieur app.config, définissez-le dans une parametersentrée:

parameters:
    contact_email: somebody@gmail.com

Vous devriez trouver que l'appel que vous effectuez dans votre contrôleur fonctionne maintenant.

Douglas Greenshields
la source
4
Comment cela fonctionnerait-il avec les environnements Dev / Prod? Donc, pour le test, je veux que les e-mails soient envoyés à un e-mail de test et que la production reçoive un autre e
Phill Pafford
2
@Phill: Si vous utilisez le swiftmailer standard dans votre symfony2, vous pouvez utiliser le paramètre suivant dans votre config_dev.yml: swiftmailer: delivery_address: [email protected] Vous pouvez trouver plus d'informations dans le livre de recettes Symfony2
Pierre
4
Dois-je injecter une classe de conteneur partout (contrôleur, entité, classe) lorsque j'utilise cette instruction $ this-> container-> getParameter ('contact_email'); ? ou existe-t-il un moyen plus simple de le faire sans injecter de classe conteneur?
webblover
1
Selon cette solution, comment puis-je accéder aux propriétés imbriquées?
Ousmane
1
@webblover Insérez simplement le paramètre lui-même en utilisant la %parameter_name%notation - (en YAML)
MauganRa
173

Alors que la solution de déplacer le contact_emailvers parameters.ymlest simple, comme proposé dans d'autres réponses, cela peut facilement encombrer votre fichier de paramètres si vous traitez avec de nombreux bundles ou si vous traitez des blocs de configuration imbriqués.

  • Tout d'abord, je vais répondre strictement à la question.
  • Plus tard, je donnerai une approche pour obtenir ces configurations à partir de services sans jamais passer par un espace commun en tant que paramètres.

PREMIÈRE APPROCHE: bloc de configuration séparé, l'obtenir comme paramètre

Avec une extension ( plus d'informations sur les extensions ici ), vous pouvez garder cela facilement "séparé" en différents blocs dans le config.yml, puis l'injecter en tant que paramètre récupérable par le contrôleur.

Dans votre classe Extension dans le DependencyInjectionrépertoire, écrivez ceci:

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
    }

Puis dans votre config.yml, config_dev.yml et ainsi vous pouvez définir

my_nice_project:
    contact_email: someone@example.com

Pour pouvoir traiter cela config.ymldans votre, MyNiceBundleExtensionvous aurez également besoin d'une Configurationclasse dans le même espace de noms:

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

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

        return $treeBuilder;
    }
}

Ensuite, vous pouvez obtenir la configuration de votre contrôleur, comme vous le souhaitez dans votre question d'origine, mais en gardant la parameters.ymlnetteté et en la définissant dans les config.ymlsections séparées:

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

DEUXIÈME APPROCHE: bloc de configuration séparé, injectant la configuration dans un service

Pour les lecteurs à la recherche de quelque chose de similaire mais pour obtenir la configuration d'un service, il existe même un moyen plus agréable qui n'encombre jamais l'espace commun des "paramètres" et n'a même pas besoin de container d'être transmis au service (passer le conteneur entier est pratique pour éviter).

Cette astuce ci-dessus "injecte" encore dans l'espace des paramètres votre config.

Néanmoins, après avoir chargé votre définition du service, vous pouvez ajouter un appel de méthode comme par exemple setConfig() qui injecte ce bloc uniquement dans le service.

Par exemple, dans la classe Extension:

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' ] ) );
    }
}

Ensuite, dans votre services.ymlvous définissez votre service comme d'habitude, sans aucun changement absolu:

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

Et puis dans votre SillyManagerclasse, ajoutez simplement la méthode:

class SillyManager
{
    private $contact_email;

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

Notez que cela fonctionne également pour les tableaux au lieu des valeurs scalaires! Imaginez que vous configurez une file d'attente de lapin et que vous avez besoin d'un hôte, d'un utilisateur et d'un mot de passe:

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

Bien sûr, vous devez changer votre arbre, mais vous pouvez ensuite faire:

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

puis dans le service faire:

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

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

J'espère que cela t'aides!

Xavi Montero
la source
Si vous vous demandez ce qui est différent entre la première approche et la documentation, il est que les valeurs de configuration sont converties en paramètres dans la MyNiceProjectExtension->load()méthode avec cette ligne: $container->setParameter( 'my_nice_project.contact_email', $processedConfig[ 'contact_email' ]);. Merci Xavi!
jxmallett
Réponse parfaite, dommage que symfony ne vous laisse pas accéder à la configuration de la même manière qu'il le fait aux paramètres.
Martin Lyne
C'est une bonne réponse, mais elle expose la manière obtuse de Symfony de "configurer" une application. Quel est l'intérêt d'avoir des fichiers de configuration d'environnement arbitraires lorsque vous devez écrire et appeler des services spécifiques pour y accéder. Quelqu'un chez Symfony n'est-il pas resté assis là et s'est rendu compte: «Peut-être que les développeurs voudraient réellement fournir des valeurs spécifiques à l'environnement dans leurs applications auxquelles ils peuvent accéder. Ils suivent le modèle de conception "STKTFANREO": "Réglez les boutons sur F'd et arrachez-les"
eggmatters
Il a plusieurs applications, notamment dans le déploiement de tests automatiques parallélisés, et spécialement lorsqu'une équipe développe un bundle qui est principalement modèle ou logique qui est consommé par plusieurs autres équipes dans différentes applications, par exemple une application qui est un front-end utilisateur, un autre qui est une façade Web du panneau d'administration et un autre qui est une API REST. Chacun de ceux-ci est une application différente prête à configurer différemment. Cela est multiplié par plusieurs environnements (production, pré-production, test, développement, etc.). Cela donne facilement 12 ou 15 configurations dans une seule entreprise.
Xavi Montero
@XaviMontero J'ai suivi votre instruction SECONDE APPROCHE: et quand var_dump le $ this-> contact_email ou ajoute un exit () dans la fonction setConfig () il ne se termine pas. Il semble que setConfig ne soit pas appelé
user742736
35

Je dois ajouter à la réponse de douglas, vous pouvez accéder à la configuration globale, mais symfony traduit certains paramètres, par exemple:

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

sont

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

Vous pouvez utiliser var_dump pour rechercher une clé ou une valeur spécifiée.

Felipe Buccioni
la source
17

Afin de pouvoir exposer certains paramètres de configuration de votre bundle, vous devez consulter la documentation pour ce faire. C'est assez facile à faire :)

Voici le lien: Comment exposer une configuration sémantique pour un bundle

Nikola Petkanski
la source
Honnêtement, cette question a été posée il y a plus de 2 ans, à l'époque, l'article ci-dessus n'existait pas.
josef.van.niekerk
10
Je suis d'accord avec cette affirmation. J'ai défini la réponse au cas où quelqu'un ouvrirait cet article de nos jours. Merci pour la note négative - vous avez fait ma journée.
Nikola Petkanski
Mes excuses, maintenant que j'y pense, mon vote défavorable était injustifié. J'apprécie votre contribution, j'ai essayé de voter mais SO ne le permet plus. Le lien est très utile et je suis sûr que d'autres en profiteront! Peut-être que l'administrateur peut m'aider à changer mon vote défavorable ???
josef.van.niekerk
Je crois que vous pouvez cliquer à nouveau pour annuler.
Nikola Petkanski
Vous ne pouvez pas annuler votre vote plus de X (5?) Minutes après l'avoir fait ou jusqu'à ce que le message soit modifié
cheesemacfly
3

J'ai appris un moyen facile à partir de l'exemple de code de http://tutorial.symblog.co.uk/

1) Notez le ZendeskBlueFormBundle et l'emplacement du fichier

# myproject/app/config/config.yml

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

framework:

2) notez Zendesk_BlueForm.emails.contact_email et l'emplacement du fichier

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

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

3) Remarquez comment je l'obtiens dans $ client et l'emplacement du fichier du contrôleur

# 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"));
    ...
    }
Bouse
la source