I have a Symfony form built with
class BracketCommandForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
//...
}
public function getName() {
return 'bracket_command_form';
}
}
When this form is rendered, it comes with this heading-like <legend>New bracket command</legend> with the actual form below it.
Goal
I want to override the legend, without changing the name of the form or anything else. Can this be done? If so, where?
Any tips appreciated!
That text didn't came from your FormType class, it is passed from the Controller (by default in newAction function)
Try this in your controller
$form = $this->createForm(new BracketCommandForm (), $command, array(
'show_legend' => true, //false if you don't want the legend at all
'label' => 'My Text',
));
Alternatively, I believe you could have this as part of the defaults for that form
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'label' => 'My Text',
));
}
Related
Is it possible to set the label value of a form type to be a property value that is available in the data object?
My FormType class:
class ShapeFractionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('value', NumberType::class, [
'label' => 'name'
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => ShapeFraction::class,
]);
}
}
The ShapeFraction data class:
class ShapeFraction
{
public string $name;
public string $type;
public float $value;
// ...
}
Rendering the form:
$shapeFraction = new ShapeFraction('A', 'length', 10);
$form = $formFactory->create(ShapeFractionType::class, $shapeFraction);
// Render using Twig...
The result is a simple form containing a single input with 'name' as label. Is it possible to use the property value of ShapeFraction::$name as the label of the field? Result will become like this: A: <input..>.
I would like to achieve this without using the object data directly in Twig or something.
Thanks in advance!
You can access the data that you pass to your form using $options['data'].
That means you can do this:
/** #var ShapeFraction $shapeFraction */
$shapeFraction= $options['data'];
$builder->add('value', NumberType::class, [
'label' => $shapeFraction->name
]);
I have three three select fields for one entity attribute. As the picture below shows.
Is there a way to detect which of the select fields is used; then get its value and map it with the corresponding attribute?
And is it possible to send parameters to a form type (in this example TestType , please see below). I am trying to make it generic and re-usable for other attributes.
Here is what I have up to now.
MyForm.php
<?php
namespace MyBundle\Form;
use MyBundle\Form\Type\TestType;
use ..etc
class MyForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class)
->add('D1', TestType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'MyBundle\Entity\Project'
));
}
public function getBlockPrefix()
{
return 'mybundle_project';
}
}
TestType.php
<?php
namespace MyBundle\Form\Type;
use Sonata\AdminBundle\Form\Type\Filter\ChoiceType;
use ..etc
class TestType extends AbstractType
{
/*
* private $myArray1;
* private $myArray2;
* private $myArray3; numberOfSeletcs
* private $numberOfSeletcs;
Secondary Question: Is it possible to send these values as parameters?
public function __construct($array1, $array2, $array3, $n)
{
$this->myArray1= $array1;
$this->myArray2= $array2;
$this->myArray3= $array3;
$this->numberOfSeletcs= $n;
}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$myArray1 = array('label1'=>'','Value1'=>'Value1', 'Value2'=>'Value2','Value3'=>'Value3');
$myArray2 = array('label2'=>'', 'Value4'=>'Value4','Value5'=>'Value5');
$myArray3 = array('label3'=>'', 'Value6'=>'Value6','Value6'=>'Value6');
$builder
// ...
->add('H1', 'choice', array(
'choices' => $myArray1,
'choice_attr' => ['label1' => ['disabled selected hidden'=>'']]))
->add('H2', 'choice', array(
'choices' => $myArray2,
'choice_attr' => ['label2' => ['disabled selected hidden'=>'']]))
->add('H3', 'choice', array(
'choices' => $myArray3,
'choice_attr' => ['label3' => ['disabled selected hidden'=>'']]));
}
}
Thanks.
To detect which of the select fields is used you have to use Javascript. As you know Symfony is a PHP framework working on the server-side and to detect event on client-side javascript is needed. And for pass parameter to your form type you have the answer in this topic
Using Symfony 3.2 and FOS REST Bundle I have created some REST endpoints for a resource and use a Symfony Form to define the fields for API DOC. Everything is working fine to this point.
Now I'm trying to improve my schema and added a sub entity (one-to-one) to my resource. I want the main resource to save the sub entity - there is no dedicated endpoint for the sub entity.
I followed the instruction on the Symfony documentation and removed all other fields to isolate any issues.
This is how my form type looks now:
<?php
namespace VendorName\MyBundle\Form;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CountryType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('mySubEntity', EntityType::class, array(
'multiple' => false,
'expanded' => false,
'property' => 'name',
'class' => 'MyBundle\Entity\mySubEntity'));
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'VendorName\MyBundle\Entity\Country',
'csrf_protection' => false
));
}
}
Now when I load my api-docs, I receive the error message The option "property" does not exist. Defined options are: "action", "allow_extra_fields", [...].
To be honest, I don't even know if adding the Entity to the form is the right approach to make it show up in the API Docs. Any help in resolving the above issue and / or best practices to achieve this would be appreciated.
EDIT: Thanks to #miikes this error is now resolved and I can see the api doc showing up correctly with the fields of the nested form. However, now my issue is that the form does not populate the sub entity on the parent entity. This seems to be related to the way I modelled the parent-child relationship and I have posted a new question for this issue.
To resolve your error try to use choice_label, instead of property option.
'choice_label' => 'name'
But referring to the documentation, EntityType is a kind of ChoiceType, so using this type, you can only select existing entity, not persist new one.
The easiest and most clear way for creating new entity instance is creating another type class, designed for your entity, and adding the type as the field to your CountryType.
class MyEntityType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('some-field', TextType::class)
->add('another-field', TextType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => MyEntity::class
]);
}
}
class CountryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('mySubEntity', MyEntityType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Country::class,
'csrf_protection' => false
));
}
}
So you should pass form data as
['mySubEntity']['some-field'] = 'foo'
['mySubEntity']['another-field'] = 'bar'
Another tip is to use Country::class instead of string 'VendorName\MyBundle\Entity\Country', because in case of renaming class, IDE refactoring should affect on your type.
I need to embed one form into another form and I'm doing as follow:
use Symfony\Component\Form\AbstractType,
Symfony\Component\Form\FormBuilderInterface,
Symfony\Component\OptionsResolver\OptionsResolverInterface,
Common\CommonBundle\Form\AddressExtraInfoType;
class StandardAddressType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('country', 'entity', array( ... ))
->add('state', 'entity', array( ... ))
->add('city', 'entity', array( ... ))
->add('extra_info', new AddressExtraInfoType());
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'Common\CommonBundle\Entity\StandardAddress'
));
}
public function getName() {
return 'common_commonbundle_standard_address';
}
}
Since the main form need to be attached to the 'data_class' => 'Common\CommonBundle\Entity\StandardAddress' then when I try to get the form this error come up:
Neither the property "extra_info" nor one of the methods "getExtraInfo()", "isExtraInfo()", "hasExtraInfo()", "__get()" exist and have public access in class "Common\CommonBundle\Entity\StandardAddress"
How I can fix this? How I can embed the second form into the first one without get this eror?
try this:
$builder->add('extra_info', new AddressExtraInfoType(), array('mapped' => false));
You don't have field extra_info in class Common\CommonBundle\Entity\StandardAddress so you must use non mapped field in form type
Finally and after read my code once again I found where the error was. In my AddressExtraInfoentity I had address_extra_info and of course changing that to extra_info fix the issue, anyway thanks for your reply
I use Symfony2.1's FormBuilder to create a dynamic form in the controller:
$form = $this->createFormBuilder($defaultData);
$form->add('field','text');
I would like to embed another form in the same way and embed it with the main form.
$subForm = $this->createFormBuilder();
$subForm->add('subfield','text');
// Does not work
$form->add('subform', $subForm);
Unfortunately this setup does not work properly. I could not find any way how to add a dynamically generated subform into a dynamically generated form, like the example above.
What's the function call I am missing?
The exception thrown by the example code above is
UnexpectedTypeException: Expected argument of type "string or
Symfony\Component\Form\FormTypeInterface",
"Symfony\Component\Form\Form" given.
I would create two Form Clases in two separate fields:
<?php
namespace Acme\DemoBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class FirstFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('field', 'text')
->add('subform', new SecondFormType());
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\DemoBundle\Entity\FirstEntity'
));
}
public function getName()
{
return 'first';
}
}
<?php
namespace Acme\DemoBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class SecondFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('subfield', 'text');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\DemoBundle\Entity\SecondEntity',
));
}
public function getName()
{
return 'second';
}
}
After this creation you can create your form from any Controller with this line for creation forms:
$form = $this->createForm(new FirstFormType());
or for edition forms:
$form = $this->createForm(new FirstFormType(), $first);
In your example code you are trying to assig to a field an entire form instead of a Form Type.
Hope it helps
Recommended symfony-way is to create separate FormType classes, as mentioned above. But if you really want to..
You can add dynamic subform into form builder, by calling
$formBuilder->add($subform /* FormBuilder */);
This subform will have name "form" if created with $this->createFormBuilder(); , that means that you can not add two or more subforms created this way - newer one will overwrite previous with same name.
If you need to add multiple sub-forms, you have to create their builders with
$this->get('form.factory')->createNamedBuilder($uniqName)
Without making classes... inside a Controller Action:
$subFormBuilder = $this->createFormBuilder(
null /* default data */,
['label' => 'Sub Form'] /* options */
)
->add('name');
$form = $this->createFormBuilder()
->add($subFormBuilder)
->add('number')
->getForm();