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);
}
}
}
There is now a better solution:
The constructor of
UploadedFile
has a boolean$test
parameter which disables the check usingis_uploaded_file
. This parameter has been added for testing/fixture code.Just set it to true and the
isValid()
check ofUploadedFile
will not be a problem anymore.Example:
Thanks to stof, the solution is to make
Attachment::setFile()
(orDocument::setFile()
if using the cookbook example) hint for an instance ofUploadedFile
's parent class,Symfony\Component\HttpFoundation\File\File
, and in the fixtures class, create a new instance and pass it to the setFile methodAttachment.php
AttachmentFixtures.php