感谢您的关注,
我想在单个实体中管理我的所有上传(图像,PDF,视频等...),因此我使用实体继承来获取各种“类型”和OneToOne关系以将父实体与正确的上载链接起来。我没有找到任何捆绑来做这件事并面临问题:
而不是在每个表中有一个文件管理(这是安静的详细)我更喜欢只有一个表Uploads
来处理每个上传。然后我只需要做OneToOne关系来获取我的文件,加上使用继承我可以根据Image
或PDF
应用各种处理。
我至少有4个需要图像的实体,所以我认为1to1关系是一个不错的选择。
但我在做这样的事情时遇到了问题:
Constraints
没有考虑到$file
的版本应该设置$file->file
(它不会从Uploads
/ Image
发送实体,而是创建此实体的文件有没有人这样做过?我无法找到如何正确实现这一目标。
看看断言问题,我试图:
Image
上定义断言(这不像预期的那样工作,因为$file
的WithImage
形式目标)
使用注释@Assert\Image()
使用loadValidatorMetadata
使用注释@Assert\Callback()
'constraints' => array(new Assert\Image())
上定义断言,这可行,但需要在我使用它的任何地方定义...看着被误用的二传手我找到了一个解决方法,但这很安静丑陋:
public function setFile($file = null)
{
if ($file instanceof \Symfony\Component\HttpFoundation\File\UploadedFile) {
$tmpfile = new Image();
$tmpfile->setFile($file);
$file = $tmpfile;
}
$this->file = $file;
return $this;
}
(PS:我读过关于避免复制/粘贴代码的特性,我已经检查了SonataMediaBundle但这似乎不适用于我的情况)
所以我设计了我的课程如下:
Entity \ Uploads.php处理从上传到删除文件的所有生命(以及访问,移动,编辑,可能缩略图等...)
<?php
namespace Acme\CoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Acme\CoreBundle\Utils\UUID;
/**
* Uploads
*
* @ORM\Table(name="uploads")
* @ORM\Entity(repositoryClass="Acme\CoreBundle\Repository\UploadsRepository")
* @ORM\InheritanceType("SINGLE_TABLE")
* @ORM\DiscriminatorColumn(name="class", type="string")
* @ORM\DiscriminatorMap({"image" = "Image"})
* @ORM\HasLifecycleCallbacks
*/
abstract class Uploads
{
protected $file;
private $tempFileName;
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var \DateTime
*
* @ORM\Column(name="date", type="datetime")
*/
private $date;
/**
* @var string
*
* @ORM\Column(name="fileName", type="string", length=36, unique=true)
*/
private $fileName; // UUID
/**
* @var string
*
* @ORM\Column(name="extension", type="string", length=4)
*/
private $extension;
/**
* Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set date.
*
* @param \DateTime $date
*
* @return uploads
*/
public function setDate($date)
{
$this->date = $date;
return $this;
}
/**
* Get date.
*
* @return \DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* Set fileName.
*
* @param string $fileName
*
* @return uploads
*/
public function setFileName($fileName)
{
$this->fileName = $fileName;
return $this;
}
/**
* Get fileName.
*
* @return string
*/
public function getFileName()
{
return $this->fileName;
}
/**
* Set extension
*
* @param string $extension
*
* @return string
*/
public function setExtension($extension)
{
$this->extension = $extension;
return $this;
}
/**
* Get extension
*
* @return string
*/
public function getExtension()
{
return $this->extension;
}
public function getFileNameExt()
{
return $this->getFileName().'.'.$this->getExtension();
}
public function setFile(UploadedFile $file)
{
$this->file = $file;
if (null !== $this->getId()) {
$this->tempFileName = $this->getFileNameExt();
$this->fileName = null;
$this->extension = null;
}
}
public function getFile()
{
return $this->file;
}
/**
* @ORM\PrePersist()
* @ORM\PreUpdate()
*/
public function preUpload()
{
if (null === $this->file) {
return;
}
$this->extension = $this->file->guessExtension();
$this->fileName = UUID::v4();
$this->preUpdateFile();
}
protected function preUpdateFile(){} // To define if specific treatment
/**
* @ORM\PrePersist()
*/
public function prePersistDate()
{
$this->date = new \DateTime();
return $this;
}
/**
* @ORM\PostPersist()
* @ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->file) {
return;
}
if (null !== $this->tempFileName) {
$oldFile = $this->getUploadRootDir().$this->tempFileName;
if (file_exists($oldFile)) {
unlink($oldFile);
}
}
$this->file = $this->file->move(
$this->getUploadRootDir(),
$this->getFileNameExt()
);
$this->postUpdateFile();
}
protected function postUpdateFile(){} // To define if specific treatment
/**
* @ORM\PreRemove()
*/
public function preRemoveUpload()
{
// On sauvegarde temporairement le nom du fichier
$this->tempFileName = $this->getFileNameExt();
$this->preRemoveFile();
}
protected function preRemoveFile(){} // To define if specific treatment
/**
* @ORM\PostRemove()
*/
public function removeUpload()
{
$oldFile = $this->getUploadRootDir().$this->tempFileName;
if (file_exists($oldFile)) {
unlink($oldFile);
}
$this->postRemoveFile();
}
protected function postRemoveFile(){} // To define if specific treatment
public function getFileUri()
{
return $this->getUploadDir().$this->getFileNameExt();
}
public function getUploadDir()
{
return 'uploads/';
}
protected function getUploadRootDir()
{
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
public function __toString() {
return $this->getFileNameExt();
}
}
Entity \ Image.php具有自己的约束和文件管理的特定类型的上载
<?php
namespace Acme\CoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Image
*
* @ORM\Entity(repositoryClass="Acme\CoreBundle\Repository\ImageRepository")
*/
class Image extends Uploads
{
}
Entity \ WithImage.php需要Image
的实体
<?php
namespace Acme\CoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* WithImage
*
* @ORM\Table(name="with_image")
* @ORM\Entity(repositoryClass="Acme\CoreBundle\Repository\WithImageRepository")
*/
class WithImage
{
/**
* @ORM\OneToOne(targetEntity="Acme\CoreBundle\Entity\Image", cascade={"persist", "remove"})
*/
protected $file;
}
我想到了一些想法来帮助你实现你想要的。
首先,你必须在一个表单中上传文件,并且约束应该在一个实体的属性中(除非你想要在每个表单中编写约束的痛苦,这不是很难以实现)。因此,对于将要拥有文件的每个实体,定义文件属性(不是ORM anotated)并在那里编写约束。还要添加相应的getter和setter。
/**
* @var UploadedFile
* @Assert\NotBlank(groups={"New"})
* @Assert\File(mimeTypes={"text/html", "text/markdown", "text/plain"})
*/
private $file;
其次,您可能会问¿但是如何将它们保存到其他实体?这是我建议你使用Doctrine事件订阅者的时候。基本上,是一个使用doctrine.event_subscriber
标记定义的服务,该类实现了Doctrine\Common\EventSubscriber
接口。你可以订阅像preUpdate
,postLoad
这样的活动,以及有趣的你:prePersist
。
我对此的看法是你订阅了prePersist
事件。该事件将传递给您实体(我们创建的文件非orm属性,其中包含保存文件信息的UploadedFile
实例)。
然后,使用该文件的信息,创建一个新的上传实体,传递所需的所有信息,然后在真实文件orm映射属性中设置该属性,该属性保存与所需实体的文件关系。为此,如果我没记错的话,你必须启用持久级联。
这样做的好处:1。您可以在实体中定义约束。 2.您可以拥有所需的上传实体。
唯一的主要问题是您必须通过侦听器检索,存储和更新Uploads实体。但是我唯一能想到的就是帮助你。