Este foro ya no está activo, así que no puedes publicar nuevas preguntas ni responder a las preguntas existentes.

Problema con un formulario Symfony de preguntas

18 de febrero de 2015

Hola.

Mi situación es la siguiente. Tengo preguntas con sus respectivas alternativas. Tengo dos implementaciones:

1) La primera esta implementada en una encuesta por tanto el formulario es estático.

Esto quiere decir que cada pregunta tiene fijo el numero de alternativas y se presentan en el mismo order cada ves que se llama la vista que dibuja el formulario.

| P1 | 
| -- | 
| A1 | 
| A2 | 
| A3 | 
| A4 | 
| A5 |

2) En el segundo caso tengo una evaluación donde tengo almacenada N alternativas de las cuales una es la correcta.

Unos de los requerimientos es que las alternativas a mostrar para cada pregunta son 5, y se muestran al azar dentro de N alternativas almacenadas.

| P1 | 
| -- | 
| A3 | 
| A5 | 
| A2* | 
| A1 | 
| A4 |

otro

| P1 | 
| -- | 
| A1 | 
| A5 | 
| A3 | 
| A4 | 
| A2* |

Mi problema es cuando dejo alguna pregunta sin respuesta. Esto genera que se active las validación que no debe haber un pregunta sin seleccionar una alternativa. Al volver a mostrar el formulario muestra al azar las alternativas.

Las preguntas y las alternativas asociadas a mostrar se genera en la clase del formulario en un array.

Mi pregunta es cuando se genera el orden de las alternativas en el formulario estos datos (array) mantengan almacenados, en el caso cuando no pasa la validación, utilizar esos valores en vez de generarlos nuevamente.

Gracias y saludos.


Respuestas

#1

Buenas, ¿podrías mostrar como estás haciendo el ordenamiento al azar de las alternativas?

Lo que se me ocurre así de buenas a primeras es utilizar el evento pre_submit del formulario y crear las alternativas en el orden en que vienen de $event->getData().

Por otro lado, podrás validar en el cliente para que no se envíe el formulario hasta que estén todas las preguntas con al menos una respuesta.

Una última opción que se me ocurre es hacerlo definiendo un tema de formularios para las alternativas, y verificar si el Request contiene los datos y claves de esos elementos para en base a ello, mostrar las alternativas. Ejemplo:

{% block alternativas_row %}
{% if submitted %}
    {% for key, value in app.request.get(full_name, [], true) %}
        {{ form_row(form[key]) }}
    {% endfor %}
{% else %}
    {# el renderizado por defecto #}
{% endif %}
{% endblock %}

@manuel_j555

19 febrero 2015, 0:39
#2

Este código formulario donde la variable $this->preguntas es un array que contiene la pregunta y las opciones relacionadas para cada una. Es decir que cada pregunta tiene 5 o mas opciones, de las cuales una es correcta.

public function buildForm(FormBuilderInterface $builder, array $options)
{
    foreach ($this->preguntas as $pregunta) {
        $choices = array();                        
        $alternativas = $this->orderArray($pregunta['opciones']);
 
        foreach ($alternativas as $choice) {
            $choices[$choice['id']] = $choice['opcion'];
        }
 
        $options = array(
            'label' => $pregunta['pregunta'],
            'choices' => $choices,
        );
 
        $additionalOptions = array(
            'expanded' => true,
            'multiple' => false,
        );
 
        $constraints = array(
            'constraints' => array(
                new NotNull(array('message' => "Por favor, seleccione una opción.")),
                new Choice(array('choices' => array_keys($choices)))
        ));
 
        $options = array_merge($options, $additionalOptions, $constraints);
 
        $builder
            ->add(sprintf('pregunta_%s', $pregunta['id']), 'choice', $options)
        ;
    }
}

La función orderArray() devuelve un array compuesto con 5 opciones incluido la opción correcta. Las 4 opciones restantes se seleccionan al azar dentro de las opciones disponibles y al final devuelve un array con las opciones en orden aleatorio para una pregunta.

Después se declaran algunas opciones y restricciones. Al final se genera un campo en el formulario por cada pregunta:

$builder->add(sprintf('pregunta_%s', $pregunta['id']), 'choice', $options);

En el caso del controlador $event->getData(), me devuelve solo los ids de cada opción seleccionada.

@dariongg

19 febrero 2015, 13:32
#3

Hola @manuel_j555

¿cómo puedo hacer esto que comentas?

Por otro lado, podrás validar en el cliente para que no se envíe el formulario hasta que estén todas las preguntas con al menos una respuesta.

Gracias

@dariongg

19 febrero 2015, 13:38
#4

Hola, podrias usar jQuery e implementar algo como:

// Asumiendo que cada pregunta es un div con la clase pregunta
$('form').on('submit', function(event) {
   $(".pregunta", this).each(function() {
      //por cada pregunta validas las respuestas:
      if ($(':radio:checked', this).size() == 0) {
         //si no hay ningun elemento checkeado.
         $(this).append (
             "<span class='error'>Seleccione al menos una alternativa</span>"
         );
 
         event.preventDefault(); //detenemos el envío del formulario
      }
   });
 
});

El ejemplo es muy básico pero puede dar una idea.

Saludos!

@manuel_j555

19 febrero 2015, 15:11
#5

El formulario genera esto para cada pregunta

<label class="required">P1</label> 
                                    <div class="well well-small">
                                            <div id="cap_evaluacion_type_pregunta_1"><label  for="cap_evaluacion_type_pregunta_1_0"><input type="radio" id="cap_evaluacion_type_pregunta_1_0" name="cap_evaluacion_type[pregunta_1]" required="required" value="3" /> O3
        </label><label  for="cap_evaluacion_type_pregunta_1_1"><input type="radio" id="cap_evaluacion_type_pregunta_1_1" name="cap_evaluacion_type[pregunta_1]" required="required" value="6" /> O6
        </label><label  for="cap_evaluacion_type_pregunta_1_2"><input type="radio" id="cap_evaluacion_type_pregunta_1_2" name="cap_evaluacion_type[pregunta_1]" required="required" value="4" /> O4
        </label><label  for="cap_evaluacion_type_pregunta_1_3"><input type="radio" id="cap_evaluacion_type_pregunta_1_3" name="cap_evaluacion_type[pregunta_1]" required="required" value="1" /> O1
        </label><label  for="cap_evaluacion_type_pregunta_1_4"><input type="radio" id="cap_evaluacion_type_pregunta_1_4" name="cap_evaluacion_type[pregunta_1]" required="required" value="5" /> O5
        </label></div>                            
                                    </div> 
 
y dentro de la plantilla tengo ento para dibujar choice y radio 
 
{% block choice_widget %}
    {% spaceless %}
        {% if expanded %}
            <div {{ block('widget_container_attributes') }}>
                {% for child in form %}
                    {{ form_widget(child) }}
                      {#{{ form_label(child) }} #} 
                {% endfor %}
            </div>
        {% else %}
 
            <select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
                {% if empty_value is not none %}
                    <option value="">{{ empty_value|trans }}</option>
                {% endif %}
                {% if preferred_choices|length > 0 %}
                    {% set options = preferred_choices %}
                    {{ block('widget_choice_options') }}
                    {% if choices|length > 0 and separator is not none %}
                        <option disabled="disabled">{{ separator }}</option>
                    {% endif %}
                {% endif %}
                {% set options = choices %}
                {{ block('widget_choice_options') }}
            </select>
        {% endif %}
    {% endspaceless %}
{% endblock choice_widget %}
 
{% block radio_widget %}    
    {% spaceless %}
        <label  for="{{ id }}">
            <input type="radio" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} /> {{ label|trans }}
        </label>
    {% endspaceless %}
{% endblock radio_widget %}

@dariongg

19 febrero 2015, 15:16