Mer*_*che 8 php events symfony-forms symfony symfony-3.1
问题是市政领域没有任何东西加载,它是未定义的.在AJAX代码中,我很好地获得了该省的价值.但是在类addMunicipioField.php中没有取$省的值,它始终是nul
我正在尝试制作一个注册表单,其中部分通常的字段(name, nick, password, ...)我还添加了两个依赖字段Municipality和Province.
编解码器Controler:
class UserController extends Controller {
private $session;
public function __construct() {
$this->session = new Session();
}
public function registerAction(Request $request) {
if (is_object($this->getUser())) {
return $this->redirect('home');
}
$user = new DbUsuario();
$form = $this->createForm(RegistreUserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery('SELECT u FROM BackendBundle:DbUsuario u WHERE u.email = :email OR u.nick = :nick')
->setParameter('email', $form->get("email")->getData())
->setParameter('nick', $form->get("nick")->getData());
$user_isset = $query->getResult();
if (count($user_isset) == 0) {
$factory = $this->get("security.encoder_factory");
$encoder = $factory->getEncoder($user);
$password = $encoder->encodePassword($form->get("password")->getData(), $user->getSalt());
$user->setPassword($password);
$user->setRole("ROLE_USER");
$user->setImagen(null);
$em->persist($user);
$flush = $em->flush();
if ($flush == null) {
$status = "Te has registrado correctamente";
$this->session->getFlashBag()->add("status", $status);
return $this->redirect("login");
} else {
$status = "No te has registrado correctamente";
}
} else {
$status = "Usuario ya esta registrado.";
}
} else {
$status = "No te has registrado correctamente.";
}
$this->session->getFlashBag()->add("status", $status);
}
return $this->render('AppBundle:User:register.html.twig', array(
"form" => $form->createView() # Genera el html del formulario.
));
}
Run Code Online (Sandbox Code Playgroud)
创建表单的实体是DbUsuario,它具有该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;
}
Run Code Online (Sandbox Code Playgroud)
然后与'省'连接的DbMunicipio 实体:
/** @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;
}
// And implement this function.
public function __toString(){
return $this->getMunicipio();
}
/**@return \BackendBundle\Entity\DbProvincia */
public function getProvincia(){
return $this->provincia;
}
Run Code Online (Sandbox Code Playgroud)
而实体 DbProvincia只有fields(id (integer), slug (String) and province (String)).
我将表单定义如下:
namespace AppBundle\Form;
use ....
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'; }
}
Run Code Online (Sandbox Code Playgroud)
我在AppBundle\Form\eventListener\AddProvinciaField中定义了以下形式调用的类:
namespace AppBundle\Form\EventListener;
use ....
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);
}
}
Run Code Online (Sandbox Code Playgroud)
后来我定义了AddMunicipioField .php:
namespace AppBundle\Form\EventListener;
use ....
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);
} elseif (is_numeric($provincia)) {
$qb->where('provincia.id = :provincia')
->setParameter('provincia', $provincia);
} else {
$qb->where('provincia.provincia = :provincia')
->setParameter('provincia', null);
}
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('provincia_input', $data) ? $data['provincia_input'] : null;
$this->addMunicipioForm($form, $provincia);
}
Run Code Online (Sandbox Code Playgroud)
}
最后是AJAX请求:
$(document).ready(function(){
var $form = $(this).closest('form');
$(".provincia-input").change(function(){
var data = { idMunicipio: $(this).val() };
$.ajax({
type: 'POST',
url: $form.attr('action'),
data: data,
success: function(data) {
for (var i=0, total = data.length; i < total; i++) {
$('.municipio-input').append('<option value="' + data[i].id + '">' + data[i].municipio + '</option>');
}
}
});
});
});
Run Code Online (Sandbox Code Playgroud)
我在代码中添加了var_dump和alert().这是输出的方式.
在这种情况下,省的值始终为null.
addMunicipioField.php
public function preSetData(FormEvent $event){
$data = $event->getData();
$form = $event->getForm();
if (null === $data) {
return;
}
$provincia = ($data->getIdMunicipio()) ? $data->getIdMunicipio()->getProvincia() : null ;
var_dump('presetdata');
var_dump($provincia);
$this->addMunicipioForm($form, $provincia);
}
Run Code Online (Sandbox Code Playgroud)
AJAX:
$(document).ready(function(){
var $form = $(this).closest('form');
$(".provincia-input").change(function(){
alert($('.provincia-input').val()); // THIS IS CORRECT VALUE, INTEGER.
var data = { idMunicipio: $(this).val() };
$.ajax({
type: 'POST',
url: $form.attr('action'),
data: data,
success: function(data) {
alert(data);
alert(data.length); // THIS IS INCORRECT.
for (var i=0, total = data.length; i < total; i++) {
$('.municipio-input').append('<option value="' + data[i].id + '">' + data[i].municipio + '</option>');
}
}
});
});
});
Run Code Online (Sandbox Code Playgroud)
另一种观点 实体是相同的.在这种情况下它可以工作,但我必须按下发送按钮.如果不按下按钮我怎么能这样做,它是自动更改?
RegistreUserType类扩展AbstractType我添加以下行.
$builder -> 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;
}
));
$builder->add('idMunicipio', EntityType::class, array(
'class' => 'BackendBundle:DbMunicipio',
'label' => 'Municipio',
'placeholder' => '_ Elegir _',
'auto_initialize' => false,
'mapped' => false,
'attr'=> array('class' => 'form-municipio form-control municipio-input')
));
$builder->addEventSubscriber(new AddMunicipioField());
Run Code Online (Sandbox Code Playgroud)
新类AddMunicpioField():
class AddMunicipioField implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return array(
FormEvents::PRE_SUBMIT => 'preSubmit',
FormEvents::PRE_SET_DATA => 'preSetData',
);
}
public function preSubmit(FormEvent $event){
$data = $event->getData();
$this->addField($event->getForm(), $data['provincia']);
}
protected function addField(Form $form, $provincia){
$form->add('idMunicipio', EntityType::class, array(
'class' => 'BackendBundle:DbMunicipio',
'label' => 'Municipio',
'placeholder' => '_ Elegir _',
'auto_initialize' => false,
'mapped' => false,
'attr'=> array('class' => 'form-municipio form-control municipio-input'),
'query_builder' => function(EntityRepository $er) use ($provincia){
$qb = $er->createQueryBuilder('idMunicipio')
->where('idMunicipio.provincia = :provincia')
->setParameter('provincia', $provincia);
return $qb;
}
));
}
Run Code Online (Sandbox Code Playgroud)
Codec Ajax:
$(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 (data) {
$('.municipio-input').replaceWith($(html).find('.municipio-input'));
}
});
});
Run Code Online (Sandbox Code Playgroud)
});
解决了!!
在我的表单中,我添加了对两个新类的调用:
$builder -> addEventSubscriber(new AddMunicipioFieldSubscriber('idMunicipio'));
$builder -> addEventSubscriber(new AddProvinceFieldSubscriber('idMunicipio'));
Run Code Online (Sandbox Code Playgroud)
第一个选择是省份,这是班级:
class AddProvinceFieldSubscriber implements EventSubscriberInterface {
private $propertyPathToMunicipio;
public function __construct($propertyPathToMunicipio) {
$this->propertyPathToMunicipio = $propertyPathToMunicipio;
}
public static function getSubscribedEvents() {
return array(
FormEvents::PRE_SET_DATA => 'preSetData',
FormEvents::PRE_SUBMIT => 'preSubmit'
);
}
private function addProvinceForm($form, $Province = null) {
$formOptions = array(
'class' => 'BackendBundle:DbProvincia',
'mapped' => false,
'label' => 'Provincia',
'attr' => array(
'class' => 'class_select_provincia',
),
);
if ($Province) {
$formOptions['data'] = $Province;
}
$form->add('provincia', EntityType::class, $formOptions);
}
public function preSetData(FormEvent $event){
$data = $event->getData();
$form = $event->getForm();
if (null === $data) {
return;
}
$accessor = PropertyAccess::createPropertyAccessor();
$municipio = $accessor->getValue($data, $this->propertyPathToMunicipio);
$provincia = ($municipio) ? $municipio->getIdMunicipio()->getProvincia() : null;
$this->addProvinceForm($form, $provincia);
}
public function preSubmit(FormEvent $event){
$form = $event->getForm();
$this->addProvinceForm($form);
}
}
Run Code Online (Sandbox Code Playgroud)
第二类是Municipi:
class AddMunicipioFieldSubscriber implements EventSubscriberInterface {
//put your code here
private $propertyPathToMunicipio;
public function __construct($propertyPathToMunicipio){
$this->propertyPathToMunicipio = $propertyPathToMunicipio;
}
public static function getSubscribedEvents(){
return array(
FormEvents::PRE_SET_DATA => 'preSetData',
FormEvents::PRE_SUBMIT => 'preSubmit'
);
}
private function addCityForm($form, $province_id){
$formOptions = array(
'class' => 'BackendBundle:DbMunicipio',
'label' => 'Municipio',
'attr' => array(
'class' => 'class_select_municipio',
),
'query_builder' => function (EntityRepository $repository) use ($province_id) {
$qb = $repository->createQueryBuilder('municipio')
->innerJoin('municipio.provincia', 'provincia')
->where('provincia.id = :provincia')
->setParameter('provincia', $province_id)
;
return $qb;
}
);
$form->add($this->propertyPathToMunicipio, EntityType::class, $formOptions);
}
public function preSetData(FormEvent $event){
$data = $event->getData();
$form = $event->getForm();
if (null === $data) {
return;
}
$accessor = PropertyAccess::createPropertyAccessor();
$municipio = $accessor->getValue($data, $this->propertyPathToMunicipio);
$province_id = ($municipio) ? $municipio->getIdMunicipio()->getProvincia()->getId() : null;
$this->addCityForm($form, $province_id);
}
public function preSubmit(FormEvent $event){
$data = $event->getData();
$form = $event->getForm();
$province_id = array_key_exists('provincia', $data) ? $data['provincia'] : null;
$this->addCityForm($form, $province_id);
}
}
Run Code Online (Sandbox Code Playgroud)
控件添加这个功能:
public function municipioTestAction(Request $request){
$provincia_id = $request->get('provincia_id');
$em = $this->getDoctrine()->getManager();
$provincia = $em->getRepository('BackendBundle:DbMunicipio')->findByProvinceId($provincia_id);
return new JsonResponse($provincia);
}
Run Code Online (Sandbox Code Playgroud)
在函数 findByProvinceId 中,我将其创建为实体 DbMunicipio 的存储库。
class DbMunicipioRepository extends EntityRepository{
public function findByProvinceId($provincia_id){
$query = $this->getEntityManager()->createQuery("
SELECT muni
FROM BackendBundle:DbMunicipio muni
LEFT JOIN muni.provincia provin
WHERE provin.id = :provincia_id
")->setParameter('provincia_id', $provincia_id);
return $query->getArrayResult();
}
}
Run Code Online (Sandbox Code Playgroud)
以及 AJAX 解码器。
$(document).ready(function () {
$(".class_select_provincia").change(function(){
var data = {
provincia_id: $(this).val()
};
$.ajax({
type: 'POST',
url: URL+'/municipio-test',
data: data,
success: function(data) {
var $muni_selector = $('.class_select_municipio');
alert(data);
$muni_selector.html('<option>Ciudad</option>');
for (var i=0, total = data.length; i < total; i++) {
$muni_selector.append('<option value="' + data[i].id + '">' + data[i].municipio + '</option>');
}
}
});
});
});
Run Code Online (Sandbox Code Playgroud)