”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 将值对象注入到自动装配的 Symfony 服务中

将值对象注入到自动装配的 Symfony 服务中

发布于2024-08-16
浏览:725

Inject Value Objects Into An Autowired Symfony Service

与我的团队一起开发 Symfony 项目时,我需要将特定的值对象实例注入到我的一项服务中。在这种特殊情况下,值本身需要根据 .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 类型的前缀进行区分,因此创建基本 Trait 是有意义的。如果您愿意,这可以是一个抽象类。我不需要应用程序中的 TwilioStringIdentifier 概念作为参数类型或类似的东西,所以我在这里更喜欢 Trait 而不是 Abstract Class。

此 Trait 确实定义了每个 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 能够定义通过工厂实例化的服务,但从未真正见过(我记得)任何关于注入一个对象的内容,该对象是从其他地方调用方法的结果。我还知道这些工厂方法可以将参数传递给它们,我只是不确定如何使用一个值对象实例来执行此操作。

定义特定值对象实例

Symfony 的服务定义允许您命名每个服务。通常它是通过服务类的名称完成的:

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

但是,该服务名称不必与类名称匹配。它可以是 app.my_service 或 Foo\Bar\Baz\Service 或其他。

那么,如果我创建一个具有唯一名称的服务,该名称是我需要的值对象的实例化实例,该怎么办?我可以将 .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 足够灵活且足够直观,很容易弄清楚如何做到这一点。由于我在其他地方找不到执行此操作的快速参考,因此我想我应该将其写下来作为未来我和其他可能需要执行类似操作的人的参考

干杯,祝编码愉快!

