# Base de datos: Paginación

# Introducción

En otros frameworks, la paginación puede ser muy difícil. El paginador de Laravel está integrado con el constructor de consultas y el ORM Eloquent, proporcionando una conveniente y fácil manera de usar paginación de resultados de forma predeterminada. El HTML generado por el paginador es compatible con el Framework de CSS Bootstrap.

# Uso básico

# Paginando los resultados del constructor de consultas

Hay varias formas de paginar los elementos. La más simple es usando el método paginate en el constructor de consultas o una Consulta de Eloquent. El método paginate se encarga automáticamente de la configuración del límite y desplazamiento apropiado de la página actual que está siendo vista por el usuario. Por defecto, la página actual es detectada por el valor del argumento de cadena de consulta page en la solicitud HTTP. Este valor es detectado automáticamente por Laravel y también es insertado automáticamente dentro de los enlaces generados por el paginador.

En este ejemplo, el único argumento pasado al método paginate es el número de elementos que prefieres que sean mostrados "por página". En este caso, vamos a especificar que nos gustaría mostrar 15 elementos por página:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;

class UserController extends Controller
{
    /**
    * Show all of the users for the application.
    *
    * @return Response
    */
    public function index()
    {
        $users = DB::table('users')->paginate(15);

        return view('user.index', ['users' => $users]);
    }
}

Nota

Actualmente, las operaciones de paginación que usan una instrucción GroupBy no pueden ser ejecutados eficientemente por Laravel. Si necesitas usar una cláusula GroupBy con un conjunto de resultados paginados, es recomendable que consultes la base de datos y crees un paginador manualmente.

# Paginación sencilla

Si necesitas mostrar solamente enlaces "Siguiente" y "Anterior" en tu vista de paginación, puedes usar el método simplePaginate para ejecutar una consulta más eficiente. Esto es muy útil para grandes colecciones de datos cuando no necesitas mostrar un enlace para cada número de página al momento de renderizar tu vista.

$users = DB::table('users')->simplePaginate(15);

# Paginando resultados de eloquent

También puedes paginar consultas de Eloquent. En este ejemplo, paginaremos el modelo User con 15 elementos por página. Como puedes ver, la sintaxis es casi idéntica a la paginación de los resultados del constructor de consultas.

$users = App\User::paginate(15);

Puedes ejecutar paginate después de configurar otras restricciones en la consulta, tal como las cláusulas where:

$users = User::where('votes', '>', 100)->paginate(15);

También puedes usar el método simplePaginate al momento de paginar los modelos de Eloquent.

$users = User::where('votes', '>', 100)->simplePaginate(15);

# Creando un paginador manualmente

Algunas veces puedes desear crear una instancia de paginación manualmente, pasándole un arreglo de elementos. Puedes hacer eso al crear una instancia de la clase Illuminate\Pagination\Paginator o Illuminate\Pagination\LengthAwarePaginator, dependiendo de tus necesidades.

La clase Paginator no necesita conocer el número total de elementos en el conjunto de resultados; sin embargo, debido a esto, la clase no tiene métodos para obtener el índice de la última página. La clase LengthAwarePaginator acepta casi los mismos argumentos que la clase Paginator; sin embargo, si requiere una cuenta del total del número de elementos en el conjunto de resultados.

En otras palabras, la clase Paginator corresponde al método simplePaginate en el constructor de consultas y Eloquent, mientras la clase LengthAwarePaginator corresponde al método paginate.

Nota

Cuando creas manualmente una instancia del paginador, deberías manualmente "recortar en partes" el arreglo de resultados que pasas al paginador. Si estás inseguro de cómo hacer esto, inspecciona la función de PHP array_slice.

# Mostrando los resultados de la paginación

Cuando ejecutas el método paginate, recibirás una instancia de la clase Illuminate\Pagination\LengthAwarePaginator. Cuando ejecutas el método simplePaginate, recibirás una instancia de la clase Illuminate\Pagination\Paginator. Estos objetos proporcionan varios métodos que afectan la presentación del conjunto de resultados. Además de estos métodos helpers, las instancias del paginador son iteradoras, es decir, pueden ser recorridas por un ciclo repetitivo igual que un arreglo. Así, una vez que has obtenido los resultados, puedes mostrar los resultados y renderizar los enlaces de página usando Blade:

<div class="container">
    @foreach ($users as $user)
        {{ $user->name }}
    @endforeach
</div>

{{ $users->links() }}

El método links renderizará los enlaces para el resto de las páginas en el conjunto de resultados. Cada uno de estos enlaces ya contendrá la variable de cadena de consulta page apropiada. Recuerda, el HTML generado por el método links es compatible con el Framework de CSS Boostrap.

# Personalizando la URI del paginador

El método withPath permite personalizar la URI usada por el paginador al momento de generar enlaces. Por ejemplo, si quieres que el paginador genere enlaces como http://example.com/custom/url?page=N, deberías pasar custom/url al método withPath:

Route::get('users', function () {
    $users = App\User::paginate(15);

    $users->withPath('custom/url');

    //
});

# Agregando enlaces de paginación

Puedes agregar la cadena de consulta a los enlaces de paginación usando el método appends. Por ejemplo, para agregar sort=votes a cada enlace de paginación, deberías hacer la siguiente ejecución del método appends:

{{ $users->appends(['sort' => 'votes'])->links() }}

Si deseas agregar un "fragmento con el símbolo numeral #" a las URLs del paginador, puedes usar el método fragment. Por ejemplo, para agregar #foo al final de cada enlace de paginación, haz la siguiente ejecución del método fragment:

{{ $users->fragment('foo')->links() }}

# Ajustando la ventana de enlace de paginación

Puedes controlar cuántos enlaces adicionales son mostrados en cada lado de la "ventana" de la URL del paginador. Por defecto, tres enlaces son mostrados en cada lado de los enlaces primarios del paginador. Sin embargo, puedes controlar este número usando el método onEachSide:

{{ $users->onEachSide(5)->links() }}

# Convirtiendo resultados a JSON

Las clases resultantes del paginador de Laravel implementan la interfaz Illuminate\Contracts\Support\Jsonable y exponen el método toJson, así es muy fácil convertir los resultados de tu paginación a JSON. También puedes convertir una instancia del paginador al devolverlo desde una ruta o acción de controlador:

Route::get('users', function () {
    return App\User::paginate();
});

El JSON devuelto por el paginador incluirá meta información tal como total, current_page, last_page y más. Los objetos de resultados reales estarán disponibles por medio de la clave data en el arreglo JSON. Aquí está un ejemplo del JSON creado al regresar una instancia del paginador desde una ruta:

{
    "total": 50,
    "per_page": 15,
    "current_page": 1,
    "last_page": 4,
    "first_page_url": "http://laravel.app?page=1",
    "last_page_url": "http://laravel.app?page=4",
    "next_page_url": "http://laravel.app?page=2",
    "prev_page_url": null,
    "path": "http://laravel.app",
    "from": 1,
    "to": 15,
    "data":[
        {
            // Result Object
        },
        {
            // Result Object
        }
    ]
}

# Personalizando la vista de la paginación

De forma predeterminada, las vistas que son renderizadas para mostrar los enlaces de paginación son compatibles con el framework de CSS Bootstrap. Sin embargo, si no estás usando Bootstrap, eres libre de definir tus propias vistas para renderizar esos enlaces. Al momento de ejecutar el método links en una instancia del paginador, pasa el nombre de la vista como primer argumento del método:

{{ $paginator->links('view.name') }}

// Passing data to the view...
{{ $paginator->links('view.name', ['foo' => 'bar']) }}

Sin embargo, la forma más fácil de personalizar las vistas de paginación es exportándolas a tu directorio resources/views/vendor usando el comando vendor:publish:

php artisan vendor:publish --tag=laravel-pagination

Este comando ubicará las vistas dentro del directorio resources/views/vendor/pagination. El archivo default.blade.php dentro de este directorio corresponde a la vista de paginación predeterminada. Edita este archivo para modificar el HTML de paginación.

Si quieres designar un archivo distinto como la vista de paginación por defecto, se pueden usar los métodos de paginador defaultView y defaultSimpleView en tu AppServiceProvider:

use Illuminate\Pagination\Paginator;

public function boot()
{
    Paginator::defaultView('view-name');

    Paginator::defaultSimpleView('view-name');
}

# Métodos de la instancia paginadora

Cada instancia del paginador proporciona información de paginación adicional por medio de los siguientes métodos:

Método Descripción
$results->count() Obtiene el número de elementos para la página actual.
$results->currentPage() Obtiene el número de la página actual.
$results->firstItem() Obtiene el número de resultado del primer elemento en los resultados.
$results->getOptions() Obtiene las opciones del paginador.
$results->getUrlRange($start, $end) Crea un rango de URLs de paginación.
$results->hasMorePages() Determina si hay suficientes elementos para dividir en varias páginas.
$results->items() Obtener los elementos de la página actual.
$results->lastItem() Obtiene el número de resultado del último elemento en los resultados.
$results->lastPage() Obtiene el número de página de la última página disponible. (No disponible cuando se utiliza simplePaginate).
$results->nextPageUrl() Obtiene la URL para la próxima página.
$results->onFirstPage() Determine si el paginador está en la primera página.
$results->perPage() El número de elementos a mostrar por página.
$results->previousPageUrl() Obtiene la URL de la página anterior.
$results->total() Determine el número total de elementos coincidentes en el almacén de datos. (No disponible cuando se utiliza simplePaginate).
$results->url($page) Obtiene la URL para un número de página dado.
$results->getPageName() Obtiene la variable string usada para almacenar la página.
$results->setPageName($name) Determina la variable string usada para almacenar la página.