Jak odczytać ustawienia konfiguracji z Symfony2 config.yml?

191

Dodałem ustawienie do mojego pliku config.yml jako takie:

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

Przez całe moje życie nie mogę wymyślić, jak odczytać to w zmiennej. Próbowałem czegoś takiego w jednym z moich kontrolerów:

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

Ale pojawia się błąd z informacją:

Parametr „contact_email” musi zostać zdefiniowany.

Wyczyściłem pamięć podręczną, szukałem też wszędzie w dokumentacji przeładowanej witryny Symfony2, ale nie mogę się dowiedzieć, jak to zrobić.

Prawdopodobnie po prostu zbyt zmęczony, aby to teraz zrozumieć. Czy ktoś może w tym pomóc?

josef.van.niekerk
źródło

Odpowiedzi:

194

Zamiast definiować contact_emailwewnątrz app.config, zdefiniuj go we parameterswpisie:

parameters:
    contact_email: somebody@gmail.com

Powinieneś znaleźć połączenie, które wykonujesz na swoim kontrolerze, teraz działa.

Douglas Greenshields
źródło
4
Jak to działa ze środowiskami Dev / Prod? Więc do testowania chcę, aby e-maile były wysyłane na e-mail testowy, a produkcja otrzyma inny e
Phill Pafford
2
@Phill: Jeśli używasz standardowego swiftmailera w swoim symfony2, możesz użyć następującego ustawienia w pliku config_dev.yml: swiftmailer: delivery_address: [email protected] Więcej informacji można znaleźć w książce kucharskiej Symfony2
Pierre
4
Czy powinienem wstrzykiwać klasę kontenera wszędzie (kontroler, encja, klasa), kiedy używam tej instrukcji $ this-> container-> getParameter ('contact_email'); ? czy jest prostszy sposób na zrobienie tego bez wstrzykiwania klasy kontenera?
webblover
1
Zgodnie z tym rozwiązaniem, w jaki sposób mogę uzyskać dostęp do zagnieżdżonych właściwości?
Ousmane,
1
@webblover Wystarczy wstawić sam parametr, używając %parameter_name%notacji (w YAML)
MauganRa
173

Rozwiązanie przeniesienia contact_emaildo parameters.ymljest łatwe, jak zaproponowano w innych odpowiedziach, ale może łatwo zaśmiecać plik parametrów, jeśli masz do czynienia z wieloma pakietami lub jeśli masz do czynienia z zagnieżdżonymi blokami konfiguracji.

  • Najpierw odpowiem ściśle na pytanie.
  • Później przedstawię podejście do pobierania tych konfiguracji z usług bez przechodzenia przez wspólną przestrzeń jako parametry.

PIERWSZE PODEJŚCIE: Oddzielny blok konfiguracji, otrzymując go jako parametr

Z przedłużeniem ( więcej o rozszerzeniach tutaj ) możesz to łatwo „rozdzielić” na różne bloki wconfig.yml a następnie wstrzyknąć jako parametr gettable ze sterownika.

Wewnątrz klasy Extension wewnątrz DependencyInjection katalogu napisz:

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
    }

Następnie w config.yml, config_dev.yml i możesz ustawić

my_nice_project:
    contact_email: someone@example.com

Aby móc przetworzyć to config.ymlw swoim wnętrzu MyNiceBundleExtension, potrzebujesz równieżConfiguration klasy w tej samej przestrzeni nazw:

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

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

        return $treeBuilder;
    }
}

Następnie możesz uzyskać konfigurację ze swojego kontrolera, tak jak chciałeś w swoim pierwotnym pytaniu, ale utrzymując parameters.ymlczystość i ustawiając ją wconfig.yml w oddzielnych sekcjach:

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

DRUGIE PODEJŚCIE: Oddzielny blok konfiguracji, wstrzykiwanie konfiguracji do usługi

Dla czytelników szukających czegoś podobnego, ale do uzyskania konfiguracji z usługi, istnieje jeszcze lepszy sposób, który nigdy nie zaśmieca wspólnej przestrzeni „parametrów”, a nawet nie potrzebuje container być przekazywany do usługi (przekazywanie całego kontenera jest praktyką uniknąć).

Ta sztuczka powyżej nadal „wstrzykuje” do przestrzeni parametrów twojej konfiguracji.

Niemniej jednak po załadowaniu definicji usługi można dodać wywołanie metody, na przykład setConfig()wstrzykuje ten blok tylko do usługi.

Na przykład w klasie 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' ] ) );
    }
}

Następnie services.ymldefiniujesz swoją usługę jak zwykle, bez żadnych absolutnych zmian:

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

A następnie w swojej SillyManagerklasie po prostu dodaj metodę:

