Como leio as configurações do Symfony2 config.yml?

191

Eu adicionei uma configuração ao meu arquivo config.yml da seguinte forma:

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

Pela minha vida, não consigo descobrir como lê-lo em uma variável. Eu tentei algo assim em um dos meus controladores:

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

Mas eu recebo um erro dizendo:

O parâmetro "contact_email" deve ser definido.

Limpei meu cache, também procurei em todos os lugares a documentação do site recarregada pelo Symfony2, mas não consigo descobrir como fazer isso.

Provavelmente cansado demais para descobrir isso agora. Alguém pode ajudar com isso?

josef.van.niekerk
fonte

Respostas:

194

Em vez de definir contact_emaildentro app.config, defina-o em uma parametersentrada:

parameters:
    contact_email: somebody@gmail.com

Você deve encontrar a chamada que está fazendo no seu controlador agora funciona.

Douglas Greenshields
fonte
4
Como isso funcionaria com os ambientes Dev / Prod? Então, para testar Eu quero que os e-mails para enviar a um email de teste e produção iria receber outro e-mail
Phill Pafford
2
@Phill: Se você estiver usando o swiftmailer padrão no symfony2, poderá usar a seguinte configuração no config_dev.yml: swiftmailer: delivery_address: [email protected] Você pode encontrar mais informações no livro de receitas
Pierre
4
Devo injetar classe de contêiner em qualquer lugar (controlador, entidade, classe) quando usar esta instrução $ this-> container-> getParameter ('contact_email'); ? ou existe uma maneira mais simples de fazer isso sem injetar classe de contêiner?
webblover 24/09/14
1
De acordo com esta solução, como posso acessar propriedades aninhadas?
Ousmane
1
@webblover Basta inserir o parâmetro em si usando o %parameter_name%- notação (em YAML)
MauganRa
173

Embora a solução de mover contact_emailpara to parameters.ymlseja fácil, conforme proposto em outras respostas, isso pode facilmente confundir seu arquivo de parâmetros se você lidar com muitos pacotes configuráveis ​​ou se você lidar com blocos de configuração aninhados.

  • Primeiro, eu responderei estritamente a pergunta.
  • Mais tarde, darei uma abordagem para obter essas configurações de serviços sem nunca passar por um espaço comum como parâmetros.

PRIMEIRA ABORDAGEM: Bloco de configuração separado, obtendo-o como parâmetro

Com uma extensão ( mais sobre extensões aqui ), você pode mantê-la facilmente "separada" em diferentes blocos noconfig.yml e, em seguida, injetar isso como um parâmetro que pode ser obtido do controlador.

Dentro da classe Extension dentro do DependencyInjectiondiretório, escreva isto:

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
    }

Em seguida, no seu config.yml, config_dev.yml e assim você pode definir

my_nice_project:
    contact_email: someone@example.com

Para poder processar isso config.ymldentro do seu, MyNiceBundleExtensionvocê também precisará de uma Configurationclasse no mesmo espaço para nome:

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

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

        return $treeBuilder;
    }
}

Em seguida, você pode obter a configuração do seu controlador, conforme desejado na sua pergunta original, mas mantendo-a parameters.ymllimpa e configurando-a config.ymlnas seções separadas:

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

SEGUNDA ABORDAGEM: Bloco de configuração separado, injetando a configuração em um serviço

Para os leitores que procuram algo semelhante, mas para obter a configuração de um serviço, existe uma maneira ainda melhor que nunca atrapalha o espaço comum "paramaters" e nem precisa do container ser passado para o serviço (passar o contêiner inteiro é prática evitar).

Este truque acima ainda "injeta" no espaço de parâmetros sua configuração.

No entanto, depois de carregar sua definição do serviço, você pode adicionar uma chamada de método, como por exemplo setConfig() que injeta esse bloco apenas no serviço.

Por exemplo, na 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' ] ) );
    }
}

Então, no seu, services.ymlvocê define seu serviço como de costume, sem nenhuma alteração absoluta:

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

E então na sua SillyManagerturma, basta adicionar o método:

