web-dev-qa-db-ja.com

Symfony2:すべてのパラメーターをサービスに注入する方法は?

すべてのパラメーターをサービスに注入するにはどうすればよいですか?

私はできることを知っています:_arguments: [%some.key%]_ __parameters: some.key: "value"_をサービス__constructに渡します。

私の質問は、parametersの下にあるすべてのものをサービスに注入する方法ですか?

これは、ナビゲーションマネージャーサービスを作成するために必要です。ここでは、すべての構成エントリのさまざまな設定に従って、さまざまなメニュー/ナビゲーション/ブレッドクラムが生成されます。

必要なだけ多くのパラメーターを注入できることはわかっていますが、パラメーターの数を使用し、時間の経過とともに拡大するので、最初からすべてを渡した方がよいと思います。

他のアプローチは、コントローラーで行うことができるようにサービス内のパラメーターを取得できる場合です$this -> container -> getParameter('some.key');ですが、これは依存性注入の考え方に反すると思いますか?

前もって感謝します!

27
Tony Bogdanov

注:このソリューションは設計の観点からは最善ではないことを知っていますが、それは機能します。したがって、ダウン投票は避けてください。

\ 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();
}
5
Anton Babenko

コンテナ全体をサービスに注入することはお勧めできません。また、サービスに必要なパラメータが多数ある場合、それらをすべて1つずつサービスに注入するのは適切ではありません。代わりに私はこの方法を使用します:

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)5月のサービスでは、次のようなパラメーターにアクセスできます。

namespace Saman\ProductBundle\Service;

use Symfony\Bundle\FrameworkBundle\Translation\Translator;

class Shopping
{   
    protected $translator;
    protected $parameters;

    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'
47
Saman Shafigh

パラメータを簡単に取得する別の方法-ParameterBagをサービスに設定するだけです。引数またはsetメソッドを使用して、さまざまな方法でそれを行うことができます。 setメソッドを使用した例を示します。

したがって、services.ymlで次のようなものを追加する必要があります。

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

クラスMyService\Classに、useを追加するだけです。

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');
10

パラメータを個別に渡すことになっていると思います。サービスクラスがAppKernelに依存しないように設計されていると思います。そうすれば、Symfonyプロジェクトの外でサービスクラスを再利用できます。サービスクラスをテストするときに役立つもの。

8
dan-klasson

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フラグを考慮する必要があります。

コンパイラパスを使用してこれを行うこともできると思いますが、試したことはありません。

7
Cerad

Services.ymlでサービスを定義し、parameterBagを挿入して任意のパラメーターにアクセスできるようにする提案

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

サービスを注入すると、以下を使用してパラメーターを取得できます

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

別のアプローチとしては、DI拡張機能をバンドルしてContainer-> getParameterBagを介して実際にアプリケーションパラメータをサービスに注入することができます。

    <?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\DependencyInjection\Exception\RuntimeException]
パラメータがオブジェクトまたはリソースの場合、サービスコンテナをダンプできません。

Symfonyバージョンの下でテスト2.3.4

3
andrew