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.