0

I would like to know if there is a way to "manage" the many to one association in a symfony form different from a select (input with jQuery autocomplete for example).

I found this question so I read the documentation about DataTransformers

Here my transformer class

// src/AppBundle/Form/DataTransformer/ZipcodesTransformer.php
namespace AppBundle\Form\DataTransformer;

use AppBundle\Entity\Issue;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;

class ZipcodesTransformer implements DataTransformerInterface {
    private $manager;
    public function __construct(ObjectManager $manager) {
        $this->manager = $manager;
    }

    public function transform($zipcode) {
        if (null === $zipcode) {
            return '';
        }
        return $zipcode->getId();
    }

    public function reverseTransform($zipcodeId) {
        if (!$zipcodeId) {
            return;
        }

        $zipcode = ->this->manager->getRepository('AppBundle:Zipcodes')->find($zipcodeId)
        ;

        if (null === $zipcode) {
            throw new TransformationFailedException(sprintf(
                'An zipcode with number "%s" does not exist!',
                $zipcodeId
            ));
        }

        return $zipcode;
    }
}

Then the selector Type class

// src/AppBundle/Form/ZipcodeSelectorType.php
namespace AppBundle\Form;

use AppBundle\Form\DataTransformer\ZipcodesTransformer;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;

class ZipcodeType extends AbstractType
{
    private $manager;

    public function __construct(ObjectManager $manager)
    {
        $this->manager = $manager;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $transformer = new ZipcodesTransformer($this->manager);
        $builder->addModelTransformer($transformer);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'invalid_message' => 'The selected ZIPCODE does not exist',
        ));
    }

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

And the class for the object form is

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use AppBundle\Form\DataTransformer\ZipcodesTransformer;

class CustomerType extends AbstractType
{

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class ,array('label'=>'Customer Name'))
            ...
            ->add('email', EmailType::class)
            ->add('flag', CheckboxType::class, array('required' => false))
            ->add('zipcode', ZipcodeType::class)
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults(array('data_class' => 'AppBundle\Entity\Customer'));
    }
}

Thanks to Kern the code is now correct and working. Now in order to "activate" the jQuery autocomplete already tested I modify the ZipcodeSelectorType.php and add this function

public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(
        array (
            'invalid_message' => 'The selected ZIPCODE does not exist',
            'attr' => array('class'=>'zipcodeac'),//ADDED THIS LINE
            'placeholder'=>'Type to select a zipcode'//ADDED THIS LINE
          )
        );
    }

but when renderig the form the input has this class

class="zipcodeac form-control ui-autocomplete-input"

and the attribute

autocomplete="off"

and the Ajax is not fired.

Community
  • 1
  • 1
AlexMI
  • 824
  • 1
  • 15
  • 36
  • I think you are looking for Entity field type :) ! Documentation: http://symfony.com/doc/current/reference/forms/types/entity.html – Kern Sep 27 '16 at 14:27
  • @Kern - you're perfectly right. I used EntityType and CollectionType to manage OneToMany or ManyToOne associations. When the number of options selectable increase over thousands I need something different. Thanks. – AlexMI Sep 27 '16 at 15:01

1 Answers1

0

You missed the use statement in your ZipcodeType class which you are calling in the getParent() method.

Adding use Symfony\Component\Form\Extension\Core\Type\TextType; which solve the current error.

Anyway, if you have "over thousands" options as described in your comment, the better approach is to make an autocomplete webservice based on your discriminator field :) !

Kern
  • 858
  • 1
  • 8
  • 24