Symfony 2 - Form collection for one entity without parent entity - forms

I have problem with form collection. I want to show one form with all values from one entity and I want to be able to add or remove some record(line) from this entity on one page. I have the following solutions, which is ok.
CurrencyController
class CurrencyController extends Controller {
/**
* #Template()
*/
public function testAction() {
$em = $this->getDoctrine()->getManager();
$currencies = $em->getRepository('MyWebBundle:Currency')->findAll();
$arr = array('currencies' => $currencies);
$form = $this->createFormBuilder($arr)
->add('currencies', 'collection', array(
'type' => new CurrencyType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
))
->add('submit', 'button', array('label' => 'Odeslat'))
->getForm();
return array(
'form' => $form->createView(),
);
}
}
CurrencyType
class CurrencyType extends AbstractType {
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('abbreviation', 'text')
->add('rate', 'number')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'My\WebBundle\Entity\Currency'
));
}
/**
* #return string
*/
public function getName() {
return 'currency';
}
}
Twig
{% extends '::base.html.twig' %}
{% block body -%}
<h1>Test</h1>
{{ form(form) }}
{% endblock %}
If I use form class for CurrenciesType, then Symfony throws exception
Notice: Object of class My\WebBundle\Entity\Currency could not be converted to int in
....\web\vendor\symfony\symfony\src\Symfony\Component\
Form\Extension\Core\ChoiceList\ChoiceList.php line 462
Code for this is below.
CurrencyController
class CurrencyController extends Controller {
/**
* #Template()
*/
public function testAction() {
$em = $this->getDoctrine()->getManager();
$currencies = $em->getRepository('MyWebBundle:Currency')->findAll();
$arr = array('currencies' => $currencies);
$form = $this->createForm(new CurrenciesType(), $arr);
return array(
'form' => $form->createView(),
);
}
}
CurrenciesType
class CurrenciesType extends AbstractType {
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('currencies', 'collection', array(
'type' => new CurrencyType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
))
->add('submit', 'button', array('label' => 'Send'))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => null
));
}
/**
* #return string
*/
public function getName() {
return 'my_webbundle_currencies';
}
}
CurrencyType and Twig are same as above.
I found solution these solution #1 solution #2, but my symfony still throws exception as above and I don't see different in my solution and these solutions. Please help with this problem. Thank you all :)

Related

Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException: The options " " do not exist. Known options are: ""

This is my form
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class JoseType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nombre')
->add('apellido','entity', array(
// 'required' => false,
'empty_value' => 'Select',
'mapped' => false,
'class' => 'AppBundle:SolutionTypeCategory',
'attr' => array(
'placeholder' => 'Select',
'data-msg-required' => "Required Solution Type Category",
),
))
->add('edad')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Jose'
));
}
/**
* #return string
*/
public function getName()
{
return 'appbundle_jose';
}
}
I receive this error
Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException: The options "attr", "class", "empty_value", "mapp
ed" do not exist. Known options are: "".
And the following is my test:
class ProjectTypeTest extends TypeTestCase
{
public function testJose()
{
$type = new JoseType();
$form = $this->factory->create($type);
}
// get extensions...
protected function getExtensions()
{
$mockEntityType = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\Type\EntityType')
->disableOriginalConstructor()
->getMock();
$mockEntityType->expects($this->any())->method('getName')
->will($this->returnValue('entity'));
return array(new PreloadedExtension(array(
$mockEntityType->getName() => $mockEntityType,
), array()));
}
}
I don't understand that error, looking take the values array options of form.
Why?
Help me please!
When you invoke ->add() from $builder - there is a list of pre set options that you are allowed to use.
Each form type has a number of options to configure it, as explained in the Symfony form types reference.

Form Subscriber and "this form should not contain extra fields" error

