使用Symfony Forms和Doctrine处理多个文件上传

时间:2014-10-22 20:08:39

标签: php symfony symfony-forms symfony-2.5

通过文档实现下载文件。但是当我决定使用' multiple'时,发出错误

"Catchable Fatal Error: Argument 1 passed to Kulabuhov\MainBundle\Entity\Photo::setFile() must be an instance of Symfony\Component\HttpFoundation\File\UploadedFile, array given," 

。我明白,而不是Object传递一个数组。但是如何实现多个文件上传而不破坏您在文档中写的任何内容?

$builder
            ->add('file','file',['multiple'=>true])
            ->add('article')
        ;

2 个答案:

答案 0 :(得分:2)

你提供了很少的代码,告诉你如何使用Doctrine跟踪文件上传功能,这将有所帮助,因为有十几种方法可以解决文件命名约定的执行方式,而且你甚至都没有显示你自己尝试修改你正在使用句柄多文件上传的实体,但我会给你一个机会。这假设您已经完成了所有指令。

当您按照说明操作时,您可能会创建一个setFile函数,如:

public function setFile(UploadedFile $file = null)
{
    $this->file = $file;
    // check if we have an old image path
    if (isset($this->path)) {
        // store the old name to delete after the update
        $this->temp = $this->path;
        $this->path = null;
    } else {
        $this->path = 'initial';
    }
}

但是,当然,您向UploadedFile函数提交了一个setFile对象数组,它与所需的UploadedFile参数不匹配。您也只为路径存储一个字符串,因此您也必须修复它。

首先,您应该将$path变量类型从string更改为某种类型的数组。假设您不需要与每个文件关联的大量数据,并且文件名中没有逗号,那么让我们坚持使用simple_array

/**
 * @ORM\Column(name="paths", type="simple_array")
 */
private $paths = array();

现在你需要为file属性声明一个数组:

/**
 * @Assert\File(maxSize="60000000")
 */
private $files = array();

现在你必须改变你的setFile函数来处理数组输入(让我们重命名为setFiles以保持一致性):

public function setFiles($files)
{
    $this->files = $files;
    // In this scenario, we'll delete the old batch of uploads, so store it in $temp
    if (!empty($this->paths)) {
        $this->temp = $this->getAbsolutePaths();
    }
    $this->paths = array();
}

getFiles

public function getFiles()
{
    return $this->files;
}

现在您的新upload()功能:

/**
 * @ORM\PostPersist()
 * @ORM\PostUpdate()
 */
public function upload()
{
    if (empty($this->files)) {
        return;
    }

    // Now we have to iterate through each file object
    foreach ($this->getFiles() as $file) {
        // Change $tempPath to whatever random filename strategy you use
        $tempPath = sha1(uniqid(mt_rand(), true)) . '.' . $file->guessExtension();
        $file->move(
            $this->getUploadRootDir(),
            $tempPath
        );
        // Now add it to the paths array
        $this->paths[] = $tempPath;
    }

    // Need to delete all of the old files
    foreach ($this->temp as $del) {
        if (is_file($del)) {
            unlink($del);
        }
    }

    // Reset the $files var
    $files = array();
}

然后删除,完全删除所有文件:

/**
 * @ORM\PostRemove()
 */
public function removeUpload()
{
    foreach ($this->getAbsolutePaths() as $path) {
        if (is_file($path)) {
            unlink($path);
        }
    }
}

当您使用该对象时,您现在正在处理一系列路径,因此您还必须更新Web和绝对路径函数:

public function getAbsolutePaths()
{
    $out = array();
    foreach ($this->getPaths() as $path) {
        $out[] = $this->getUploadRootDir().'/'.$this->path;
    }
    return $out;
}

public function getWebPath()
{
    $out = array();
    foreach ($this->getPaths() as $path) {
        $out[] = '/' . $this->getUploadDir() . '/' . $this->path;
    }
}

并且瞧......一旦您更新构建器以转到files而不是file,它应该能够正确处理多个文件上传。尽管上面的代码都是未经测试的,但这应该可以为您提供足够的工作。

答案 1 :(得分:0)

问题不在于您的表单,而在于您的模型。 setFile()上的Photo方法意味着接收UploadedFile,而不是数组。如果照片要包含多个文件,请将关系声明为OneToMany并实现接受数组的setFiles()函数:

protected $files;

function setFiles(array $files)
{
    $this->files = $files;

    return $this;
}