サービスからアプリケーションパラメータにアクセスする方法は?


81

私のコントローラから、私は(のそれらのアプリケーションのパラメータにアクセス/app/configして)

$this->container->getParameter('my_param')

しかし、サービスからアクセスする方法がわかりません(私のサービスクラスは拡張されないはずSymfony\Bundle\FrameworkBundle\Controller\Controllerです)。

次のように、必要なパラメータをサービス登録にマッピングする必要があります。

#src/Me/MyBundle/Service/my_service/service.yml
parameters:
    my_param1: %my_param1%
    my_param2: %my_param2%
    my_param3: %my_param3%

または同様のもの?サービスからアプリケーションパラメータにアクセスするにはどうすればよいですか?


この質問は同じように見えますが、私は実際にそれに答えています(コントローラーからのパラメーター)。私はサービスからのアクセスについて話しています。



私の質問は実際にこれ(コントローラーからのパラメーター)に答えます、私はここのサービスからアクセスすることについて話している
Pierre deLESPINAY18年

私はあなたを理解しているかどうかわかりません。重複に同意しますか?コントローラーは最近のSymfonyのサービスです。
トマーシュVotruba

私は重複に同意しません。もう1つの質問は、でパラメーターを簡単に取得できるコントローラーを具体的に求めることです$this->getParameter()
Pierre de LESPINAY 2018年

それは本当です、私は同意します。そしてそれはまだ可能です。また、どこにでも注入されるコンテナから離れて、コンストラクター注入に移行する傾向があります。PSR-4サービスの自動検出とパラメーターバインディングのおかげで:symfony.com/blog/new-in-symfony-3-4-local-service-binding、それはクリーンで、操作するのがはるかに短いです。
トマーシュVotruba

回答:


123

他のサービスを挿入するのと同じ方法で、サービス定義でパラメーターを指定することにより、パラメーターをサービスに渡すことができます。たとえば、YAMLでは次のようになります。

services:
    my_service:
        class:  My\Bundle\Service\MyService
        arguments: [%my_param1%, %my_param2%]

ここで、%my_param1%etcはmy_param1。という名前のパラメータに対応します。その場合、サービスクラスコンストラクターは次のようになります。

public function __construct($myParam1, $myParam2)
{
    // ...
}

パラメータが存在しない場合に処理する方法はありますか?symfonyの例外IOCの代わりに。
Mohammed Yassine CHABLI 2018

の値はmy_param1どこから来るのですか?
SLIQ

@ Sliq、parameters.ymlで定義します
グラフ

35

クリーンウェイ2018

2018とSymfony3.4以降、はるかにクリーンな方法があります-セットアップと使用が簡単です。

コンテナとサービス/パラメータロケータのアンチパターンを使用する代わりに、コンストラクタを介してクラスにパラメータを渡すことができます。心配しないでください。時間のかかる作業ではなく、一度セットアップしてアプローチを忘れてください

2つのステップで設定するにはどうすればよいですか?

1.1。 config.yml

# config.yml
parameters:
    api_pass: 'secret_password'
    api_user: 'my_name'

services:
    _defaults:
        autowire: true
        bind:
            $apiPass: '%api_pass%'
            $apiUser: '%api_user%'

    App\:
        resource: ..

2.任意 Controller

<?php declare(strict_types=1);

final class ApiController extends SymfonyController
{
    /**
     * @var string 
     */
    private $apiPass;

    /**
     * @var string
     */
    private $apiUser;

    public function __construct(string $apiPass, string $apiUser)
    {
        $this->apiPass = $apiPass;
        $this->apiUser = $apiUser;
    }

    public function registerAction(): void
    {
        var_dump($this->apiPass); // "secret_password"
        var_dump($this->apiUser); // "my_name"
    }
}

インスタントアップグレードの準備ができました!

古いアプローチを使用する場合は、Rectorを使用して自動化できます。

続きを読む

これは、サービスロケーターアプローチに対するコンストラクターインジェクションと呼ばれます

これについてもっと読むには、私の投稿「Symfonyコントローラーでパラメーターを取得する方法」をチェックしてください。

(テスト済みで、新しいSymfonyメジャーバージョン(5、6 ...)用に更新されています)。


