Related
I'm trying to make a form with Symfony to be able to adding new row by clicking button. I can't use SubmitType class because after submit symfony can't add new row. ButtonType class doesn't have a basic function isClicked(). Here is my Form:
<?php
namespace App\Form;
use App\Entity\Team;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
final class TeamFormType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('teamName', TextType::class, [
'label' => false,
'attr' => array(
'placeholder' => 'Wpisz Nazwe Drużyny'
)
])
->add('teamCity', TextType::class, [
'label' => false,
'attr' => array(
'placeholder' => 'Wpisz Nazwe Miasta'
)
])
->add('teamCoach', TextType::class, [
'label' => false,
'attr' => array(
'placeholder' => 'Wpisz Imie i Nazwisko Trenera'
)
]);
$builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){
$form = $event->getForm();
for ($i = 1; $i <= 6; $i++) {
$name = 'zawodnik' . $i .'';
$form->add($name, TextType::class, [
'mapped' => false,
'label' => false,
'attr' => array(
'placeholder' => 'Imie i Nazwisko Zawodnika'
)
]);
}
$form->add('agreeTerms', CheckBoxType::class, [
'mapped' => false,
'required' => true,
'label' => 'Zaakceptuj regulamin'
])
->add('Submit', SubmitType::class, [
'label' => 'Wyślij Zgłoszenie'
])
->add('addRow', ButtonType::class, [
'label' => 'Dodaj zawodnika'
]);
});
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Team::class,
'csrf_protection' => true,
'csrf_field_name'=> '_token',
'csrf_token_id' => 'team_item'
]);
}
}
And Controller :
<?php
namespace App\Controller;
use App\Form\TeamFormType;
use Doctrine\DBAL\Types\TextType;
use Doctrine\ORM\EntityManagerInterface;
use http\Env\Request;
use http\Env\Response;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class FormsController extends AbstractController
{
public function createTeamForm(Request $request, EntityManagerInterface $entityManager) :Response
{
$teamEntity = new Team();
$form = $this->createForm(TeamFormType::class);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
if($form->get('addRow')->isClicked()) {
$form->add('something', TextType::class, [
'label' => false,
'attr' => array(
'placeholder' => 'Imie i Nazwisko zawodnika.'
)
]);
}
$entityManager->persist($teamEntity);
$entityManager->flush();
$this->addFlash('success', 'Pomyślnie Utworzono Drużyne');
return $this->redirectToRoute('index');
}
}
}
Anyone have a idea to create button like that ?
I suggest you using Javascript and css, create your row and just hide it, then, onClick, let em appear with a JS function that modify the css sheet
I would like to use my UserType form class to register a user and to edit the user profile. As I want to the admins to register a user while setting up their roles, I don't want the user to modify that options. So I would like to use 2 different forms but for the same type User.
Can I create 2 different buildForm() functions in one FormType class ?
Or do I need to create another type ?
Here is my UserType class (main purpose was to register a user) :
<?php
namespace App\Form;
use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('firstname', TextType::class)
->add('lastname', TextType::class)
->add('birthdate', BirthdayType::class, array(
'placeholder' => '-'))
->add('email', EmailType::class)
->add('username', TextType::class)
->add('plainPassword', RepeatedType::class, array(
'type' => PasswordType::class,
'first_options' => array('label' => 'password'),
'second_options' => array('label' => 'repeat-password'),
))
->add('roles', ChoiceType::class, [
'multiple' => true,
'expanded' => true, // render check-boxes
'choices' => [
'Administrateur' => 'ROLE_ADMIN',
'Direction' => 'ROLE_MANAGER',
'Comptabilite' => 'ROLE_ACCOUNTING',
'Commercial' => 'ROLE_MARKETING',
'Docteur' => 'ROLE_DOCTOR',
'Client' => 'ROLE_CLIENT',
],
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::class,
));
}
}
You can use a variable to dynamically add the roles to the formType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->is_admin = $options['is_admin'];
// [...]
if ($this->is_admin)
$builder
->add('roles', ChoiceType::class, [
'multiple' => true,
'expanded' => true,
'choices' => [
'Administrateur' => 'ROLE_ADMIN',
'Direction' => 'ROLE_MANAGER',
'Comptabilite' => 'ROLE_ACCOUNTING',
'Commercial' => 'ROLE_MARKETING',
'Docteur' => 'ROLE_DOCTOR',
'Client' => 'ROLE_CLIENT',
],
])
// [...]
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
// [...]
'is_admin' => false,
]);
}
Then pass the variable like
$form = $this->createForm(UserType::class, $user, array(
'is_admin' => $this->isGranted('ROLE_ADMIN'),
);
you can easily handle this using array $optionsin controller set choices of roles and add them to $optionand in userType do something like this:
->add('roles', ChoiceType::class, [
'multiple' => true,
'expanded' => true, // render check-boxes
'choices' => $options['choices'],
])
Quick explanation of the subject:
A "Project" can have several "Activities"
I had to create simultaneously as many "Activities" as needed (You click on a button "Add an activity" and you got a new line which means a new activity). I managed to do that by doing Collections on my fields.
Here's the code of the formBuilder :
namespace CoreBundle\Form\Type;
use CoreBundle\Entity\Activities;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CreateNewActivitiesType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'aeAmount',
CollectionType::class,
array(
'entry_type' => TextType::class,
'allow_add' => true,
'allow_delete' => true,
'label' => 'Montant de l\'AE',
'label_attr' => array(
'class' => 'aeAmount visuallyhidden'
),
'entry_options' => array(
'attr' => array(
'placeholder' => '80 000 €'
),
),
'required' => true
)
)
->add(
'amountSpent',
CollectionType::class,
array(
'entry_type' => TextType::class,
'allow_add' => true,
'allow_delete' => true,
'label' => 'RDP : ',
'label_attr' => array(
'class' => 'amountSpent visuallyhidden'
),
'entry_options' => array(
'attr' => array(
'placeholder' => '35 000 €'
)
),
'required' => true,
)
)
->add(
'afName',
CollectionType::class,
array(
'entry_type' => TextType::class,
'allow_add' => true,
'allow_delete' => true,
'required' => true,
'label' => 'AF : ',
'label_attr' => array(
'class' => 'afName visuallyhidden',
),
'entry_options' => array(
'attr' => array(
'placeholder' => 'AERT-496'
)
)
)
)
->add(
'year',
CollectionType::class,
array(
'entry_type' => TextType::class,
'allow_delete' => true,
'allow_add' => true,
'required' => true,
'entry_options' => array(
'attr' => array(
'readonly' => true
)
),
'label' => 'Année : ',
'label_attr' => array(
'class' => 'year visuallyhidden'
)
)
)
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'CoreBundle\Entity\Activities'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'corebundle_collection_activities';
}
}
(I know i can do this much shorter, but refactorisation will be later.)
So, this is currently working, with his associated controller to add my activities, here it is :
/**
* #param integer $projectId
* #param string $projectType
* #param integer $rdId
*
* #return \Symfony\Component\HttpFoundation\Response
*/
public function createNewActivityAction($projectId, $projectType, $rdId)
{
$activity = new Activities();
$request = $this->get('request_stack')->getCurrentRequest();
$form = $this->createForm(CreateNewActivitiesType::class, $activity);
$form->handleRequest($request);
$em = $this->getDoctrine()->getManager();
if ($form->isSubmitted() && $form->isValid()) {
$rdAffiliated = $em->getRepository('CoreBundle:DecisionStatement')->findOneBy(['id' => $rdId]);
$formData = $form->getData();
$yearList = $formData->getYear();
$aeAmountList = $formData->getAeAmount();
$afNameList = $formData->getAfName();
$amountSpentList = $formData->getAmountSpent();
for ($i = 0; $i < count($yearList); $i++) {
$yearDatetime = new DateTime($yearList[$i] . '-01-01 00:00:00');
$existingActivity = $em->getRepository('CoreBundle:Activities')->getExistingActivityWithoutIdentifier(
$yearDatetime,
$rdAffiliated
);
if ($existingActivity) {
/**
* #var Activities $currentActivity
*/
$currentActivity = $existingActivity[0];
$currentActivity->setAeAmount(
$currentActivity->getAeAmount() + $aeAmountList[$i]
);
$currentActivity->setAmountSpent(
$currentActivity->getAmountSpent() + $amountSpentList[$i]
);
$em->persist($currentActivity);
} else {
$newActivity = new Activities();
$newActivity->setYear($yearDatetime)
->setAeAmount($aeAmountList[$i])
->setAfName($afNameList[$i])
->setAmountSpent($amountSpentList[$i])
->setAfReception(false)
->setDecisionStatement($rdAffiliated)
->setPeopleByMonth(0);
$em->persist($newActivity);
}
}
$em->flush();
return $this->redirectToRoute('rd_show_activities', array(
'rdId' => $rdId,
'projectType' => $projectType,
'projectId' => $projectId
));
}
return $this->render('#Core/html/13-edit-activite.html.twig', array(
'page' => 'activities_creation',
'createActivitiesForm' => $form->createView(),
'projectParentId' => $projectId,
'projectParentType' => $projectType,
'rdId' => $rdId
));
}
Here is also a screenshot from the var_dump when activities form is submitted :
But where's my problem begins, it is when I want to edit because my form is based on the entity "Activities". But I want to edit all the existing "Activities" for a given project, I'll have an array containing my "Activities" objects (found by the findBy method), so I can't pass my array into my form, which results in an error.
How to transform this array of many "Activities" objects into only one "Activities" object?
I don't understand why you have only one object "Activities" that contains several collection.
You should create an object activities that contains several activities.
Each activity has only one attribute "year", "amountSpent"...
When you edit your object "ActivitieS" with the appropriate form you will be able to edit each activity linked with this object.
Embed a collection of forms
To correctly manage this kind of problem you need to build a Collection of forms in Symfony.
A "Project" can have several "Activities"
I had to create simultaneously as many "Activities" as needed [...]
At first you need to build a Project entity that will contain all the Activities as a Doctrine ArrayCollection as you can see below:
src/AppBundle/Entity/Project.php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
class Project
{
protected $activities;
public function __construct()
{
$this->activities = new ArrayCollection();
}
public function getTags()
{
return $this->tags;
}
}
src/AppBundle/Form/Type/ProjectType.php
namespace AppBundle\Form\Type;
use AppBundle\Entity\Project;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class ProjectType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('tags', CollectionType::class, array(
'entry_type' => ActivitiesType::class,
'allow_add' => true,
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Project::class,
));
}
}
Then you need to enable the user to dynamically add an Activity to a Project you need to make advantage of the prototype variable, using Twig and JavaScript.
I've taken into consideration all the comments that you made and decided to review the whole thing.
DecisionStatement.php :
Added in the __construct() method a new ArrayCollection for the Activities affiliated for a given DecisionStatement.
The method to return the Activities affiliated was already here.
documents = new ArrayCollection();
$this->activitiesAffiliated = new ArrayCollection();
}
/**
* Get activitiesAffiliated
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getActivitiesAffiliated()
{
return $this->activitiesAffiliated;
}
I've created a new FormType (DecisionStatementType.php), to have my Collection of forms :
use CoreBundle\Entity\DecisionStatement;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class DecisionStatementType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'activitiesAffiliated',
CollectionType::class,
array(
'entry_type' => NewActivityType::class,
'allow_add' => true,
'allow_delete' => true
)
)
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => DecisionStatement::class
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'corebundle_collection_decisionstatement';
}
}
And here is the "subForm", newActivityType.php :
use CoreBundle\Entity\Activities;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class NewActivityType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'aeAmount',
TextType::class,
array(
'label' => 'Montant de l\'AE',
'label_attr' => array(
'class' => 'aeAmount visuallyhidden'
),
'attr' => array(
'placeholder' => '80 000 €'
),
'required' => true
)
)
->add(
'amountSpent',
TextType::class,
array(
'label' => 'RDP : ',
'label_attr' => array(
'class' => 'amountSpent visuallyhidden'
),
'attr' => array(
'placeholder' => '35 000 €'
),
'required' => true,
)
)
->add(
'afName',
TextType::class,
array(
'required' => true,
'label' => 'AF : ',
'label_attr' => array(
'class' => 'afName visuallyhidden',
),
'attr' => array(
'placeholder' => 'AERT-496'
)
)
)
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'CoreBundle\Entity\Activities'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'corebundle_collection_activities';
}
}
In my view's DOM, i have now this :
FormCollection Data-Prototype in DOM
So, is this a bit cleaner ?
I have a form with a collection of forms in which I want to chain two drop boxes with an event.
I do not manage to make the event listener to work as I get a null value when I call $data->getCursValutar().
Here is the code:
<?php
namespace Mnv\CoreBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ClientiType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$idSocietate = $options['data']->getSocietati()->getIdSocietate();
// var_dump($dateClienti);
$builder->add('cod','text', array('required' => false));
$builder->add('denumire','text', array('required' => true));
$builder->add('cod_fiscal','text', array('required' => true));
$builder->add('cont_analitic','text', array('required' => false));
$builder->add('telefon','text', array('required' => false));
$builder->add('email','email', array('required' => false));
$builder->add('judet','text', array('required' => false));
$builder->add('adresa','text', array('required' => false));
$builder->add('nr_reg_comertului','text', array('required' => false));
$builder->add('cont','text', array('required' => false));
$builder->add('banca','text', array('required' => false));
$builder->add('delegat','text',array('required' => false));
$builder->add('delegat_serie_ci','text',array('required' => false));
$builder->add('delegat_nr_ci','text',array('required' => false));
$builder->add('delegat_ci_eliberat','text',array('required' => false));
$builder->add('delegat_mij_transport','text',array('required' => false));
$builder->add('agent','text',array('required' => false));
$builder->add('discount','text',array('required' => false));
$builder->add('date_clienti', 'collection', array(
'type' => new DateClientiType($idSocietate),
'cascade_validation' => true,
'prototype' => true,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'required' => false,
));
$builder->add('adauga','submit');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Mnv\CoreBundle\Entity\Clienti',
'cascade_validation' => true,
));
}
public function getName()
{
return 'form_clienti';
}
}
And the second form:
<?php
namespace Mnv\CoreBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Mnv\CoreBundle\Entity\Orase;
class DateClientiType extends AbstractType
{
private $idSocietate;
function __construct($idSocietate) {
$this->idSocietate = $idSocietate;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::POST_SUBMIT, function ($event) {
$event->stopPropagation();
}, 900);
$builder->add('suprafata_inchiriata','text',array('required' => false));
$builder->add('suma_chirie','text',array('required' => false));
$builder->add('suma_fixa_chirie','text',array('required' => false));
$builder->add('curs_bnr','checkbox', array('required' => false));
$builder->add('platitor_tva','checkbox', array('required' => false));
$builder->add('fact_auto','checkbox', array('required' => false));
$builder->add('nr_contract','text',array('required' => false));
$builder->add('data_contract','date', array('required' => false, 'widget' => 'single_text', 'format'=>'dd/MM/yyyy'));
$builder->add('act_aditional','text',array('required' => false));
$builder->add('data_actaditional','date', array('required' => false, 'widget' => 'single_text', 'format'=>'dd/MM/yyyy'));
$builder->add('strada_spatiu','text',array('required' => false));
$builder->add('etaj_spatiu','text',array('required' => false));
$builder->add('pozitie_spatiu','text',array('required' => false));
$builder->add('achitare','text',array('required' => false));
$builder->add('tip_fact_utilitati', 'choice', array(
'choices' => array(
'cumulata' => 'Cumulata',
'unitara' => 'Unitara',
'separata' => 'Separata'
),
'required' => false,
'expanded' => false,
'multiple' => false,
'invalid_message' => 'Valoarea aleasa nu este valida!',
'empty_value' => false
));
$builder->add('orase', 'entity', array(
'class' => 'MnvCoreBundle:Orase',
'property' => 'oras',
'empty_value' => 'Selectati',
));
$idSocietate = $this->idSocietate;
$formModifier = function (FormInterface $form, Orase $orase = null) use ($idSocietate) {
$positions = array();
if (null !== $orase) {
$positions = $orase;
}
$form->add('cursuri', 'entity', array(
'class' => 'MnvCoreBundle:CursValutar',
'query_builder' => function(EntityRepository $er) use ($idSocietate,$positions) {
return $er->createQueryBuilder('c')
->where('c.societati = :idSocietate AND c.orase = :oras')
->setParameter('idSocietate', $idSocietate)
->setParameter('oras', $positions)
->orderBy('c.idCurs', 'ASC');
},
'empty_value' => 'Selectati',
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
// this would be your entity, i.e. SportMeetup
$data = $event->getData();
var_dump($data); exit;
$formModifier($event->getForm(), $data->getCursValutar());
}
);
$builder->get('orase')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
// It's important here to fetch $event->getForm()->getData(), as
// $event->getData() will get you the client data (that is, the ID)
$oras = $event->getForm()->getData();
// since we've added the listener to the child, we'll have to pass on
// the parent to the callback functions!
$formModifier($event->getForm()->getParent(), $oras);
}
);
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Mnv\CoreBundle\Entity\DateClienti',
'cascade_validation' => true,
));
}
public function getName()
{
return 'date_clienti';
}
}
I am new to symfony and I am doing a battle to learn it. What am I doing wrong?
Your problem was already answered here: Symfony2 PRE_SET_DATA $event->getData() return wrong object
It was in the related question block.
Ok! I found the solution :) after 3 days of pain ):
It was simple, of course.
Read the comments:
<?php
namespace Mnv\CoreBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Mnv\CoreBundle\Entity\Orase;
use Mnv\CoreBundle\Entity\DateClienti;
class DateClientiType extends AbstractType
{
private $idSocietate;
function __construct($idSocietate) {
$this->idSocietate = $idSocietate;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::POST_SUBMIT, function ($event) {
$event->stopPropagation();
}, 900);
$builder->add('suprafata_inchiriata','text',array('required' => false));
$builder->add('suma_chirie','text',array('required' => false));
$builder->add('suma_fixa_chirie','text',array('required' => false));
$builder->add('curs_bnr','checkbox', array('required' => false));
$builder->add('platitor_tva','checkbox', array('required' => false));
$builder->add('fact_auto','checkbox', array('required' => false));
$builder->add('nr_contract','text',array('required' => false));
$builder->add('data_contract','date', array('required' => false, 'widget' => 'single_text', 'format'=>'dd/MM/yyyy'));
$builder->add('act_aditional','text',array('required' => false));
$builder->add('data_actaditional','date', array('required' => false, 'widget' => 'single_text', 'format'=>'dd/MM/yyyy'));
$builder->add('strada_spatiu','text',array('required' => false));
$builder->add('etaj_spatiu','text',array('required' => false));
$builder->add('pozitie_spatiu','text',array('required' => false));
$builder->add('achitare','text',array('required' => false));
$builder->add('tip_fact_utilitati', 'choice', array(
'choices' => array(
'cumulata' => 'Cumulata',
'unitara' => 'Unitara',
'separata' => 'Separata'
),
'required' => false,
'expanded' => false,
'multiple' => false,
'invalid_message' => 'Valoarea aleasa nu este valida!',
'empty_value' => false
));
$builder->add('orase', 'entity', array(
'class' => 'MnvCoreBundle:Orase',
'property' => 'oras',
'empty_value' => 'Selectati',
));
$idSocietate = $this->idSocietate;
$formModifier = function (FormInterface $form, Orase $orase = null) use ($idSocietate) {
$positions = array();
if (null !== $orase) {
$positions = $orase;
}
$form->add('curs_valutar', 'entity', array(
'class' => 'MnvCoreBundle:CursValutar',
'query_builder' => function(EntityRepository $er) use ($idSocietate,$positions) {
return $er->createQueryBuilder('c')
->where('c.societati = :idSocietate AND c.orase = :oras')
->setParameter('idSocietate', $idSocietate)
->setParameter('oras', $positions)
->orderBy('c.idCurs', 'ASC');
},
'empty_value' => 'Selectati',
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
// this would be your entity, i.e. SportMeetup
$data = $event->getData();
//var_dump($data); exit;
// so after var dumping i noticed the $data was null
// i tried many solutions found online with no success
// so the problem was the error i got when getOrase was called on a non
// object, so i need it an object and here it is:
if ($data !== null) { // chack to see if $data is not null
// now we can safely call getOrase() on event
$formModifier($event->getForm(), $data->getOrase());
} else { // if it is null
$data = new DateClienti; // instantiate the class
// (don't forget to import the class)
$formModifier($event->getForm(), $data->getOrase()); // no error now :)
}
}
);
$builder->get('orase')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
// It's important here to fetch $event->getForm()->getData(), as
// $event->getData() will get you the client data (that is, the ID)
$oras = $event->getForm()->getData();
// since we've added the listener to the child, we'll have to pass on
// the parent to the callback functions!
$formModifier($event->getForm()->getParent(), $oras);
}
);
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Mnv\CoreBundle\Entity\DateClienti',
'cascade_validation' => true,
));
}
public function getName()
{
return 'date_clienti';
}
}
I have an Entity called News which contains a ManyToMany relation with the User Entity. This means that an article can be written by multiple authors.
/**
* #ORM\ManyToMany(targetEntity="GW2\UserBundle\Entity\User")
*/
private $authors;
The problem is that I would like to add authors dynamically in the form I use to add News, but I don't know how to store the data, and keep the relation between my two Entities. The number of authors is not fixed, and not limited.
I did some research about the collection type and added it to my NewsType, but I don't really know how to use it.
Edit: Here is my current NewsType (without the authors collection):
<?php
namespace GW2\SiteBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class NewsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', 'text', array('error_bubbling' => true))
->add('introduction', 'textarea', array('attr' => array('class' => 'input-block-level redactor_content'), 'error_bubbling' => true))
->add('content', 'textarea', array('attr' => array('class' => 'input-block-level redactor_content'), 'error_bubbling' => true))
->add('publication', 'checkbox', array('required' => false, 'error_bubbling' => true))
->add('categories', 'entity', array(
'class' => 'GW2SiteBundle:Category',
'property' => 'name',
'required' => false,
'multiple' => true
))
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'GW2\SiteBundle\Entity\News'
));
}
public function getName()
{
return 'gw2_sitebundle_newstype';
}
}
I finally fixed my problem by adding a collection with the FOSUB type, while specifying the allow_add and allow_delete options.
->add('authors', 'collection', array(
'type'=> 'fos_user_username',
'allow_add' => true,
'allow_delete' => true
))
Then I added the adding-removing solution with JavaScript to dynamically add fields in the form (thanks to Thomas Potaire).