Symfony form collection custom prototype - symfony

I have a problem with form collection on symfony.
I have 3 entities Article, AdditionnalFile, AdditionnalInformation
Article entity
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Category", inversedBy="articles")
* #ORM\JoinColumn(nullable=false)
* #Gedmo\Versioned
*/
private $category;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\AdditionnalInformation", mappedBy="article", cascade={"persist", "remove"})
* #ORM\JoinColumn(nullable=true)
*/
private $additionnalInformations;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\AdditionnalFile", mappedBy="article", cascade={"persist", "remove"})
* #ORM\JoinColumn(nullable=true)
*/
private $additionnalFiles;
AdditionnalInformation entity
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Article", inversedBy="additionnalInformations")
*/
private $article;
/**
* #ORM\ManyToMany(targetEntity="UserLdapBundle\Entity\Group", inversedBy="additionnalInformations")
* #ORM\JoinColumn(nullable=false)
*
* #Assert\Count(
* min = 1,
* max = 5,
* minMessage = "Il faut au minimum 1 groupe autorisé",
* maxMessage = "Il faut au maximum {{ limit }} groupe autorisé"
* )
*/
private $groups;
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255)
* #Gedmo\Versioned
* #Assert\Type(type="string")
* #Assert\NotBlank()
*/
private $title;
/**
* #var string
*
* #ORM\Column(name="text", type="text")
* #Gedmo\Versioned
* #Assert\Type(type="string")
* #Assert\NotBlank()
*/
private $text;
I don't give the last entity because it's not important
I have create a form type for AdditionnalFile
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'title',
TextType::class,
array(
'attr' => array(
'placeholder' => 'Titre'
),
'label' => 'Titre :'
)
)
->add(
'text',
TextareaType::class,
array(
'attr' => array(
'placeholder' => 'Texte'
),
'label' => 'Texte :'
)
)
->add(
'groups',
EntityType::class,
array(
'attr' => array(
'placeholder' => 'Droits'
),
'class' => 'UserLdapBundle:Group',
'choice_label' => 'name',
'expanded' => true,
'multiple' => true,
'label' => 'Accessible pour :'
)
);
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => AdditionnalInformation::class,
));
}
And I have create my article formtype who "embed" my additionnalInformationType
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'title',
TextType::class,
array(
'attr' => array(
'placeholder' => 'Titre'
),
'label' => 'Titre :'
)
)
->add(
'category',
EntityType::class,
array(
'attr' => array(
'placeholder' => 'Catégorie'
),
'class' => 'AppBundle\Entity\Category',
'choice_value' => 'id',
'choice_label' => 'name',
'multiple' => false,
'label' => 'Catégorie :'
)
)
->add(
'text',
TextareaType::class,
array(
'attr' => array(
'placeholder' => 'Texte',
'class' => 'tinymce'
),
'label' => 'Texte :',
'required' => false
)
)
->add(
'tags',
TextType::class,
array(
'attr' => array(
'placeholder' => 'Tags'
),
'label' => 'Tags :'
)
)
->add(
'ticketNumber',
TextType::class,
array(
'attr' => array(
'placeholder' => 'Numéro de ticket, 301, 302,'
),
'label' => 'Numéro(s) de ticket :',
'required' => false
)
)
->add(
'groups',
EntityType::class,
array(
'attr' => array(
'placeholder' => 'Droits'
),
'class' => 'UserLdapBundle:Group',
'choice_label' => 'name',
'expanded' => true,
'multiple' => true,
'label' => 'Accessible pour :'
)
)
->add(
'additionnalInformations',
CollectionType::class,
array(
'entry_type' => AdditionnalInformationType::class,
'allow_add' => true,
'label' => 'Information(s) additionnel(s) :',
'prototype' => true
)
)
->add(
'additionnalFiles',
CollectionType::class,
array(
'entry_type' => AdditionnalFileType::class,
'allow_add' => true,
'label' => 'Fichier(s) :',
'prototype' => true
)
)
->add(
'save',
SubmitType::class,
array(
'label' => 'Sauvegarder',
'attr' => array(
'class' => 'btn-primary'
)
)
);
But now i have some question... :)
How can i custom the prototype? i want to use a bootstrap panel and put the additionnalInformation form inside.
And duplicate this for add other AdditionnalInformation
Is that possible ?

