Documentación de Laravel 10.x
Aquí encontrarás fragmentos de código de Laravel y consejos útiles sobre desarrollo web.
En otros frameworks, la paginación puede ser muy tediosa. Esperamos que el enfoque de Laravel hacia la paginación sea un soplo de aire fresco. El paginador de Laravel está integrado con el constructor de consultas y Eloquent ORM y proporciona una paginación conveniente y fácil de usar de los registros de la base de datos sin configuración alguna.
Por defecto, el HTML generado por el paginador es compatible con el framework Tailwind CSS; sin embargo, también hay soporte para la paginación de Bootstrap.
Si estás utilizando las vistas de paginación Tailwind predeterminadas de Laravel y el motor Tailwind JIT, debes asegurarte de que la clave content
del archivo tailwind.config.js
de tu aplicación haga referencia a las vistas de paginación de Laravel para que sus clases de Tailwind no se purguen:
content: [ './resources/**/*.blade.php', './resources/**/*.js', './resources/**/*.vue', './vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',],
Hay varias formas de paginar elementos. La más simple es utilizando el método paginate
en el constructor de consultas o en una consulta Eloquent. El método paginate
se encarga automáticamente de establecer los valores de "límite" y "desplazamiento" de la consulta según la página actual que esté viendo el usuario. Por defecto, la página actual se detecta según el valor del argumento de cadena de consulta page
en la solicitud HTTP. Este valor se detecta automáticamente por Laravel y también se inserta automáticamente en los enlaces generados por el paginador.
En este ejemplo, el único argumento pasado al método paginate
es la cantidad de elementos que deseas mostrar "por página". En este caso, especifiquemos que queremos mostrar 15
elementos por página:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use Illuminate\Support\Facades\DB;use Illuminate\View\View; class UserController extends Controller{ /** * Mostrar todos los usuarios de la aplicación. */ public function index(): View { return view('user.index', [ 'users' => DB::table('users')->paginate(15) ]); }}
El método paginate
cuenta el número total de registros coincidentes con la consulta antes de recuperar los registros de la base de datos. Esto se hace para que el paginador sepa cuántas páginas de registros hay en total. Sin embargo, si no planeas mostrar el número total de páginas en la interfaz de usuario de tu aplicación, la consulta de conteo de registros es innecesaria.
Por lo tanto, si solo necesitas mostrar enlaces simples "Siguiente" y "Anterior" en la interfaz de usuario de tu aplicación, puedes usar el método simplePaginate
para realizar una única y eficiente consulta:
$users = DB::table('users')->simplePaginate(15);
También puedes paginar consultas Eloquent. En este ejemplo, paginaremos el modelo App\Models\User
e indicaremos que planeamos mostrar 15 registros por página. Como puedes ver, la sintaxis es casi idéntica a paginar los resultados del constructor de consultas:
use App\Models\User; $users = User::paginate(15);
Por supuesto, puedes llamar al método paginate
después de establecer otras restricciones en la consulta, como cláusulas where
:
$users = User::where('votes', '>', 100)->paginate(15);
También puedes usar el método simplePaginate
al paginar modelos Eloquent:
$users = User::where('votes', '>', 100)->simplePaginate(15);
De manera similar, puedes usar el método cursorPaginate
para paginar modelos Eloquent utilizando cursores:
$users = User::where('votes', '>', 100)->cursorPaginate(15);
A veces puede ser necesario renderizar dos paginadores separados en una sola pantalla generada por su aplicación. Sin embargo, si ambas instancias del paginador utilizan el parámetro de cadena de consulta page
para almacenar la página actual, los dos paginadores entrarán en conflicto. Para resolver este conflicto, puedes pasar el nombre del parámetro de cadena de consulta que deseas usar para almacenar la página actual del paginador mediante el tercer argumento proporcionado a los métodos paginate
, simplePaginate
y cursorPaginate
:
use App\Models\User; $users = User::where('votes', '>', 100)->paginate( $perPage = 15, $columns = ['*'], $pageName = 'users');
Mientras que paginate
y simplePaginate
crean consultas utilizando la cláusula SQL "offset", la paginación por cursor funciona construyendo cláusulas "where" que comparan los valores de las columnas ordenadas contenidas en la consulta, proporcionando el rendimiento de base de datos más eficiente disponible entre todos los métodos de paginación de Laravel. Este método de paginación es particularmente adecuado para conjuntos de datos grandes e interfaces de usuario de "desplazamiento infinito".
A diferencia de la paginación basada en offset, que incluye un número de página en la cadena de consulta de las URL generadas por el paginador, la paginación basada en cursor coloca una cadena de "cursor" en la cadena de consulta. El cursor es una cadena codificada que contiene la ubicación desde la cual la próxima consulta paginada debería comenzar a paginar y la dirección en la que debería paginar:
http://localhost/users?cursor=eyJpZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0
Puedes crear una instancia de paginador basado en cursor mediante el método cursorPaginate
ofrecido por el generador de consultas. Este método devuelve una instancia de Illuminate\Pagination\CursorPaginator
:
$users = DB::table('users')->orderBy('id')->cursorPaginate(15);
Una vez que hayas obtenido una instancia de paginador basado en cursor, puedes mostrar los resultados de la paginación como lo harías normalmente al usar los métodos paginate
y simplePaginate
. Para obtener más información sobre los métodos de instancia ofrecidos por el paginador basado en cursor, consulta la documentación de métodos de instancia de paginador basado en cursor.
Advertencia Tu consulta debe contener una cláusula "order by" para aprovechar la paginación con cursores.
Para ilustrar las diferencias entre la paginación basada en offset y la paginación basada en cursor, examinemos algunas consultas SQL de ejemplo. Ambas consultas siguientes mostrarán la "segunda página" de resultados para una tabla users
ordenada por id
:
# Offset Pagination...select * from users order by id asc limit 15 offset 15; # Cursor Pagination...select * from users where id > 15 order by id asc limit 15;
La consulta de paginación por cursor ofrece las siguientes ventajas sobre la paginación basada en offset:
Sin embargo, la paginación por cursor tiene las siguientes limitaciones:
simplePaginate
, la paginación por cursor solo se puede utilizar para mostrar enlaces "Siguiente" y "Anterior" y no admite la generación de enlaces con números de página.null
.En ocasiones, es posible que desees crear manualmente una instancia de paginación, pasándole una matriz de elementos que ya tienes en memoria. Puedes hacerlo creando una instancia de Illuminate\Pagination\Paginator
, Illuminate\Pagination\LengthAwarePaginator
o Illuminate\Pagination\CursorPaginator
, según tus necesidades.
Las clases Paginator
y CursorPaginator
no necesitan conocer el número total de elementos en el conjunto de resultados; sin embargo, debido a esto, estas clases no tienen métodos para recuperar el índice de la última página. El LengthAwarePaginator
acepta casi los mismos argumentos que el Paginator
; sin embargo, requiere un recuento del número total de elementos en el conjunto de resultados.
En otras palabras, el Paginator
corresponde al método simplePaginate
en el generador de consultas, el CursorPaginator
corresponde al método cursorPaginate
, y el LengthAwarePaginator
corresponde al método paginate
.
Advertencia Cuando creas manualmente una instancia de paginador, debes "cortar" manualmente la matriz de resultados que pasas al paginador. Si no estás seguro de cómo hacer esto, consulta la función array_slice de PHP.
Por defecto, los enlaces generados por el paginador coincidirán con la URI de la solicitud actual. Sin embargo, el método withPath
del paginador te permite personalizar la URI utilizada por el paginador al generar enlaces. Por ejemplo, si deseas que el paginador genere enlaces como http://example.com/admin/users?page=N
, debes pasar /admin/users
al método withPath
:
use App\Models\User; Route::get('/users', function () { $users = User::paginate(15); $users->withPath('/admin/users'); // ...});
Puedes agregar a la cadena de consulta de los enlaces de paginación utilizando el método appends
. Por ejemplo, para agregar sort=votes
a cada enlace de paginación, debes realizar la siguiente llamada a appends
:
use App\Models\User; Route::get('/users', function () { $users = User::paginate(15); $users->appends(['sort' => 'votes']); // ...});
Puedes utilizar el método withQueryString
si deseas agregar todos los valores de la cadena de consulta de la solicitud actual a los enlaces de paginación:
$users = User::paginate(15)->withQueryString();
Si necesitas agregar un "fragmento de hash" a las URL generadas por el paginador, puedes utilizar el método fragment
. Por ejemplo, para agregar #users
al final de cada enlace de paginación, debes invocar el método fragment
de la siguiente manera:
$users = User::paginate(15)->fragment('users');
Al llamar al método paginate
, recibirás una instancia de Illuminate\Pagination\LengthAwarePaginator
, mientras que llamar al método simplePaginate
devuelve una instancia de Illuminate\Pagination\Paginator
. Y, finalmente, al llamar al método cursorPaginate
se obtiene una instancia de Illuminate\Pagination\CursorPaginator
.
Estos objetos proporcionan varios métodos que describen el conjunto de resultados. Además de estos métodos auxiliares, las instancias de paginador son iteradores y se pueden recorrer como un array. Entonces, una vez que hayas obtenido los resultados, puedes mostrarlos y renderizar los enlaces de la página usando Blade:
<div class="container"> @foreach ($users as $user) {{ $user->name }} @endforeach</div> {{ $users->links() }}
El método links
renderizará los enlaces al resto de las páginas en el conjunto de resultados. Cada uno de estos enlaces ya contendrá la variable de cadena de consulta page
adecuada. Recuerda, el HTML generado por el método links
es compatible con el framework Tailwind CSS.
Cuando el paginador muestra enlaces de paginación, se muestra el número de página actual, así como enlaces para las tres páginas antes y después de la página actual. Usando el método onEachSide
, puedes controlar cuántos enlaces adicionales se muestran en cada lado de la página actual dentro de la ventana media deslizante de enlaces generados por el paginador:
{{ $users->onEachSide(5)->links() }}
Las clases de paginador de Laravel implementan el contrato de la interfaz Illuminate\Contracts\Support\Jsonable
y exponen el método toJson
, así que es muy fácil convertir los resultados de la paginación a JSON. También puedes convertir una instancia de paginador a JSON devolviéndola desde una ruta o acción del controlador:
use App\Models\User; Route::get('/users', function () { return User::paginate();});
El JSON del paginador incluirá información adicional como total
, current_page
, last_page
, y más. Los registros de resultados están disponibles a través de la clave data
en el array JSON. Aquí tienes un ejemplo del JSON creado al devolver una instancia de 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":[ { // Grabar... }, { // Grabar... } ]}
Por defecto, las vistas renderizadas para mostrar los enlaces de paginación son compatibles con el framework Tailwind CSS. Sin embargo, si no estás utilizando Tailwind, eres libre de definir tus propias vistas para renderizar estos enlaces. Al llamar al método links
en una instancia de paginador, puedes pasar el nombre de la vista como primer argumento al método:
{{ $paginator->links('view.name') }} <!-- Passing additional 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
mediante el comando vendor:publish
:
php artisan vendor:publish --tag=laravel-pagination
Este comando colocará las vistas en el directorio resources/views/vendor/pagination
de tu aplicación. El archivo tailwind.blade.php
dentro de este directorio corresponde a la vista de paginación predeterminada. Puedes editar este archivo para modificar el HTML de paginación.
Si deseas designar un archivo diferente como la vista de paginación predeterminada, puedes invocar los métodos defaultView
y defaultSimpleView
del paginador dentro del método boot
de tu clase App\Providers\AppServiceProvider
:
<?php namespace App\Providers; use Illuminate\Pagination\Paginator;use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider{ /** * Iniciar cualquier servicio de la aplicación. */ public function boot(): void { Paginator::defaultView('view-name'); Paginator::defaultSimpleView('view-name'); }}
Laravel incluye vistas de paginación construidas con Bootstrap CSS. Para usar estas vistas en lugar de las vistas de Tailwind predeterminadas, puedes llamar a los métodos useBootstrapFour
o useBootstrapFive
del paginador dentro del método boot
de tu clase App\Providers\AppServiceProvider
:
use Illuminate\Pagination\Paginator; /** * Iniciar cualquier servicio de la aplicación. */public function boot(): void{ Paginator::useBootstrapFive(); Paginator::useBootstrapFour();}
Cada instancia de paginador proporciona información adicional de paginación a través de los siguientes métodos:
Método | Descripción |
---|---|
$paginator->count() |
Obtén el número de elementos para la página actual. |
$paginator->currentPage() |
Obtén el número de página actual. |
$paginator->firstItem() |
Obtén el número de resultado del primer elemento en los resultados. |
$paginator->getOptions() |
Obtén las opciones del paginador. |
$paginator->getUrlRange($start, $end) |
Crea un rango de URLs de paginación. |
$paginator->hasPages() |
Determina si hay suficientes elementos para dividir en varias páginas. |
$paginator->hasMorePages() |
Determina si hay más elementos en el almacén de datos. |
$paginator->items() |
Obtén los elementos para la página actual. |
$paginator->lastItem() |
Obtén el número de resultado del último elemento en los resultados. |
$paginator->lastPage() |
Obtén el número de página de la última página disponible. (No disponible al usar simplePaginate ). |
$paginator->nextPageUrl() |
Obtén la URL de la siguiente página. |
$paginator->onFirstPage() |
Determina si el paginador está en la primera página. |
$paginator->perPage() |
El número de elementos a mostrar por página. |
$paginator->previousPageUrl() |
Obtén la URL de la página anterior. |
$paginator->total() |
Determina el número total de elementos coincidentes en el almacén de datos. (No disponible al usar simplePaginate ). |
$paginator->url($page) |
Obtén la URL para un número de página dado. |
$paginator->getPageName() |
Obtén la variable de cadena de consulta utilizada para almacenar la página. |
$paginator->setPageName($name) |
Establece la variable de cadena de consulta utilizada para almacenar la página. |
$paginator->through($callback) |
Transforma cada elemento usando un callback. |
Cada instancia de paginador basado en cursor proporciona información adicional de paginación a través de los siguientes métodos:
Método | Descripción |
---|---|
$paginator->count() |
Obtén el número de elementos para la página actual. |
$paginator->cursor() |
Obtén la instancia actual del cursor. |
$paginator->getOptions() |
Obtén las opciones del paginador. |
$paginator->hasPages() |
Determina si hay suficientes elementos para dividir en varias páginas. |
$paginator->hasMorePages() |
Determina si hay más elementos en el almacén de datos. |
$paginator->getCursorName() |
Obtén la variable de cadena de consulta utilizada para almacenar el cursor. |
$paginator->items() |
Obtén los elementos para la página actual. |
$paginator->nextCursor() |
Obtén la instancia de cursor para el siguiente conjunto de elementos. |
$paginator->nextPageUrl() |
Obtén la URL de la siguiente página. |
$paginator->onFirstPage() |
Determina si el paginador está en la primera página. |
$paginator->onLastPage() |
Determina si el paginador está en la última página. |
$paginator->perPage() |
El número de elementos a mostrar por página. |
$paginator->previousCursor() |
Obtén la instancia de cursor para el conjunto anterior de elementos. |
$paginator->previousPageUrl() |
Obtén la URL de la página anterior. |
$paginator->setCursorName() |
Establece la variable de cadena de consulta utilizada para almacenar el cursor. |
$paginator->url($cursor) |
Obtén la URL para una instancia de cursor dada. |