Foros del Web » Programando para Internet » PHP » Symfony »

problema al validar un formulario embebido

Estas en el tema de problema al validar un formulario embebido en el foro de Symfony en Foros del Web. Hola comunidad hace algunos días tengo un problema con symfony 2.3, tengo el siguiente escenario: Una entidad Usuario y una Teléfono, con una relación de ...
  #1 (permalink)  
Antiguo 21/09/2015, 12:39
 
Fecha de Ingreso: febrero-2013
Mensajes: 66
Antigüedad: 11 años, 2 meses
Puntos: 0
problema al validar un formulario embebido

Hola comunidad hace algunos días tengo un problema con symfony 2.3, tengo el siguiente escenario: Una entidad Usuario y una Teléfono, con una relación de Uno a Mucho, es decir un usuario puede tener muchos teléfonos. Muestro un formulario en donde el usuario puede ir dinámicamente insertando hasta 3 teléfonos. Y en caso de editar el usuario dicha información puede modificar sus teléfonos o eliminar alguno o insertarlo en caso de ser posible. Cuando un usuario se va a crear nuevo todo funciona perfectamente, el gran problema esta cuando un usuario desea editar sus teléfonos, el problema consiste en que el usuario al modificar un teléfono e insertar uno numero no valido, que no cumple con una expresión regular que defino, el formulario cuando lo envió me da error y me muestra perfectamente el mensaje, pero cuando reviso en la base de datos, el numero se modifico o se inserto aunque este mal escrito. He estado buscando y todo parece estar en cuando ejecuto el
Código:
$form->bind($request),
al parecer al ejecutar esta línea ya se insertan los teléfonos en la base de datos y luego cuando ejecuto el
Código:
$form->isValid()
, me da los errores, pero ya se ha insertado los campos de teléfonos en, la base de datos.
Espero que me puedan ayudar con esto, si necesitan mas información para encontrar la solución yo se las puedo subir.
Gracias a todos los que me puedan ayudar de antemano.
  #2 (permalink)  
Antiguo 22/09/2015, 09:22
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 10 años, 9 meses
Puntos: 379
Respuesta: problema al validar un formulario embebido

De entrada el uso de bind es obsoleto, debes de utiliza handleRequest($request), por otro lado ese método no realiza el inser en la base de datos. Me temo que el isValid() no esta usando las reglas que puso para validar el telefono. Puedes publicar tu entidad y tu form para ver que estas haciendo ?
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #3 (permalink)  
Antiguo 22/09/2015, 17:42
 
Fecha de Ingreso: febrero-2013
Mensajes: 66
Antigüedad: 11 años, 2 meses
Puntos: 0
Respuesta: problema al validar un formulario embebido