I'm using symfony 2.3, so apparently, I can't use the 'allow_extra_fields' option discussed here.
I have a main Form Type, RegistrationStep1UserType :
/**
* Class RegistrationStep1UserType
* #package Evo\DeclarationBundle\Form\Type
*/
class RegistrationStep1UserType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('customer', new RegistrationStep1CustomerType(), [
'label' => false,
'data_class' => 'Evo\UserBundle\Entity\Customer',
'cascade_validation' => true,
])
->add('declaration', 'evo_declaration_bundle_registration_step1_declaration_type', [
'label' => false,
'cascade_validation' => true,
])
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Evo\UserBundle\Entity\User',
'validation_groups' => false,
));
}
/**
* #return string
*/
public function getName()
{
return 'evo_declaration_bundle_registration_step1_user_type';
}
}
This form type includes an embedded Form Type (on "declaration" field), RegistrationStep1DeclarationType, registered as a service :
/**
* Class RegistrationStep1DeclarationType
* #package Evo\DeclarationBundle\Form\Type
*/
class RegistrationStep1DeclarationType extends AbstractType
{
/**
* #var EntityManagerInterface
*/
private $em;
/**
* #var EventSubscriberInterface
*/
private $addBirthCountyFieldSubscriber;
/**
* RegistrationStep1DeclarationType constructor.
* #param EntityManagerInterface $em
* #param EventSubscriberInterface $addBirthCountyFieldSubscriber
*/
public function __construct(EntityManagerInterface $em, EventSubscriberInterface $addBirthCountyFieldSubscriber)
{
$this->em = $em;
$this->addBirthCountyFieldSubscriber = $addBirthCountyFieldSubscriber;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('birthLastname', null, [
'label' => 'Nom de naissance',
'attr' => [
'required' => true,
],
])
->add('nationality', 'entity', [
'label' => 'Nationalité',
'class' => 'Evo\GeoBundle\Entity\Country',
'property' => 'nationalityFr',
'attr' => [
'required' => true,
'class' => 'selectpicker',
],
'preferred_choices' => $this->fillPreferredNationalities(),
])
->add('birthCountry', 'entity', [
'label' => 'Pays de naissance',
'class' => 'Evo\GeoBundle\Entity\Country',
'property' => 'nameFr',
'empty_value' => '',
'empty_data' => null,
'attr' => [
'required' => true,
'class' => 'trigger-form-modification selectpicker',
],
'preferred_choices' => $this->fillPreferredBirthCountries(),
])
->add('birthCity', null, [
'label' => 'Ville de naissance',
'attr' => [
'required' => true,
],
])
;
$builder->get("birthCountry")->addEventSubscriber($this->addBirthCountyFieldSubscriber);
}
/**
* #return array
*/
private function fillPreferredNationalities()
{
$nationalities = $this->em->getRepository("EvoGeoBundle:Country")->findBy(["isDefault" => true]);
return $nationalities;
}
/**
* #return array|\Evo\GeoBundle\Entity\Country[]
*/
private function fillPreferredBirthCountries()
{
$countries = $this->em->getRepository("EvoGeoBundle:Country")->findBy(["isDefault" => true]);
return $countries;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'required' => false,
'data_class' => 'Evo\DeclarationBundle\Entity\Declaration',
'validation_groups' => false,
));
}
/**
* #return string
*/
public function getName()
{
return 'evo_declaration_bundle_registration_step1_declaration_type';
}
}
This embedded Form Type adds a Subscriber (registered as a service too, because it needs injection of EntityManager) on the "birthCountry" field.
The goal is to dynamically add or remove an extra field (called "birthCounty") depending on the value of the birthCountry choice list (note the 2 fields are different here, "birthCountry" and "birthCounty").
Here is the Subscriber :
/**
* Class AddBirthCountyFieldSubscriber
* #package Evo\CalculatorBundle\Form\EventListener
*/
class AddBirthCountyFieldSubscriber implements EventSubscriberInterface
{
/**
* #var EntityManagerInterface
*/
private $em;
/**
* AddBirthCountyFieldSubscriber constructor.
* #param EntityManagerInterface $em
*/
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
/**
* #return array
*/
public static function getSubscribedEvents()
{
return array(
FormEvents::POST_SET_DATA => 'postSetData',
FormEvents::POST_SUBMIT => 'postSubmit',
);
}
/**
* #param FormEvent $event
*/
public function postSetData(FormEvent $event)
{
$birthCountry = $event->getData();
$form = $event->getForm()->getParent();
$this->removeConditionalFields($form);
if ($birthCountry instanceof Country && true === $birthCountry->getIsDefault()) {
$this->addBirthCountyField($form);
}
}
/**
* #param FormEvent $event
*/
public function postSubmit(FormEvent $event)
{
$birthCountry = $event->getData();
$form = $event->getForm()->getParent();
if (!empty($birthCountry)) {
$country = $this->em->getRepository("EvoGeoBundle:Country")->find($birthCountry);
$this->removeConditionalFields($form);
if ($country instanceof Country && true === $country->getIsDefault()) {
$this->addBirthCountyField($form);
}
}
}
/**
* #param FormInterface $form
*/
private function addBirthCountyField(FormInterface $form)
{
$form
->add('birthCounty', 'evo_geo_bundle_autocomplete_county_type', [
'label' => 'Département de naissance',
'attr' => [
'required' => true,
],
])
;
}
/**
* #param FormInterface $form
*/
private function removeConditionalFields(FormInterface $form)
{
$form->remove('birthCounty');
}
}
In the view, when the "birthCountry" choice list changes, it trigger an AJAX request to the controller, which handles the request and render the view again (as explained in the documentation about dynamic form submission) :
$form = $this->createForm(new RegistrationStep1UserType(), $user);
if ($request->isXmlHttpRequest()) {
$form->handleRequest($request);
} elseif ("POST" == $request->getMethod()) {
[...]
}
The problem is the following :
When I make a change on the birthCountry choice list and select a Country supposed to hide the "birthCounty" field, the form correctly render without that field, but it shows an error message :
Ce formulaire ne doit pas contenir des champs supplémentaires.
or
this form should not contain extra fields (in english)
I tried many different solutions :
adding a 'validation_groups' option to RegistrationStep1UserType and RegistrationStep1DeclarationType
adding a preSubmit event to AddBirthCountyFieldSubscriber replicating the logic of preSetData and postSubmit methods
even adding 'mapped' => false, to the birthCounty field triggers the error. very surprising
Even $form->getExtraData() is empty if I dump it just after $form->handleRequest($request);
But in vendor\symfony\symfony\src\Symfony\Component\Form\Extension\Validator\Constraints\FormValidator, I can see an extra field
array(1) {
["birthCounty"]=>
string(0) ""
}
here :
// Mark the form with an error if it contains extra fields
if (count($form->getExtraData()) > 0) {
echo '<pre>';
\Doctrine\Common\Util\Debug::dump($form->getExtraData());
echo '</pre>';
die();
$this->context->addViolation(
$config->getOption('extra_fields_message'),
array('{{ extra_fields }}' => implode('", "', array_keys($form->getExtraData()))),
$form->getExtraData()
);
}
Did I miss something about form dynamic extra fields ?
I did not analyzed all the question but, I guess, that you can invert the logic: always add that field and remove it when the condition is not satisfied.
That way you don't need to perform operations in postSubmit (that is where the issue is)