Here is a working example which I have used:
{% block _article_additionnalInformations_entry_row %}
<br>
<div class="panel panel-primary">
<div class="panel-heading">Information supplémentaire
<a href="#" class="btn btn-xs btn-danger pull-right">
<span class="glyphicon glyphicon-remove confirmation-suppression"></span>
</a>
</div>
<div class="panel-body">
<div class="row">
<div class="col-lg-8">
{{ form_row(form.title) }}
{{ form_row(form.text) }}
</div>
<div class="col-lg-4">
{{ form_row(form.groups) }}
</div>
</div>
</div>
</div>
{% endblock %}

You should try to write a custom twig theme. You can find more information on this page.
You can for example try to put this code in your template (where you render your form):
{% form_theme form _self %}
{% block _additionnalFiles_entry_widget %}
<tr>
<td>{{ form_widget(form.task) }}</td>
<td>{{ form_widget(form.dueDate) }}</td>
</tr>
{% endblock %}
Just make sure to use the right block name. You can do that by understanding how form fragment are named or just inspect a {{ dump(form) }} in your template.

Related

Query QueryBuilder with NOT IN and usage in controller

After several weeks of research, I turn to you to try to understand the QueryBuilder part and implement it on my application.
Concretely, here is what I would like to do:
Depending on the agent(s) chosen by the user, display targets with the same nationality.
My agent entity and my target entity each have a nationality. They are both connected thanks to Doctrine on my Mission entity.
I think I should use NOT IN in my request but don't know how to do it. I show you what I did without results.
/**
* Récupère les nationalités de l'agent
*/
public function findNationality()
{
$this
->createQueryBuilder ('m')
->select ('*')
->join('m.agents', 'a')
->join('m.cibles', 'c')
->where('a.nationality = c.nationality')
->getQuery()
->getResult();
}
My MissionType
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('title')
->add('description')
->add('code_name')
->add('country')
->add('speciality', EntityType::class, [
'label' => 'Choisir une spécialité: ',
'placeholder' => 'Choisir une spécialité',
'class' => Specialite::class,
'choice_label' => 'name'
])
->add('agents', EntityType::class, [
'label' => 'Choisir un ou des agent(s): ',
'class' => Agent::class,
'choice_label' => 'identification_code',
'multiple' => true,
'expanded' => true
])
->add('contacts', EntityType::class, [
'label' => 'Selectionner le(les) contact(s): ',
'class' => Contact::class,
'choice_label' => 'code_name',
'multiple' => true,
'expanded' => true
])
->add('cibles', EntityType::class, [
'label' => 'Selectionner la(les) cible(s): ',
'class' => Cible::class,
'choice_label' => 'code_name',
'multiple' => true,
'expanded' => true
])
->add('planques', EntityType::class, [
'label' => 'Selectionner la(les) planque(s): ',
'class' => Planque::class,
'choice_label' => 'code',
'multiple' => true,
'expanded' => true,
])
->add('start_date', DateType::class, [
'widget' => 'single_text'
])
->add('end_date', DateType::class, [
'widget' => 'single_text'
])
->add('status', EntityType::class, [
'label' => 'Statut de la Mission: ',
'class' => Status::class,
'choice_label' => 'name'
])
->add('type', EntityType::class, [
'label' => 'Type de Mission: ',
'class' => TypeMission::class,
'choice_label' => 'name'
]);
}
My Mission Entity
class Mission
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $title;
/**
* #ORM\Column(type="text")
*/
private $description;
/**
* #ORM\Column(type="string", length=255)
*/
private $code_name;
/**
* #ORM\Column(type="string", length=255)
*/
private $country;
/**
* #ORM\Column(type="date")
*/
private $start_date;
/**
* #ORM\Column(type="date")
*/
private $end_date;
/**
* #ORM\OneToMany(targetEntity=Agent::class, mappedBy="mission", cascade={"persist", "merge"})
*/
private $agents;
/**
* #ORM\OneToMany(targetEntity=Cible::class, mappedBy="mission", cascade={"persist", "merge"})
*/
private $cibles;
/**
* #ORM\OneToMany(targetEntity=Contact::class, mappedBy="mission", cascade={"persist", "merge"})
*/
private $contacts;
/**
* #ORM\OneToMany(targetEntity=Planque::class, mappedBy="mission", cascade={"persist", "merge"})
*/
private $planques;
/**
* #ORM\ManyToOne(targetEntity=Specialite::class, inversedBy="missions", cascade={"persist", "merge"})
*/
private $speciality;
/**
* #ORM\ManyToOne(targetEntity=Status::class, inversedBy="missions", cascade={"persist", "merge"})
*/
private $status;
/**
* #ORM\ManyToOne(targetEntity=TypeMission::class, inversedBy="missions", cascade={"persist", "merge"})
*/
private $type;
public function __construct()
{
$this->agents = new ArrayCollection();
$this->cibles = new ArrayCollection();
$this->contacts = new ArrayCollection();
$this->planques = new ArrayCollection();
}
I would like the list of targets to update dynamically according to the choice of agents.
Any help will be welcome and I thank you in advance because I admit going around in circles and no longer know where I am.