@hhs: aqui te dejo las entitades y los formularios que estoy utilizando. Te los muestro solo con los atributos necesarios.
Entidades
Código PHP:
Ver original
  1. <?php
  2.  
  3. namespace AppBundle\Entity;
  4.  
  5. use Doctrine\ORM\Mapping as ORM;
  6. use Symfony\Bridge\Doctrine\Validator\Constraints as DoctrineAssert;
  7. use Symfony\Component\Validator\Constraints as Assert;
  8.  
  9. /**
  10.  * User
  11.  *
  12.  * @ORM\Table(name="user")
  13.  * @ORM\Entity(repositoryClass="AppBundle\Entity\UserRepository")
  14.  */
  15. class User
  16. {
  17.     /**
  18.      * @var integer
  19.      *
  20.      * @ORM\Column(name="id", type="integer")
  21.      * @ORM\Id
  22.      * @ORM\GeneratedValue(strategy="AUTO")
  23.      */
  24.     private $id;
  25.    
  26.     /**
  27.      * @var Phones
  28.      *
  29.      * @ORM\OneToMany(targetEntity="Phone", mappedBy="user", cascade={"persist" , "remove"})    
  30.      */
  31.     private $phones;
  32.    
  33.     /**
  34.      * Get id
  35.      *
  36.      * @return integer
  37.      */
  38.     public function getId()
  39.     {
  40.         return $this->id;
  41.     }
  42.    
  43.     /**
  44.      * Constructor
  45.      */
  46.     public function __construct()
  47.     {      
  48.         $this->phones = new \Doctrine\Common\Collections\ArrayCollection();
  49.     }
  50.  
  51.     /**
  52.      * Add phones
  53.      *
  54.      * @param \AppBundle\Entity\Phone $phones
  55.      * @return User
  56.      */
  57.     public function addPhone(\AppBundle\Entity\Phone $phone)
  58.     {        
  59.         $phone->setUser($this);
  60.         $this->phones->add($phone);    
  61.     }
  62.  
  63.     /**
  64.      * Remove phones
  65.      *
  66.      * @param \AppBundle\Entity\Phone $phones
  67.      */
  68.     public function removePhone(\AppBundle\Entity\Phone $phone)
  69.     {
  70.         $this->phones->removeElement($phone);
  71.     }
  72.  
  73.     /**
  74.      * Get phones
  75.      *
  76.      * @return \Doctrine\Common\Collections\Collection
  77.      */
  78.     public function getPhones()
  79.     {
  80.         return $this->phones;
  81.     }    
  82.    
  83.     public function setPhones(\Doctrine\Common\Collections\Collection $phones)
  84.     {
  85.         die('setPhones');
  86.         $this->phones = $phones;
  87.         foreach ($phones as $phone) {
  88.             $phone->setUser($this);
  89.         }
  90.     }
  91.        
  92. }

Código PHP:
Ver original
  1. <?php
  2.  
  3. namespace AppBundle\Entity;
  4.  
  5. use Doctrine\ORM\Mapping as ORM;
  6. use Symfony\Component\Validator\Constraints as Assert;
  7. use Symfony\Bridge\Doctrine\Validator\Constraints as DoctrineAssert;
  8.  
  9. /**
  10.  * Phone
  11.  *
  12.  * @ORM\Table()
  13.  * @ORM\Entity(repositoryClass="AppBundle\Entity\PhoneRepository")
  14.  */
  15. class Phone
  16. {
  17.     /**
  18.      * @var integer
  19.      *
  20.      * @ORM\Column(name="id", type="integer")
  21.      * @ORM\Id
  22.      * @ORM\GeneratedValue(strategy="AUTO")
  23.      */
  24.     private $id;
  25.  
  26.     /**
  27.      * @var string
  28.      *
  29.      * @ORM\Column(name="number", type="string", length=20)
  30.      * @Assert\Regex(pattern="/^\+53\ ?[0-9]{8}$/", message = "field.phone")
  31.      */
  32.     private $number;
  33.  
  34.     /**
  35.      * @var \User
  36.      *
  37.      * @ORM\ManyToOne(targetEntity="User", inversedBy="phones", cascade={"persist"})
  38.      * @ORM\JoinColumns({
  39.      *   @ORM\JoinColumn(name="user", referencedColumnName="id", onDelete="Cascade", nullable=false)
  40.      * })
  41.      */
  42.     private $user;
  43.  
  44.     /**
  45.      * Get id
  46.      *
  47.      * @return integer
  48.      */
  49.     public function getId()
  50.     {
  51.         return $this->id;
  52.     }
  53.  
  54.     /**
  55.      * Set number
  56.      *
  57.      * @param string $number
  58.      * @return Phone
  59.      */
  60.     public function setNumber($number)
  61.     {
  62.         $this->number = $number;
  63.         return $this;
  64.     }
  65.  
  66.     /**
  67.      * Get number
  68.      *
  69.      * @return string
  70.      */
  71.     public function getNumber()
  72.     {
  73.         return $this->number;
  74.     }
  75.    
  76.     /**
  77.      * Set user
  78.      *
  79.      * @param \AppBundle\Entity\User $user
  80.      * @return Phone
  81.      */
  82.     public function setUser(\AppBundle\Entity\User $user)
  83.     {
  84.         $this->user = $user;
  85.  
  86.         return $this;
  87.     }
  88.  
  89.     /**
  90.      * Get user
  91.      *
  92.      * @return \AppBundle\Entity\User
  93.      */
  94.     public function getUser()
  95.     {
  96.         return $this->user;
  97.     }
  98.    
  99.     public function __toString() {
  100.         return $this->number;
  101.     }
  102. }
