I'm building a complex file upload form. This form exists of normal data and a set of 4 filetypes with multiple file uploads possible per type.
The UploadedFile entity has a filename, description etc..
Use case: Now, I'm submitting the form with 4 Photos and 2 Reports, all 6 files are ok. But there are some other errors in the form. But I want to show the uploaded files again so that the user doesn't have to reupload them again. These files are already persisted, so when I come back to the same page with a GET, files are shown correctly.
What I already did/tried:
That's all working fine, BUT since I change my Report and Attachments AFTER the bind the data shown after a post can't be changed. I can't do setData($report) on a submitted form.
So existing files aren't show anymore as the form data is still the old report object (from the post).
When I do a normal GET of the page, the $report is retrieved from the database and is shown correctly. But after a POST with already uploaded files, the database data is correct but the form view doesn't know anything about changed data (after the bind).
Any ideas? Or a better way to do this?
I've made solution below. You can adapt it for your needs. But you need additional command that cleans up old files in uploads/tmp directory. And you need two parameters under parameters section in config:
parameters:
uploads_dir: %kernel.root_dir%/../web/uploads
uploads_tmp_dir: %uploads_dir%/tmp
The form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file',ImageFileType::TYPE_NAME,array(
'fileField' => 'file',
'pathField' => 'path',
'required' => false,
'label' => 'makeswapping.form.single_image',
'imgclass' => 'tumbnail imgbox full-width',
'constraints' => array(
new Assert\Image(array(
'minWidth' => '440'
))
)
));
$container = $this->container;
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (FormEvent $event) use ($container) {
$form = $event->getForm();
$data = $event->getData();
$uploadsTmpDir = $container->getParameter('uploads_tmp_dir');
if (isset($data['file'])) {
$filename = sprintf('%s.%s', uniqid('tmp_'), $data['file']->getClientOriginalExtension());
if (!file_exists($uploadsTmpDir)) {
mkdir($uploadsTmpDir, 0755, true);
}
copy($data['file']->getRealPath(), $uploadsTmpDir . '/' . $filename);
$form->add('file_hidden', 'hidden', array(
'mapped' => false,
'required' => false,
'empty_data' => $filename,
));
} else if (!isset($data['file']) && isset($data['file_hidden'])) {
$fileInfo = new \SplFileInfo($uploadsTmpDir . '/' . $data['file_hidden']);
$mimeTypeGuesser = MimeTypeGuesser::getInstance();
$uploadedFile = new UploadedFile(
$fileInfo->getRealPath(),
$fileInfo->getBasename(),
$mimeTypeGuesser->guess($fileInfo->getRealPath()),
$fileInfo->getSize(),
null,
true
);
$form->add('file_hidden', 'hidden', array(
'mapped' => false,
'required' => false,
'empty_data' => $data['file_hidden'],
));
$form->get('file')->setData($uploadedFile);
$data['file'] = $uploadedFile;
$event->setData($data);
}
}
);
}
Ok, after some days of trail and error I found a matching solution.
Here is what I did, in short.
In the UploadedFile entity I added 2 new fields: file and uniqueId. These fields aren't mapped in ORM as I only need them in the form.
When submitting the form I add newly uploaded file in a specific session var, and assign a unique id to them (because I need to be able to delete them and I needed an identifier). I also upload the files to their new location.
If the form is valid I add this collection I saved in the session to the entity that holds this collection.
If the form is invalid the files are shown because I retrieve this specific collection from the session. Even when I revisit the page with GET, all uploaded files are shown.
If I delete a file in the view I put a list of deleted unique id's in an input field. So after the submit I check which files I should delete from the array.
I think my answer is as unclear as my question :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With