ホームページ >バックエンド開発 >PHPチュートリアル >自動接続された Symfony サービスに値オブジェクトを注入する

自動接続された Symfony サービスに値オブジェクトを注入する

王林
王林オリジナル
2024-08-11 11:16:32557ブラウズ

Inject Value Objects Into An Autowired Symfony Service

チームで Symfony プロジェクトに取り組んでいるとき、サービスの 1 つに特定の値オブジェクト インスタンスを挿入する必要がありました。この特定のケースでは、値自体は .env ファイルで提供される値から設定する必要がありました。

もちろん、文字列値をサービスに直接渡して、サービスがコンストラクターで値オブジェクトをインスタンス化できるようにすることもできますが、services.yaml ファイルで設定して注入できるかどうかを確認したかったのです。代わりに、完全にインスタンス化されたオブジェクトが使用されます。これにより、それらのオブジェクト インスタンスを複数のサービスに渡すことができ、それぞれのサービス内で値オブジェクトの作成を繰り返す必要がなくなります。

これが私がやった方法です...

背景

私たちのアプリケーションは Twilio SDK を利用しています。 SDK 呼び出しをラップするさまざまなサービスがあり、それらは環境固有の設定値 (環境ごとの当社の API キーなど) を使用する必要があります。

Twilio API は文字列識別子 (SID) を使用します。 SID の各タイプには、それに関連付けられた異なる 2 文字のプレフィックスがあり、その後に数字 0 ~ 9 と文字 A ~ F (大文字と小文字) で構成される 32 文字が続きます。

例:

  • ConferenceSid にはプレフィックス CF があり、CFabcdef0123456789abcdef0123456789 のようになります。
  • CallSid にはプレフィックス CA があり、CAabcdef0123456789abcdef0123456789 のようになります。
  • 他のタイプの SID があり、それらはすべて同じ形式を使用し、プレフィックスによってのみ区別されます

各 SID タイプの値オブジェクトが、渡された値にその SID タイプに適切なプレフィックスがあることを検証するとともに、文字列が正しい長さであり、許可されている文字のみで構成されていることを確認したかったのです。 .

値オブジェクト

私の各 SID タイプは同じ検証ロジックと機能を使用し、SID タイプのプレフィックスによってのみ区別されるため、基本特性を作成することは理にかなっています。必要に応じて、これを抽象クラスにすることもできます。アプリにはパラメータ型などとして TwilioStringIdentifier の概念は必要ないので、ここでは抽象クラスよりもトレイトを好みます。

この特性は、各 SID タイプが実装する必要がある抽象メソッド getPrefixForSidType() を定義し、その特定のタイプに適切なプレフィックスを提供します。また、検証ロジックも実行します。

namespace App\Domain\Model\Twilio\Sid;

use Assert\Assert;

trait TwilioStringIdentifier
{
    private readonly string $sid;

    abstract private function getPrefixForSidType(): string;

    public static function fromString(string $string): self
    {
        return new self($string);
    }

    public function __construct(string $sid)
    {
        Assert::that($sid)
            ->startsWith($this->getPrefixForSidType())
            ->length(34)
            ->regex('/^[a-zA-Z]{2}[0-9a-fA-F]{32}$/')
        ;

        $this->sid = $sid;
    }

    public function asString(): string
    {
        return $this->sid;
    }
}    

SID クラス

各 SID タイプを表す値オブジェクト クラスは単純です。必要なのは、TwilioStringIdentifier Trait を使用し、getPrefixForSidType() メソッドで適切なプレフィックスを定義することだけです。

namespace App\Domain\Model\Twilio\Sid;

final readonly class AccountSid
{
    use TwilioStringIdentifier;

    private function getPrefixForSidType(): string
    {
        return 'AC';
    }
}

他の SID タイプ クラスは、定義されたプレフィックスを除いて同一です。

インスタンス化されたオブジェクトの注入

これらの値オブジェクトはアプリケーション全体で使用され、会社のグローバル値だけでなく、さまざまな値が関連付けられて使用されるため、定義された値ですでにインスタンス化されている特定のタイプのオブジェクトをサービスに注入する方法が必要でした。 .env ファイル

Symfony には、Factory 経由でインスタンス化されるサービスを定義できる機能があることは知っていましたが、他の場所からのメソッド呼び出しの結果であるオブジェクトの注入については、実際に見たことがありませんでした (私の記憶では)。また、これらの Factory メソッドに引数を渡すことができることも知っていましたが、1 つの Value Object インスタンスでこれを行う方法がわかりませんでした。

特定の値のオブジェクトインスタンスの定義

Symfony のサービス定義では、各サービスに名前を付けることができます。通常、これは Service クラスの名前で行われます:

App\Path\To\My\Service:
    class: App\Path\To\My\Service
    arguments: []

ただし、そのサービス名はクラス名と一致する必要はありません。 app.my_service や FooBarBazService などです。

では、必要な値オブジェクトのインスタンス化されたインスタンスである一意の名前を持つサービスを作成したらどうなるでしょうか? .env 値を引数として渡して、そのオブジェクト インスタンスをサービス クラスに注入することができます!

サービス.yaml

# Create services named with a Global "namespace"
Global\Twilio\Sid\Account:
    factory: ['App\Domain\Model\Twilio\Sid\AccountSid', 'fromString']
    arguments: ['%env(TWILIO_ACCOUNT_SID)%']

Global\Twilio\Sid\Api:
    factory: ['App\Domain\Model\Twilio\Sid\ApiSid', 'fromString']
    arguments: ['%env(TWILIO_API_SID)%']

Global\Twilio\Sid\Application:
    factory: ['App\Domain\Model\Twilio\Sid\ApplicationSid', 'fromString']
    arguments: ['%env(TWILIO_APP_SID)%']

次に、それらのサービス (オブジェクト) を名前付き引数を介して Twilio サービスに渡します。

App\Service\Vendor\Twilio\TwilioService:
    arguments:
        $accountSid: '@Global\Twilio\Sid\Account'
        $apiSid: '@Global\Twilio\Sid\Api'
        $applicationSid: '@Global\Twilio\Sid\Application'
        $apiSecret: '%env(TWILIO_API_SECRET)%'

これで、私のサービス クラスは、完全にインスタンス化された値オブジェクト インスタンスを受け取ることができるようになりました。

Twilioサービス

namespace App\Service\Vendor\Twilio;

use App\Domain\Model\Twilio\Sid\AccountSid;
use App\Domain\Model\Twilio\Sid\ApiSid;
use App\Domain\Model\Twilio\Sid\ApplicationSid;

final readonly class TwilioService
{
    public function __construct(
        private AccountSid $accountSid,
        private ApiSid $apiSid,
        private ApplicationSid $applicationSid,
        private string $apiSecret
    ) {}
}

出来上がり!

symfony は十分に柔軟で直観的であるため、これを行う方法を理解するのは簡単でした。これを行うためのクイックリファレンスが他に見つからなかったので、Future Me や同様のことを行う必要がある他の人のためのリファレンスとしてこれを書き留めておこうと思いました

乾杯、コーディングを楽しんでください!

以上が自動接続された Symfony サービスに値オブジェクトを注入するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。