class SillyManager
{
    private $contact_email;

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

Observe que isso também funciona para matrizes em vez de valores escalares! Imagine que você configure uma fila de coelhos e precisa de host, usuário e senha:

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

Claro que você precisa mudar sua Árvore, mas pode fazer:

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

e depois no serviço faça:

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 isto ajude!

Xavi Montero
fonte
Se você está se perguntando o que é diferente entre a primeira abordagem e a documentação, é que os valores de configuração são convertidos em parâmetros no MyNiceProjectExtension->load()método com esta linha: $container->setParameter( 'my_nice_project.contact_email', $processedConfig[ 'contact_email' ]);. Obrigado Xavi!
jxmallett
Resposta perfeita, pena que o symfony não permita que você acesse a configuração da mesma forma que os parâmetros.
Martin Lyne
Essa é uma boa resposta, mas expõe a maneira obtusa do Symfony de "configurar" um aplicativo. Qual é o objetivo de ter arquivos de configuração do ambiente arbitrário quando você precisar gravar e chamar serviços específicos para acessá-los. Alguém no Symfony não ficou parado lá e percebeu: 'Talvez os desenvolvedores realmente desejem fornecer valores específicos do ambiente em seus aplicativos que possam acessar'. Tipo de ponto dos arquivos de configuração, não é? Eles estão seguindo o padrão de design "STKTFANREO": "Coloque os botões em F'd e arranque-os"
eggmatters
Ele possui vários aplicativos, especialmente na implantação de testes automáticos paralelos, e especialmente quando uma equipe desenvolve um pacote que é principalmente modelo ou lógica consumida por várias outras equipes em aplicativos diferentes, por exemplo, um aplicativo que é um front-end de usuário, outro que é uma frente da Web do painel do administrador e outro que é uma API REST. Cada um deles é um aplicativo diferente, disposto a configurar diferentemente. Isso é multiplicado por vários ambientes (produção, pré-produção, teste, desenvolvimento etc.). Isso resulta facilmente em 12 ou 15 configurações em uma única empresa.
Xavi Montero
@XaviMontero Segui sua instrução SEGUNDA ABORDAGEM: e quando var_dump o $ this-> contact_email ou adiciona uma exit () na função setConfig (), ela não sai. Parece que setConfig não é chamado
user742736 8/16
35

Eu tenho que adicionar à resposta de douglas, você pode acessar a configuração global, mas o symfony traduz alguns parâmetros, por exemplo:

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

estão

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

Você pode usar var_dump para procurar uma chave ou valor especificado.

Felipe Buccioni
fonte
17

Para poder expor alguns parâmetros de configuração do seu pacote, consulte a documentação para fazê-lo. É bastante fácil de fazer :)

Aqui está o link: Como expor uma configuração semântica para um pacote

Nikola Petkanski
fonte
Honestamente, essa pergunta foi feita há mais de 2 anos, na época, o artigo acima não existia.
precisa saber é o seguinte
10
Eu concordo com essa afirmação. Eu dei a resposta no caso de alguém abrir este artigo hoje em dia. Obrigado pela classificação negativa - você fez o meu dia.
Nikola Petkanski
Minhas desculpas, agora que penso nisso, meu voto negativo foi desnecessário. Agradeço sua contribuição, tentei votar, mas o SO não permite mais. O link é muito útil e tenho certeza que outras pessoas se beneficiarão com ele! Talvez o administrador possa ajudar a mudar meu voto negativo ???
precisa saber é o seguinte
Acredito que você pode clicar novamente para desfazer.
Nikola Petkanski
Você não pode desfazer seu voto mais de X (5?) Minutos depois de ter feito isso ou até que a mensagem é editada
cheesemacfly
3

Aprendi uma maneira fácil com o exemplo de código de http://tutorial.symblog.co.uk/

1) observe o ZendeskBlueFormBundle e o local do arquivo

# myproject/app/config/config.yml

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

framework:

2) observe o Zendesk_BlueForm.emails.contact_email e o local do arquivo

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

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

3) observe como o consigo em $ client e local do arquivo do 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"));
    ...
    }
Estrume
fonte