Constraints\Callback annotation validate the previous (not submitted) entity

I'm using a Callback to validate an entity
/**
* #ORM\Entity(repositoryClass="AppBundle\Repository\Foo")
* #ORM\Table(name="foo")
* #Constraints\Callback(methods={"validate"})
*/
class Foo
{
...
function validate(ExecutionContextInterface $context)
{
if ($this->foos) {
$context->buildViolation('Foos cannot be emty')
->atPath('foos')
->addViolation();
}
}
A form is using this entity:
class FooFormType extends AbstractType
{
private $foosService;
function __construct(FoosService $foosService) {
$this->foosService = $foosService;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('foos', EntityType::class, array(
'label' => false,
'class' => 'AppBundle:Entity\Foo',
'choices' => $this->foosService->getSomeFoos($builder->getData()),
'expanded' => true,
'multiple' => true,
'required' => true,
))
->getForm();
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Foo',
));
}
}
This form is called within a factory:
public function getFooForm(Foo $foo)
{
return $this->formFactory->create(new FooFormType($this->foosService), $foo);
}
Finally, in the controller:
...
$form = $this->get('my_factory')->getFooForm($foo);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
...
}
...
This seems to work correctly, but the validation is being done over the previous entity. I mean, if I submit empty foos I can see the validation error, but if I sumbit some foos, and then I remove those foosand submit again, the validation doesn't throw any exception because it's being done over the last entity, which had some foos. I've checked that the submitted data is correct, and indeed, Foo entity is been persisted with empty foos (only if the previous one had foos).
What can be causing this weird behaviour?

Symfony2 : data not binded to form with handleRequest()

I have created a complex symfony form with nested collection. When i create my form with data from orm it works :
$categories = $this->getDoctrine()->getRepository('xx:CategoryNutritionProgram')->findAll();
$form = $this->createForm(new CategoryCollectionFormType(), array('categories' => $categories));
CategoryCollectionFormType :
class CategoryCollectionFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('categories', 'collection', array(
'type' => new CategoryFormType(),
'cascade_validation' => true,
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
'prototype_name' => '__i__'
));
}
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName()
{
return 'simulator_category_collection';
}
}
CategoryFormType :
class CategoryFormType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'hidden');
$builder->add('nutritionPrograms', 'collection', array(
'type' => new NutritionProgramFormType(),
'cascade_validation' => true,
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
'prototype_name' => '__j__'
));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'xx\Entity\CategoryNutritionProgram'
));
}
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName()
{
return 'simulator_category';
}
}
etc ...
But handleRequest() function doesn't work and $data are empty when i submit form. Where is the problem ? my code seems good
$data = array('categories' => array());
$form = $this->createForm(new CategoryCollectionFormType(), $data);
$form->handleRequest($request);
Below the data sent on POST request :
simulator_category_collection[categories][0][name]:cat1
simulator_category_collection[categories][0][nutritionPrograms][0][name]:prog1
simulator_category_collection[categories][0][nutritionPrograms][0][applications][0][name]:app1
simulator_category_collection[categories][0][nutritionPrograms][0][applications][0][product]:1
simulator_category_collection[categories][0][nutritionPrograms][0][applications][0][dose]:5
simulator_category_collection[categories][0][nutritionPrograms][0][applications][0][unit]:5
simulator_category_collection[categories][0][nutritionPrograms][0][applications][1][name]:app2
simulator_category_collection[categories][0][nutritionPrograms][0][applications][1][product]:2
simulator_category_collection[categories][0][nutritionPrograms][0][applications][1][dose]:6
simulator_category_collection[categories][0][nutritionPrograms][0][applications][1][unit]:6
simulator_category_collection[categories][0][nutritionPrograms][1][name]:prog2
simulator_category_collection[categories][0][nutritionPrograms][1][applications][0][name]:app3
simulator_category_collection[categories][0][nutritionPrograms][1][applications][0][product]:3
simulator_category_collection[categories][0][nutritionPrograms][1][applications][0][dose]:7
simulator_category_collection[categories][0][nutritionPrograms][1][applications][0][unit]:7
simulator_category_collection[categories][1][name]:cat2
simulator_category_collection[categories][1][nutritionPrograms][0][name]:prog3
simulator_category_collection[_token]:xxx
Thx for help
Resolved, instead of trying to get data from orginal object like this :
$data = array('categories' => array());
$form = $this->createForm(new CategoryCollectionFormType(), $data);
$form->handleRequest($request);
// here array $data is empty
I have to use $form->getData() because my array is passed by value

How to merge 2 form in Symfony2

