Paginación de resultados con filtros en PHP y MySQL

Hola de nuevo. Hace tiempo que no escribía de seguido y para resarcirme os propongo realizar una paginación de resultados que incluya filtros. Para ello voy a partir de un proyecto que les suelo plantear a mis alumnos cuando imparto php con bases de datos mysql.

php_y_mysql

El proyecto en sí en la creación de un blog simple, en el que hay tres tipos de usuarios (usuario registrado que podrá hacer comentarios, editores y administradores). En la página del inicio del blog se muestran los post publicados ordenados por fecha, empezando por el más reciente. Así mismo se muestra un panel lateral con el listado de etiquetas que se pueden usar para filtrar. Esta es la página que usaremos para implementar el paginador. Mostraremos pues solamente 10 artículos y luego mediante el paginador podremos acceder otros 10, y así sucesivamente. El aspecto de todo esto es el siguiente:

blog_sup

Y del paginador que aparece en la parte inferior:

blog_inf

Para que podáis seguir este ejemplo os voy a dejar el archivo sql para crear la base de datos:

Necesitaríais crear una base de datos MySQL y utilizar esas sentencias para crear las tablas e introducir los datos de ejemplo (tenéis un botón para poder copiar todo el código). Además tendréis que crear vosotros el archivo con vuestros datos de conexión a vuestra base de datos. También la conexión a la que yo he llamado $con:

Explico un poco la idea. Un post puede estar etiquetado en varias categorías por lo que tenemos una tabla para las etiquetas llamada labels ,otra para los posts, y otra que las relaciona, posts_labels. En posts tendremos entradas como estas:

posts

Y en labels y posts_labels, como las siguientes:

 

labels

 

posts_labels

 

 

 

 

 

 

 

 

 

Como podéis ver, en posts_labels, para el post con id=1 hay dos entradas, es decir existen dos etiquetas para ese post, HTML y JAVASCRIPT. Para poder relacionar varios posts con un mismo usuario he decidido crear una tabla user_posts que los relaciona. Bien una vez conocida la estructura sobre la que vamos a trabajar, empezamos.

Creando la estructura de la página

Para el proyecto vamos a usar bootstrap. Si no lo conoces no pasa nada, otro día ya hablaremos de él con detalle. Para ello incluye los archivos necesarios, en el head:

Y al final de tu documento, antes de cerrar el body:

Con esto ya podemos usar las clases de bootstrap. Vamos a crear dos contenedores, uno grande  a la izquierda para que aparezcan 5 posts o artículos de cada vez y uno lateral pequeño que muestre las etiquetas o labels por las que podemos filtrar. Estos los crearemos en en su momento con la consulta a la bbdd, pero hemos de mterlos en un container y en un row para que floten correctamente.

Nuestro paginador, ese menú de  botones con números que alojaremos al final de nuestra página, nos permitirá acceder a grupos de por ejemplo 5 resultados de cada vez. Si hacemos click en el botón nº 3  se nos mostrarán los resultados del 10 al 15. Para crear estos grupos de resultados se habrá tenido en cuenta el filtro aplicado, veamos como hacerlo.

Configurando el paginador

 

Para crear un paginador nos vamos a basar en la cláusula limit de sql que permite limitar la cantidad de registros devueltos pasándole dos parámetros, donde queremos empezar a contar y cuantos registros queremos obtener.

Así que definiremos una variable llamada $reg que representará ese último parámetro, para nuestro ejercicio la inicializaremos a 5, con lo que mostraremos 5 posts de cada vez.  A parte de esa variable necesitaremos otra para establecer donde empezamos a contar, la llamaremos $inicio. Esta será diferente en función de la página de resultados a la que vayamos. Así que también necesitamos una que represente el nº de la página de resultados, será $pagina. Explico esto: Si tenemos 20 artículos obtendremos 4 páginas ya que mostramos 5 artículos por página. Si queremos ver los resultados del 15 al 20 tendremos que ir a la página nº 4. En este caso $pagina=4 y $inicio=15.

Tras el último post que mostremos, aparecerá el paginador, que mostrará el nº de las páginas como enlaces en los que podemos hacer click para ir a esa página en concreto. Por lo tanto necesitamos conocer en que página estamos y a cual vamos. Esto lo implementamos pasando el nº de página por url (y capturando ese valor mediante el método GET de PHP):

Si no hemos usado el paginador iniciamos la variable $pagina a 1 y $inicio a 0, en caso de que ya lo hayamos usado el valor de $pagina será el que hayamos pasado por GET y el de $inicio  lo calculamos en función de la página que toque. Por ejemplo para la página 2 sería (2-1)*5=5, es decir empezamos a contar en el registro nº 5 (recordar que el nº de registros de una consulta se empiezan a contar sede cero, no desde 1) y contamos cinco registros (hasta el 9, la página 1, en cambio, mostrará los resultados de 0 a 4).

Para saber la cantidad de páginas necesitaremos una consulta a la bbdd que nos diga cuantos registros hay en total (para este caso se podía haber usado simplemente SELECT * FROM posts, pero para simplificar he decidido usar la consulta que utilizaremos luego para extraer todos los datos necesarios):

El campo publicado=2 se refiere a que el post está publicado(Los no publicados lo tienen a 1).

Y ejecutando la consulta y con las funciones necesaria mysqli sabemos el nº de registros:

Para hacer el cálculo usamos el método ceil de PHP que redondea un valor por arriba quitando los decimales, y se lo aplicamos al resultado de dividir el nº de resultados obtenidos en esta consulta por el nº de registros que decidimos mostrar.

Las consultas van a variar en función de si se ha aplicado un filtro o no. Así que para que lo anterior funcione si se ha aplicado el filtro de alguna etiqueta habrá que usar una cláusula WHERE:

Como podéis ver tenemos dos opciones, una si existe un filtro de etiqueta aplicado ($label) y otra si no. Si se ha recogido en $label el filtro de la etiqueta, es decir, al hacer click en el filtro de una etiqueta se ha pasado por url el id de esa etiqueta, se usará etse valor en en la consulta. Con estas consultas sabemos ya cuantos registros hay y el nº de páginas que nos salen.

Aahora necesitamos que las consultas usen esos parámetros para que obtengan los registros necesarios en función de la página que toque (por ejemplo los registros del del 5 al 9 si estamos en la página 2) y si se ha usado el filtro o no:

Una vez definidas correctamente las consultas, ahora la ejecutamos y mostramos los artículos resultantes de la consulta (doy por echo que estáis ejecutando este código dentro del div con la clase row ):

Creando y mostrando el paginador

 

Llegados a este punto mostramos los botones de el paginador, voy a usar la estructura que nos ofrece bootstrap que queda bastante bien.  Abro lo primero el menú de navegación del paginador:

Ahora necesitamos mostrar los vínculos o botones para páginas anteriores, siguientes y mostrar la página actual. Primero, se pregunta si hay más de una página, y en ese caso se pregunta si la página actual no es la primera, esto significa que no es la primera vez que listamos y por ende se despliega el vínculo para volver a páginas anteriores, enviando como parámetro el número de página menos 1 para que se reseteen las variables del inicio del código. Además en caso de que se haya aplicado un filtro, se añade a la url de los enlaces la variable id_label para que pueda recogerse por get y ser usada en la consulta que use $label en su clausula WHERE.

Con esto ya tenemos el paginador que funciona también cuando se le pasan labels por url (para que la consulta a la bbdd utilice ese label como parámetro y pueda obtener un paginado con el filtro aplicado). Necesitamos ahora el menú de navegación lateral con esos labels.

Creando el menú lateral de filtros

Esta el la parte más sencilla, sólo tenemos que hacer una consulta a la tabla labels para sacar su nombre. A la hora de mostrar los botones o enlaces de los labels, el enlace que los contenga tiene que adjuntar en su src una variable con el id del label:

Como podéis observar cuando el id del label actual que se está usando como filtro coincide con un elemento del menú de filtros a ese elemento se le pone la clase active para destacar que se está usando como filtro. Además si se está usando algún label como filtro se muestra un botón para volver a la página pero sin filtros. Si habéis creado la bbdd con el sql que os he dejado, podéis probar filtrando por la etiqueta LINUX y también con la de  PHP, pues se han insertado 6 post de ejemplo para cada una de esas etiquetas. Podréis ver entonces como funciona correctamente el paginador con el filtro aplicado.

Bueno y esto es todo. Un poco largo pero si se lee con calma es ácil de entender.

 


3 thoughts on “Paginación de resultados con filtros en PHP y MySQL”

  • 1
    Arthur on 23 marzo, 2018 Responder

    Cómo es que no dejas el script ya en funcionamiento??

    • 2
      Imobach on 7 abril, 2018 Responder

      Hola Arthur. Antes de nada gracias por comentar.
      Y respecto a tu comentario ¿a qué te refieres con dejar es script funcionando?.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *