Transform forms from Symfony2 to Symfony3 - forms

I want to transform a form like this to comply with Symfony3 code :
$form = $this->createForm(new AjoutQC(array('idcolle' => $idColle,'idqc' => $question->getId())),
$question,
array('action' => $this->generateUrl('paces_colle_qc_update',
array(
'id' => $question->getId(),
'idColle' => $idColle,
'idTuteur' => $idTuteur)
),
'method' => 'PUT',
));
$form->add('submit', SubmitType::class, array('label' => 'Sauvegarder'));
Symfony3 asks for something like :
AjoutQC::class
instead of :
new AjoutQC...
I didn't find anything about it after some research.

Check these upgrade notes for forms.
It says:
Passing type instances to Form::add(), FormBuilder::add() and the FormFactory::create*() methods is not supported anymore. Pass the fully-qualified class name of the type instead.
Before:
$form = $this->createForm(new MyType());
After:
$form = $this->createForm(MyType::class);
You can use OptionsResolver and pass your data array('idcolle' => $idColle,'idqc' => $question->getId()) that you are currently passing to your form type as a third argument to createForm method:
$form = $this->createForm(AjoutQC::class, $question, array(
'action' => $this->generateUrl('paces_colle_qc_update', array(
'id' => $question->getId(),
'idColle' => $idColle,
'idTuteur' => $idTuteur,
)),
'method' => 'PUT',
'idcolle' => $idColle,
'idqc' => $question->getId(),
));
Then in your AjoutQC type you need to do something like:
use Symfony\Component\OptionsResolver\OptionsResolver;
// ..
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->idcolle = $options['idcolle'];
$this->idqc = $options['idqc'];
$builder
->add(...)
// ..
;
}
// ..
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setRequired(array('idcolle', 'idqc'));
}
This will set idcolle, idqc options as required, that must be passed to your form type (AjoutQC).

In Symfony 3 you need to use FQCN (fully-qualified class name) instead of an instance of the form (or a string reference to a service).
$form = $this->createForm(
AjoutQC::class,
$question,
array(
'action' => $this->generateUrl(
'paces_colle_qc_update',
array(
'id' => $question->getId(),
'idColle' => $idColle,
'idTuteur' => $idTuteur
)
),
'method' => 'PUT',
'idColle' => $idColle,
'idQc' => $question->getId()
)
)
In your AjoutQC class you need to go to your configureOptions method and add the idcolle and idqc options:
class AjoutQC extends AbstractType {
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setRequired(array('idColle','idQc'));
$resolver->setDefaults(
array(
'data_class' => 'Your\Entity\Path',
'idColle' => null,
'idQc' => null
)
);
}
}

If you are just wondering about the ::class notation, you can find information about that here: http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.class
::class requires php >= 5.5
If you are using <5.5 you can just simply use the FQCN e.g. MyLong\Namespace\Fully\Qualified\ClassNameType

Related

Not to validate the form in Symfony 2

Here is my form, I build in the controller:
$defaulData = ....
$formBuilder = $this->createFormBuilder($defaultData);
$entity_options = array(
'class' => 'MyBundle:Param',
'property' => 'description',
'query_builder' => function(EntityRepository $er) {
return $er->getParamsFromCategorieQueryBuilder(MyController::$category_for_list);
},
'label' => 'Donnée à afficher'
);
$formBuilder
->add('entity_types', 'entity', $entity_options);
The form is a list of Param objects, it displays good but for some reason, when I submit the form, I have an error on entity_types field saying that the value cannot be blank though there is one Param selected (even by default).
So I was wondering if I could disable validation.
When whould I put this validation_groups to false ? if it is in $entity_options, I tried it already and it does not work.
ty
You should modify you options like this (both require and groups are needed):
$entity_options = array(
'class' => 'MyBundle:Param',
'property' => 'description',
'query_builder' => function(EntityRepository $er) {
return $er->getParamsFromCategorieQueryBuilder(MyController::$category_for_list);
},
'required' => false,
'validation_groups' => false,
'label' => 'Donnée à afficher'
);
If the error is instead on the Form class itself, you should change in:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => false,
));
}
The way to prevent validation for good is this one :
$formBuilder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
$event->stopPropagation();
}, 900);
It prevents from calling the validation event.
The solution that giosh94mhz gave me what not good because even with validation_group = false some validation are still done.