Formularios
Código PHP:
Ver original
  1. <?php
  2.  
  3. namespace AppBundle\Form;
  4.  
  5. use Symfony\Component\Form\AbstractType;
  6. use Symfony\Component\Form\FormBuilderInterface;
  7. use Symfony\Component\OptionsResolver\OptionsResolverInterface;
  8. use Symfony\Component\Validator\Constraints\Regex;
  9. use Symfony\Component\Validator\Constraints\NotBlank;
  10.  
  11. class PhoneType extends AbstractType {
  12.  
  13.     /**
  14.      * @param FormBuilderInterface $builder
  15.      * @param array $options
  16.      */
  17.     public function buildForm(FormBuilderInterface $builder, array $options) {
  18.         $builder
  19.                 ->add('number', 'text', array(
  20.                     'max_length' => 15,
  21.                     'required' => false,
  22.                     'label' => null,
  23.                     'constraints' => array(
  24.                         new Regex(array(
  25.                             'pattern' => "/^\+53\ ?[0-9]{8}$/",
  26.                             'message' => 'field.phone'
  27.                                 )),
  28.                         new NotBlank()
  29.                     )
  30.                 ))
  31.         ;
  32.     }
  33.  
  34.     /**
  35.      * @param OptionsResolverInterface $resolver
  36.      */
  37.     public function setDefaultOptions(OptionsResolverInterface $resolver) {
  38.         $resolver->setDefaults(array(
  39.             'data_class' => 'AppBundle\Entity\Phone'
  40.         ));
  41.     }
  42.  
  43.     /**
  44.      * @return string
  45.      */
  46.     public function getName() {
  47.         return 'appbundle_phone';
  48.     }
  49.  
  50. }

Código PHP:
Ver original
  1. <?php
  2.  
  3. namespace AppBundle\Form;
  4.  
  5. use Symfony\Component\Form\AbstractType;
  6. use Symfony\Component\Form\FormBuilderInterface;
  7. use Symfony\Component\OptionsResolver\OptionsResolverInterface;
  8. use Symfony\Component\Validator\Constraints\NotBlank;
  9. use Symfony\Component\Validator\Constraints\Email;
  10. use Symfony\Component\Validator\Constraints\Length;
  11. use AppBundle\Form\PhoneType;
  12.  
  13. class UserType extends AbstractType {
  14.  
  15.     /**
  16.      * @param FormBuilderInterface $builder
  17.      * @param array $options
  18.      */
  19.     public function buildForm(FormBuilderInterface $builder, array $options) {
  20.         $builder                
  21.                 ->add('phones', 'collection', array(
  22.                     'label' => false,
  23.                     'type' => new PhoneType(),
  24.                     'allow_add' => true,
  25.                     'allow_delete' => true,
  26.                     'by_reference' => false,
  27.                     'cascade_validation' => true,
  28.                 ))
  29.         ;
  30.     }
  31.  
  32.     /**
  33.      * @param OptionsResolverInterface $resolver
  34.      */
  35.     public function setDefaultOptions(OptionsResolverInterface $resolver) {
  36.         $resolver->setDefaults(array(
  37.             'data_class' => 'AppBundle\Entity\User'
  38.         ));
  39.     }
  40.  
  41.     /**
  42.      * @return string
  43.      */
  44.     public function getName() {
  45.         return 'appbundle_user';
  46.     }
  47.  
  48. }
  #4 (permalink)  
Antiguo 22/09/2015, 18:05
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 10 años, 9 meses
Puntos: 379
Respuesta: problema al validar un formulario embebido