class SillyManager
{
    private $contact_email;

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

Zauważ, że działa to również dla tablic zamiast wartości skalarnych! Wyobraź sobie, że konfigurujesz kolejkę królika i potrzebujesz hosta, użytkownika i hasła:

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

Oczywiście musisz zmienić swoje Drzewo, ale możesz zrobić:

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

a następnie w serwisie wykonaj:

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

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

Mam nadzieję że to pomoże!

Xavi Montero
źródło
Jeśli zastanawiasz się, co różni się od pierwszego podejścia i dokumentacji, to, że wartości konfiguracyjne są przekształcane w parametrów MyNiceProjectExtension->load()metody z tej linii: $container->setParameter( 'my_nice_project.contact_email', $processedConfig[ 'contact_email' ]);. Dzięki, Xavi!
jxmallett,
Idealna odpowiedź, wstyd symfony nie pozwala na dostęp do konfiguracji w ten sam sposób, w jaki robi parametry.
Martin Lyne,
To dobra odpowiedź, ale ujawnia tępy sposób „konfigurowania” aplikacji przez Symfony. Jaki jest sens posiadania dowolnych plików konfiguracyjnych środowiska, gdy trzeba pisać i wywoływać określone usługi, aby uzyskać do nich dostęp. Czy ktoś w Symfony nie siedział i nie zdawał sobie sprawy: „Być może programiści chcieliby podać w swoich aplikacjach wartości specyficzne dla środowiska, do których mogą uzyskać dostęp”. Zasadniczo z punktu widzenia plików konfiguracyjnych, prawda? Kierują się wzorem „STKTFANREO”: „Ustaw pokrętła w pozycji F'd i zdzieraj je”
eggmatters
Ma kilka aplikacji, szczególnie do wdrażania równoległych testów automatycznych, a zwłaszcza, gdy zespół opracowuje pakiet, który jest głównie modelowy lub logiczny, z którego korzysta kilka innych zespołów w różnych aplikacjach, na przykład aplikacja będąca interfejsem użytkownika, inny, który jest interfejsem WWW panelu administracyjnego i inny, który jest interfejsem API REST. Każda z nich to inna aplikacja chętnie konfigurująca się w różny sposób. Mnożymy to przez kilka środowisk (produkcja, przedprodukcja, testowanie, rozwój itp.). Daje to łatwo w 12 lub 15 konfiguracjach w jednej firmie.
Xavi Montero
@XaviMontero Postępowałem zgodnie z twoją instrukcją DRUGIE PODEJŚCIE: a kiedy var_dump $ this-> contact_email lub dodaj exit () w funkcji setConfig (), to nie wychodzi. Wygląda na to, że setConfig nie zostaje wywołany
użytkownik742736
35

Muszę dodać do odpowiedzi Douglasa, możesz uzyskać dostęp do globalnej konfiguracji, ale symfony tłumaczy niektóre parametry, na przykład:

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

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

Możesz użyć var_dump, aby wyszukać określony klucz lub wartość.

Felipe Buccioni
źródło
17

Aby móc ujawnić niektóre parametry konfiguracyjne pakietu, należy zapoznać się z dokumentacją. To dość łatwe do zrobienia :)

Oto link: Jak ujawnić konfigurację semantyczną dla pakietu

Nikola Petkanski
źródło
Szczerze mówiąc, pytanie to zostało zadane ponad 2 lata temu, wtedy ów artykuł nie istniał.
josef.van.niekerk
10
Zgadzam się z tym stwierdzeniem. Ustawiłem odpowiedź na wypadek, gdyby ktoś otworzył ten artykuł w dzisiejszych czasach. Dzięki za negatywną ocenę - zrobiłeś mi dzień.
Nikola Petkanski
Przepraszam, teraz, kiedy o tym myślę, moje głosowanie było nieuzasadnione. Doceniam twój wkład, starałem się głosować, ale SO już na to nie pozwala. Link jest najbardziej pomocny i jestem pewien, że inni ludzie skorzystają z niego! Może administrator może pomóc zmienić moje zdanie ???
josef.van.niekerk
Wierzę, że możesz kliknąć ponownie, aby cofnąć.
Nikola Petkanski
Nie możesz cofnąć swojego głosowania dłużej niż X (5?) Minut po tym, jak to zrobisz lub dopóki wiadomość nie zostanie zredagowana
cheesemacfly
3

Nauczyłem się w prosty sposób z przykładu kodu http://tutorial.symblog.co.uk/

1) zwróć uwagę na ZendeskBlueFormBundle i lokalizację pliku

# myproject/app/config/config.yml

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

framework:

2) powiadom Zendesk_BlueForm.emails.contact_email i lokalizację pliku

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

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

3) zauważ, jak dostaję go do $ klienta i lokalizacji pliku kontrolera

# 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"));
    ...
    }
Łajno
źródło