如何在Symfony2 DataFixture中添加文件上传?

16
我似乎无法理解如何在DataFixture中添加文件上传。我正在尝试上传一个图片,用于我的fixture加载的虚拟内容。这似乎是一个有用的技能。

1
对于Symfony4.1 https://stackoverflow.com/a/53380949/624533 - Sudhakar Krishnan
4个回答

21
尽管这个问题在一年前就被提出了,但似乎关于如何通过doctrine数据fixture上传文件的信息并不多。我只找到了这篇文章。
我一直在寻找,并采取了与ornj略有不同的方法(可能与Symfony的更新有关)。
首先,我必须……
use Symfony\Component\HttpFoundation\File\UploadedFile;

然后使用copy()函数复制图片,因为ornj说它会移动。

copy($art1->getFixturesPath() . '01.jpg', $art1->getFixturesPath() . '01-copy.jpg');

然后使用以下命令创建并添加文件:

$file = new UploadedFile($art1->getFixturesPath() . '01-copy.jpg', 'Image1', null, null, null, true);

$art1->setFile($file);

$manager->persist($art1);

如果在“UploadedFile”构造函数中没有将最后一个参数设置为“true”,会在运行“doctrine:fixtures:load”时抛出未知错误。
这个参数是“测试模式是否激活”。既然它是fixture,将其设置为测试模式是有意义的。
方法“getFixturesPath()”只是检索存储示例图像的路径。
// Entity file
public function getFixturesPath()
{
    return $this->getAbsolutePath() . 'web/uploads/art/fixtures/';
}

''getAbsolutePath()''方法来自Doctrine文件上传

完整的可工作代码: 实体:

<?php
//src/User/MyBundle/Entity/Art.php

namespace User/MyBundle/Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * 
 * Art Entity
 * 
 * @ORM\Entity(repositoryClass="User\MyBundle\Entity\Repository\ArtRepository")
 * @ORM\Table(name="art")
 * @ORM\HasLifecycleCallbacks
 */
class Art
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(type="string", length=100)
     */
    protected $title;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    protected $path;

    /**
     * @Assert\File(maxSize="6000000")
     */
    private $file;

    private $temp;

    public function getAbsolutePath()
    {
        return null === $this->path ? null : $this->getUploadRootDir() . '/' . $this->path;
    }

    public function getWebPath()
    {
        return null === $this->path ? null : $this->getUploadDir() . '/' . $this->path;
    }

    protected function getUploadRootDir()
    {
        // the absolute directory path where uploaded
        // documents should be saved
        return __DIR__ . '/../../../../web/' . $this->getUploadDir();
    }

    protected function getUploadDir()
    {
        // get rid of the __DIR__ so it doesn't screw up
        // when displaying uploaded doc/image in the view.
        return 'uploads/art';
    }

    public function getFixturesPath()
    {
        return $this->getAbsolutePath() . 'web/uploads/art/fixtures/';
    }

    /**
     * Sets file.
     *
     * @param UploadedFile $file
     */
    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';
        }
    }

    /**
     * Get file.
     *
     * @return UploadedFile
     */
    public function getFile()
    {
        return $this->file;
    }

    /**
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function preUpload()
    {
        if (null !== $this->getFile()) {
            // do whatever you want to generate a unique filename
            $filename = sha1(uniqid(mt_rand(), true));
            $this->path = $filename . '.' . $this->getFile()->guessExtension();
        }
    }

    /**
     * @ORM\PostPersist()
     * @ORM\PostUpdate()
     */
    public function upload()
    {
        // the file property can be empty if the field is not required
        if (null === $this->getFile()) {
            return;
    }

        // if there is an error moving the file, an exception will
        // be automatically thrown by move(). This will properly prevent
        // the entity from being persisted to the database on error
        $this->getFile()->move($this->getUploadRootDir(), $this->path);

        // check if we have an old image
        if (isset($this->temp)) {
            // delete the old image
            unlink($this->getUploadRootDir() . '/' . $this->temp);
            // clear the temp image path
            $this->temp = null;
        }

        $this->file = null;
    }

    /**
     * @ORM\PostRemove()
     */
    public function removeUpload()
    {
        if ($file = $this->getAbsolutePath()) {
            unlink($file);
        }
    }
}

