I am trying to make a registration form where apart from the usual fields name, alias, password ( nombre
, nick
and password
)... I also add two dependent fields, Municipio
and Provincia
.
The problem is that it only shows multiple messages of undefined in the municipality field.
The entity ( Entity
) that creates the form is DbUsuario
, which has the field idMunicipio
.
/** @var \BackendBundle\Entity\DbMunicipios */
private $idMunicipio;
/**
* Set idMunicipio
* @param \BackendBundle\Entity\DbMunicipio $idMunicipio
* @return DbUsuario
*/
public function setIdMunicipio(\BackendBundle\Entity\DbMunicipio $idMunicipio = null) {
$this->idMunicipio = $idMunicipio;
return $this;
}
/**
* Get idMunicipio
* @return \BackendBundle\Entity\DbMunicipio
*/
public function getIdMunicipio() {
return $this->idMunicipio;
}
Then the entity DbMunicipio
that connects with the province:
/** @var \BackendBundle\Entity\DbProvincia */
private $provincia;
/**@param \BackendBundle\Entity\DbProvincia $provincia
* @return DbMunicipio
*/
public function setProvincia(\BackendBundle\Entity\DbProvincia $provincia = null){
$this->provincia = $provincia;
return $this;
}
/**@return \BackendBundle\Entity\DbProvincia */
public function getProvincia(){
return $this->provincia;
}
And the Entity DbProvincia
that only has the fields id
( integer
), slug
( String
) and provincia
( String
).
I define the form as follows:
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\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Doctrine\ORM\EntityRepository;
use AppBundle\Form\EventListener\AddProvinciaField;
use AppBundle\Form\EventListener\AddMunicipioField;
class RegistreUserType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$factory = $builder->getFormFactory();
$builder->add('nombre', TextType::class, array('label' => 'Nombre',
'required' => 'required',
'attr' => array('class' => 'form-nombre form-control')
));
$builder->add('apellido', TextType::class, array('label' => 'Apellido',
'required' => 'required',
'attr' => array('class' => 'form-apellido form-control')
));
$builder->add('nick', TextType::class, array('label' => 'Nick',
'required' => 'required',
'attr' => array('class' => 'form-nick form-control nick-input')
));
$provinSubscriber = new AddProvinciaField($factory);
$builder->addEventSubscriber($provinSubscriber);
$muniSubscriber = new AddMunicipioField($factory);
$builder->addEventSubscriber($muniSubscriber);
$builder->add('email', EmailType::class, array('label' => 'Correo electrónico',
'required' => 'required',
'attr' => array('class' => 'form-email form-control')
));
$builder->add('password', PasswordType::class, array('label' => 'Password',
'required' => 'required',
'attr' => array('class' => 'form-password form-control')
));
$builder->add('Registrarse', SubmitType::class, array("attr" => array("class" => "form-submit btn btn-success")));
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'data_class' => 'BackendBundle\Entity\DbUsuario'
));
}
public function getBlockPrefix() { return 'backendbundle_dbusuario'; }
}
I define inside AppBundle\Form\eventListener the classes, called in the form:
AddProvinciaField
namespace AppBundle\Form\EventListener;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use BackendBundle\Entity\DbProvincia;
class AddProvinciaField implements EventSubscriberInterface
{
private $factory;
public function __construct(FormFactoryInterface $factory) {
$this->factory = $factory;
}
public static function getSubscribedEvents() {
return array(
FormEvents::PRE_SET_DATA => 'preSetData',
FormEvents::PRE_SUBMIT => 'preSubmit'
);
}
private function addProvinciaForm($form, $provincia) {
$form -> add('provincia', EntityType::class, array(
'class' => 'BackendBundle:DbProvincia',
'label' => 'Provincia',
'placeholder' => '_ Elegir _',
'auto_initialize' => false,
'mapped' => false,
'attr'=> array('class' => 'form-provincia form-control provincia-input'),
'query_builder' => function (EntityRepository $repository) {
$qb = $repository->createQueryBuilder('provincia');
return $qb;
}
));
}
public function preSetData(FormEvent $event){
$data = $event->getData();
$form = $event->getForm();
if (null === $data) {return;}
$provincia = ($data->getIdMunicipio()) ? $data->getIdMunicipio()->getProvincia() : null ;
$this->addProvinciaForm($form, $provincia);
}
public function preSubmit(FormEvent $event) {
$data = $event->getData();
$form = $event->getForm();
if (null === $data) { return;}
$provincia = array_key_exists('provincia-input', $data) ? $data['provincia-input'] : null;
$this->addProvinciaForm($form, $provincia);
}
}
And later I define AddMunicipioField.php :
namespace AppBundle\Form\EventListener;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use BackendBundle\Entity\DbProvincia;
class AddMunicipioField implements EventSubscriberInterface {
private $factory;
public function _construct(FormFactoryInterface $factory) {
$this->factory = $factory;
}
public static function getSubscribedEvents() {
return array(
FormEvents::PRE_SET_DATA => 'preSetData',
FormEvents::PRE_SUBMIT => 'preSubmit'
);
}
private function addMunicipioForm($form, $provincia) {
$form->add('idMunicipio', EntityType::class, array(
'class' => 'BackendBundle:DbMunicipio',
'label' => 'Municipio',
'placeholder' => '_ Elegir _',
'auto_initialize' => false,
'attr'=> array('class' => 'form-municipio form-control municipio-input'),
'query_builder' => function (EntityRepository $repository) use ($provincia) {
$qb = $repository->createQueryBuilder('idMunicipio')
->innerJoin('idMunicipio.provincia', 'provincia');
if ($provincia instanceof DbProvincia) {
$qb->where('idMunicipio.provincia = :provincia')
->setParameter('provincia', $provincia);
var_dump($provincia);
} elseif (is_numeric($provincia)) {
$qb->where('provincia.id = :provincia')
->setParameter('provincia', $provincia);
var_dump($provincia);
} else {
$qb->where('provincia.provincia = :provincia')
->setParameter('provincia', null);
var_dump($provincia);
}
return $qb;
}
));
}
public function preSetData(FormEvent $event){
$data = $event->getData();
$form = $event->getForm();
if (null === $data) { return; }
$provincia = ($data->getIdMunicipio()) ? $data->getIdMunicipio()->getProvincia() : null ;
$this->addMunicipioForm($form, $provincia);
}
public function preSubmit(FormEvent $event){
$data = $event->getData();
$form = $event->getForm();
if (null === $data) { return; }
$provincia = array_key_exists('select_provincia', $data) ? $data['select_provincia'] : null;
$this->addMunicipioForm($form, $provincia);
}
}
And finally the AJAX request :
$(document).ready(function () {
$('.provincia-input').change(function () {
var $form = $(this).closest('form');
var data = $('.provincia-input').serialize();
$.ajax({
url: $form.attr('action'),
type: 'POST',
data: data,
success: function (html) {
$('.municipio-input').replaceWith($(html).find('.municipio-input'));
}
});
});
});