I am trying to set the label of an embedded form type (collection type).
These labels have to be different for the different collections.
For example I have two collections and an array with the labels ['label1','label2'] in die form type.
I think I need the index of the collection iteration to get the right label.
Like below i need the index for the entry_options label to get the right value of the $labels array.
Thats my buildForm Method
public function buildForm(FormBuilderInterface $builder, array $options)
{
$labels = ['label1', 'label2'];
$builder
->add('otherForms', CollectionType::class, [
'entry_type' => otherFormType::class,
'entry_options' => ['label' => $labels[$index]],
])
...
;
}
After reading your comments, I must agree that translation bundles are sometimes heavy weight and quite inconvenient.
The CollectionType usually ignores the index/key of collection items given to it, though.
Now I see two scenarios: you want to give the labels as an option to your form or the form shall be dependent on the data (using form events). Your code so far suggests, that languages are set globally and will not be added on the fly in some other manner.
In the first scenario it's very simple (see below), the second scenario requires some event listener in your form, but apart from that, it's quite similar.
The essential idea is to just create the forms you need (optionally inside the pre-submit handler), since you apparently already know which forms you need from the label array:
foreach($labels as $index => $label) {
$builder->add('otherForms'.$index, otherFormType::class, [
'label' => $label,
'property_path' => 'otherForms['.$index.']',
]);
}
The use of property_path will help you access the proper elements (however, changing the language (= key) of a translation might be difficult, but that should not happen, usually. And even if it happens, only some copy-pasta is necessary).
Your otherForms keys probably will be differently, but I guess you'll figure it out.
Related
I have an entity Machine which has a relation MM with other entity Piece. The pieces can be from 3 different types. Currently the form Machine is built with a selection list in which the whole array collection Machine.pieces is fetched. My idea is to build 3 different selection lists with a subset of Machine.pieces each.
I have tried two different approaches but I have no been able to accomplish it.
Use a MachineRepository class where a method
public function findPiecesByPieceType($pieceTypeID)
returns the proper query->getResult().
Then I add a choiceType in MachineType but I am not able to populate it from MachineController. I have used $form->get('pieces')->setData($arrcollectPieces) and other methods to add choices but I always get error.
How could I add choices from the controller to a Form?
In the form I use a queryBuilder
->add('pieces', EntityType::class, array(
'label' => 'label_pieces',
'class' => 'AppBundle\Entity\Piece',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('p')
->where('p.pieceType = :pieceType')
->setParameter('pieceType', 1);
},
)
)
this works but when I try to add more queryBuilders (->add('pieces2'... and so on) I have the error because
Neither the property pieces2 nor one of the methods getPiecess2(), pieces2(), isPieces2(), hasPieces2(), __get() exist and have public access in class AppBundle\Entity\Machine.
How can I use the various queryBuilders not bounded to a method name in that way?
Maybe both approaches are incorrect and I should solve this in a different way?
(Posted on behalf of the OP).
How to make it using 1.
In MachineController forget setData(), instead turn the arrayCollection into 2 arrays (arKeys, arValues) and send them to the form as the 3rd parameter in createForm().
$form = $this->createForm(<type>, <data>,
array ('p_keys' => array(...), 'p_values' => array(...)));
From MachineType.ConfigureOptions() we can fetch them
$resolver->setDefined(["p_keys",'p_values']);
and they will be available in MachineType.buildForm()
$options['p_keys'];
$options['p_values'];
I have a problem, I want to create a simple search form with a filter assembly. These filters are attributes that belong to attribute groups.
group 1
[] Attribute 1
[] Attribute 2
[] Attribute 3
group 2
[] Attribute 1
[] Attribute 2
[] Attribute 3
But the problem is that I can not do (graphic aspect)
$builder->add('attribut', 'entity', array(
'class' => 'RestoFrontBundle:Attribut',
'group_by' => 'groupeAttribut.id',
'expanded' => true,
'multiple' => true,
'query_builder' => function(AttributRepository $er) {
return $er->createQueryBuilder('a')
->join("a.groupeAttribut", 'g')
->where("a.statut = 1");
}
))
->getForm();
Also I can not manage the game if the checkbox has been checked.
You note that the graphic aspect is the hard part. That is due to the way checkboxes are used in HTML. Unlike select inputs there is no notion of an optgroup. The closest analog for checkboxes would be a fieldset with a legend.
You may want explore using a Choice Field type rather than an entity type. Provide your choices via some provider function within which you format the options array(s) whether or not you retrieved them from a database. ( For the record, that's exactly how I populate the select at http://stayattache.com which has multiple places to retrieve options from. ) You may even want to explore creating your own form field type and template to format the output. Checkout the documentation on creating your own field type.
I hope that helps a bit. There are probably plenty of other ways to approach this as well.
I have an array which can have various keys. However, always exists two keys which are required. I use the OptionsResolver component now. It is works fine until there is no any extra keys. I also considered the Validator component and as I understood there is the same behaviour. So I need always set the full list of keys but as I wrote above I need validate only some of them. Is there a way to solve this problem?
Thanks!
Hello you can define required, optional and defaults values in OptionResolver.
Maybe I will give you some example so it will be easier than describing it:
$resolver = new Symfony\Component\OptionsResolver\OptionsResolver;
$resolver
->setRequired(['required1', 'required2'])
->setOptional(['optional1', 'optional2'])
->setDefaults(['defaultValue' => '123'])
;
$options = $resolver->resolve(
[
'required1' => 'test',
'required2' => 'test123',
'optional1' => 'opt'
]
);
then options will be looks like that
[
'defaultValue' => '123',
'required1' => 'test',
'required2' => 'test123',
'optional1' => 'opt',
]
if we do not set required1 or required2 in resolved array then we gotSymfony\Component\OptionsResolver\Exception\MissingOptionsException exception.
If we give not know option (not defined in setRequired, setOptional or setDefaults) then we got Symfony\Component\OptionsResolver\Exception\InvalidOptionsException exception.
I also considered the Validator component and as I understood there is the same behaviour
You can decide which values should be "required"... but not sure if I got what you mean exactly
A client requested this. He wants to allow multiple date formats for a birthday field. The documentation didn't give me any clues how to realize it and neither did google.
Anyone who experienced such a request before and has a lead how to achieve this?
Currently it looks like this:
$builder->add('xxx', 'birthday', array('widget' => 'single_text', 'invalid_message' => 'some message (dd-MM-yyyy)', 'format' => 'dd-MM-yyyy'))
If you want to handle different date formats in your form, you ought to look at DataTransformer
It helps you to transform data from one format to another, for example:
2013-03-26 ==transform==> 2013/03/26
2013.03.26 ==transform==> 2013/03/26
26.03.2013 ==transform==> 2013/03/26
Data transformer should NOT be used in this case.
The main point of data transformer is to convert a data back and forth between view <=> norm <=> model.
It's not your case, you don't want a bidirectional transformation.
What you want is to filter the data, and for that, you can use a form event:
$builder->add(
$builder
->create('xxx', 'birthday', [...])
->addEventListener(
FormEvents::PRE_SUBMIT,
function(FormEvent $event) {
$value = $event->getData();
// Do the filtering you want (for example replacement of special chars with a dash)
// $value = preg_replace('[^\d]', '-', $value)
$event->setData($value);
}
)
);
And you are done, the data is filtered on the PRE_SUBMIT event, before validation.
I wrote this example from memory and didn't tested it, maybe you'll should adapt it (and add your field option instead of [...].
I have a form that has an "I have read and agree to the terms of service" checkbox on it. The box must be checked in order for the form to be considered valid, but there's no reason to save that value to the database, of course, and there's no reason to add an attribute to the Entity.
What's a good way to implement this kind of functionality in Symfony2 such that the form won't be considered valid unless the box is checked?
This question is quite old and Symfony has updated this a lot. For Symfony 3.x you can do something like:
$builder->add('terms', CheckboxType::class, [
'mapped' => false,
'constraints' => new IsTrue(),
]);
From symfony docs:
When mapping forms to objects, all fields are mapped. Any fields on the form that do not exist on the mapped object will cause an exception to be thrown.
In cases where you need extra fields in the form (for example: a "do you agree with these terms" checkbox) that will not be mapped to the underlying object, you need to set the property_path option to false:
use Symfony\Component\Form\FormBuilderInterface;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('task');
$builder->add('dueDate', null, array('property_path' => false));
}
The field data can be accessed in a controller with:
$form->get('dueDate')->getData();