jueves, 6 de febrero de 2014

Nuevas mini preguntas en el blog


Hay entradas que me gustaría saber si os ha funcionado u os ha sido útil lo que he explicado por lo que he escrito una mini utilidad para añadir preguntas.



Como podeis ver en la entrada sobre acceder al router Livebox 2 de Orange el funcionamiento es muy sencillo. Una pregunta, un par de opciones y entre paréntesis al lado de cada opción el número de clics que se han hecho en cada una.


Los resultados son sólo orientativos, al final uno podría votar tanto como quisiera aunque tendría que estar actualizando la página. Pero también hace la participación extremadamente sencilla.

Entrando más a las entrañas veamos primero la implementación dentro del código html.

<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.min.js">$lt;/script>
  <script type="text/javascript" src="survey.js"></script>
</head>
<body>
  <div id="survey">
    Are you ok?
    <button value="1">Yes</button>
    <button value="0">No</button>
  </div>
</body>
</html>

Necesitamos cargar jQuery y el fichero donde están las funciones relacionadas survey.js. La zona de la pregunta está identificada como id="survey" y los valores que serán recogidos en la base de datos se encuentran en el atributo value de cada button. En este caso, la respuesta Yes será registrada como 1 y la respuesta No será registrada como 0.


El contenido de survey.js es el que enviará la información cuando hagas clic.

var origin = window.location.protocol + "//" + window.location.host + window.location.pathname;
var url = "collector.php"; //url of collector.php;
 
$(document).ready(function() {
  $("#survey button").on("click", function( event ) {
    answer = $( this ).val();
    xhr_get({url:origin, answer: answer}).done(function(){
      $("#survey button").prop("disabled", true)
    });
  });
  xhr_get({url:origin});
});

function is_undefined(data){
  if(typeof data === "undefined"){
    return "0";
  }else{
    return data;
  }
}

function xhr_get(data){
  return $.ajax({
    type: "POST",
    dataType: "json",
    url: url,
    data: data
  }).done(function(resp){
    if(resp !== null){
      $("#survey button[value=1]").text("Sí ("+is_undefined(resp[1])+")");
      $("#survey button[value=0]").text("No ("+is_undefined(resp[0])+")");
    }
  });
}

En la segunda línea deberemos indicarle dónde se encuentra el archivo que recibirá y tratará las respuestas.

Entre verificaciones y lógica, cuando se carga la página contacta con la contrapartida en el servidor (el próximo fichero) para saber si hay respuestas y ponerlas entre paréntesis (línea 11). Además cuando se haga clic sobre alguno de los botones envía el value de ese botón junto a la url de la página al servidor.

Aquí ya se ve alguna limitación en el código, pero lo comentaré globalmente al final.

Y finalmente el código que hace de intermediaro entre la base de datos y la web, el fichero collector.php

<?php
 
$host="localhost"; //url of database server;
$dbname=""; //database name;
$user=""; //database username;
$pass=""; //database password;
$table=""; //database table;
 
//Connection to mysql server;
$DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
 
if(isset($_REQUEST['answer'])){
  # STH means "Statement Handle"
  $data = array('url' => $_REQUEST['url'], 'answer'=> (int) $_REQUEST['answer']);
  $STH = $DBH->prepare("INSERT INTO Q_funciona ( url, answer ) values ( :url, :answer)");
  $STH->execute($data);
}
 
$data = array('url' => $_REQUEST['url']);
$STH = $DBH->prepare("SELECT url, answer, COUNT(answer) AS total FROM Q_funciona WHERE url=:url GROUP BY answer");
$STH->execute($data);
 
while($row = $STH->fetch()) {
  $array[$row['answer']] = $row['total'];
}
 
echo json_encode($array);
 
# close the connection
$DBH = null;
 
?>

Hay que indicar la información de conexión a la base de datos así como el nombre de la tabla donde queramos guardar la información. El acceso a la base de datos está implementado usando PDO por lo que no debería suponer ningún problema usar otra base de datos que no fuera mysql.

En la base de datos he hecho una tabla de 3 columnas, una clave primaria (Id) que se autoincrementa, un campo que contiene la dirección de la página dónde se hizo clic y un tercer campo que guarda la respuesta.

Un clic se guarda como un registro nuevo formado por la url de orígen y el valor. Por ejemplo, si la pregunta se responde 25 veces (10 Sí, 15 No) habrá 25 registros 10 de ellos con un 1 y 15 con un 0, y todos con la misma url.

Podría ser mejor y es probable que lo cambie. Se me antojan muchos registros con lo que por ejemplo, en vez de añadir registros nuevos podría tener 3 columnas (url, sí, no) y sumar +1 al contenido de la respuesta que correspondiese. Aunque entonces estoy limitado en cantidad de respuestas al número de columnas que tenga en esa tabla. Prometo relacionar un par de tablas para hacerlo como toca y ampliar las posibilidades, en otro fascículo claro.

En este caso, la consulta para leer los resultados filtra por url, agrupa por respuesta y suma las ocurrencias de cada respuesta. Limpia y devuelve los valores al cliente.

Entre las limitaciones actuales se encuentra el hecho de que sólo puede haber una pregunta por página (url), aunque ésta puede tener más de dos respuestas habría que ajustar las líneas 29-30 de survey.js para que muestre las cantidades de clics donde toca. Por desgracia el tamaño de la tabla puede crecer demasiado tal como se registran los resultados. Además el tipo de datos que se podrán guardar depende de cómo se definan los campos en la base de datos.

Podreis ver nuevas versiones de éste "fantástico" código mezcla de php, html y javascript con jQuery, aderezado con un poco de ajax y consultas SQL a una base de datos mysql utilizando la clase PDO para aumentar la portabilidad, en el Gist.

Sí, todo este rollo para anunciar que habrá entradas del blog con alguna pregunta, como por ejemplo:

¿Y tú de quién eres?

No hay comentarios:

Publicar un comentario