夹具:

<?php
// src/User/MyBundle/DataFixtures/ORM/ArtFixtures.php

namespace User\MyBundle\DataFixtures\ORM;

use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Fredzz\LotwBundle\Entity\Art;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class ArtFixtures extends AbstractFixture implements OrderedFixtureInterface
{
    public function load(ObjectManager $manager)
    {
        $art1 = new Art();
        $art1->setTitle('MyTitle');
        $art1->setDescription('My description');

        copy($art1->getFixturesPath() . '01.jpg', $art1->getFixturesPath() . '01-copy.jpg');
        $file = new UploadedFile($art1->getFixturesPath() . '01-copy.jpg', 'Image1', null, null, null, true);
        $art1->setFile($file);

        $art1->setUser($manager->merge($this->getReference('user-1')));

        $manager->persist($art1);
        $manager->flush();
    }
}

希望这能对某些人有所帮助!如果有错误请见谅,我还在学习中 :)

2
你在实体类中包含了太多的逻辑!所有这些助手方法(如获取绝对值、获取固定装置等)应该在某个助手服务中实现,或者在FixtureData类中实现。 - Almog Baku
1
这真的帮了我很多 - 最重要的技巧是将 UploadedFile 的 $testMode 设置为 true。 - Maerlyn

9

我已经找到了问题的答案。我需要使用类Symfony\Component\HttpFoundation\File\File来创建文件。Symfony会物理移动文件而不是创建副本,所以您需要为每个fixture拥有一个新文件,或者使用copy()创建可移动的文件副本。

$image = new Image();
$file = new File('path/to/file.jpg');
$image->file = $file;
$om->persist($image);

类似于这样的东西。


图片是我的实体,用于处理文件上传。请参考http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html。 - ornj
5
请使用UploadedFile代替File!一些bundles(例如VichUploader)会验证文件是否已上传...(实际上我花了一个小时才发现为什么VichUploader无法将我的fixture文件上传到gaufrette。) - Almog Baku
1
它不起作用。可行的解决方案在@Fred Duarte的答案中。 - ioleo

0

您想使用的图像应位于您的“Web”文件夹中,并且在您的数据夹具中只应使用文件指针字符串(即“/web/images/test.png”)。

通常应避免将图像存储在数据库中。


当然。我试图通过实体加载文件,并允许Doctrine管理该文件。使用这篇文章作为例子,我正在尝试在此基础上构建,以允许数据夹具上传临时文件。 - ornj

0

我为 PHP 5.3+ 创建了一个 FileUpload 类。

如何使用?

文档

来自 RFC 3023(XML 媒体类型):

顶级媒体类型“text”对 MIME 实体有一些限制,这些限制在 [RFC2045] 和 [RFC2046] 中描述。特别是,不允许使用 UTF-16 家族、UCS-4 和 UTF-32(除了使用类 MIME 机制的 HTTP[RFC2616])。

仅允许上传 yaml 文件:

<?php
$file = new FileUpload\FileUpload();
$file->setInput( "file" );
$FileUpload->setAllowedMimeTypes(array(
    "text/x-yaml", //RFC 3023
    "application/x-yaml", // Ruby on Rails
    "text/plain",//Possible option( only text plain )
    "text/yaml",//Possible option
    "text/x-yaml",//Possible option
    "application/yaml",//Possible option
));
$file->setDestinationDirectory("/var/www/html/myapp/");
$file->save();
if ($file->getStatus()) {
    echo "Okay";
}
?>

所有 MIME 类型的示例:

<?php
$file = new FileUpload\FileUpload();
$file->setInput( "file" );
$file->save();
if ($file->getStatus()) {
    echo "is Upload!";
}
?>
<html>
    <head>
        <title>FileUpload Example</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    </head>
    <body>
        <form method="post" action="" enctype="multipart/form-data">
            <input type="file" name="file" />
            <input type="submit" value="Upload now!" />
        </form>
    </body>
</html>

GitHub: https://github.com/olaferlandsen/FileUpload-for-PHP


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接