Symfony HttpFoundation UploadedFile “not uploaded due to unknown error” when using Doctrine DataFixtures

♀尐吖头ヾ 提交于 2019-12-09 18:29:47

问题


I've been using my Attachment entity based on the cookbook recipie How To Handle File Uploads With Doctrine in Symfony 2.3.

It works well, even in functional tests. However using it with Doctrine DataFixtures is causing me problems.

[Symfony\Component\HttpFoundation\File\Exception\FileException]
The file "o-rly-copy.jpg" was not uploaded due to an unknown error.

This was not helpful, however I did run php app/console doctrine:fixtures:load -v to bring up a stack trace and it appears the exception is thrown not on the persisting method, but on $manager->flush()

Attachment::setFile() requires an instance of UploadedFile so I wonder if there is a way round that.

It appears the error occurs on line 225 of Symfony\Component\HttpFoundation\File\UploadedFile

return $this->test ? $isOk : $isOk && is_uploaded_file($this->getPathname())

The condition for is_uploaded_file() returns false because the file was already on the server.

<?php

/**
 * Prepopulate the database with image attachments.
 */
final class AttachmentFixtures extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
{
    private static $imageData = array(
        array(
            'name' => "O RLY?",
            'file' => "o-rly",
            'type' => "jpg",
        ),
        //...
    );

    public function getPathToImages()
    {
        return $this->container->get('kernel')->getRootDir() . '/../src/Acme/DemoBundle/Resources/public/default/images';
    }

    public function getPathToUploads()
    {
        return $this->container->get('kernel')->getRootDir() . '/../web/uploads/fixtures';
    }

    /**
     * {@inheritDoc}
     */
    public function load(ObjectManager $manager)
    {
        $imageReferences = array();
        $filesystem = $this->container->get('filesystem');

        foreach (self::$imageData as $image) {
            $imageFilename         = sprintf('%s.%s',      $image['file'], $image['type']);
            $copiedImageFilename   = sprintf('%s-copy.%s', $image['file'], $image['type']);

            $pathToImageFile = sprintf('%s/%s', $this->getPathToImages(), $imageFilename);

            try {
                $filesystem->copy($pathToImageFile, $pathToCopiedFile = sprintf('%s/%s', $this->getPathToUploads(), $copiedImageFilename));
                $filesystem->chmod($pathToCopiedFile, 0664);
            } catch (IOException $e) {
                $this->container->get('logger')->err("An error occurred while copying the file or changing permissions.");
            }

            $imageFile = new UploadedFile(
                $pathToCopiedFile,                                              // The full temporary path to the file
                $copiedImageFilename,                                           // The original file name
                'image/' . 'jpg' === $image['type'] ? 'jpeg' : $image['type'],  // Mime type - The type of the file as would be provided by PHP
                filesize($pathToCopiedFile),
                null,
                null,
                true
            );

            $imageAttachment = new Attachment();

            $imageAttachment->setName($image['name']);
            $imageAttachment->setFile($imageFile);

            // Populate a reference array for later use
            $imageReferences['attachment-'.$image['file']] = $imageAttachment;

            $manager->persist($imageAttachment);
        }

        $manager->flush(); // <-- Exception throw here


        // Create references for each image to be used by other entities that
        // maintain a relationship with that image.
        foreach ($imageReferences as $referenceName => $image) {
            $this->addReference($referenceName, $image);
        }
    }
}

回答1:


There is now a better solution:

The constructor of UploadedFile has a boolean $test parameter which disables the check using is_uploaded_file. This parameter has been added for testing/fixture code.

Just set it to true and the isValid() check of UploadedFile will not be a problem anymore.

Example:

// My data fixture code.
$test = true;
$userPhoto->setImageFile(new UploadedFile($photoDir . $photoFile, $photoFile, null, null, null, $test));



回答2:


Thanks to stof, the solution is to make Attachment::setFile() (or Document::setFile() if using the cookbook example) hint for an instance of UploadedFile's parent class, Symfony\Component\HttpFoundation\File\File, and in the fixtures class, create a new instance and pass it to the setFile method

Attachment.php

<?php

namespace Acme\DemoBundle\Entity;

use Symfony\Component\HttpFoundation\File\File;
//...

class Attachment
{
    /**
     * Sets file.
     *
     * @param File $file
     */
    public function setFile(File $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';
        }
    }

    //...
}

AttachmentFixtures.php

<?php

namespace Acme\DemoBundle\DataFixtures\ORM;

use Symfony\Component\HttpFoundation\File\File;
//...

class AttachmentFixtures //...
{
    //...

    public function load(ObjectManager $manager)
    {
        //...
        $imageFile = new File($pathToCopiedFile);

        $imageAttachment = new Attachment();

        $imageAttachment->setFile($imageFile);
        //...
    }
}


来源:https://stackoverflow.com/questions/18978295/symfony-httpfoundation-uploadedfile-not-uploaded-due-to-unknown-error-when-usi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!