Symfony - Embedded Collection Form validation conditionally

I have a carousel with a collection of slides (OneToMany) and each slide contain a file that I have to validate if not exist.
When a slide has no file, the field is required but when the file exist, it's not required.
My CarouselType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('slides', CollectionType::class, [
'entry_type' => SlideType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' => false,
'row_attr' => [
'class' => 'hidden'
]
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Carousel::class,
]);
}
My SlideType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class, [
'row_attr' => [
'class' => 'form-group'
],
'attr' => [
'class' => 'form-control'
],
'required' => false
])
->add('url', UrlType::class, [
'row_attr' => [
'class' => 'form-group'
],
'attr' => [
'class' => 'form-control'
],
'required' => false
])
->add('file', FileType::class, [
'row_attr' => [
'class' => 'form-group'
],
'attr' => [
'class' => 'form-control'
],
'required' => false
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Slide::class,
'validation_groups' => function (FormInterface $form) {
$data = $form->getData();
if ($data->getFile() === null && $data->getFileName() === null) {
return ['upload'];
}
return ['Default'];
},
]);
}
My Carousel Entity:
/**
* #ORM\Entity(repositoryClass=CarouselRepository::class)
*/
class Carousel
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToMany(
* targetEntity=Slide::class,
* mappedBy="carousel",
* fetch="EXTRA_LAZY",
* orphanRemoval=true,
* cascade={"persist"}
* )
* #Assert\Count(min=1, minMessage="carousel.slides.count.min")
* #Assert\Valid(groups={"upload"})
*/
private $slides;
...
...
}
My Slide Entity:
/**
* #ORM\Entity(repositoryClass=SlideRepository::class)
*/
class Slide
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=100, nullable=true)
*/
private $title;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $url;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $fileName;
/**
* #var UploadedFile
* #Assert\NotNull(message="slide.file.not_null", groups={"upload"})
*/
protected $file;
/**
* #ORM\ManyToOne(targetEntity=Carousel::class, inversedBy="slides")
* #ORM\JoinColumn(nullable=false)
*/
private $carousel;
...
...
}
I've added validation_groups in my SlideType but it's not working.
What's wrong with my code ?
Use PreSetData Event for adding file in the SlideType
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$data = $event->getData();
$isNotRequired = ($data instanceof Slide) && $data->getUrl();
$constraints = isNotRequired ? [] : [new NotBlank()];
$event->getForm()->add('file', FileType::class, [
'row_attr' => [
'class' => 'form-group'
],
'attr' => [
'class' => 'form-control'
],
'required' => !$isNotRequired,
'constraints' => $constraints,
]);
});
You need to use "valid" to validate the subform.
https://symfony.com/doc/current/reference/constraints/Valid.html
$builder->add('slides', CollectionType::class, [
'entry_type' => SlideType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' => false,
'row_attr' => [
'class' => 'hidden'
],
'constraints' => [new Valid()],
]);

sonata admin one to many and many to many form

