in a symfony2 application a entity Message has a one-to-many relation to documents. Documents represents user uploads. i created a form. I realized two Forms: MessageForm and DocumentForm. DocumentForm lives inside a collection FormField in MessageForm. Uploading and processing files does work.
But if i want to edit the entity Message the Form contains as many empty FileInputs as there are Documents existing. desired behaviour would be:
- FileInputs to upload new files
- Filename (link) to existing files
- Possibility to delete existing files
This should be handled inside the form. Changes should be done when the form is submitted.
How can this be realized?
Solution is to write a custom form type extension. as described on http://symfony.com/doc/2.1/cookbook/form/create_form_type_extension.html.
filetype extension
<?php
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* Class FileTypeExtension
*
* @see http://symfony.com/doc/2.1/cookbook/form/create_form_type_extension.html
*/
class FileTypeExtension extends AbstractTypeExtension
{
/**
* Returns the name of the type being extended.
*
* @return string The name of the type being extended
*/
public function getExtendedType()
{
return 'file';
}
/**
* Add the image_path option
*
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setOptional(array('file_path', 'file_name'));
}
/**
* Pass the image url to the view
*
* @param FormView $view
* @param FormInterface $form
* @param array $options
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
if (array_key_exists('file_path', $options)) {
$parentData = $form->getParent()->getData();
if (null !== $parentData) {
$propertyPath = new PropertyPath($options['file_path']);
$fileUrl = $propertyPath->getValue($parentData);
} else {
$fileUrl = null;
}
$view->set('file_url', $fileUrl);
}
if (array_key_exists('file_name', $options)) {
$parentData = $form->getParent()->getData();
if (null !== $parentData) {
$propertyPath = new PropertyPath($options['file_name']);
$fileName = $propertyPath->getValue($parentData);
} else {
$fileName = null;
}
$view->set('file_name', $fileName);
}
}
}
customized file_widget
{% block file_widget %}
{% spaceless %}
{% if file_url is not null %}
<div><a href="{{ file_url }}">{{ file_name }}</a></div>
<div style="display:none">{{ block('form_widget') }}</div>
{% else %}
{{ block('form_widget') }}
{% endif %}
{% endspaceless %}
{% endblock %}
services.yml
parameters:
foobar.file_type_extension.class: Foobar\Form\Extension\FileTypeExtension
services:
foobar.file_type_extension:
class: %replacethis.file_type_extension.class%
tags:
- { name: form.type_extension, alias: file }
inside a formtype
$builder->add('file','file', array(
"label" => "Datei",
"required" => true,
"attr" => array(),
"file_path" => "webPath",
"file_name" => "name"
));
that's it ;)
In addition to the above answere - wich will let you build a file input wich can be rendered as a link (if it has an url) or a field (if it doesn't) - you might take a look at
http://symfony.com/doc/2.0/cookbook/form/form_collections.html
Wich in conjunction with some jQuery will let you add fields in UI.