AlexMI AlexMI - 2 months ago 22
jQuery Question

Doctrine Many To One association in Symfony form

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.

Answer

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 :) !