PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Sunday, February 6, 2022

[FIXED] Dynamically modify the form choices in a Custom FormType using Form Events Symfony 5

 February 06, 2022     symfony, symfony-forms, symfony5     No comments   

Issue

I want to build a custom AjaxEntityType that loads the options over ajax. I cannot build the form with all the choices because there are too many and the performance is greatly affected.

The problem is that if I readd the form field (like in the cookbook) from within the custom type the data doesn't get submitted at all.

I need a way to change the choices from within the Custom Type Class without readding the form field.

Here is my class:

<?php

namespace App\Form\Type;

class AjaxEntityType extends AbstractType
{


    protected $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'ajax_url' => null
        ]);
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        
        $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($options) {
            $data = $event->getData();
            if ($data === null || $data === []) {
                return;
            }
            // here i get the ids from the submited data, get the entities from the database and I try to set them as choices
            $entityIds = is_array($data) ? $data : [$data];
            $entities = $this->em->getRepository($event->getForm()->getConfig()->getOptions()['class'])->findBy(["id" => $entityIds]);

            $options['choices'] = $entities;

            $event->getForm()->getParent()->add(
                $event->getForm()->getName(),
                self::class,
                $options
            );
            // the result is that the from gets submitted, but the new data is not set on the form. It's like the form field never existed in the first place.
        });

    }

    /**
     * {@inheritdoc}
     */
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['ajax_url'] = $options['ajax_url'];
    }

    public function getParent()
    {
        return EntityType::class;
    }
}

My controller is as simple as it gets:

public function create(Request $request, ProductService $productService, Product $product = null)
    {
        if(empty($product)){
            $product = new Product();
        }

        $form = $this->createForm(ProductType::class, $product);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {

            $this->getDoctrine()->getManager()->persist($product);
            $this->getDoctrine()->getManager()->flush();
            return $this->redirectToRoute('products_list');

        }

        return $this->render('admin/products/form.html.twig', [
            'page_title' => "Product form",
            'product' => $product,
            'form' => $form->createView()
        ]);
    }

Solution

Altering the form in the PRE_SET_DATA (to keep the selected choices in the form) and in the PRE_SUBMIT (to add the newly selected items to the choice list) ended up being a huge headache. Always needed some adjustments with a lot of complications.

So as a final solution I removed all the choices in the buildView method of my custom type class, it works well.

// in file App\Form\Type\AjaxEntityType.php
/**
 * {@inheritdoc}
 */
public function buildView(FormView $view, FormInterface $form, array $options)
{
    $view->vars['ajax_url'] = $options['ajax_url'];

    // in case it's not a multiple select
    if(!is_array($view->vars['value'])){
        $selected = [$view->vars['value']];
    }else{
        $selected = $view->vars['value'];
    }

    foreach($view->vars['choices'] as $index => $choice){
        if(!in_array($choice->value, $selected)){
            unset($view->vars['choices'][$index]);
        }
    }

}


Answered By - Vlad Dogarescu
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing