Symfony2:使用 VichUploaderBundle 手动上传文件
如何在没有表单的情况下使用 VichUploaderBundle 上传文件?
我的某个目录中有文件(例如
web/media/tmp/temp_file.jpg
)
如果我尝试此操作:
$file = new UploadedFile($path, $filename);
$image = new Image();
$image->setImageFile($file);
$em->persist($image);
$em->flush();
我收到此错误:
The file "temp_file.jpg" was not uploaded due to an unknown error.
我需要从远程 URL 上传文件。因此,我将文件上传到
tmp
目录(使用 curl),然后我继续尝试将其注入 VichUploadBundle(如上所示)。
接受的答案不再正确?。根据
使用文档
您确实可以手动上传
File
,而无需使用 Symfony 的表单组件:
/**
* If manually uploading a file (i.e. not using Symfony Form) ensure an instance
* of 'UploadedFile' is injected into this setter to trigger the update. If this
* bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
* must be able to accept an instance of 'File' as the bundle will inject one here
* during Doctrine hydration.
*
* @param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
*/
public function setImageFile(File $image = null)
{
$this->imageFile = $image;
if ($image) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->updatedAt = new \DateTime('now');
}
}
您应该使用
Symfony\Component\HttpFoundation\File\UploadedFile
而不是
File
:
$file = new UploadedFile($filename, $filename, null, filesize($filename), false, true);
VichUploaderBundle
将处理此对象。
要结合答案并解决 VichUploader 和
inject_on_load: true
在
postLoad
事件期间更改
updatedAt
的问题。
问题解释
由于 VichUploader 映射属性不受 Doctrine ORM 监控,您需要确保 ORM 管理的至少一个属性已更改以触发 VichUploader 用于管理文件引用的
prePersist
或
preUpdate
事件。
这通常是通过在文件设置器中使用
updatedAt
DATETIME 列来完成的,但可以是任何由 ORM 管理的属性。
postLoad
事件设置器
File
实例问题
验证
UploadedFile
的实例是否提供给映射的属性设置器方法,将确保
updatedAt
仅
在
表单提交期间或手动提供时更改,而不是在
postLoad
事件期间更改 - 其中 VichUpload 向相同的映射 setter 方法提供
File
的实例。否则,当 Doctrine 加载并管理
Image
对象的实例时,如果您调用
$em::flush()
,则会导致视图中的
updatedAt
值发生更改,并可能更改数据库值。
App\Entity\Image
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* @ORM\Entity
* @Vich\Uploadable
*/
class Image
{
/**
* @var \DateTime
* @ORM\Column(name="updated_at", type="datetime")
*/
private $updatedAt;
/**
* @var \Symfony\Component\HttpFoundation\File\File
* @Vich\UploadableField(mapping="your_mapping", fileNameProperty="image")
*/
private $imageFile;
/**
* @var string|null
* @ORM\Column(name="image", type="string", length=255, nullable=true)
*/
private $image;
public function __construct()
{
$this->updatedAt = new \DateTime('now');
}
//...
public function setImageFile(File $image = null)
{
$this->imageFile = $image;
if ($image instanceof UploadedFile) {
$this->updatedAt = new \DateTime('now');
}
}
}
然后,您可以通过实例化
UploadedFile
对象并将
error
参数设置为
null
并将
test
参数设置为
true
来手动定义要在实体中使用的文件,这将禁用验证
UPLOAD_ERR_OK
和
is_uploaded_file()
[sic]
.
Symfony <= 4.0
use Symfony\Component\HttpFoundation\File\UploadedFile;
$file = new UploadedFile($path, $filename, null, filesize($path), null, true);
Symfony 4.1+
在 Symfony 4.1 及更高版本中,文件大小参数已被弃用。
use Symfony\Component\HttpFoundation\File\UploadedFile;
$file = new UploadedFile($path, $filename, null, null, true);
现在,您可以使用手动上传的文件成功保留和/或刷新您的实体。
$image = new Image();
$image->setImageFile($file);
$em->persist($image);
$em->flush();