I have this Symfony form, it displays the values of the entity 'Manifestation' that has a many to many relationship.
So I do: ->add('manifestations').
But when I try to add an empty_value 'All' in the select list, it doesn't work!
Can any one help me ? Thanks
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('manifestations', 'entity', array(
'class' => 'PrifProtocoleBundle:Manifestation',
'multiple' => true,
'property' => 'name',
'empty_value' => 'All',
'required' => false,));
}
empty values New in Symfony version 2.3 .
empty values are also supported if the expanded option is set to true like Symfony 2.3 Documentation
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('manifestations', 'entity', array(
'class' => 'PrifProtocoleBundle:Manifestation',
'multiple' => true,
'expanded' => true,
'property' => 'name',
'empty_value' => 'All',
'required' => false,));
}
Related
Friends. This is the first question I ask here; so, any feedback will be welcome.
I'm new to Symfony; the version in which I'm working is 3.4
I already implemented three Type classes for my form and the structure is something like this:
There is a Registry which has a header plus zero, one or more questions. Each question is a "RegistryElement" which consist on zero, one or more answers plus an "elementScore" and an optional "elementComment."
The Type classes buildForm methods look like this:
On RegistryType.php:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('registryHeaderId', RegistryHeaderType::class, array(
'label' => false,
))
->add('registryElements', CollectionType::class, array(
'label'=>false,
'entry_type' => RegistryElementType::class,
'entry_options' => [
'label' => false,
'tokens'=>$options['tokens'],
],
'allow_add' => true,
'by_reference' => false,
))
->add('save', SubmitType::class, array("attr"=>array(
"class"=>"form-submit btn-success",
"style"=>"margin:10px;"
)))
;
}
On RegistryElementType.php:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('registryElementAnswers', CollectionType::class, array(
'label'=>false,
'entry_type' => RegistryElementAnswerType::class,
'entry_options' => [
'label' => false,
],
'allow_add' => true,
'by_reference' => false,
))
->add('elementScore', CheckboxType::class, array(
"label"=>'type.registry_element_type.score',
'required' => false,
"translation_domain" => "FirstPieceBundle",
))
->add('elementComment', TextType::class, array(
"label"=>'type.registry_element_type.element_comment',
"required"=>false,
"attr"=>array(
"class"=>"form-name form-control",
),
"translation_domain" => "FirstPieceBundle",
))
;
}
And, on RegistryElementAnswerType.php:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('answer', TextType::class, array(
"label"=>false,
"required"=>false,
"attr"=>array(
"class"=>"form-name form-control",
),
"translation_domain" => "FirstPieceBundle",
))
;
}
Now, what I would like to know is if there is a way to "add a different type of field" depending on a condition. Something like this:
public function buildForm(FormBuilderInterface $builder, array $options)
{
if(condition){
$builder
->add('answer', TextType::class, array(
"label"=>false,
"required"=>false,
"attr"=>array(
"class"=>"form-name form-control",
),
"translation_domain" => "FirstPieceBundle",
))
;
}
else{
$builder
->add('answer', ChoiceType::class, array(
"label"=>false,
"required"=>false,
"attr"=>array(
"class"=>"form-name form-control",
),
"translation_domain" => "FirstPieceBundle",
))
;
}
}
I tried to pass some values through the $options array, but I really got stuck here.
I'd really appreciate your knowledge and guidance.
Greetings.
What exactly is your condition you need to use there?
If you want to pass data in the $options array, you will need to add the option key as a required option in the configureOptions method.
Let's say you want to pass condition in the $options, your RegistryElementAnswerType class should contain:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setRequired('condition');
}
Now you are required to pass this option whenever you are referring to the RegistryElementAnswerType.
I have a form which looks roughly like this: first there is the ItemType:
class ItemType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, array())
->add('item_user_role', CollectionType::class, array(
'entry_type' => 'MyBundle\Form\ItemUserRoleType',
'allow_add' => true,
'mapped' => false,
'constraints' => array(
new ItemUserRole()
)
))
;
}
...
}
Then there is the ItemUserRoleType:
class ItemUserRoleType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'id',
TextType::class,
array(
'mapped' => false,
'constraints' => array(),
)
)
->add('roleid', EntityType::class, array(
'class' => 'MyBundle\Entity\Role',
'placeholder' => 'Select Role',
'required' => false,
'choice_label' => 'name',
'multiple' => false,
'expanded' => false,
'constraints' => array(
new NotNull(),
new NotBlank()
)
))
->add('userid', EntityType::class, array(
'class' => 'MyBundle\Entity\User',
'required' => false,
'choice_label' => 'LastName',
'multiple' => false,
'expanded' => false,
'constraints' => array(
new NotNull(),
new NotBlank()
)
))
;
}
}
What I want to achieve is that a submitted form can either contain only userid and roleid (which is used to create a new ItemUserRole) or contain an id as well (which is used to edit an existing ItemUserRole).
My Problem is now that in my custom Validator "ItemUserRole" I need to access the ID to make sure if the ID is set, then the user is allowed to modify it. But since it is not mapped, I haven't yet found out how to do that.
What I tried was this:
class ItemUserRoleValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
$tmp = $this->context->getRoot()->get('item_user_role')->getData()[0];
var_dump($tmp->getId());
return;
}
}
But that returns NULL. Any hints? Thanks in advance.
Use the $value variable.
class ItemUserRoleValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
$tmp = $value[0];
var_dump($tmp->getId());
return;
}
}
$this->context, doesn't contain any form data, but the collection of all the constraints violations discovered at this time.
I have the following form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('type', ChoiceType::class, array(
'expanded' => true,
'multiple' => false,
'choices' => array(
'Friend' => 'friend',
'Guide' => 'guide'
)
));
}
How can I make 'Friend' checkbox to be checked by default when the form is rendered ?
I think you should try with data option, but it's just in the case where you don't even have a data saved inside your object, because it will override it else.
Important : It's good for create action, but not for edit action.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('type', ChoiceType::class, array(
'expanded' => true,
'multiple' => false,
'choices' => array(
'Friend' => 'friend',
'Guide' => 'guide'
),
'data' => 'friend'
));
}
Official link
Extract :
When you create a form, each field initially displays the value of the
corresponding property of the form's domain object (if an object is
bound to the form). If you want to override the initial value for the
form or just an individual field, you can set it in the data option
UPDATE If YOU NEED EMPTY VALUE:
As the answer below, replace data with empty_data if you need in any case to update default value
Use the empty_data form field option. (not data because it will override any posted data unless you set it dynamically).
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('type', ChoiceType::class, array(
'expanded' => true,
'multiple' => false,
'choices' => array(
'Friend' => 'friend',
'Guide' => 'guide'
),
'empty_data' => 'friend'
));
}
Another option for complex cases is to use Sf Dynamic Form Events.
If you don't want to override value for an edition you can do this :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
$form->add(
'type',
ChoiceType::class,
[
'expanded' => true,
'multiple' => false,
'choices' => [
'Friend' => 'friend',
'Guide' => 'guide'
],
'data' => $event->getData() ?: 'friend'
]);
});
}
I think it would be better to set initial values in the Entity constructor:
public function __construct()
{
$this->exercises = new ArrayCollection();
$this->setTitle("WOCHE#") ;
$this->setYear(date('Y'));
$this->setWeekInCalendar(Week::getCurrentWeekInCalendar());
}
An other solution would be to set placeholder as false.
This would set the first value as default and minimize setup effort.
If the field needs to be nullable you could add one more choice i.e. 'empty' => null
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('type', ChoiceType::class, array(
'expanded' => true,
'multiple' => false,
'choices' => array(
'Friend' => 'friend',
'Guide' => 'guide'
),
'placeholder' => false
));
}
I have one superclass which gets extended by two entities. The superclass has a N:M relation with another entity. In the formbuilder of the latter, I need to separate the two subtypes into excluding separate fields.
This is its FormType::buildForm method:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('options_subtype_1', 'entity', [
'class' => 'AcmeExampleBundle:Options',
'expanded' => true,
'multiple' => true,
'property_path'=> 'options',
'query_builder' => /* specific filter 1 */
])
->add('options_subtype_2', 'entity', [
'class' => 'AcmeExampleBundle:Options',
'expanded' => true,
'multiple' => true,
'property_path'=> 'options',
'query_builder' => /* specific filter 2 */
])
;
}
However, no options are saved on form submission, except when I comment one of the two fields above (the one left is saved). I imagine setting property_path to the same property from two fields on the same form does not work.
How can I achieve this?
I'm still searching for the perfect solution by myself. For now I handle this kind of issues with a mapped hidden field and a PRE_SUBMIT Form Event. This could look like
FormType::buildForm
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('options_subtype_1', 'entity', [
'class' => 'AcmeExampleBundle:Options',
'expanded' => true,
'multiple' => true,
'mapped'=> false,
'data' => $builder->getData()->getOptions(),
'query_builder' => /* specific filter 1 */
])
->add('options_subtype_2', 'entity', [
'class' => 'AcmeExampleBundle:Options',
'expanded' => true,
'multiple' => true,
'mapped' => false,
'data' => $builder->getData()->getOptions(),
'query_builder' => /* specific filter 2 */
])
->add('options', 'entity', [
'class' => 'AcmeExampleBundle:Options',
'required' => false,
'multiple' => true,
'attr' => ['style' => 'visibility: hidden;'],
'label' => false
]);
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (FormEvent $event) {
$data = $event->getData();
unset($data['options']);
$data['options'] = array_merge($data['options_subtype_1'], $data['options_subtype_2']);
$event->setData($data);
}
);
}
I have the following entity relations:
A Customer has one-to-many Address
An Address has many-to-one County and many-to-one City
A County has one-to-many City.
So, in my CustomerType, I have
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
...
->add('addresss', 'collection', array(
'label' => 'customer.address',
'type' => new AddressType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
))
;
}
And in my AddressType, I have
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
...
->add('city', 'entity', array(
'class' => 'MyCustomerBundle:City',
'query_builder' => function(CityRepository $cr) use ($options) {
return $cr->getCityQB($options['county']);
},
'property' => 'city',
'empty_value' => '',
))
;
}
My goal is to only display the set of cities for their corresponding county. I can get the values into CustomerType from $options but how can I pass down the values to AddressType? So that each address gets its corresponding county to look up the cities?
Any help would be appreciated. Thanks!
in symfony3 :
$builder->add('example', CollectionType::class, array(
'entry_type' => ExampleType::class,
'entry_options' => array(
'my_custom_option' => true),
));
Use the constructor in AddressType, its works for me..
CustomerType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
...
->add('addresss', 'collection', array(
'label' => 'customer.address',
'type' => new AddressType($your_variable),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
))
;
}
AddressType:
private $your_variable;
public function __construct($variable)
{
$this->your_variable= $variable;
}
...
public function buildForm(FormBuilderInterface $builder, array $options){
$your_variable = $this->your_variable;
'query_builder' => function(CityRepository $cr) use ($your_variable) {
return $cr->getCityQB($your_variable);
},
}
I think you could use the 'options' option of the collection type. It's better than using the constructor in case you want to reuse the form elsewhere.
Symfony Form Reference: Collection Type
But remember to define the variable in your setDefaultOptions method. (Both forms must have it)