It is a very common use case to upload a file along with other input data when dealing with Symfony forms. When you have a form that involves a one to many or many to many relationships, you may follow this example:
Prerequisites:
- How to implement Symfony forms with children forms (form collections)
- How to implement a many to many with Symfony form
- How to implement a Symfony form with a one to many shown in a dropdown
To allow users to upload a files in the previous example, we'll modify the AuthorType
form to include a FileType
field that will enable the uploading of files associated with each author. Additionally, we'll update the BookType
form to enable file uploads for each author. Let's assume we want to add a file upload field for the "avatar"
of each author.
Update the Author Entity:
Add a new property to the "Author"
entity to store the avatar image filename.
// src/Entity/Author.php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class Author
{
// ... other properties and annotations ...
/**
* @ORM\Column(type="string", nullable=true)
*/
private $avatarFilename;
// ... getters and setters ...
}
Update the AuthorType Form:
Update the "AuthorType"
form to include a FileType
field for the avatar upload.
// src/Form/AuthorType.php
namespace App\Form;
use App\Entity\Author;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AuthorType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class)
->add('avatar', FileType::class, [
'label' => 'Avatar (JPEG/PNG file)',
'required' => false,
'mapped' => false, // This is not a property of the Author entity
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Author::class,
]);
}
}
Update the BookType Form:
Update the "BookType"
form to allow multiple file uploads for each author.
// src/Form/BookType.php
namespace App\Form;
use App\Entity\Book;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class BookType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class)
->add('authors', CollectionType::class, [
'entry_type' => AuthorType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Book::class,
]);
}
}
Update the Twig Template:
Update the Twig template to include the file upload field for each author in the "authors" collection.
{# templates/book/create_book.html.twig #}
{% extends 'base.html.twig' %}
{% block content %}
<h1>Create Book</h1>
{{ form_start(form) }}
{{ form_row(form.title) }}
<h2>Authors</h2>
<ul id="authors-list">
{% for authorForm in form.authors %}
<li>
{{ form_row(authorForm.name) }}
{{ form_row(authorForm.avatar) }}
<a href="#" class="remove-author-link">Remove</a>
</li>
{% endfor %}
</ul>
<a href="#" id="add-author-link">Add Author</a>
<button type="submit">Create Book</button>
{{ form_end(form) }}
<script>
// JavaScript to handle adding and removing author forms
// (Same as the previous example)
</script>
{% endblock %}
Now, when you access the "/book/create"
or "/book/update/{id}"
route, the form will display a file upload field for each author in the "authors" collection.
Users can upload avatar images for each author along with other information about the book and its authors.