如何在 Symfony 5 中使用 vich 上传器上传多个文件
How to upload multiple files with vich uploader in Symfony 5
在尝试使用 collectionType
的 formtype
中的 vichuploader
上传多个文件时给出的预期参数类型为“AppBundle\Entity\File”、“AppBundle\Entity”
我已经为一个非常有用的包 [VichUploader] 创建了一个解决方案,它缺少多个上传的功能,并且它适用于我在 [Symfony] 5.2 上创建的每个 Symfony 版本。
它在 OneToMany 关系上并且工作正常。所以我在我的自定义表单中使用了 CollectionType 和 [VichFileType] 并在我的控制器中使用了一些小技巧,这里是代码并查看所有项目,你可以在我的 GitHub
中找到它
[一个link]https://github.com/malek-laatiri
Admission.php
class Admission
{
/**
* @ORM\OneToMany(targetEntity=Diplome::class, mappedBy="admission")
*/
private $diplomes;
/**
* @return Collection|Diplome[]
*/
public function getDiplomes(): Collection
{
return $this->diplomes;
}
public function addDiplome(Diplome $diplome): self
{
if (!$this->diplomes->contains($diplome)) {
$this->diplomes[] = $diplome;
$diplome->setAdmission($this);
}
return $this;
}
public function removeDiplome(Diplome $diplome): self
{
if ($this->diplomes->removeElement($diplome)) {
// set the owning side to null (unless already changed)
if ($diplome->getAdmission() === $this) {
$diplome->setAdmission(null);
}
}
return $this;
}
}
Diplome.php
<?php
namespace App\Entity;
use App\Repository\DiplomeRepository;
use Doctrine\ORM\Mapping as ORM;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* @ORM\Entity(repositoryClass=DiplomeRepository::class)
* @Vich\Uploadable
*/
class Diplome
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity=Admission::class, inversedBy="diplomes",cascade={"persist","remove"})
*/
private $admission;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/**
* @Vich\UploadableField(mapping="product_image", fileNameProperty="name")
* @var File
*/
private $file;
public function getId(): ?int
{
return $this->id;
}
public function getAdmission(): ?Admission
{
return $this->admission;
}
public function setAdmission(?Admission $admission): self
{
$this->admission = $admission;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getFile()
{
return $this->file;
}
public function setFile( $file)
{
$this->file = $file;
return $this;
}
}
AdmissionType.php
<?php
namespace App\Form;
use App\Entity\Admission;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Vich\UploaderBundle\Form\Type\VichFileType;
class Admission1Type extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('diplomes', CollectionType::class, [
'entry_type' => DiplomeType::class,
'allow_add' => true,
'allow_delete' => true,
'required' => false,
'label'=>false,
'by_reference' => false,
'disabled' => false,
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Admission::class,
]);
}
}
DiplomeType.php
<?php
namespace App\Form;
use App\Entity\Diplome;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Vich\UploaderBundle\Form\Type\VichFileType;
class DiplomeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file',VichFileType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Diplome::class,
"allow_extra_fields" => true,
]);
}
}
_form.html.twig
<ul id="diplomes-fields-list"
data-prototype="{{ form_widget(form.diplomes.vars.prototype)|e }}"
data-widget-tags="{{ '<li></li>'|e }}"
data-widget-counter="{{ form.diplomes|length }}">
{% for emailField in form.diplomes %}
<li>
{{ form_errors(emailField) }}
{{ form_widget(emailField) }}
</li>
{% endfor %}
</ul>
<button type="button"
class="add-another-collection"
data-list-selector="#diplomes-fields-list">Add another email
</button>
script.js
jQuery(document).ready(function () {
jQuery('.add-another-collection').click(function (e) {
var list = $("#diplomes-fields-list");
var counter = list.data('widget-counter') | list.children().length;
var newWidget = list.attr('data-prototype');
newWidget = newWidget.replace(/__name__/g, counter);
counter++;
list.data('widget-counter', counter);
var newElem = jQuery(list.attr('data-widget-tags')).html(newWidget);
newElem.appendTo(list);
newElem.append('<a href="#" class="remove-tag" style="color: darkred">remove</a>');
$('.remove-tag').click(function(e) {
e.preventDefault();
$(this).parent().remove();
});
});
});
Controller.php
$admission = new Admission();
$form = $this->createForm(Admission1Type::class, $admission);
$form->handleRequest($request);
$entityManager = $this->getDoctrine()->getManager();
if ($form->isSubmitted() && $form->isValid()) {
foreach ($form->getData()->getNotes() as $dip){
$entityManager->persist($dip);
$admission->addNote($dip);
}
$entityManager->persist($admission);
$entityManager->flush();
在尝试使用 collectionType
的 formtype
中的 vichuploader
上传多个文件时给出的预期参数类型为“AppBundle\Entity\File”、“AppBundle\Entity”
我已经为一个非常有用的包 [VichUploader] 创建了一个解决方案,它缺少多个上传的功能,并且它适用于我在 [Symfony] 5.2 上创建的每个 Symfony 版本。
它在 OneToMany 关系上并且工作正常。所以我在我的自定义表单中使用了 CollectionType 和 [VichFileType] 并在我的控制器中使用了一些小技巧,这里是代码并查看所有项目,你可以在我的 GitHub
中找到它
[一个link]https://github.com/malek-laatiri
Admission.php
class Admission
{
/**
* @ORM\OneToMany(targetEntity=Diplome::class, mappedBy="admission")
*/
private $diplomes;
/**
* @return Collection|Diplome[]
*/
public function getDiplomes(): Collection
{
return $this->diplomes;
}
public function addDiplome(Diplome $diplome): self
{
if (!$this->diplomes->contains($diplome)) {
$this->diplomes[] = $diplome;
$diplome->setAdmission($this);
}
return $this;
}
public function removeDiplome(Diplome $diplome): self
{
if ($this->diplomes->removeElement($diplome)) {
// set the owning side to null (unless already changed)
if ($diplome->getAdmission() === $this) {
$diplome->setAdmission(null);
}
}
return $this;
}
}
Diplome.php
<?php
namespace App\Entity;
use App\Repository\DiplomeRepository;
use Doctrine\ORM\Mapping as ORM;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* @ORM\Entity(repositoryClass=DiplomeRepository::class)
* @Vich\Uploadable
*/
class Diplome
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity=Admission::class, inversedBy="diplomes",cascade={"persist","remove"})
*/
private $admission;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/**
* @Vich\UploadableField(mapping="product_image", fileNameProperty="name")
* @var File
*/
private $file;
public function getId(): ?int
{
return $this->id;
}
public function getAdmission(): ?Admission
{
return $this->admission;
}
public function setAdmission(?Admission $admission): self
{
$this->admission = $admission;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getFile()
{
return $this->file;
}
public function setFile( $file)
{
$this->file = $file;
return $this;
}
}
AdmissionType.php
<?php
namespace App\Form;
use App\Entity\Admission;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Vich\UploaderBundle\Form\Type\VichFileType;
class Admission1Type extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('diplomes', CollectionType::class, [
'entry_type' => DiplomeType::class,
'allow_add' => true,
'allow_delete' => true,
'required' => false,
'label'=>false,
'by_reference' => false,
'disabled' => false,
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Admission::class,
]);
}
}
DiplomeType.php
<?php
namespace App\Form;
use App\Entity\Diplome;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Vich\UploaderBundle\Form\Type\VichFileType;
class DiplomeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file',VichFileType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Diplome::class,
"allow_extra_fields" => true,
]);
}
}
_form.html.twig
<ul id="diplomes-fields-list"
data-prototype="{{ form_widget(form.diplomes.vars.prototype)|e }}"
data-widget-tags="{{ '<li></li>'|e }}"
data-widget-counter="{{ form.diplomes|length }}">
{% for emailField in form.diplomes %}
<li>
{{ form_errors(emailField) }}
{{ form_widget(emailField) }}
</li>
{% endfor %}
</ul>
<button type="button"
class="add-another-collection"
data-list-selector="#diplomes-fields-list">Add another email
</button>
script.js
jQuery(document).ready(function () {
jQuery('.add-another-collection').click(function (e) {
var list = $("#diplomes-fields-list");
var counter = list.data('widget-counter') | list.children().length;
var newWidget = list.attr('data-prototype');
newWidget = newWidget.replace(/__name__/g, counter);
counter++;
list.data('widget-counter', counter);
var newElem = jQuery(list.attr('data-widget-tags')).html(newWidget);
newElem.appendTo(list);
newElem.append('<a href="#" class="remove-tag" style="color: darkred">remove</a>');
$('.remove-tag').click(function(e) {
e.preventDefault();
$(this).parent().remove();
});
});
});
Controller.php
$admission = new Admission();
$form = $this->createForm(Admission1Type::class, $admission);
$form->handleRequest($request);
$entityManager = $this->getDoctrine()->getManager();
if ($form->isSubmitted() && $form->isValid()) {
foreach ($form->getData()->getNotes() as $dip){
$entityManager->persist($dip);
$admission->addNote($dip);
}
$entityManager->persist($admission);
$entityManager->flush();