Symfony2:使用 VichUploaderBundle 手动上传文件

Symfony2: manual file upload with 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(如上所示)。

简答:VichUploaderBundle不支持不使用 Symfony Form 组件上传文件。

I need to upload file from remote url. So I upload file to tmp direcotry (with curl) and then I keep trying to inject it to VichUploadBundle (as you can see above).

这样的话,你不需要上传,你需要下载。这不是 VichUploaderBundle 的本意。

接受的答案不正确(现在?)。根据 usage documentation 您确实可以手动上传 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: truepostLoad 事件期间更改 updatedAt 的问题。

问题说明

由于 VichUploader 映射 属性 不受 Doctrine ORM 监控,您将需要确保至少更改 ORM 管理的一个属性以触发 prePersistpreUpdate VichUploader 用于管理文件引用的事件。
这通常是通过在文件 setter 中使用 updatedAt DATETIME 列来完成的,但也可以是 ORM 管理的任何 属性。

postLoad 事件 setter File 实例问题

验证 UploadedFile 的实例提供给映射的 属性 setter 方法,将确保 updatedAt 被更改 在表单提交期间或手动提供时,而不是在 postLoad 事件期间 - 其中 VichUpload 将 File 的实例提供给相同的映射 setter 方法。如果在 Image 对象的实例由 Doctrine 加载并因此进行管理时调用 $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_OKis_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);

现在您可以成功持久化 and/or 使用手动上传的文件刷新您的实体。

$image = new Image();
$image->setImageFile($file);

$em->persist($image);
$em->flush();