Primer paso, el constraints se utiiza cuando tu formulario no tiene una entidad asociada, asi que quita eso del formulario PhoneType y cambia el "cascade_validation" a false en UserType.
Para validar una entidad que tiene relaciones le tienes que decir que delegue esa responsabilidad a la entidad asociada a la relación en el Assert. Eso se logra usando el Asset Valid: http://symfony.com/doc/current/refer...nts/Valid.html
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #5 (permalink)  
Antiguo 22/09/2015, 18:53
 
Fecha de Ingreso: febrero-2013
Mensajes: 66
Antigüedad: 11 años, 2 meses
Puntos: 0
Respuesta: problema al validar un formulario embebido

Ya hice todo lo que me dijiste, y leyendo en la url que me dejaste el atributo phones en la entidad User le modifique las anotaciones de la siguiente manera:
Código PHP:
Ver original
  1. /**
  2.      * @var Phones
  3.      *
  4.      * @ORM\OneToMany(targetEntity="Phone", mappedBy="hostal", cascade={"persist" , "remove"})  
  5.      * @Assert\Valid
  6.      */
  7.     protected $phones;

pero lamentablemente me sigue dando el mismo error, me valida, pero cuando reviso la base de datos el teléfono ha sido modificado, voy a ponerte también a continuación el código del controlador para que también lo veas

Código PHP:
Ver original
  1. <?php
  2.  
  3. namespace AppBundle\Controller\Admin;
  4.  
  5. use Symfony\Bundle\FrameworkBundle\Controller\Controller;
  6. use Symfony\Component\HttpFoundation\Request;
  7.  
  8. class UserController extends Controller {
  9.  
  10.  public function editAction(Request $request, $id) {
  11.         $translator = $this->get('translator');
  12.         $em = $this->getDoctrine()->getManager();
  13.         $user = $em->getRepository('AppBundle:User')->findOneById($id);
  14.  
  15.         if (!$user)
  16.             return Helpers::error404($this, $translator->trans('user.not.found', array(), 'admin'), $translator->trans('back.users', array(), 'admin'), 'fa fa-bed fa-fw', $this->generateUrl('admin_users'));
  17.    
  18.         $originalPhones = array();
  19.         // Create an array of the current phones objects in the database
  20.         foreach ($user->getPhones() as $phone) {
  21.             $originalPhones[] = $phone;
  22.         }
  23.  
  24.        
  25.         $form = $this->createForm(new UserType(), $user);
  26.  
  27.         if ($request->getMethod() == 'POST') {
  28.            
  29.             $form->handleRequest($request);
  30.  
  31.             if ($form->isValid()) {
  32.  
  33.                 //process to update the phones
  34.                 // filter $originalPhones to contain tags no longer present
  35.                 foreach ($user->getPhones() as $phone) {
  36.                     foreach ($originalPhones as $key => $toDel) {
  37.                         if ($toDel->getId() === $phone->getId()) {
  38.                             unset($originalPhones[$key]);
  39.                         }
  40.                     }
  41.                 }
  42.  
  43.                 // remove the relationship between the phone and the User
  44.                 foreach ($originalPhones as $phone) {
  45.                     $user->getPhones()->removeElement($phone);
  46.                     $em->remove($phone);
  47.                 }
  48.  
  49.                 $em->persist($user);
  50.                 $em->flush();
  51.                              
  52.                 return $this->redirect($this->generateUrl('admin_users'));
  53.             }
  54.         }
  55.        
  56.         return $this->render('AppBundle:Admin/user:form.html.twig', array(
  57.                     'form' => $form->createView(),                  
  58.                     'action' => 'Edit',`                    
  59.         ));
  60.     }
  61. }

Última edición por daymerrf; 22/09/2015 a las 18:55 Razón: Metodo con error
  #6 (permalink)  
Antiguo 25/09/2015, 07:40
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 10 años, 9 meses
Puntos: 379
Respuesta: problema al validar un formulario embebido

Si agregaste el assert en la entidad Phone ?
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.

Etiquetas: embebido, formulario
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 19:45.