remove entity from entity form field if custom condition is matched

I have an unsubscribe form, where the first field is a entity field, fetching my UnsubscribeType entities :
$builder
->add('type', 'entity', array(
'class' => 'Evo\SubscriptionBundle\Entity\UnsubscribeType',
'property' => 'name',
'label' => 'Choose process type',
'empty_value' => 'Choose an option',
'empty_data' => null,
'label_attr' => array(
'class' => 'control-label',
),
'attr' => array(
'class' => 'form-control',
),
))
this collection contains 2 entities, #1 and #2. I would like to remove entity #2 from the select field if a custom test about the authed user fails.
Let's say I'd to test $this->getUser()->getCustomField(). If it is false, then i would like to remove entity #2 from the select field containing my UnsubscribeType entities.
Any idea how to do that ?
Perhaps you could pass to the form builder the result of the test from you controller and then, either use 'property' => 'name' or 'choices => // fetch entity #1 here.
So, something like this
public function buildForm(FormBuilderInterface $builder, array $options)
{
if($options['customField'] === TRUE)
{
$builder
->add('type', 'entity', array(
'class' => 'Evo\SubscriptionBundle\Entity\UnsubscribeType',
'property' => 'name',
// ..
;
}
else
{
$builder
->add('type', 'entity', array(
'class' => 'Evo\SubscriptionBundle\Entity\UnsubscribeType',
'choices' => $options['customField'],
// ..
;
}
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
// ..
$resolver->setRequired(array(
'customField'
));
}
And in your controller:
$form = $this->get('form.factory')->create(new EntryType(), $entry, array(
'customField' => $this->getUser()->getCustomField()
));
with getCustomField() returning either true or the entity (or collection of entities) that you want populating your select field. My solution would involve changing the getCustomField method though, don't know if that would suit.

Symfony form creates new object and create first one-to-many object

I have an entity for support tickets: SupportTicket(). I also have an entry for replies to each ticket: SupportEntry(). I setup a one-to-many relationship between SupportTicket() and SupportEntry().
Now what I'm trying to do is build my form so that it creates the initial SupportTicket and then inserts the first SupportEntry, all in the same form. I've been messing around with my code for a while, only half-understanding what I'm doing, but this is where I'm at right now:
// My controller, creating the form
$supportTicket = new SupportTicket();
$form = $this->createFormBuilder($supportTicket)
->add('subject', 'text', array(
'label' => 'Subject'
))
->add('jobNumber', 'text', array(
'label' => 'Job Number'
))
->add('supportGroup', 'entity', array(
'label' => 'Group',
'class' => 'ShawmutClientBundle:SupportGroup',
'property' => 'name',
'multiple' => true,
'expanded' => true
))
// ->add('supportEntries', new SupportEntryType())
->add('supportEntries', new SupportEntryType())
->add('Save', 'submit')
->getForm();
My attempt at the custom form type
<?php
namespace Shawmut\ClientBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class SupportEntryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('comment', 'textarea');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Shawmut\ClientBundle\Entity\SupportEntry',
));
}
public function getName()
{
return 'SupportEntryType';
}
}
The form does have the comment box that I've pulled in from the form type, but when I try to submit the form, I get this error:
Neither the property "supportEntries" nor one of the methods "setSupportEntries()", "_set()" or "_call()" exist and have public access in class "Me\MyBundle\Entity\SupportTicket".
And yeah, that makes sense. It should be the addSupportEntries() method which is there. So how do I tell the form builder to use addSupportEntries instead of setSupportEntries?
Thanks in advance
Give the collection form type a go.
->add(
'supportEntries',
'collection',
array(
'type' => new SupportEntryType(),
'label' => 'Support Entries',
'error_bubbling' => true,
'cascade_validation' => true,
)
)
If you are using the collection form type, and the textarea is not showing, add:
'allow_add' => true
to the properties array().
The code would look something like this:
->add(
'supportEntries',
'collection',
array(
'type' => new SupportEntryType(),
'label' => 'Support Entries',
'error_bubbling' => true,
'allow_add' => true
'cascade_validation' => true,
)
)
To show the widget, assuming you are using twig:
{{ form_widget(form.supportEntries.vars.prototype.comment) }}
For saving the support entry, depending on how you built your entities, you might need to make some extra modifications.
The documentation should help you get it right:
How to Embed a Collection of Forms

