在 Symfony 中为实体 属性 生成预签名 URL 的最佳方法

Best approach to generate presigned URL for entity property in Symfony

我有一个 User 对象,它有一个 profilePicturePresignedUrl 属性。 profilePicturePresignedUrl 的值 属性 需要使用服务计算。

看起来最有效的方法是在用户实体 class 中创建一个方法来注入所需的服务,如下所示:

Entity/User.php

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

public function getProfilePicturePresignedUrl(): string
{
    return $this->fileDownloader->generatePresignedUrl($this->profilePicturePath);
}

但是,我了解到在实体 classes 中注入服务被认为是不好的做法,并且在文档中找不到如何这样做的参考资料。

替代方案是在控制器中生成此值:

Controller/UserController.php

public function getUserInfo(FileDownloader $fileDownloader)
{
    $user = $this->getUser();
    
    $user->setProfilePicturePresignedUrl($fileDownloader->generatePresignedUrl($user->getProfilePicturePath()));

    return $this->createResponse($user);
}

但是,有许多调用 getUser 的控制器方法,在所有方法中复制此逻辑似乎不正确...在这种情况下注入生成预签名所需的服务是否有意义URL 在实体 class 中还是有更好的替代方法?

Doctrine 实体监听器

实体侦听器定义为 PHP classes,它们侦听单个实体 class 上的单个 Doctrine 事件。例如,假设您希望在从数据库加载特定实体时准备该实体。为此,为 postLoad Doctrine 事件定义一个侦听器。参见 documentation

这样,在您的情况下,每次您从数据库中获取用户实体时,属性 将被初始化并准备好在您的代码中的任何地方使用。请注意,我不建议将它用于繁重的任务,因为它会显着降低您的应用性能。

src/EventListener/UserListener.php

namespace App\EventListener;

use App\Entity\User;
use App\Service\FileDownloader;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\Event\LifecycleEventArgs;

class UserListener
{
  private $entityManager;
  private $fileDownloader;

  public function __construct(EntityManagerInterface $entityManager, FileDownloader $fileDownloader)
  {
    $this->entityManager = $entityManager;
    $this->fileDownloader = $fileDownloader; 
  }

  public function postLoad(User $user, LifecycleEventArgs $event): void
  {
    $path = $user->getProfilePicturePath();
    $url = $this->fileDownloader->generatePresignedUrl($path);
    $user->setProfilePicturePresignedUrl($url);
  }
}

config/services.yaml

services:
  App\EventListener\UserListener:
    tags:
      - {
          name: doctrine.orm.entity_listener,
          entity: 'App\Entity\User',
          event: "postLoad"
        }