2012-02-15 3 views
25

Как я могу ввести ВСЕ параметры в службу?Symfony2: Как вводить ВСЕ параметры в услугу?

Я знаю, что могу сделать: arguments: [%some.key%], который передаст parameters: some.key: "value" на обслуживание __construct.

Мой вопрос в том, как вводить все, что находится под parameters в услугу?

Мне нужно это, чтобы создать службу диспетчера навигации, где различные меню/навигационные/панировочные сухари должны создаваться в соответствии с различными настройками через все записи конфигурации.

Я знаю, что я мог бы вводить столько параметров, сколько хочу, но так как он собирается использовать их и со временем будет расширяться, я думаю, что лучше всего передать все в самом начале.

Другой подход может быть, если бы я мог получить параметры внутри службы, как вы можете сделать в контроллере $this -> container -> getParameter('some.key');, но я думаю, что это было бы против идеи инъекции зависимостей?

Заранее благодарен!

ответ

7

Примечание: Я знаю, что это решение не является BEST с точки зрения дизайна, но оно выполняет эту работу, поэтому, пожалуйста, избегайте голосования.

Вы можете вводить объект \ AppKernel, а затем получить доступ ко всем параметрам, как это:

config.yml:

my_service: 
    class: MyService\Class 
    arguments: [@kernel] 

MyService\Class И внутри:

public function __construct($kernel) 
{ 
    $this->parameter = $kernel->getContainer()->getParameter('some.key'); 
    // or to get all: 
    $this->parameters = $kernel->getContainer()->getParameterBag()->all(); 
} 
+0

То, что мне было нужно, я забыл о ядре. Спасибо! –

+0

Вау! У меня был совершенно другой вопрос, ваш ответ решил мою проблему! – Arsham

+33

Плохая идея для ввода ядра – kratos

7

AppKernel будет работать, но это еще хуже (с точки зрения объема), чем впрыскивание контейнера, поскольку в нем есть еще больше вещей.

Вы можете посмотреть xxxProjectContainer в своем каталоге кеша. Оказывается, что отсортированные параметры скомпилированы непосредственно в него как большой массив. Таким образом, вы можете ввести контейнер, а затем просто вытащить параметры. Нарушает букву закона, но не дух закона.

class MyService { 
    public function __construct($container) { 
     $this->parameters = $container->parameters; // Then discard container to preclude temptation 

И только вид Мессинг вокруг, я обнаружил, что я мог бы сделать это:

$container = new \arbiterDevDebugProjectContainer(); 
    echo 'Parameter Count ' . count($container->parameters) . "\n"; 

Таким образом, вы могли бы на самом деле создать службу, которая была в основном пустую копию главного контейнера и вводить его только, чтобы получить параметры. Примите во внимание флагов dev/debug, которые могут быть больны.

Я подозреваю, что вы также можете сделать это с помощью компилятора, но никогда не пробовали.

+3

Я не буду рекомендовать напрямую инжекторное обслуживание, поскольку оно нарушит концепцию инъекции зависимостей. – GusDeCooL

8

Я считаю, что вы должны передавать параметры по отдельности. Я думаю, что это сделано таким образом, чтобы ваш класс обслуживания не зависел от AppKernel. Таким образом, вы можете повторно использовать свой класс обслуживания вне вашего проекта Symfony. Что-то, что полезно при тестировании вашего класса обслуживания.

+1

+1 для передачи параметров по отдельности – kratos

3

Как альтернативный подход будет то, что вы можете вводить параметры приложения в вашу службу через container-> getParameterBag в вас связывайте DI Extension

<?php 

    namespace Vendor\ProjectBundle\DependencyInjection; 

    use Symfony\Component\DependencyInjection\ContainerBuilder; 
    use Symfony\Component\Config\FileLocator; 
    use Symfony\Component\HttpKernel\DependencyInjection\Extension; 
    use Symfony\Component\DependencyInjection\Loader; 

    /** 
    * This is the class that loads and manages your bundle configuration 
    * 
    * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html} 
    */ 
    class VendorProjectExtension extends Extension { 

     /** 
     * {@inheritDoc} 
     */ 
     public function load(array $configs, ContainerBuilder $container) { 
      $configuration = new Configuration(); 
      $config = $this->processConfiguration($configuration, $configs); 
      $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); 
      $loader->load('services.yml'); 
      /** set params for services */ 
      $container->getDefinition('my.managed.service.one') 
        ->addMethodCall('setContainerParams', array($container->getParameterBag()->all())); 
      $container->getDefinition('my.managed.service.etc') 
        ->addMethodCall('setContainerParams', array($container->getParameterBag()->all())); 

     } 
} 

Пожалуйста, обратите внимание, что мы не можем вводить объект ParameterBag непосредственно, потому что он бросает :

[Symfony \ Component \ внедрение зависимости \ Exception \ RuntimeException]
Невозможно сбросить контейнер службы, если параметр является объектом или ресурс.

Протестировано под Symfony версии 2.3.4

+0

Плохая идея для инъекций DI – kratos

+0

$ container-> getParameterBag() -> all() actual return [array] (https://github.com/symfony/symfony/blob/master/src/ Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php # L75) – andrew

42

Это не очень хорошая практика, чтобы ввести весь контейнер в сервис. Также, если у вас есть много параметров, которые вам нужны для вашей службы, нехорошо вставлять их все по одному в вашу службу. Вместо этого я использую этот метод:

1) В config.yml я определить параметры, которые нужны для моей службы, как это:

parameters: 
    product.shoppingServiceParams: 
     parameter1: 'Some data' 
     parameter2: 'some data' 
     parameter3: 'some data' 
     parameter4: 'some data' 
     parameter5: 'some data' 
     parameter6: 'some data' 

2) Тогда я вводить этот корневой параметр для моей службы как:

services: 
    product.shoppingService: 
    class: Saman\ProductBundle\Service\Shopping 
    arguments: [@translator.default, %product.shoppingServiceParams%] 

3) в мае службе я могу получить доступ к этим параметрам, как:

namespace Saman\ProductBundle\Service; 

use Symfony\Bundle\FrameworkBundle\Translation\Translator; 

class Shopping 
{ 
    protected $translator; 
    protected $paramaters; 

    public function __construct(
     Translator $translator, 
     $parameters 
     ) 
    { 
     $this->translator = $translator; 
     $this->parameters = $parameters; 
    } 

    public function dummyFunction() 
    { 
     var_dump($this->getParameter('parameter2')); 
    } 

    private function getParameter($key, $default = null) 
    { 
     if (isset($this->parameters[$key])) { 
      return $this->parameters[$key]; 
     } 

     return $default; 
    } 
} 

4) Я также могу ев и другие значения для разных сред. Например, в config_dev.yml

parameters: 
    product.shoppingServiceParams: 
     parameter1: 'Some data for dev' 
     parameter2: 'some data for dev' 
     parameter3: 'some data for dev' 
     parameter4: 'some data for dev' 
     parameter5: 'some data for dev' 
     parameter6: 'some data' 
+3

Определенно лучший подход imho! – MediaVince

+0

@Saman зачем использовать array_key_exists, если вы возвращаете значение null для не найденных параметров? isset() даст тот же результат, только быстрее. - Хороший ответ. – OIS

+0

Спасибо, да, вы абсолютно пишете –

4

Предложение определить сервис на services.yml, которая будет впрыскивать parameterBag и разрешить доступ к любой из ваших параметров

service.container_parameters: 
    public: false 
    class: stdClass 
    factory_service: service_container 
    factory_method: getParameterBag 

Вводите свой сервис, и вы можете получите свой параметр, используя ниже

$parameterService->get('some.key'); 
7

Другой вариант, как легко получить параметры - вы можете просто установить ParameterBag к вашим услугам. Вы можете сделать это по-разному - через аргументы или с помощью методов набора. Позвольте мне показать мой пример с помощью метода set.

Так services.yml вы должны добавить что-то вроде:

my_service: 
    class: MyService\Class 
    calls: 
     - [setParameterBag, ["@=service('kernel').getContainer().getParameterBag()"]] 

и в классе MyService \ Class просто добавить использование:

use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; 

и создать 2 метода:

/**                                          
* Set ParameterBag for repository                                  
*                                          
* @param ParameterBagInterface $params                                 
*/ 
public function setParameterBag(ParameterBagInterface $params) 
{ 
    $this->parameterBag = $params; 
} 

/**                                          
* Get parameter from ParameterBag                                  
*                                          
* @param string $name                                     
* @return mixed                                       
*/ 
public function getParameter($name) 
{ 
    return $this->parameterBag->get($name); 
} 

и теперь вы можете использовать в классе:

$this->getParameter('your_parameter_name'); 
Смежные вопросы