how to inject data into a form in symfony2

I have a call at my controller:
Controller:
if($appointment->getAnamnese() == NULL){
$entity = new Anamnese($appointment);
$form = $this->createForm(new AnamneseType(),null,array('history' => 'Digite o Historico aqui'));
}else{
$entity = $appointment->getAnamnese();
$form = $this->createForm(new AnamneseType(), null, array('history' => $entity->getHistory()));
}
AnamneseType:
$builder->add('history', 'ckeditor', array(
'data' => $options['history'], 'toolbar' => $toolbar));
}
public function getDefaultOptions(array $options)
{
return array(
'history' => "Digite o Historico aqui"
);
}
and i want to inject that history information to my form but its not working as i thought it would be, just setting the 'data' option...
how can i do it?
the problem is that after inserting data, i cant put it back to the form..
Use the setData() function to set your data:
For example:
$form = $this->createForm(new AnamneseType())->setData($entity);
Or maybe even:
$form = $this->createForm(new AnamneseType(), $entity);
You're looking at it the wrong way.
You have to use options here.
to create the form:
$form = $this->createForm(new AnamneseType(), null, array('history' => $entity->getHistory()));
And your form should look like:
public function buildForm(FormBuilder $builder, array $options){
$toolbar = array(
array(
'name' => 'document',
'items' => array('Source','-','DocProps','Preview','Print','-','Templates')
),
array(
'name' => 'clipboard',
'items' => array('Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo')
),
array(
'name' => 'editing',
'items' => array('Find','Replace','-','SelectAll','-','SpellChecker', 'Scayt')
),
array(
'name' => 'basicstyles',
'items' => array('Bold','Italic','Underline','Strike','Subscript','Superscript','-','RemoveFormat')
),
'/',
array(
'name' => 'paragraph',
'items' => array('NumberedList','BulletedList','-','Outdent','Indent','-','Blockquote','CreateDiv','-','JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock','-','BidiLtr','BidiRtl')
),
array(
'name' => 'links',
'items' => array('Link','Unlink','Anchor')
),
array(
'name' => 'insert',
'items' => array('Image','Table','HorizontalRule','Smiley','SpecialChar','PageBreak')
),
'/',
array(
'name' => 'styles',
'items' => array('Styles','Format','Font','FontSize')
),
array(
'name' => 'colors',
'items' => array('TextColor','BGColor')
),
array(
'name' => 'tools',
'items' => array('Maximize', 'ShowBlocks','-','About')
)
);
$builder->add('history', 'ckeditor', array( 'data' => $options['history'] , 'toolbar' => $toolbar));
}
...
public function getDefaultOptions(array $options)
{
return array(
'history' => "Digite o Historico aqui"
);
}
Well, looks like the form is generated in the second condition and $entity->getHistory() returns null.
Edit your controller code as below
$historyValue = 'Digite o Historico aqui'; // Default history value
if($appointment->getAnamnese()){
$entity = $appointment->getAnamnese();
// Checks whether the history is not empty (null or equals '' in this case)
if (!empty($entity->getHistory())) {
$historyValue = $entity->getHistory();
}
}
$form = $this->createForm(new AnamneseType(),null,array('history' => $historyValue));
I'd highly recommend you to read the official documentation.
Symfony Forms
Form data is supposed to be passed from a controller.
Replace
$form = $this->createForm(new AnamneseType($entity->getHistory()));
With
$form = $this->createForm(new AnamneseType(), array(
'history' => null === $entity->getHistory()
? 'Digite o Historico aqui'
: $entity->getHistory,
));
Remove constructor from the form class and replace
if($this->history != NULL){
$builder->add('history', 'ckeditor', array( 'data' => $this->history , 'toolbar' => $toolbar));
}else{
$builder->add('history', 'ckeditor', array( 'data' => "Digite o Historico aqui" , 'toolbar' => $toolbar));
}
With
$builder->add('history', 'ckeditor', array('toolbar' => $toolbar));
If you are going to map the data back to the entity check Forms official documentation
UPD:
To pass some value to a template from the history field edit its definition like:
$builder->add('history', 'ckeditor', array(
'attr' => array(
'toolbar' => $toolbar,
),
));
You can access the toolbar option by:
{{ form.history.get('attr').toolbar }}
There is better solution: Create Custom Form Type

