Hacer una búsqueda con un dato que envía el usuario

Hola de nuevo a toda la gente de LibrosWeb que trabaja con Symfony, tengo la siguiente cuestión:

Lo que pasa es que quiero agregar un dato a una entidad que llamo "reporteemergencia" en la cual como primera condición el usuario tiene que demostrar que está en la base de datos (mediante un usuario previamente cargado). Si la respuesta es afirmativa entonces me debería habilitar los campos para ingresar datos respecto al reporte:

Mi entidad:

class ReporteEmergencia
{
 
    private $id;
 
    private $detalle;
 
    /**
     *
     * @ORM\ManyToOne(targetEntity="SeguridadSocial", inversedBy="remer")
     * @ORM\JoinColumn(name="ssocial_id", referencedColumnName="id")
     */
    private $ssocial;
 
    // ...getters and setters..
}

He creado una consulta en la clase repositorio:

class ReporteEmergenciaRepository extends EntityRepository
{
    public function findById($id){
        $em = $this->getEntityManager();
 
        $consulta = $em->createQuery('
            SELECT u
            FROM adminBundle:Usuarios u
            WHERE u.id = :id
        ');
 
        $consulta->setParameter('id',$id);
 
        return $consulta->getResult();
 
    }
}

Lo llamo en el controlador:

public function createAction(Request $request){
       ...
        $usuario =  $em->findById();
       ...
 }

Esto me genera tres dudas:

  1. ¿Como hago para enviarle el dato para que el usuario averigüe si realmente existe en la base de datos, aclarando que debe ser un campo en el formulario que no se relaciona con la entidad, pero que si realiza la búsqueda, ademas de traerme datos que se relacionen con el usuario?
  2. ¿En caso de que se encuentre el registro en la base de datos cómo puedo habilitar y deshabilitar campos en el formulario?
  3. He tratado de añadir un formulario con 'include' llamándolo en el formulario de creación pero me genera el siguiente error:
The profiler template "@WebProfiler/Collector/form.html.twig.twig.html.twig" for data collector "form" does not exist.

¿Hay alguna forma de incluir campos de un formulario que no se relacionan con la entidad dentro del archivo donde se crea formulario (en mi caso ReporteEmergenciaType.php), o como añadir de manera correcta un formulario a mi archivo de creación de registros (add.html.twig en mi caso)?

Gracias de antemano y un saludo

Respuestas

#1

En primer lugar, el error que muestras es "imposible" que se produzca. Está relacionado con una plantilla interna de Symfony usada para mostrar los formularios en el profiler. Me extraña mucho que hayas tocado esa plantilla, así que no se qué puede estar pasando ahí.

Por otra parte, creo que la solución que quieres implementar es demasiado compleja. Al parecer quieres mostrar un formulario a un tipo de personas y otro formulario con más campos a otro tipo de personas. Si esto es así, yo lo que haría son dos formularios (uno con más campos que otro) y entonces en la plantilla simplemente comprobaría el tipo de usuario:

{% if is_granted('ROLE_ADVANCED_SEARCH') %}
    {{ include('.../.../advanced_form.html.twig') }}
{% else %}
    {{ include('.../.../regular_form.html.twig') }}
{% endif %}
#2

Javier creo que preguntado de una forma muy compleja, pido disculpas por eso. En palabras breves, lo que quisiera es con un <input> de tipo text que no tiene que ver nada con el formulario de la entidad que sería la de los reportes de emergencia haga una búsqueda con la base de datos donde estoy almacenando los usuarios en una tabla llamada de la misma forma.

En caso de que se encuentre el registro relacionado a lo que se envío en el <input> me habilite los campos para ingresar los datos referentes al reporte. En PHP es fácil, pero no se como hacerlo en Symfony. Cómo enviar el dato en el <input> para que mi función findById() reciba un parámetro, funcione y haga la consulta.

Además de no saber cómo agregar ese <input> text y un submit al formulario, lo hice llamando un formulario que he creado, que precisamente era el que me provocaba el error que mencionaba en el final de mi pregunta (creo que era un problema en el cache ya que se solucionó).

(creo que no fue en breves palabras)

Así sería el formulario con el que hago todo el proceso: imagen

Un saludo

#3

Ahora entiendo mejor la pregunta. Aunque algún experto en formularios Symfony me puede contradecir y con razón, creo que este es un ejemplo perfecto de cuando no utilizar los formularios Symfony.

Los formularios Symfony están pensados principalmente para formularios relativamente complejos, con muchos campos y mucha validación y sobre todo, muy estáticos. En cuanto quieres hacer algo dinámico en el navegador, deberías pensar si los formularios de Symfony son la mejor opción.

Mi consejo sería, haz un formulario HTML normal y corriente, usa JavaScript para mostrar/ocultar partes del formulario cuando te convenga y usa simples peticiones Ajax a la aplicación Symfony para obtener la información del usuario y actuar en consecuencia.

#4

Hola @Andres11362 Para las preguntas que planteas, mis comentarios son los siguientes:

  1. ¿Como hago para enviarle el dato para que el usuario averigüe si realmente existe en la base de datos, aclarando que debe ser un campo en el formulario que no se relaciona con la entidad, pero que si realiza la búsqueda, ademas de traerme datos que se relacionen con el usuario?

Yo pasaría el campo al formulario desde el type, como este campo no tiene ninguna relación con la entidad así que le pongo la propiedad mapped como false. Con esto ya tendría el campo en el formulario.

  1. En caso de que se encuentre el registro en la base de datos cómo puedo habilitar y deshabilitar campos en el formulario?

La búsqueda la haría por ajax, si el usuario existe, en la respuesta del ajax mostraría o habilitaría los campos, de lo contrario mostraría un mensaje.

  1. He tratado de añadir un formulario con 'include' llamándolo en el formulario de creación pero me genera el siguiente error:

En este caso, la forma correcta de hacer el include es como lo muestra @javiereguiluz, aunque yo en lugar de incluir un formulario incluiría un controlador.

Esto lo pienso en caso de que la consulta que quieras hacer sea con un usuario anónimo, porque si el usuario ya está autenticado desde el inicio, no tendría que hacer validación.

Espero que te sirva, Si necesitas más ayuda no dudes en escribir.

#5

Estimados,

Yo tuve un problema parecido. Mi solución fue muy similar a la expuesta por @miguelplazasr y además me base en los eventos del formulario para ocultar o mostrar campos, puesto que en mi caso esos campos eran entidades que variaban en función de otra. Algo muy similar a lo expuesto en la charla de "formularios al límite" impartida por Ignacio Velázquez en la conferencia deSymfony2012.

Espero hayas podido solucionar tu problema. Coméntanos como te fue y cual fue la solución.

Saludos desde Chile

#6

Hola de nuevo @javiereguiluz, @miguelplazasr, @SebaRiquelmeP, perdon mi tardanza les comento que he podido realizar de otra forma por recomendaciones de un compañero:

  1. Me comentaba que por razones de seguridad era mejor hacer otro formulario para encontrar los resultados (a donde se envian los resultado, ya que alguien con conocimientos en html, puede mostrar el formulario y asi invalidar las acciones que tiene que hacer el modulo de reportes.

  2. La idea es que teniendolos en el formulario donde se encuentran los resultados, esos datos enviarlos al reporte, en un cuadro de texto al que llamo detalles.

La buena noticia es que he logrado que la consulta se haga de manera efectiva y me envia al formulario de "resultados".

Mis dudas se generan al saber como puedo enviar el resultado de la consulta en unos input de tipo text para despues enviarlos al formulario de reportes, ya que como anteriormente les decia que he si envia al formulario pero no me muestra los datos.

He creado tres controladores que generan la busqueda:

//genera la busqueda y me envia a una plantilla que renderizo
  public function searchAction(Request $request){
 
        $em = $this->getDoctrine()->getManager();
        $id = $this->getRequest()->request->get('searchbox');
        $usuario = $em->getRepository('AdminBundle:Usuarios')->findById($id);
 
        if(!$usuario){
            $this->get('session')->getFlashBag()->add(
                                'mensaje',
                                'No existe el usuario'
                            );
            return $this->redirect($this->generateUrl('ud_enfermeria_reporte'));
        }
 
        $form = $this->createSearchForm();
        $form->handleRequest($request);
 
        //crear formulario de consulta
        $findform = $this->createFormBuilder($usuario)
                    ->setAction($this->generateUrl('ud_enfermeria_reporte_new'))
                    ->setMethod('POST')
                    ->add('username')
                    ->add('nombres')
                    ->add('apellidos')
                    ->getForm()
        ;
        //En este formulario es donde se deberian mostrar los resultados
        //fin
 
        if($form->isSubmitted() && $form->isValid()){
            $this->get('session')->getFlashBag()->add(
                                'mensaje',
                                'El usuario existe'
                            );
            return $this->render('EnfermeriaBundle:ReporteEmergencia:find.html.twig',
                array('usuario' => $usuario, 'find_form' =>  $findform->createView()));
            //return $this->redirect($this->generateUrl('ud_enfermeria_reporte_new'));
        }      
    }
 
   //funcion que me muestra el formulario donde hago la busqueda
    public function foundAction(){
        $form = $this->createSearchForm();
 
        return array(
            'search_form'   => $form->createView(),
        );
    }
 
//funcion en la que creo que el formulario de busqueda
 
    private function createSearchForm(){
        return $this->createFormBuilder()
               ->setAction($this->generateUrl('ud_enfermeria_reporte_search'))
               ->setMethod('POST')
               ->getForm()
            ;
    }

Mi consulta a la entidad Usuario

//La consulta que hago en DQL
   class UsuariosRepository extends EntityRepository
{
    public function findById($id){
 
        $em = $this->getEntityManager();
 
        $consulta = $em->createQuery('
            SELECT u.username, u.nombres, u.apellidos
            FROM AdminBundle:Usuarios u
            WHERE u.id = :id
        ');
 
        $consulta->setParameter('id',$id);
 
        return $consulta->getResult();
 
    }
}

La plantilla donde hago mi busqueda

{{ form_start(form, {'attr':{'id' : id|default('form')}}) }}
    {{ form_widget(form) }}
 
    {#{% if with_submit is not defined or with_submit == true %}#}
        <label for="searchbox">Busqueda</label>
        <input id="searchbox" type="text" placeholder="Ingrese el id del usuario" name="searchbox" class="form-control" />
        <br>
        <input type="submit" value="{{ 'Buscar Usuario' }}" class="btn btn-default btn-search" />
    {#{% endif %}#}
 
{{ form_end(form) }}

Aqui tengo mi plantilla de twig donde se mostrarian los resultados

{{ form_start(find_form) }}
                   <fieldset>
                        <div class="form-group">
                            {{ form_label(find_form.username) }}
                            {{ form_widget(find_form.username, { 'attr': { 'class': 'form-control', 'readonly': 'readonly'}}) }}
                        </div>
                        <div class="form-group">
                            {{ form_label(find_form.nombres) }}
                            {{ form_widget(find_form.nombres, { 'attr': { 'class': 'form-control', 'readonly': 'readonly'}}) }}
                        </div>
                        <div class="form-group">
                            {{ form_label(find_form.apellidos) }}
                            {{ form_widget(find_form.apellidos, { 'attr': { 'class': 'form-control', 'readonly': 'readonly'}}) }}
                        </div>
                    </fieldset>
                {{ form_end(find_form) }}

Un saludo y gracias por sus ayudas.

#7

Hola @Andres11362,

Algunas recomendaciones para tu código:

  • No es una buena práctica hacer el formulario en el controlador, lo ideal es separarlo creando una clase Type que se encargue del formulario.
  • No es necesario hacer la consulta findById esa la hace Doctrine automáticamente.

Yo vuelvo a insistir en que uses Ajax para este caso, te ahorras el recargar la página con la busqueda y puedes llenar los inputs que quieres con la respuesta del mismo Ajax.

Pero puedes usar jQuery para hacer lo que quieres.

Saludos,

#8

Hola de nuevo @miguelplazasr me surgen nuevas dudas:

He logrado realizar una petición con AJAX pero no se como traer los datos de la consulta de una manera correcta, no se como manejar la respuesta de la peticion en el .js

Este es mi archivo searchuser.js:

$(document).ready(function(){
   var $form = $('#search-form');
 
   $form.submit(function (e) {
      //e.preventDefault();
      //se asigna el valor del id
      var id = $('#searchbox').val();
      //se agregan los campos del formulario
      var data = $form.serialize();
      //realizamos la peticion
      $.ajax({
         url: $form.attr('action').replace('id', id),
         type: $form.attr('method'),
         data: id,
         datatype: 'json',
         //codigo si la respuesta es satisfactoria
         success: function(data) {
            alert(data);
         },
         //codigo si la peticion falla
         error: function(xhr, status){
            alert('disculpe ocurrio un problema');
         },
         //codigo si la peticion se realizo sin importar si fallo o no
         complete: function(xhr, status){
            alert('peticion realizada');
         }
      });
      //alert(data);
   });
});

El controlador searchAction modificado:

public function searchAction(Request $request){
 
        /*if(!$request->isXmlHttpRequest()){
            return new JsonResponse(array( 'message' => 'Solo recibimos peticiones con ajax'), 400);
        }*/
 
        $em = $this->getDoctrine()->getManager();
 
        $id = $this->getRequest()->request->get('searchbox');
 
        $usuario = $em->getRepository('AdminBundle:Usuarios')->findById($id);
 
        if(!$usuario){
            //$mensaje = $this->get('Usuario no encontrado');
            //throw $this->createNotFoundException($mensaje);
            $this->get('session')->getFlashBag()->add(
                                'mensaje',
                                'No existe el usuario'
                            );
            echo new JsonResponse(array('message' => 'no se ha encontrado el usuario'), 500);
            return $this->redirect($this->generateUrl('ud_enfermeria_reporte'));
        }
 
        $form = $this->createSearchForm();
        $form->handleRequest($request);
 
        if($form->isSubmitted() && $form->isValid()){
            $this->get('session')->getFlashBag()->add(
                                'mensaje',
                                'El usuario existe'
                            );
            $jsonres = new JsonResponse(array('usuario' => $usuario), 200);
            echo $jsonres;
            return $this->render('EnfermeriaBundle:ReporteEmergencia:find.html.twig', array('jsonres' => $jsonres));
        }
    }

Los echo son solo para probar que si se realiza la peticion y como resultado obtengo esto:

HTTP/1.0 200 OK Cache-Control: no-cache Content-Type: application/json Date: Tue, 08 Mar 2016 22:43:02 GMT {"usuario":[{"username":"20121078057","nombres":"Rodrigo Andr\u00e9s","apellidos":"G\u00f3ngora Herrera"}]}

en caso que no encuentre el usuario:

HTTP/1.0 200 OK Cache-Control: no-cache Content-Type: application/json Date: Tue, 08 Mar 2016 22:43:02 GMT {"message":[{"no se ha encontrado el usuario"}]}

Estoy viendo es que si en el .js dejo activo e.preventDefault(); la peticion funciona, si la envio a otra pagina falla pero aun asi me redirige a la pagina a la que quiero enviarla, otra que cosa es que como respuesta (viendolo desde el firebug) me envia la pagina que manejo como index de los reportes, como si la respuesta siempre fuera que no encuentra el usuario.

Un saludo y gracias por tu valiosa ayuda.

#9

Sugerencias:

  • Crea un controlador para que manejes todas las peticiones que quieras hacer con ajax AjaxController.

  • Usa el FOSJsRoutingBundle para manejar las rutas en javascript.

  • Fíjate en esta pregunta del foro Problemas con el path de Symfony 2.7 en JS, ahi hay un fragmento de código que te da una idea de como usar las dos cosas que acabo de mencionar además puedes ver como manejar la respuesta del Ajax.

Está creado un grupo en Slack para desarrolladores de Symfony en latinoamérica, symfony-la.slack.com si quieres podemos vernos allí y trato de ayudarte al instante.

Avísame por si te interesa hacer parte del grupo.

Saludos,

#10

Miguel si me interesaria entrar en tu slack, mi correo es [email protected], estaria agradecido de entrar en el grupo.