版本声明 本文转载于:https://dev.to/mbadolato/inject-value-objects-into-an-autowired-symfony-service-3an2?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 在 Laravel 中测试排队作业的技巧
    在 Laravel 中测试排队作业的技巧
    使用 Laravel 应用程序时,经常会遇到命令需要执行昂贵任务的情况。为了避免阻塞主进程,您可能决定将任务卸载到可以由队列处理的作业。 让我们看一个例子。想象一下命令 app:import-users 需要读取一个大的 CSV 文件并为每个条目创建一个用户。该命令可能如下所示: /* Import...
    编程 发布于2024-11-05
  • 如何创建人类水平的自然语言理解 (NLU) 系统
    如何创建人类水平的自然语言理解 (NLU) 系统
    Scope: Creating an NLU system that fully understands and processes human languages in a wide range of contexts, from conversations to literature. ...
    编程 发布于2024-11-05
  • 如何使用 JSTL 迭代 HashMap 中的 ArrayList?
    如何使用 JSTL 迭代 HashMap 中的 ArrayList?
    使用 JSTL 迭代 HashMap 中的 ArrayList在 Web 开发中,JSTL(JavaServer Pages 标准标记库)提供了一组标记来简化 JSP 中的常见任务( Java 服务器页面)。其中一项任务是迭代数据结构。要迭代 HashMap 及其中包含的 ArrayList,可以使...
    编程 发布于2024-11-05
  • Encore.ts — 比 ElysiaJS 和 Hono 更快
    Encore.ts — 比 ElysiaJS 和 Hono 更快
    几个月前,我们发布了 Encore.ts — TypeScript 的开源后端框架。 由于已经有很多框架,我们想分享我们做出的一些不常见的设计决策以及它们如何带来卓越的性能数据。 性能基准 我们之前发布的基准测试显示 Encore.ts 比 Express 快 9 倍,比 Fasti...
    编程 发布于2024-11-05
  • 为什么使用 + 对字符串文字进行字符串连接失败?
    为什么使用 + 对字符串文字进行字符串连接失败?
    连接字符串文字与字符串在 C 中,运算符可用于连接字符串和字符串文字。但是,此功能存在限制,可能会导致混乱。在问题中,作者尝试连接字符串文字“Hello”、“,world”和“!”以两种不同的方式。第一个例子:const string hello = "Hello"; const...
    编程 发布于2024-11-05
  • React 重新渲染:最佳性能的最佳实践
    React 重新渲染:最佳性能的最佳实践
    React高效的渲染机制是其受欢迎的关键原因之一。然而,随着应用程序复杂性的增加,管理组件重新渲染对于优化性能变得至关重要。让我们探索优化 React 渲染行为并避免不必要的重新渲染的最佳实践。 1. 使用 React.memo() 作为函数式组件 React.memo() 是一个高...
    编程 发布于2024-11-05
  • 如何实现条件列创建:探索 Pandas DataFrame 中的 If-Elif-Else?
    如何实现条件列创建:探索 Pandas DataFrame 中的 If-Elif-Else?
    Creating a Conditional Column: If-Elif-Else in Pandas给定的问题要求将新列添加到 DataFrame 中基于一系列条件标准。挑战在于在实现这些条件的同时保持代码效率和可读性。使用函数应用程序的解决方案一种方法涉及创建一个将每一行映射到所需结果的函数...
    编程 发布于2024-11-05
  • 介绍邱!
    介绍邱!
    我很高兴地宣布发布 Qiu – 一个严肃的 SQL 查询运行器,旨在让原始 SQL 再次变得有趣。老实说,ORM 有其用武之地,但当您只想编写简单的 SQL 时,它们可能会有点让人不知所措。我一直很喜欢编写原始 SQL 查询,但我意识到我需要练习——大量的练习。这就是Qiu发挥作用的地方。 有了 Q...
    编程 发布于2024-11-05
  • 为什么 CSS 中的 Margin-Top 百分比是根据容器宽度计算的?
    为什么 CSS 中的 Margin-Top 百分比是根据容器宽度计算的?
    CSS 中的 margin-top 百分比计算当对元素应用 margin-top 百分比时,必须了解计算方式执行。与普遍的看法相反,边距顶部百分比是根据包含块的宽度而不是其高度来确定的。W3C 规范解释:根据W3C 规范,“百分比是根据生成的框包含块的宽度计算的。”此规则适用于“margin-top...
    编程 发布于2024-11-05
  • 如何解决 CSS 转换期间 Webkit 文本渲染不一致的问题?
    如何解决 CSS 转换期间 Webkit 文本渲染不一致的问题?
    解决 CSS 转换期间的 Webkit 文本渲染不一致在 CSS 转换期间,特别是缩放元素时,Webkit 中可能会出现文本渲染不一致的情况浏览器。这个问题源于浏览器尝试优化渲染性能。一种解决方案是通过添加以下属性来强制对过渡元素的父元素进行硬件加速:-webkit-transform: trans...
    编程 发布于2024-11-05
  • 使用 Reactables 简化 RxJS
    使用 Reactables 简化 RxJS
    介绍 RxJS 是一个功能强大的库,但众所周知,它的学习曲线很陡峭。 该库庞大的 API 界面,再加上向反应式编程的范式转变,可能会让新手不知所措。 我创建了 Reactables API 来简化 RxJS 的使用并简化开发人员对反应式编程的介绍。 例子 我们将构建...
    编程 发布于2024-11-05
  • 如何在 Pandas 中查找多列的最大值?
    如何在 Pandas 中查找多列的最大值?
    查找 Pandas 中多列的最大值要确定 pandas DataFrame 中多列的最大值,可以采用多种方法。以下是实现此目的的方法:对指定列使用 max() 函数此方法涉及显式选择所需的列并应用 max() 函数: df[["A", "B"]] df[[&q...
    编程 发布于2024-11-05
  • CI/CD 入门:自动化第一个管道的初学者指南(使用 Jenkins)
    CI/CD 入门:自动化第一个管道的初学者指南(使用 Jenkins)
    目录 介绍 什么是 CI/CD? 持续集成(CI) 持续交付(CD) 持续部署 CI/CD 的好处 更快的上市时间 提高代码质量 高效协作 提高自动化程度和一致性 如何创建您的第一个 CI/CD 管道 第 1 步:设置版本控制 (GitHub) 第 2 步:选择 CI/CD 工具 ...
    编程 发布于2024-11-05
  • TypeScript 如何使 JavaScript 在大型项目中更加可靠。
    TypeScript 如何使 JavaScript 在大型项目中更加可靠。
    介绍 JavaScript 广泛应用于 Web 开发,现在也被应用于不同行业的大型项目中。然而,随着这些项目的增长,管理 JavaScript 代码变得更加困难。数据类型不匹配、运行时意外错误以及代码不清晰等问题可能会导致查找和修复错误变得困难。 这就是TypeScript介入的地...
    编程 发布于2024-11-05
  • 如何使用PHP的password_verify函数安全地验证用户密码?
    如何使用PHP的password_verify函数安全地验证用户密码?
    使用 PHP 解密加密密码许多应用程序使用密码哈希等加密算法安全地存储用户密码。然而,在验证登录尝试时,将输入密码与加密的存储版本进行比较非常重要。加密问题password_hash 使用 Bcrypt,一种一元加密算法方式哈希算法,意味着加密的密码无法逆转或解密。这是一项安全功能,可确保即使数据库...
    编程 发布于2024-11-05

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3