Symfony2 Setting a default choice field selection

I am creating a form in the following manner:
$form = $this->createFormBuilder($breed)
->add('species', 'entity', array(
'class' => 'BFPEduBundle:Item',
'property' => 'name',
'query_builder' => function(ItemRepository $er){
return $er->createQueryBuilder('i')
->where("i.type = 'species'")
->orderBy('i.name', 'ASC');
}))
->add('breed', 'text', array('required'=>true))
->add('size', 'textarea', array('required' => false))
->getForm()
How can I set a default value for the species listbox?
Thank you for your response, I apologise, I think I should rephrase my question. Once I have a value that I retrieve from the model, how do I set that value as SELECTED="yes" for the corresponding value in the species choice list?
So, that select option output from the TWIG view would appear like so:
<option value="174" selected="yes">Dog</option>
You can define the default value from the 'data' attribute. This is part of the Abstract "field" type (http://symfony.com/doc/2.0/reference/forms/types/field.html)
$form = $this->createFormBuilder()
->add('status', 'choice', array(
'choices' => array(
0 => 'Published',
1 => 'Draft'
),
'data' => 1
))
->getForm();
In this example, 'Draft' would be set as the default selected value.
If you use Cristian's solution, you'll need to inject the EntityManager into your FormType class. Here is a simplified example:
class EntityType extends AbstractType{
public function __construct($em) {
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options){
$builder
->add('MyEntity', 'entity', array(
'class' => 'AcmeDemoBundle:Entity',
'property' => 'name',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('e')
->orderBy('e.name', 'ASC');
},
'data' => $this->em->getReference("AcmeDemoBundle:Entity", 3)
));
}
}
And your controller:
// ...
$form = $this->createForm(new EntityType($this->getDoctrine()->getManager()), $entity);
// ...
From Doctrine Docs:
The method EntityManager#getReference($entityName, $identifier) lets you obtain a reference to an entity for which the identifier is known, without loading that entity from the database. This is useful, for example, as a performance enhancement, when you want to establish an association to an entity for which you have the identifier.
the solution: for type entity use option "data" but value is a object. ie:
$em = $this->getDoctrine()->getEntityManager();
->add('sucursal', 'entity', array
(
'class' => 'TestGeneralBundle:Sucursal',
'property'=>'descripcion',
'label' => 'Sucursal',
'required' => false,
'data'=>$em->getReference("TestGeneralBundle:Sucursal",3)
))
I think you should simply use $breed->setSpecies($species), for instance in my form I have:
$m = new Member();
$m->setBirthDate(new \DateTime);
$form = $this->createForm(new MemberType, $m);
and that sets my default selection to the current date. Should work the same way for external entities...
If you want to pass in an array of Doctrine entities, try something like this (Symfony 3.0+):
protected $entities;
protected $selectedEntities;
public function __construct($entities = null, $selectedEntities = null)
{
$this->entities = $entities;
$this->selectedEntities = $selectedEntities;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('entities', 'entity', [
'class' => 'MyBundle:MyEntity',
'choices' => $this->entities,
'property' => 'id',
'multiple' => true,
'expanded' => true,
'data' => $this->selectedEntities,
]);
}
I don't think you should use the data option, because this does more than just setting a default value.
You're also overriding any data that's being passed to the form during creation. So basically, you're breaking
support for that feature. - Which might not matter when you're letting the user create data, but does matter when you
want to (someday) use the form for updating data.
See http://symfony.com/doc/current/reference/forms/types/choice.html#data
I believe it would be better to pass any default data during form creation. In the controller.
For example, you can pass in a class and define the default value in your class itself.
(when using the default Symfony\Bundle\FrameworkBundle\Controller\Controller)
$form = $this->createForm(AnimalType::class, [
'species' => 174 // this id might be substituted by an entity
]);
Or when using objects:
$dog = new Dog();
$dog->setSpecies(174); // this id might be substituted by an entity
$form = $this->createForm(AnimalType::class, $dog);
Even better when using a factory:
(where dog probably extends from animal)
$form = $this->createForm(AnimalType::class, DogFactory::create());
This will enable you to separate form structure and content from each other and make
your form reusable in more situations.
Or, use the preferred_choices option, but this has the side effect of moving the default option to the top of your form.
See: http://symfony.com/doc/current/reference/forms/types/choice.html#preferred-choices
$builder->add(
'species',
'entity',
[
'class' => 'BFPEduBundle:Item',
'property' => 'name',
'query_builder' => ...,
'preferred_choices' => [174] // this id might be substituted by an entity
]
);
I'm not sure what you are doing wrong here, when I build a form using form classes Symfony takes care of selecting the correct option in the list. Here's an example of one of my forms that works.
In the controller for the edit action:
$entity = $em->getRepository('FooBarBundle:CampaignEntity')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find CampaignEntity entity.');
}
$editForm = $this->createForm(new CampaignEntityType(), $entity);
$deleteForm = $this->createDeleteForm($id);
return $this->render('FooBarBundle:CampaignEntity:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
The campaign entity type class (src: Foo\BarBundle\Form\CampaignEntityType.php):
namespace Foo\BarBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Doctrine\ORM\EntityRepository;
class CampaignEntityType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('store', 'entity', array('class'=>'FooBarBundle:Store', 'property'=>'name', 'em'=>'my_non_default_em','required' => true, 'query_builder' => function(EntityRepository $er) {return $er->createQueryBuilder('s')->orderBy('s.name', 'ASC');}))
->add('reward');
}
public function getName()
{
return 'foo_barbundle_campaignentitytype';
}
}
From the docs:
public Form createNamed(string|FormTypeInterface $type, string $name, mixed $data = null, array $options = array())
mixed $data = null is the default options. So for example I have a field called status and I implemented it as so:
$default = array('Status' => 'pending');
$filter_form = $this->get('form.factory')->createNamedBuilder('filter', 'form', $default)
->add('Status', 'choice', array(
'choices' => array(
'' => 'Please Select...',
'rejected' => 'Rejected',
'incomplete' => 'Incomplete',
'pending' => 'Pending',
'approved' => 'Approved',
'validated' => 'Validated',
'processed' => 'Processed'
)
))->getForm();
Setting default choice for symfony2 radio button
$builder->add('range_options', 'choice', array(
'choices' => array('day'=>'Day', 'week'=>'Week', 'month'=>'Month'),
'data'=>'day', //set default value
'required'=>true,
'empty_data'=>null,
'multiple'=>false,
'expanded'=> true
))
The form should map the species->id value automatically to the selected entity select field. For example if your have a Breed entity that has a OnetoOne relationship with a Species entity in a join table called 'breed_species':
class Breed{
private $species;
/**
* #ORM\OneToOne(targetEntity="BreedSpecies", mappedBy="breed")
*/
private $breedSpecies;
public function getSpecies(){
return $breedSpecies->getSpecies();
}
private function getBreedSpecies(){
return $this->$breedSpecies;
}
}
The field 'species' in the form class should pick up the species->id value from the 'species' attribute object in the Breed class passed to the form.
Alternatively, you can explicitly set the value by explicitly passing the species entity into the form using SetData():
$breedForm = $this->createForm( new BreedForm(), $breed );
$species = $breed->getBreedSpecies()->getSpecies();
$breedForm->get('species')->setData( $species );
return $this->render( 'AcmeBundle:Computer:edit.html.twig'
, array( 'breed' => $breed
, 'breedForm' => $breedForm->createView()
)
);
You can either define the right default value into the model you want to edit with this form or you can specify an empty_data option so your code become:
$form = $this
->createFormBuilder($breed)
->add(
'species',
'entity',
array(
'class' => 'BFPEduBundle:Item',
'property' => 'name',
'empty_data' => 123,
'query_builder' => function(ItemRepository $er) {
return $er
->createQueryBuilder('i')
->where("i.type = 'species'")
->orderBy('i.name', 'ASC')
;
}
)
)
->add('breed', 'text', array('required'=>true))
->add('size', 'textarea', array('required' => false))
->getForm()
;
You can use "preferred_choices" and "push" the name you want to select to the top of the list. Then it will be selected by default.
'preferred_choices' => array(1), //1 is item number
entity Field Type