1
OPは任意のサービスにパラメーターを挿入する必要があり、SF3コントローラーでは
自動配線が

ご意見をありがとうございます。上記の構成は、すべてのサービス、コントローラー、リポジトリー、または独自のサービスで機能します。違いはありません。
トマーシュVotruba

18

必要なパラメーターを1つずつマッピングする代わりに、サービスがコンテナーに直接アクセスすることを許可しないのはなぜですか?そうすることで、(サービスに関連する)新しいパラメーターが追加された場合にマッピングを更新する必要はありません。

そうするために:

サービスクラスに次の変更を加えます

use Symfony\Component\DependencyInjection\ContainerInterface; // <- Add this

class MyServiceClass
{
    private $container; // <- Add this
    public function __construct(ContainerInterface $container) // <- Add this
    {
        $this->container = $container;
    }
    public function doSomething()
    {
        $this->container->getParameter('param_name_1'); // <- Access your param
    }
}

services.ymlの「引数」として@service_containerを追加します

services:
  my_service_id:
    class: ...\MyServiceClass
    arguments: ["@service_container"]  // <- Add this

1
まさに私が探していたもの、それが私が依存性注入が好きな理由です:)
klimpond 2015

44
-1。コンテナ全体を渡すと、依存性注入の目的が無効になります。クラスには、コンテナ全体ではなく、実際に操作する必要があるものだけを指定する必要があります。
richsage 2015年

@richsage、同様の結果を達成するための代替手段はありますか?したがって、サービス宣言はパラメーターごとに更新されませんか?これは、パラメータを1つずつ挿入するよりも少しきれいに見えます。
バタンドワ2015

1
コンテナ全体をサービスに渡すことは本当に悪い考えです。@richsageが言うように、依存性注入の目的には適合しません。依存性注入を使用したくない場合は、Symfony2を使用しないでください:)
tersakyan 2016年

2
@tersakyan、しかしコントローラーはどうですか?デフォルトでは、すべてのコントローラーがコントローラーにアクセスできます。では、コントローラーも使用しないでください。:)
Alex Zheka 2016年

9

symfony 4.1以降、それを達成するための非常にクリーンな新しい方法があります。

<?php
// src/Service/MessageGeneratorService.php

use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

class MessageGeneratorService
{
 private $params;
 public function __construct(ParameterBagInterface $params)
 {
      $this->params = $params;
 }
 public function someMethod()
 {
     $parameterValue = $this->params->get('parameter_name');
...
 }
}

ソース:https//symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service


6

言及されたいくつかの問題の解決策として、配列パラメーターを定義してからそれを注入します。後で新しいパラメーターを追加するには、service_container引数または構成を変更せずに、パラメーター配列に追加するだけです。

したがって、@ richsageの回答を拡張します:

parameters.yml

parameters:
    array_param_name:
        param_name_1:   "value"
        param_name_2:   "value"

services.yml

services:
    my_service:
        class:  My\Bundle\Service\MyService
        arguments: [%array_param_name%]

次に、クラス内にアクセスします

public function __construct($params)
{
    $this->param1 = array_key_exists('param_name_1',$params)
        ? $params['param_name_1'] : null;
    // ...
}

このコメントを書いている時点で、残念ながら、のparamsのネストはsymfonyのでは不可能で、ドキュメントを参照してください。symfony.com/doc/current/service_container/...
トマーシュVotruba

5

symfonyの4.1ソリューションは非常に簡単です。

元の投稿の抜粋は次のとおりです。

// src/Service/MessageGenerator.php
// ...

use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

class MessageGenerator
{
    private $params;

    public function __construct(ParameterBagInterface $params)
    {
        $this->params = $params;
    }

    public function someMethod()
    {
        $parameterValue = $this->params->get('parameter_name');
        // ...
    }
}

元の投稿へのリンク:https//symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service


0

@richsageは正しいですが(Symfony 3.?の場合)、私のSymfony4.xでは機能しませんでした。だからここにSymfony4があります。

services.yamlファイル内

parameters:
    param1: 'hello'

Services:
    App\Service\routineCheck:
            arguments:
                $toBechecked: '%param1%'  # argument must match in class constructor

サービスクラスroutineCheck.phpファイルでコンストラクターをそのようにします