I have OneToMany related entities Gallery and Media stored in galleries_media
and I have Many To One related and Many To One related in GalleryMedia Entitiy
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="\Entity\GalleryMedia", mappedBy="gallery", cascade={"persist", "remove"})
*/
protected $galleriesMedia;
and in GalleryMedia Entitiy
/**
* #ORM\ManyToOne(targetEntity="\Entity\Gallery", inversedBy="galleriesMedia")
* #ORM\JoinColumn(name="gallery_id", referencedColumnName="id", nullable=false)
*/
protected $gllary;
/**
* #ORM\ManyToOne(targetEntity="\Entity\Media", inversedBy="galleries")
* #ORM\JoinColumn(name="media_id", referencedColumnName="id", nullable=false)
*/
protected $media;
how i do this in form
One-To-Many : sonata_type_collection
In your case:
class GalleryAdmin
{
// ...
$formMapper
->add('galleriesMedia', 'sonata_type_collection', [
'required' => false,
'label' => 'my_galleries_media_label',
'btn_add' => 'my_add_button_name',
'type_options' => [
'delete' => false,
],
], [
'edit' => 'inline', // or standard
'inline' => 'table', // or standard
'sortable' => 'id', // by any field in your entity
'limit' => 5, // you can remove this - this is a limit of items
'allow_delete' => false,
'placeholder' => $this->trans('admin.placeholder.no_media'),
])
;
class GalleriesMediaAdmin
{
// ...
$formMapper
->add('media', 'sonata_type_model_list', [
'required' => true,
'btn_add' => false,
'btn_list' => 'name_of_list_button'
'btn_delete' => false,
'btn_catalogue' => 'admin',
'label' => 'name_of_your_label',
], [
'placeholder' => 'choose media',
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'id',
])
Many-To-Many : sonata_type_model
You can make many-to-many with doctrine:
class Gallery
{
// ...
/**
* Unidirectional Many-To-Many ()
*
* Every Gallery can have a lot of medias
*
* #ORM\ManyToMany(targetEntity="\Entity\Media")
* #ORM\JoinTable(
* name="gallery_media_table",
* joinColumns={#ORM\JoinColumn(name="gallery_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={#ORM\JoinColumn(name="media_id", referencedColumnName="id", onDelete="CASCADE")}
* )
*
* #Assert\Valid()
*/
protected $medias;
Then in your GalleryAdmin you should use sonata_type_model:
$formMapper
->add('medias', 'sonata_type_model', [
'multiple' => true,
'expanded' => true, // or false
'class' => Media::class,
'property' => 'name', // or any field in your media entity
'label' => 'your_label',
'btn_add' => true,
'btn_list' => false,
'btn_delete' => true,
'btn_catalogue' => 'admin', // or your own translate catalogue in my case file admin.en.yml
])

many to many save data

I have two entity that have manytomany relation
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Esame
*
* #ORM\Table(name="esame", indexes={#ORM\Index(name="id_tipologia_esame", columns={"id_tipologia_esame"}), #ORM\Index(name="id_analisi", columns={"id_analisi"})})
* #ORM\Entity(repositoryClass="AppBundle\Repository\EsameRepository")
*/
class Esame
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \AppBundle\Entity\Nome_esame
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Nome_esame")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="id_tipologia_esame", referencedColumnName="id")
* })
*/
private $idTipologiaEsame;
/**
* #var \AppBundle\Entity\Analisi
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Analisi")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="id_analisi", referencedColumnName="id")
* })
*/
private $idAnalisi;
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\TipologiaCampione", inversedBy="esami")
*/
private $campioni;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set idAnalisi
*
* #param \AppBundle\Entity\Analisi $idAnalisi
*
* #return Esame
*/
public function setIdAnalisi($idAnalisi)
{
$this->idAnalisi = $idAnalisi;
return $this;
}
/**
* Get idAnalisi
*
* #return int
*/
public function getIdAnalisi()
{
return $this->idAnalisi;
}
/**
* Constructor
*/
public function __construct()
{
$this->campioni = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add campioni
*
* #param \AppBundle\Entity\TipologiaCampione $campioni
*
* #return Esame
*/
public function addCampioni(\AppBundle\Entity\TipologiaCampione $campioni)
{
$this->campioni[] = $campioni;
return $this;
}
/**
* Remove campioni
*
* #param \AppBundle\Entity\TipologiaCampione $campioni
*/
public function removeCampioni(\AppBundle\Entity\TipologiaCampione $campioni)
{
$this->campioni->removeElement($campioni);
}
/**
* Get campioni
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCampioni()
{
return $this->campioni;
}
/**
* Set idTipologiaEsame
*
* #param \AppBundle\Entity\Nome_esame $idTipologiaEsame
*
* #return Esame
*/
public function setIdTipologiaEsame(\AppBundle\Entity\Nome_esame $idTipologiaEsame = null)
{
$this->idTipologiaEsame = $idTipologiaEsame;
return $this;
}
/**
* Get idTipologiaEsame
*
* #return \AppBundle\Entity\Nome_esame
*/
public function getIdTipologiaEsame()
{
return $this->idTipologiaEsame;
}
}
and Entity 2
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* TipologiaCampione
*
* #ORM\Table(name="tipologia_campione")
* #ORM\Entity(repositoryClass="AppBundle\Repository\TipologiaCampioneRepository")
*/
class TipologiaCampione
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="tipologia", type="string", length=255, nullable=true)
*/
private $tipologia;
/**
* #var string
*
* #ORM\Column(name="matricola", type="string", length=255, nullable=true)
*/
private $matricola;
/**
* #var string
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Esame",mappedBy="campioni")
*/
private $esami;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set tipologia
*
* #param string $tipologia
*
* #return TipologiaCampione
*/
public function setTipologia($tipologia)
{
$this->tipologia = $tipologia;
return $this;
}
/**
* Get tipologia
*
* #return string
*/
public function getTipologia()
{
return $this->tipologia;
}
/**
* Set matricola
*
* #param string $matricola
*
* #return TipologiaCampione
*/
public function setMatricola($matricola)
{
$this->matricola = $matricola;
return $this;
}
/**
* Get matricola
*
* #return string
*/
public function getMatricola()
{
return $this->matricola;
}
/**
* Constructor
*/
public function __construct()
{
$this->esami = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add esami
*
* #param \AppBundle\Entity\Esame $esami
*
* #return TipologiaCampione
*/
public function addEsami(\AppBundle\Entity\Esame $esami)
{
$this->esami[] = $esami;
return $this;
}
/**
* Remove esami
*
* #param \AppBundle\Entity\Esame $esami
*/
public function removeEsami(\AppBundle\Entity\Esame $esami)
{
$this->esami->removeElement($esami);
}
/**
* Get esami
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getEsami()
{
return $this->esami;
}
}
now i must save data and in my controller i write this:
for($i=0;$i<$form->get('numero_campioni')->getData();$i++) {
$campione=new TipologiaCampione();
$campione->setMatricola($form['matricola_'.$i]->getData());
$campione->setTipologia($form['tipologia_'.$i]->getData());
foreach($form['esame_'.$i]->getData() as $value){
$tipo_esame = $this->getDoctrine()
->getRepository('AppBundle:nome_esame')
->find($value->getId());
$esame=new Esame();
$esame->setIdAnalisi($analisi);
$esame->setIdTipologiaEsame($tipo_esame);
$em->persist($esame);
$em->flush();
$campione->addEsami($esame); -> this don't work
}
$em->persist($campione);
$em->flush();
}
I expect that $campione->addEsami($esame); creates a new record in my table esame_tipologia_campione for each $campione but it doesn't work ..
My form Type:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Validator\Constraints\DateTime;
use AppBundle\Entity\anagrafica;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use AppBundle\Form\anagraficaType;
use Symfony\Component\Form\Extension\Core\Type\CurrencyType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use AppBundle\Form\EsameType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class AnalisiType extends AbstractType {
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$province = array(
'AG' => 'Agrigento',
'AL' => 'Alessandria',
'AN' => 'Ancona',
);
$builder->add('ruminanti', ChoiceType::class, array(
'label' => false,
'mapped' => false,
'placeholder' => 'Tipologia di modulo',
'choices' => array('Ruminanti' => 'Ruminanti', 'Suini' => 'Suini'),
'required' => true,
'data' => ($options['data']->getTipoModulo() != NULL ? $options['data']->getTipoModulo() : ''),
'attr' => array(
'placeholder' => 'Provincia',
)))
->add('idLaboratorio', EntityType::class, array(
'label' => false,
'placeholder' => 'Laboratorio a cui inviare i dati',
'class' => 'AppBundle:Laboratorio',
'choice_label' => 'nome',
// 'data'=>5
))
// Dati proprietario
->add('privato', ChoiceType::class, array(
'label' => false,
'choices' => array('Privato' => 'Privato', 'Azienda' => 'Azienda'),
'data' => 'Privato',
'expanded' => true,
'multiple' => false,
'mapped' => false,
))
->add('Nome_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getNome() : ''),
'attr' => array(
'placeholder' => 'Nome',
'novalidate' => 'novalidate'
)))
->add('Cognome_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getCognome() : ''),
'attr' => array(
'placeholder' => 'Cognome',
'novalidate' => 'novalidate'
)))
->add('Ragione_sociale_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'required' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getRagioneSociale() : ''),
'attr' => array(
'placeholder' => 'Ragione Sociale',
'novalidate' => 'novalidate'
)))
->add('Via_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getvia() : ''),
'attr' => array(
'placeholder' => 'Via'
)))
->add('Comune_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getComune() : ''),
'attr' => array(
'placeholder' => 'Comune'
)))
->add('Provincia_proprietario', ChoiceType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getProvincia() : ''),
'choices' => $province,
'placeholder' => 'Provincia'
))
->add('Telefono_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->gettel() : NULL),
'attr' => array(
'placeholder' => 'Telefono'
)))
->add('email_proprietario', EmailType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getemail() : ''),
'attr' => array(
'placeholder' => 'E-mail'
)
))
->add('Cod_allev_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getCodiceAllievo() : ''),
'attr' => array(
'placeholder' => 'Codice Allevamento'
)))
// Dati Veterinario
->add('Nome_veterinario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdProprietario()->getNome() : ''),
'attr' => array(
'placeholder' => 'Nome'
)))
->add('Cognome_veterinario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdProprietario()->getCognome() : ''),
'attr' => array(
'placeholder' => 'Cognome'
)))
->add('Via_veterinario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdVeterinario()->getvia() : ''),
'attr' => array(
'placeholder' => 'Via'
)))
->add('Comune_veterinario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdVeterinario()->getComune() : ''),
'attr' => array(
'placeholder' => 'Comune'
)))
->add('Provincia_veterinario', ChoiceType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdVeterinario()->getProvincia() : ''),
'choices' => $province,
'attr' => array(
'placeholder' => 'Provincia'
)))
->add('Telefono_veterinario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdVeterinario()->getTel() : NULL),
'attr' => array(
'placeholder' => 'Telefono'
)))
->add('email_veterinario', EmailType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdVeterinario()->getEmail() : ''),
'attr' => array(
'placeholder' => 'E-mail'
)
))
->add('trattamenti', TextareaType::class, array(
'label' => false,
'attr' => array(
'placeholder' => 'Trattamenti(inserire ANAMNESI; SINTOMATOLOGIA; TRATTAMENTI)'
)
))
->add('vacinazione', TextareaType::class, array(
'label' => false,
'attr' => array(
'placeholder' => 'Vacinazioni(obbligatorio)'
)
))
->add('numero_campioni', NumberType::class, array(
'label' => false,
'attr' => array(
'placeholder' => 'Numero Totale di campioni'
)
));
//->add('save', SubmitType::class, array('label' => 'Create Task'));
$builder->add('idTipologiaEsame', EntityType::class, array(
'label' => false,
'mapped' => false,
'class' => 'AppBundle:Nome_esame',
'choice_label' => 'nome',
'group_by' => 'idCategoriaEsame.tipo',
))
->add('Aggiungi', ButtonType::class, array(
'attr' => array(
'class' => 'btn-primary col-md-2 conferma_esame'),
))
->add('Rimuovi', ButtonType::class, array(
'attr' => array(
'class' => 'btn-primary col-md-2 conferma_esame'),
));
// for($i=0;$i<$options['data']->getNumeroCampioni();$i++){
for ($i = 0; $i < 60; $i++) {
$builder->add('checkbox_' . $i, CheckboxType::class, array(
'label' => false,
'required' => false,
'mapped' => false,
'attr' => array(
'class' => 'check_box_table',
// 'class'=>'col-md-1 col-xs-3 allineare_sinistra',
)
))
->add('matricola_' . $i, TextType::class, array(
'label' => false,
'mapped' => false,
'required' => false,
'attr' => array(
'placeholder' => 'Matricola (FACOLTATIVA)',
// 'class'=>'col-md-2 col-xs-9 allineare_sinistra',
)))
->add('tipologia_' . $i, TextType::class, array(
'label' => false,
'mapped' => false,
'required' => false,
'attr' => array(
'placeholder' => 'Tipologia (FACOLTATIVA)',
// 'class'=>'col-md-2 col-md-offset-0 col-xs-9 col-xs-offset-3 allineare_sinistra',
)))
->add('esame_' . $i, EntityType::class, array(
'label' => false,
'mapped' => false,
'class' => 'AppBundle:Nome_esame',
'required'=>true,
'multiple'=>true,
'choice_label' => 'nome',
// 'disabled' => 'disabled',
'attr' => array(
'placeholder' => 'Esami',
'class' => 'max_width esame_row select_esame',
// 'class'=>'col-md-12 col-md-offset-0 col-xs-9 col-xs-offset-3 ',
)
))
->add('Stampa', ButtonType::class, array(
'disabled' => 'disabled',
'attr' => array(
'class' => 'btn-primary text-center',
)
))
->add('saveAndAdd', SubmitType::class, array('label' => 'Save and Add'))
;
}
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Analisi'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix() {
return 'appbundle_analisi';
}
}
$esame entity and $campione entity are correctly saved.
Can anybody say to me what I'm doing wrong??
You need to create a Join Table
After that you need to choose which entity is the owner of the association (just after the manytomany chapter in the doc).
For exampre, if you may want to add "campioni" via the "esami" entity you should code a setter like this:
public function addCampioni(\AppBundle\Entity\TipologiaCampione($campioni) {
$campioni->addEsami($this);
$this->campioni[] = $campioni;
return $this;
}
Ciao!

Entities created instead of linked in CollectionType

I have a problem with one of my forms. The form has to create a new Colle entity and link some other Colle entities to it.
When I submit it, a new entity is created for each item in collesEnfants collection field. The new entity created is correctly linked to the parent and has the right 'ordre' field but it's a newly created entity and not the entity I've selected.
My form :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('nom', TextType::class,['label' => 'Nom de la colle'])
->add('collesEnfants', CollectionType::class,
['label' => false,
'entry_type' => SousColleFormType::class,
'required' => true,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'PACES\ColleBundle\Entity\Colle'
]);
}
SousColleFormType :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('matiere', EntityType::class, [
'class' => 'PACESColleBundle:Matiere',
'attr' => ['class'=> 'matiere'],
'choice_label' => 'name',
'label' => false,
'required' => false,
'placeholder' => 'Choisissez une matière',
'mapped' => false])
->add('nom', EntityType::class, [
'class' => 'PACESColleBundle:Colle',
'attr' => ['class' => 'colles'],
'choice_label' => 'nom',
'label' => false,
'group_by' => 'matiere',
'required' => true,
'placeholder' => 'choose.colle'])
->add('ordre', IntegerType::class,[
'attr'=>['class'=>'ordre'],
'required' => true,
'label' => false]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'PACES\ColleBundle\Entity\Colle'
]);
}
Controller :
$formColleMere = $this->createForm(AjoutSuperColleFormType::class, $colle);
$formColleMere->add('submit', SubmitType::class, ['label' => 'Créer']);
$formColleMere->handleRequest($request);
if ($formColleMere->isSubmitted() && $formColleMere->isValid()) {
$collesEnfants = $formColleMere->get('collesEnfants')->getData();
foreach ($collesEnfants as $enfant) {
$colle->addColleEnfant($enfant);
}
if (!$colle->getCollesEnfants()->isEmpty()) {
$em->persist($colle);
$em->flush();
}
Colle entity :
class Colle
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="Colle", mappedBy="colleMere", cascade={"persist"})
* #ORM\OrderBy({"ordre" = "asc"})
*/
private $collesEnfants;
/**
* #ORM\ManyToOne(targetEntity="Colle", inversedBy="collesEnfants", cascade={"persist"})
* #ORM\JoinColumn(name="colleMere_id", referencedColumnName="id")
*/
private $colleMere;
/**
* #var string
*
* #ORM\Column(name="nom", type="string", length=255)
*/
protected $nom;
{........}
/**
* #ORM\ManyToOne(targetEntity="PACES\ColleBundle\Entity\Matiere", inversedBy="colles", cascade={"persist"})
* #ORM\JoinColumn(name="matiere_id", referencedColumnName="id")
* #ORM\OrderBy({"name" = "ASC"})
*/
protected $matiere;
/**
* Cet attribut sert aux 'super colles' qui sont le résultat d'une fusion de colles d'une même UE
* #var integer
* #ORM\Column(name="ordre", type="integer", nullable=true)
*/
protected $ordre;
I succeeded in doing what I want by adding 'mapped' => false to collesEnfants field.
I also changed these lines in the Controller :
$collesEnfants = $formColleMere->get('collesEnfants')->getData();
foreach ($collesEnfants as $enfant) {
$colle->addColleEnfant($enfant);
}
To :
$collesEnfants = $formColleMere->get('collesEnfants')->getData();
foreach ($collesEnfants as $enfant) {
$colle->addColleEnfant($enfant['nom']);
$enfant['nom']->setOrdre($enfant['ordre']);
}

Resources