팀과 함께 Symfony 프로젝트를 진행하는 동안 내 서비스 중 하나에 특정 Value Object 인스턴스를 삽입해야 했습니다. 이 특별한 경우 값 자체는 .env 파일에 제공된 값에서 설정되어야 했습니다.
물론 문자열 값을 내 서비스에 직접 전달하고 서비스가 생성자에서 값 개체를 인스턴스화하도록 할 수 있지만 services.yaml 파일에서 이를 구성하고 삽입할 수 있는지 확인하고 싶었습니다. 대신 완전히 인스턴스화된 개체를 사용하세요. 이렇게 하면 해당 개체 인스턴스를 여러 서비스에 전달할 수 있으며 각 서비스 내에서 값 개체 생성을 반복할 필요가 없습니다.
내가 한 방법은 다음과 같습니다...
우리 애플리케이션은 Twilio SDK를 활용합니다. SDK 호출을 래핑하는 다양한 서비스가 있으며 환경별 구성 값(각 환경에 대한 회사의 API 키 등)을 사용해야 합니다.
Twilio API는 문자열 식별자(SID)를 사용합니다. 각 SID 유형에는 서로 다른 2자리 접두사가 연결되어 있으며 그 뒤에 숫자 0~9와 문자 A~F(대문자 및 소문자)로 구성된 32자가 이어집니다.
예를 들어:
각 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 유형을 나타내는 값 개체 클래스는 간단합니다. TwilioStringIdentifier 특성을 사용하고 getPrefixForSidType() 메서드를 통해 적절한 접두사를 정의하면 됩니다.
namespace App\Domain\Model\Twilio\Sid; final readonly class AccountSid { use TwilioStringIdentifier; private function getPrefixForSidType(): string { return 'AC'; } }
다른 SID 유형 클래스는 정의된 접두사를 제외하고 동일합니다.
이러한 값 개체는 우리 회사의 글로벌 가치뿐만 아니라 애플리케이션 전체와 관련된 다양한 값과 함께 사용되므로 정의된 값으로 이미 인스턴스화된 특정 유형의 개체를 서비스에 주입하는 방법이 필요했습니다. .env 파일에서
Symfony가 팩토리를 통해 인스턴스화할 서비스를 정의할 수 있다는 것을 알고 있었지만 다른 곳에서 메소드 호출의 결과인 객체를 주입하는 것에 대해 실제로 본 적이 없었습니다. 또한 이러한 Factory 메서드에 인수가 전달될 수 있다는 것도 알고 있었지만 하나의 Value Object 인스턴스로 이 작업을 수행하는 방법을 잘 몰랐습니다.
Symfony의 서비스 정의를 사용하면 각 서비스의 이름을 지정할 수 있습니다. 일반적으로 서비스 클래스 이름:
을 사용하여 수행됩니다.
App\Path\To\My\Service: class: App\Path\To\My\Service arguments: []
그러나 해당 서비스 이름이 클래스 이름과 일치할 필요는 없습니다. app.my_service 또는 Foo\Bar\Baz\Service 등이 될 수 있습니다.
그렇다면 필요한 값 개체의 인스턴스화된 인스턴스인 고유한 이름을 사용하여 서비스를 생성하면 어떻게 될까요? .env 값을 인수로 전달한 다음 해당 객체 인스턴스를 서비스 클래스에 삽입할 수 있습니다!
# 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)%'
이제 내 서비스 클래스는 완전히 인스턴스화된 값 개체 인스턴스를 수신할 것으로 예상됩니다.
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와 유사한 작업을 수행해야 하는 다른 사람을 위한 참조로 이 글을 작성해야 한다고 생각했습니다.
즐거운 코딩 되세요!
부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.
Copyright© 2022 湘ICP备2022001581号-3