private $toBechecked;

public function __construct($toBechecked)
{
    $this->toBechecked = $toBechecked;
}

public function echoSomething()
{
    echo $this->toBechecked;
}

完了。


それをさらに説明できますか?他のソリューションで正確に機能しなかったものは何ですか?エラーメッセージが表示されていますか?
ニコハーゼ

彼はコンストラクターでParameterBagInterface $ paramsを使用しましたが、services.yamlでパラメーター構成を完全に利用するために、依存性注入を使用しました。

それをさらに説明できますか?richsageによって答えはそのParameterBagInterfaceが、ちょうどあなたのコードのように注入されるパラメータのリストが含まれていない
ニコハーゼ

私の答えは、エコシステムがSymfony 2だけだった2012年に投稿されました。私はもうSymfonyを使用していないので、後続のバージョン用に更新していません。
richsage

-1

symfony3.4はこちら。

いくつかの調査の結果、コンストラクターを介してパラメーターをクラス/サービスに渡すことは、常に良い考えではないと思います。2または3よりも多くのパラメーターをコントローラー/サービスに渡す必要がある場合を想像してみてください。たとえば、最大10個のパラメータを渡すのはばかげています。

代わりに、ParameterBagymlでサービスを宣言するときにクラスを依存関係として使用し、必要な数のパラメーターを使用します。

具体的な例として、PHPMailerのようなメーラーサービスがあり、PHPMailer接続パラメーターをに設定したいとします。 paramters.ymlファイルにます。

#parameters.yml
parameters:
    mail_admin: abc@abc.abc
    mail_host: mail.abc.com
    mail_username: noreply@abc.com
    mail_password: pass
    mail_from: contact@abc.com
    mail_from_name: contact@abc.com
    mail_smtp_secure: 'ssl'
    mail_port: 465

#services.yml
services:
    app.php_mailer:
        class: AppBundle\Services\PHPMailerService
        arguments: ['@assetic.parameter_bag'] #here one could have other services to be injected
        public: true

# AppBundle\Services\PHPMailerService.php
...
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
...
class PHPMailerService
{
    private $parameterBag;
    private $mailAdmin;
    private $mailHost;
    private $mailUsername;
    private $mailPassword;
    private $mailFrom;
    private $mailFromName;
    private $mailSMTPSecure;
    private $mailPort;
}
public function __construct(ParameterBag $parameterBag)
{
    $this->parameterBag = $parameterBag;

    $this->mailAdmin      = $this->parameterBag->get('mail_admin');
    $this->mailHost       = $this->parameterBag->get('mail_host');
    $this->mailUsername   = $this->parameterBag->get('mail_username');
    $this->mailPassword   = $this->parameterBag->get('mail_password');
    $this->mailFrom       = $this->parameterBag->get('mail_from');
    $this->mailFromName   = $this->parameterBag->get('mail_from_name');
    $this->mailSMTPSecure = $this->parameterBag->get('mail_smtp_secure');
    $this->mailPort       = $this->parameterBag->get('mail_port');
}
public function sendEmail()
{
    //...
}

これがより良い方法だと思います。


-1

symfony 4では、依存性注入によってパラメーターにアクセスできます。

サービス:

   use Symfony\Component\DependencyInjection\ContainerInterface as Container;

   MyServices {

         protected $container;
         protected $path;

         public function __construct(Container $container)
         {
             $this->container = $container;
             $this->path = $this->container->getParameter('upload_directory');
         }
    }

parameters.yml:

parameters:
     upload_directory: '%kernel.project_dir%/public/uploads'

提供されたコードはDIを適切に使用していません-実際の依存関係を非表示にするため、コンテナー全体を注入することは悪いスタイルと見なされます
NicoHaase19年

あなたは概念を誤解していると思います。この例では、一般的なケースのみを示しています。疑わしい場合は、投票する前に公式のsymfonyドキュメントを参照してください。symfony.com/doc/current/components/dependency_injection.html
shadows30 0219

それをさらに説明できますか?リンクされたドキュメントには、コンテナの注入は適切ではないと明確に記載されており、このタイプの注入を使用する例は示されていません-明らかに、コンテナ全体を注入するときに依存性を注入していません
Nico Haase
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.