Salut J'ai une entité qui containt (OneToMany) Documentation. Dans Documentation j'ai un fichier, j'utilise vichuploader pour le télécharger mais j'ai un problème, quand enregistrer mon formulaire j'ai une erreur qui me dit que le nom du fichier est nul (erreur de doctrine). Est-il possible d'intégrer un champ vichuploader sur la collection de formulaires? Si quelqu'un a une idée :) j'ai poster mes fichiers Thank youSymfony vichuploader dans la collection de formulaires
product.php
class Product
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
* @Assert\Type(type="string")
* @Assert\NotBlank()
*/
private $name;
/**
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Documentation", mappedBy="product", cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=true)
* @Assert\Valid()
*/
private $documentations;
/**
* Constructor
*/
public function __construct()
{
$this->documentations = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
*
* @return Product
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Add documentation
*
* @param \AppBundle\Entity\Documentation $documentation
*
* @return Product
*/
public function addDocumentation(\AppBundle\Entity\Documentation $documentation)
{
$documentation->setProduct($this);
$this->documentations[] = $documentation;
return $this;
}
/**
* Remove documentation
*
* @param \AppBundle\Entity\Documentation $documentation
*/
public function removeDocumentation(\AppBundle\Entity\Documentation $documentation)
{
$this->documentations->removeElement($documentation);
}
/**
* Get documentations
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getDocumentations()
{
return $this->documentations;
}
}
Documentation.php
class Documentation
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Product", inversedBy="documentations")
*/
private $product;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
* @Assert\Type(type="string")
* @Assert\NotBlank()
*/
private $name;
/**
* @Vich\UploadableField(mapping="product_documentations", fileNameProperty="fileName")
* @Assert\NotBlank(message="Vous devez joindre un fichier", groups={"add"})
* @Assert\File(
* maxSize = "20M",
* maxSizeMessage = "Le fichier est trop gros, il doit faire {{ limit }} {{ suffix }}"
*)
*/
private $file;
/**
* @ORM\Column(type="string", length=255)
* @var string
*/
private $fileName;
/**
* @ORM\Column(name="updated_at", type="datetime")
* @var \DateTime $updatedAt
*/
private $updatedAt;
/**
* Get id
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Constructor
*/
public function __construct()
{
$this->groups = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Set name
*
* @param string $name
*
* @return Documentation
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param File|\Symfony\Component\HttpFoundation\File\UploadedFile $file
*
* @return Documentation
*/
public function setFile(File $file = null)
{
$this->file = $file;
if ($file) {
$this->updatedAt = new \DateTimeImmutable();
}
return $this;
}
/**
* @return File|null
*/
public function getFile()
{
return $this->file;
}
/**
* @param string $fileName
*
* @return Documentation
*/
public function setFileName($fileName)
{
$this->fileName = $fileName;
return $this;
}
/**
* @return string|null
*/
public function getFileName()
{
return $this->fileName;
}
/**
* Set updatedAt
*
* @param \DateTime $updatedAt
*
* @return Documentation
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* Get updatedAt
*
* @return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* Set product
*
* @param \AppBundle\Entity\Product $product
*
* @return Documentation
*/
public function setProduct(Product $product = null)
{
$this->product = $product;
return $this;
}
/**
* Get product
*
* @return \AppBundle\Entity\Product
*/
public function getProduct()
{
return $this->product;
}
}
DocumentationType.php
class DocumentationType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'name',
TextType::class,
array(
'attr' => array(
'placeholder' => 'Nom'
),
'label' => 'Nom :'
)
)
->add(
'file',
FileType::class,
array(
'attr' => array(
'placeholder' => 'Fichier'
),
'required' => false,
'label' => 'Fichier :'
)
)
;
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Documentation::class,
'attr' => array(
'novalidate' => 'novalidate'
)
));
}
}
ProductType.php
class ProductType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add(
'documentations',
CollectionType::class,
array(
'entry_type' => DocumentationType::class,
'by_reference' => false,
'allow_add' => true,
'allow_delete' => true,
'label' => 'Fichier(s) :',
'prototype' => true
)
)
;
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Product'
));
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_product';
}
}
new.html.twig
{% extends 'base.html.twig' %}
{% block body %}
<h1>Product creation</h1>
{{ form_start(form) }}
{{ form_row(form.name) }}
<a href="#" id="add_documentation" data-prototype-add="div#appbundle_product_documentations" class="btn btn-default btn-collection-add">
<span class="glyphicon glyphicon-plus"></span> Ajouter une documentation
</a>
{{ form_row(form.documentations) }}
<input type="submit" value="Create" />
{{ form_end(form) }}
<ul>
<li>
<a href="{{ path('product_index') }}">Back to the list</a>
</li>
</ul>
<script>
// On ajoute un nouveau champ à chaque clic sur le lien d'ajout.
$('.btn-collection-add').click(function (e) {
addDocumentation($($(this).data('prototype-add')));
e.preventDefault(); // évite qu'un # apparaisse dans l'URL
return false;
});
// La fonction qui ajoute un formulaire CategoryType
function addDocumentation($container) {
var index = $container.find(':input').length;
// Dans le contenu de l'attribut « data-prototype », on remplace :
// - le texte "__name__" qu'il contient par le numéro du champ
var template = $container.attr('data-prototype').replace(/__name__/g, index);
// On crée un objet jquery qui contient ce template
var $prototype = $(template);
// On ajoute le prototype modifié à la fin de la balise <div>
$container.append($prototype);
// Enfin, on incrémente le compteur pour que le prochain ajout se fasse avec un autre numéro
index++;
}
// Ajout du listener sur le clic du lien pour effectivement supprimer l'entrée de la collection.
$(document).on('click', '.btn-collection-delete', function (e) {
$(this).closest('.panel').remove();
e.preventDefault(); // évite qu'un # apparaisse dans l'URL
return false;
});
</script>
{% endblock %}
NewAction sur le contrôleur
public function newAction(Request $request)
{
$product = new Product();
$form = $this->createForm(
'AppBundle\Form\ProductType',
$product,
array(
'validation_groups' => array('add')
)
);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->redirectToRoute('product_show', array('id' => $product->getId()));
}
return $this->render('product/new.html.twig', array(
'product' => $product,
'form' => $form->createView(),
));
}
section Mon vich_uploader sur config.yml
vich_uploader:
db_driver: orm
mappings:
product_documentations:
uri_prefix: /products/documentations
upload_destination: '%kernel.root_dir%/../web/products/documentations'
inject_on_load: false
delete_on_update: true
delete_on_remove: true
Vous voulez donc télécharger le fichier et si l'utilisateur ne télécharge pas le fichier et ne soumet pas le formulaire que vous voulez afficher? Ai-je raison? – KondukterCRO
Salut, non, j'ai mon formulaire de produit qui intègre plusieurs formulaires de documentation. Je souhaite ajouter plusieurs formulaires de documentation avec le téléchargement. Mais quand je crée un produit avec le fichier de documentation et la forme valide j'ai une erreur: Une exception s'est produite pendant l'exécution de la documentation INSERT INTO (nom, nom_fichier, update_at, product_id) VALUES (?,?,?,?) 'Avec params [" tt ", null," 2017-09-07 09:22:05 ", 5]: SQLSTATE [23000]: Violation de la contrainte d'intégrité: 1048 La colonne 'nom_fichier' ne peut pas être nulle – eldiablo62
Je pense que le produit persiste vichuploader n'a pas fait le travail (ne pas télécharger, ne pas mettre le nom dans le nom de fichier) – eldiablo62