VichUploaderBundle:如何获取 DirectoryNamer 中的相关实体 ID?

VichUploaderBundle: How to get related entity ID in DirectoryNamer?

我正在配置一个 directory namer included in VichUploaderBundle 来上传多个文件。

我有两个实体 SoundtrackSongSong 的集合在我的控制器中是这样处理的:

//...
if ($form->isValid()) {
   $soundtrack->setSlug("sw-ep-vii");
   $soundtrack->setName("Star Wars Episode VII");
   foreach ($soundtrack->getSongs() as $song) {
      $em->persist($song);
   }
   $em->persist($soundtrack);
   $em->flush();
}

当坚持 $soundtrack VichUploaderBundle 上传 Song 文件并将它们移动到 config.yml 中定义的目录或在名为 [= 的服务中定义的动态路由19=],这是我感兴趣的。

在我的 SoundtrackDirectoryNamer 中,持续的 Song 实体自动传递给 directoryName() 方法,所以我只想 return 关联的 Soundtrack.id 作为目录名称如:

class SoundtrackDirectoryNamer implements DirectoryNamerInterface
{
    public function directoryName($song, PropertyMapping $mapping)
    {   
        return $song->getSoundtrack()->getId();                                                                                    
    }
}

现在的问题是 Soundtrack 仍然没有保存到数据库中,所以它还没有自动递增 id

如果我将 $song->getSoundtrack()->getId() 更改为 $song->getSoundtrack()->getSlug(),它会正确创建目录 sw-ep-vii,并且一切正常 - 因为我之前使用 $soundtrack->setSlug("sw-ep-vii") 在控制器中设置了 slug .

有什么解决方法吗?

我是该包的当前维护者。

这是一个已知问题(确切地说,不会修复)。

实际保存实体之前计算目录和文件名,因此对于新对象,标识符不可用。按照设计,没有任何办法可以避免这种情况……除非您不使用自动递增的标识符而是使用生成的标识符(例如 UUID 或 slugs)。

实际上有一个解决方案,即使它可能不是在所有情况下都完全可靠。这是一个与 MySQL 兼容的示例方法,您可以将其放入您的命名器 class 中以获取新实体的预期 ID(假定注入的实体管理器):

protected function getNextAutoIncrementedId($object) {
  $meta = $this->em->getClassMetadata(get_class($object));
  if(!$meta) return null;

  $conn = $this->em->getConnection();
  $table = $meta->getTableName();
  $sql = "SHOW TABLE STATUS WHERE `Name` = '$table'";
  $result = $conn->query($sql)->fetch(\PDO::FETCH_ASSOC);
  if(empty($result['Auto_increment'])) return null;

  return $result['Auto_increment'];
}