I want to have a form submitted by javascript that contains only one checkbox. But since empty checkboxes don't send their key in request, Symfony doesn't know about the form being submitted. So is there any not so hacky solution or is this kind of a "bug".
form:
class NewsletterType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('subscribingNewsletter', CheckboxType::class, [
'label' => 'form.label.newsletter',
'required' => false,
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}
part of the controller:
$newsletterForm = $this->formFactory->create(NewsletterType::class, $userToEdit);
$newsletterForm->handleRequest($request);
if ($this->newsletterFormHandler->handle($newsletterForm)) {
$this->session->getFlashBag()->add('notice', 'flash_message.newsletter_changed');
return $response;
}
handler:
public function handle(FormInterface $form): bool
{
if (!$form->isSubmitted() || !$form->isValid()) {
return false;
}
$this->userManager->update($form->getData());
return true;
}
view:
{{ form_start(NewsletterForm) }}
{{ form_row(NewsletterForm.subscribingNewsletter, {
attr: {class: 'js-newsletter-toggle'}
}) }}
{{ form_end(NewsletterForm) }}
So I finally resolved this issue. The only way I found to get this working is to add your submit button to your code like this:
class NewsletterType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('subscribingNewsletter', CheckboxType::class, [
'label' => 'form.label.newsletter',
'required' => false,
])
->add('submit', SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}
Not in your view. I was submitting the form by javascript so the way to to this is to simulate the button click in js.
Related
(Symfony 5.2, doctrine, PHP 8.0)
Take a look at this sample code:
more described here: https://symfony.com/doc/current/form/form_collections.html
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('description');
$builder->add('tags', CollectionType::class, [
'entry_type' => TagType::class,
'entry_options' => ['label' => false],
'prototype' => true,
'allow_add' => true,
'allow_delete' => true,
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Task::class,
]);
}
}
class TagType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('name');
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$tag = $event->getData();
$form = $event->getForm();
dd($tag); // empty because of prototype: true (as I said need it for adding new t
});
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Tag::class,
]);
}
}
TABLES:
TASK: id, name
TAG: id, task_id, name
my problem:
I would like to set - HTML attribute disabled for input name that meets the condition.
I need to get Task ID inside TagType so I can check if this id is used in another table and if so - disable changing tag name.
I tried multiple things but nothing worked for me.
The main problem is its a prototype (need it for adding/removing) and I don't receive tag id inside $tag = $event->getData(); in TagType so I can't get task id.
any idea? I didn't found the same problem on the internet and I'm not able to figure it out alone.
Something you can try is to use the PRE_SET_DATA event on the task form side to get the ID, and pass that ID to your tag form with the entry_options. Something like (not tested, but you'll get the idea) :
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('description');
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$task = $event->getData();
$form = $event->getForm();
$form->add('tags', CollectionType::class, [
'entry_type' => TagType::class,
'entry_options' => [
'label' => false,
'task_id' => !empty($task) ? $task->getId() : null,
],
'prototype' => true,
'allow_add' => true,
'allow_delete' => true,
]);
});
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Task::class,
]);
}
}
class TagType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
// $options['task_id']
// Use your taskId here. The value can be null, on the task creation form.
$builder->add('name');
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Tag::class,
'task_id' => null,
]);
}
}
I have 3 tables/entities. I am trying to create form to persist data to all 3 table in one form. Entitities are to long that is why I haven't added here.
Entity Client I made an array collection in Client entity for other 2 entities.
protected $Clientservice;
protected $Hostingaccount;
public function __construct()
{
$this->Clientservice = new ArrayCollection();
$this->Hostingaccount= new ArrayCollection();
}
public function getClientservice()
{
return $this->Clientservice;
}
public function getHostingaccount()
{
return $this->Hostingaccount;
}
public function setClientservice($Clientservice)
{
$this->Clientservice = $Clientservice;
return $this;
}
public function setHostingaccount($Hostingaccount)
{
$this->Hostingaccount = $Hostingaccount;
return $this;
}
And I Have 3 forms:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('CustomerID',IntegerType::class)
->add('Sex',TextType::class)
->add('Name',TextType::class)
->add('FirstName',TextType::class)
->add('LastName',TextType::class)
->add('Email', EmailType::class)
->add('Invoiceemail', EmailType::class)
->add('Iban', TextType::class)
->add('Bic', TextType::class)
->add('SEPAMandateID', TextType::class)
->add('LogoUrl', TextType::class)
->add('CreationDate', DateType::class)
->add('Clientservice', CollectionType::class, array(
'entry_type' => WhmAdminClientserviceType::class
))
->add('Hostingaccount', CollectionType::class, array(
'entry_type' => WhmAdminHostingAccountType::class
))
->getForm();
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Client::class
));
}
Clientservice form
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('Description',TextType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Clientservice::class
));
}
Hostingaccount form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('Domain',TextType::class)
->add('Domainip',IntegerType::class)
->add('UserName',TextType::class)
->add('Owner',TextType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Hostingaccount::class
));
}
In my controller I have the code like this:
public function AddWhmAdminAction(Request $request)
{
$Client = new Client();
$form = $this->createForm(WhmAdminType::class, $Client);
$form->add('submit', SubmitType::class, array(
'label' => 'Create',
'attr' => array('class' => 'btn btn-default pull-left')
));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($Client);
$em->flush();
$this->get('session')->getFlashBag()->add('green', 'Product created!');
return $this->redirectToRoute('whmAdmin');
// flash msg
}
//return $form->createView();
$build['form'] = $form->createView();
return $this->render('whm/WhmAdminForm.html.twig', $build);
}
and in my view
{{ form_start(form) }}
{% for flashMessage in app.session.flashbag.get('green') %}
{{ flashMessage }}
{% endfor %}
{{ form_end(form) }}
I followed http://symfony.com/doc/current/form/form_collections.html and this is how far I got.
My form only shows the fields from Client. It does not shows field from Clientservice and hostingaccount. How can I show the fields from clientservice and hostingaccount in the same form as Client.
If the Clientservice and Hostingaccount are in OneToOne or ManyToOne relationship then change:
->add('Clientservice', CollectionType::class, array(
'entry_type' => WhmAdminClientserviceType::class
))
->add('Hostingaccount', CollectionType::class, array(
'entry_type' => WhmAdminHostingAccountType::class
))
to:
->add('Clientservice', WhmAdminClientserviceType::class)
->add('Hostingaccount', WhmAdminHostingAccountType::class)
Otherwise leave your form builders and read about adding and removing items in collection type.
I have a trouble with a formtype with mapped=false.
In controller, I called the form with:
$form = $this->createForm(new JurisdictionUserNewType(), $jurisdiction_user);
This is my JurisdictionUserNewType:
class JurisdictionUserNewType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new CapitalLetterToLowerCaseTransformer();
$builder
->add('name', 'text')
->add($builder->create('email', 'email')
->addModelTransformer($transformer))
->add('securityUser', new SecurityUserType(), array('mapped' => false))
->add('save', 'submit');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Radmas\Open010Bundle\Document\JurisdictionUser'
));
}
public function getName()
{
return 'jurisdictionUserNew';
}
}
This is my SecurityUserType :
class SecurityUserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('first_name', null, ['label' => 'profile.edit.labels.first_name', 'icon_class' => 'fa fa-user'])
->add('last_name', null, ['label' => 'profile.edit.labels.last_name', 'icon_class' => 'fa fa-user'])
->add('nickname', null, ['label' => 'profile.edit.labels.nickname',
'attr' => [ 'help_text' => 'profile.edit.labels.nickname_help'], 'icon_class' => 'fa fa-globe']);
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Radmas\SecurityBundle\Document\SecurityUser'
));
}
public function getName()
{
return 'securityUser';
}
}
When I put data in the form, I get the object jurisdictionUser in the modalview but I dont get object securityUser.
If you set 'mapped' => false on any field, you're saying that that field isn't related to your entity, so you don't get it when you retrieve the entity from the submitted form.
You can get it anyway as a single field from the form, as:
$form->handleRequest($request);
if ($form->isValid()) {
$entity = $form->getData();
$securityUser = $form->get('securityUser')->getData();
}
I'm new to Symfony and twig templates. The problem I have is that I can't figure it out how to render the embedded form's fields separately in a twig template. I tried to search for it but probably others used a bit different forms and those examples didn't work for me.
My forms:
class RegistrationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('user', new UserType());
$builder->add(
'terms',
'checkbox',
array('property_path' => 'termsAccepted')
);
$builder->add('Register', 'submit');
}
public function getName()
{
return 'registration';
}
}
and
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('username', 'text');
$builder->add('name', 'text');
$builder->add('email', 'email');
$builder->add('password', 'repeated', array(
'first_name' => 'password',
'second_name' => 'confirm',
'type' => 'password',
'invalid_message' => 'Neteisingai pakartotas slaptažodis.',
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Keliones\MainBundle\Entity\User'
));
}
public function getName()
{
return 'user';
}
}
How the rendering field by field should look for that?
Basically Symfony and Form Framework creates Form object base on Type configuration classes. Form object has createView() method which is passed to view http://api.symfony.com/2.4/Symfony/Component/Form/FormView.html
In twig you can access embeded FormView object like that:
{# access embeded form #}
{{ form_row(form.user.username) }}
{{ form_row(form.user.email) }}
{{ form_row(form.user.password) }}
{# access main form field #}
{{ form_row(form.terms) }}
Hi I want to embed part of registration form from FOSUserBundle into another one. When I tried to add existing email, "Integrity constraint violation" exception was raised because unique validator is not used. How can I fix this. When registration form is used separately, validators are working correctly.
Main form:
class SoldierType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
...
->add('user', new NameFormType('Application\Sonata\UserBundle\Entity\User'))
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => array('registration')
));
}
public function getName()
{
return 'wnc_soldierbundle_soldiertype';
}
}
NameForm
namespace Application\Sonata\UserBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use FOS\UserBundle\Form\Type\RegistrationFormType as BaseForm;
class NameFormType extends BaseForm
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('firstname')
->add('lastname')
->add('email', 'email', array('label' => 'form.email', 'translation_domain' => 'FOSUserBundle'));
}
public function getName()
{
return 'fos_user_name';
}
}
Adding cascade_validation will make validation working in embedded forms.
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => array('Registration'),
'cascade_validation' => true,
));
}