Symfony / Doctrine - 访问实体内的服务

问题描述 投票:0回答:4

我已经创建了一个加密服务并希望在实体内部访问它。 像这样:

public function setCompanyName(string $companyName, Encryption $encryption)
{
    $this->companyName = $encryption->encrypt($companyName);
}

但是,如果不调用带有两个参数的函数setCompanyName,是否可以做到这一点?我必须在函数内注入容器并调用服务吗?

symfony doctrine
4个回答
2
投票

您想将加密数据存储在数据库中吗?

最好的方法是创建事件侦听器,该侦听器将在每个实体保存时启动,并在那里进行加密(您可以注入任何您想要侦听器的内容) 第二个事件侦听器在从数据库加载数据进行解密时启动

如果你这样做正确,所有加密/解密的事情都将在代码中透明(它只存在于那些侦听器中)

看这个 https://symfony.com/doc/3.4/doctrine/event_listeners_subscribers.html http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html


1
投票

不可能在实体内部注入服务。 但是您可以使用实体侦听器来使用您的服务并在保留之前对公司名称进行加密。 看看 https://symfony.com/doc/current/bundles/DoctrineBundle/entity-listeners.html


0
投票

您可以使用 PostLoad 实体侦听器将服务注入到您的实体中。事实上,Doctrine Lazy Collections 包含许多服务,并在水合时注入到实体中。

但是,我认为这并不是 Doctrine 和 Symfony 开发人员想象的实体的工作方式。问题是它使您的实体变得非常庞大和复杂,这使得它们难以测试。

面向对象的最初想法是将数据与转换数据的所有逻辑封装起来,以确保数据永远不会以业务逻辑代码作者不希望的方式进行转换。这使得将所有业务逻辑添加为实体上的方法变得合理。

但是,大多数 Symfony 应用程序将其业务逻辑拆分为实体类和许多无状态服务。

尽管他们对这些服务使用“类”或“构造函数”等面向对象的术语,但这更接近函数式编程的思想——您可以将无状态服务视为一个闭包,它包含注入的依赖项。这使得无状态服务更容易测试:

无状态服务的方法的结果仅取决于您在构造函数中放入的内容以及在方法的参数中放入的内容。然而,调用方法的顺序永远不会改变方法的作用。

尽管如此,实体中的封装对于确保满足某些约束非常有用。这就是为什么大多数 Symfony 应用程序将无状态服务与面向对象的实体类混合在一起。但他们试图保持实体类小、轻量级且易于测试,因此他们不鼓励依赖实体中的其他服务 - 相反,您应该以相反的方式做,让您的服务依赖于实体类(“反转”)控制”)。

如果您确实想确保数据始终加密,您有以下选择:

  • 使用侦听器服务在保存数据库加载时加密和解密实体上的数据(如之前的答案中建议的那样)
  • 创建一个“EncryptedData”值对象,并将其声明为 setter 中的类型提示。 “EncryptedData”类包装您的加密数据,并且只能由加密服务创建,调用者在您的实体上设置数据之前必须使用该服务
  • 如果您使用 Psalm 或 PHPStan,您可以通过在其上方添加
    @psalm-internal Path\To\EncryptionService
    @phpstan-internal Path\To\EncryptionService
    注释来确保“EncryptedData”对象仅由该服务创建
  • 如果您不使用 Psalm 或 PHPStan,您可以将“EncryptedData”的构造函数设为私有,并在该类上创建一个静态“加密”方法,该方法采用加密服务作为参数,对数据进行加密并返回一个新实例本身与加密数据

对于加密数据,第一个选项可能是最合理的,但我想提供其他选项,以防人们遇到类似的情况,即在持久和加载时转换数据不太合理。


-1
投票

也许在 Encrypt 类中创建一个静态方法,并直接在实体中调用它?

class Encryption {
    public static function encrypt(string $string) {
        // your code
    }
}

public function setCompanyName(string $companyName) {
    $this->companyName = Encryption::encrypt($companyName);
}
© www.soinside.com 2019 - 2024. All rights reserved.