I'm trying to create a very simple forum with Symfony2.
My entities are:
ForumCategory (name, description...)
ForumTopic (category_id, title)
ForumPost (isFirstPost, body, topic_id, author_id...)
When a user try to create a Topic, I want to display only one form in the same page to create a Topic and the first post message. Like:
Insert topic title: ...
Insert topic body (related Post Body): ...
[...]
How can I do that? It's possible merge two form in this case?
Make a form type that contains both of your sub forms.
class MergedFormType
$builder->add('topic', new TopicFormType());
$builder->add('post', new PostFormType());
In your controller just pass an array to MergedFormType
public function myAction()
$formData['topic'] = $topic;
$formData['post'] = $post;
$form = $this->createForm(new MergedFormType(), $formData);
Incase if you are looking to merge forms for 2 entities with one to many or one to one relationship; you will need to use form collection extension of symfony 2 component. for eg: where Task entity has many Tags
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('description');
$builder->add('tags', 'collection', array('type' => new TagType()));
}
Rendering can be done this way
{{ form_start(form) }}
<h3>Tags</h3>
<ul class="tags">
{# iterate over each existing tag and render its only field: name #}
{% for tag in form.tags %}
<li>{{ form_row(tag.name) }}</li>
{% endfor %}
</ul>
Further details:
http://symfony.com/doc/2.7/cookbook/form/form_collections.html
You can also map the same entity to multiple merged forms.
$entity = new Form();
$form = $this->get('form.factory')->create(FormType::class, [
'form_builder' => $entity,
'submit_builder' => $entity,
]);
FormType.php
<?php
namespace GenyBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\OptionsResolver\OptionsResolver;
use GenyBundle\Entity\Form;
class FormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('form_builder', FormBuilderType::class, [
'data_class' => Form::class,
'label' => false, // Important!
])
->add('submit_builder', SubmitBuilderType::class, [
'data_class' => Form::class,
'label' => false,
])
->add('save', Type\SubmitType::class, [
'label' => 'geny.type.form.save.label',
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'translation_domain' => 'geny',
]);
}
}
FormBuilderType.php
<?php
namespace GenyBundle\Form\Type;
use GenyBundle\Base\BaseType;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class FormBuilderType extends BaseType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', Type\TextType::class, [
'attr' => [
'placeholder' => 'geny.type.form.title.placeholder',
],
'empty_data' => $this->get('translator')->trans('geny.type.form.title.default', [], 'geny'),
'label' => 'geny.type.form.title.label',
'required' => true,
])
->add('description', Type\TextareaType::class, [
'attr' => [
'placeholder' => 'geny.type.form.description.placeholder',
],
'empty_data' => null,
'label' => 'geny.type.form.description.label',
'required' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'GenyBundle\Entity\Form',
'translation_domain' => 'geny',
]);
}
}
SubmitBuilderType.php
<?php
namespace GenyBundle\Form\Type;
use GenyBundle\Base\BaseType;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class SubmitBuilderType extends BaseType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('submit', Type\TextType::class, [
'attr' => [
'placeholder' => 'geny.type.submit.submit.placeholder',
],
'empty_data' => $this->get('translator')->trans('geny.type.submit.submit.default', [], 'geny'),
'label' => 'geny.type.submit.submit.label',
'required' => true,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'GenyBundle\Entity\Form',
'translation_domain' => 'geny',
]);
}
}
Form.php
<?php
namespace GenyBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serializer;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Table(name="geny_form")
* #ORM\Entity(repositoryClass="GenyBundle\Repository\FormRepository")
* #ORM\ChangeTrackingPolicy("DEFERRED_EXPLICIT")
* #Serializer\ExclusionPolicy("NONE")
*/
class Form
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Id
* #Serializer\Exclude
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=128)
* #Assert\Length(min = 1, max = 128)
* #Serializer\Type("string")
*/
protected $title;
/**
* #var string
*
* #ORM\Column(name="description", type="text", nullable=true)
* #Assert\Length(min = 0, max = 4096)
* #Serializer\Type("string")
*/
protected $description;
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="Field", mappedBy="form", cascade={"all"}, orphanRemoval=true)
* #ORM\OrderBy({"position" = "ASC"})
* #Assert\Valid()
* #Serializer\Type("ArrayCollection<GenyBundle\Entity\Field>")
*/
protected $fields;
/**
* #var string
*
* #ORM\Column(name="submit", type="text")
* #Assert\Length(min = 1, max = 64)
* #Serializer\Type("string")
*/
protected $submit;
}
Result: