Laravel: paginación de registros

En este post te voy a mostrar cómo puedes realizar una paginación en Laravel; es decir, mostrar registros (de la base de datos) por página, en lugar de mostrarlos todos a la vez.

Laravel ya provee una manera realmente sencilla de agregar paginación, incluso da la opción de agregar los enlaces a la página, y por supuesto, también permite cosas como la búsqueda u otros métodos del Query Builder, todo esto sin escribir ninguna consulta SQL manual.

Paginación simple

Paginación de resultados en Laravel

Si simplemente quieres paginar tus resultados, invoca a paginate de tu modelo y pásale como argumento cuántos elementos quieres por página.

Por ejemplo, yo tengo mi modelo llamado Producto:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Producto extends Model
{
    protected $fillable = ["codigo_barras", "descripcion", "precio_compra", "precio_venta", "existencia", "es_servicio",
    ];
}

Ahora en mi controlador para enviarlo a la vista, indico el uso del namespace:

use App\Producto;

Y para paginar, envío los resultados así:

<?php
$productos = Producto::paginate(5);
return view("productos.productos_index", [
    "productos" => $productos,
]);

En este caso estoy paginando cada 5 registros. Ahora en mi vista los dibujo en una tabla; puedo iterarlos fácilmente con un foreach:

<table class="table table-bordered">
    <thead>
    <tr>
        <th>Código de barras</th>
        <th>Descripción</th>
        <th>Precio de compra</th>
        <th>Precio de venta</th>
        <th>Utilidad</th>
        <th>Existencia</th>
        <th>¿Servicio?</th>
        <th>Editar</th>
        <th>Eliminar</th>
    </tr>
    </thead>
    <tbody>
    @foreach($productos as $producto)
        <tr>
            <td>{{$producto->codigo_barras}}</td>
            <td>{{$producto->descripcion}}</td>
            <td>{{$producto->precio_compra}}</td>
            <td>{{$producto->precio_venta}}</td>
            <td>{{$producto->precio_venta - $producto->precio_compra}}</td>
            <td>{{$producto->existencia}}</td>
            <td>
                @if($producto->es_servicio)
                    <i class="fa fa-check"></i>
                @else
                    <i class="fa fa-times"></i>
                @endif
            </td>
            <td>
                <a class="btn btn-warning" href="{{route("productos.edit",[$producto])}}">
                    <i class="fa fa-edit"></i>
                </a>
            </td>
            <td>
                <form action="{{route("productos.destroy", [$producto])}}" method="post">
                    @method("delete")
                    @csrf
                    <button type="submit" class="btn btn-danger">
                        <i class="fa fa-trash"></i>
                    </button>
                </form>
            </td>
        </tr>
    @endforeach
    </tbody>
</table>

Además, si quiero que se muestren los enlaces para navegar a las distintas páginas (por defecto Laravel genera el HTML para Bootstrap) invoco a links justo abajo de mi tabla:

{{$productos->links()}}

El código completo queda así:

<div class="table-responsive">
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>Código de barras</th>
            <th>Descripción</th>
            <th>Precio de compra</th>
            <th>Precio de venta</th>
            <th>Utilidad</th>
            <th>Existencia</th>
            <th>¿Servicio?</th>
            <th>Editar</th>
            <th>Eliminar</th>
        </tr>
        </thead>
        <tbody>
        @foreach($productos as $producto)
            <tr>
                <td>{{$producto->codigo_barras}}</td>
                <td>{{$producto->descripcion}}</td>
                <td>{{$producto->precio_compra}}</td>
                <td>{{$producto->precio_venta}}</td>
                <td>{{$producto->precio_venta - $producto->precio_compra}}</td>
                <td>{{$producto->existencia}}</td>
                <td>
                    @if($producto->es_servicio)
                        <i class="fa fa-check"></i>
                    @else
                        <i class="fa fa-times"></i>
                    @endif
                </td>
                <td>
                    <a class="btn btn-warning" href="{{route("productos.edit",[$producto])}}">
                        <i class="fa fa-edit"></i>
                    </a>
                </td>
                <td>
                    <form action="{{route("productos.destroy", [$producto])}}" method="post">
                        @method("delete")
                        @csrf
                        <button type="submit" class="btn btn-danger">
                            <i class="fa fa-trash"></i>
                        </button>
                    </form>
                </td>
            </tr>
        @endforeach
        </tbody>
    </table>
    {{$productos->links()}}
</div>

Si te fijas, toma el número de página de la URL. Por ejemplo, lo siguiente muestra la página 2:

http://localhost/nombre_de_tu_proyecto/public/productos?page=2

Fíjate en el parámetro de page que está en 2.

Paginación con búsqueda

Si quieres agregar filtros o aprovechar lo que ofrece el query builder, puedes invocar a varios métodos y al final paginar con paginate.

Por ejemplo, supongamos que quieres filtrar los productos por búsqueda basándote en una variable de la URL, y que los quieres ordenar por descripción.

<?php
# Función llamada desde el controlador; es un ejemplo, tú puedes colocar el código donde gustes
public function index(Request $request)
{
    $busqueda = "";
    if ($request->get("busqueda")) {
        $busqueda = $request->get("busqueda");
    }
    # Exista o no exista búsqueda, los ordenamos
    $builder = Producto::orderBy("descripcion");
    if ($busqueda) {
        # Si hay búsqueda, agregamos el filtro
        $builder->where("descripcion", "LIKE", "%$busqueda%");
    }
    # Al final de todo, invocamos a paginate que tendrá todos los filtros
    $productos = $builder->paginate(5);
    return view("productos.productos_index", [
        "productos" => $productos,
    ]);
}

En este caso podemos invocar a todos los métodos para hacer consultas de SQL. Por ejemplo, estamos invocando a orderBy y a where; pero al final obtenemos los resultados con paginate.

Todo sigue funcionando igual, haya búsqueda o no, y los links también funcionan. Si hay menos resultados para la búsqueda, el número de enlaces para páginas cambiará, es decir, se toman en cuenta todos los filtros y el total de registros devueltos.

Si no usas bootstrap

En caso de que no utilices el framework Bootstrap o quieras mostrar los enlaces de manera manual, también es posible. Puedes obtener el total de elementos accediendo a total, así:

$productos->total();

Para saber cuántos mostrar por página (aunque eso también se define al invocar a paginate, pero esto funciona para hacerlo desde la vista) invoca a perPage.

Ya con esto puedes obtener las páginas así:

$paginas = ceil($productos->total() / $productos->perPage()

Y hacer un ciclo for que muestre los enlaces desde 1 hasta el total de páginas, justo como lo detallo en mi post de paginación manual de registros con PHP.

Recuerda que en este caso $productos es lo que devuelve el método paginate al invocarlo sobre un modelo.

Si te gusta este framework, te invito a ver más sobre Laravel en mi blog.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

2 comentarios en “Laravel: paginación de registros”

Dejar un comentario

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