Подтвердить что ты не робот

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

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

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

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

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

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

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

Спасибо заранее!

4b9b3361

Ответ 1

Примечание. Я знаю, что это решение не является 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();
}

Ответ 2

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

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

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

Ответ 4

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, которые могут быть больны.

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

Ответ 5

Другой вариант, как легко получить параметры - вы можете просто установить 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');

Ответ 6

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

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

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

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

Ответ 7

В качестве альтернативного подхода можно было бы фактически ввести параметры приложения в вашу службу через Container- > getParameterBag в комплекте с расширением DI

    <?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