База Данных: Пагинация
- Введение
- Основное использование
- Отображение результатов пагинации
- Настройка представления пагинации
- Пагинатор и методы экземпляра пагинатора с учетом длины
- Методы экземпляра курсор пагинатора
Введение
В других фреймворках разбиение на страницы может быть очень болезненным. Мы надеемся, что подход Laravel к нумерации страниц станет глотком свежего воздуха. Пагинатор Laravel интегрирован с конструктором запросов и Eloquent ORM и обеспечивает удобную и простую в использовании разбивку на страницы. записи базы данных с нулевой конфигурацией.
По умолчанию HTML-код, сгенерированный пагинатором, совместим с платформой Tailwind CSS; однако также доступна поддержка нумерации страниц Bootstrap.
Tailwind JIT
Если вы используете стандартные представления Laravel для разбивки на страницы Tailwind и JIT-движок Tailwind, вы должны убедиться, что ключ content
в файле tailwind.config.js
вашего приложения ссылается на представления разбиения на страницы Laravel, чтобы их классы Tailwind не удалялись:
content: [ './resources/**/*.blade.php', './resources/**/*.js', './resources/**/*.vue', './vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',],
Основное использование
Пагинация результатов query builder
Существует несколько способов разбиения элементов на страницы. Самый простой — использовать метод paginate
в конструкторе запросов или Eloquent запросе. Метод paginate
автоматически устанавливает "limit" и "offset" запроса на основе текущей страницы, просматриваемой пользователем. По умолчанию текущая страница определяется значением аргумента строки запроса page
в HTTP-запросе. Это значение автоматически определяется Laravel, а также автоматически вставляется в ссылки, сгенерированные пагинатором.
В этом примере единственным аргументом, передаваемым методу paginate
, является количество элементов, которые вы хотите отобразить «на странице». В этом случае давайте укажем, что мы хотели бы отображать 15
элементов на странице:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use Illuminate\Support\Facades\DB; class UserController extends Controller{ /** * Show all application users. * * @return \Illuminate\Http\Response */ public function index() { return view('user.index', [ 'users' => DB::table('users')->paginate(15) ]); }}
Простая пагинация
Метод paginate
подсчитывает общее количество записей, соответствующих запросу, перед извлечением записей из базы данных. Это сделано для того, чтобы пагинатор знал, сколько всего страниц записей. Однако, если вы не планируете отображать общее количество страниц в пользовательском интерфейсе вашего приложения, запрос количества записей не нужен.
Поэтому, если вам нужно отображать только простые ссылки «Далее» и «Предыдущий» в пользовательском интерфейсе вашего приложения, вы можете использовать метод simplePaginate
для выполнения одного эффективного запроса:
$users = DB::table('users')->simplePaginate(15);
Результаты Eloquent пагинации
Вы также можете разбивать запросы Eloquent на страницы. В этом примере мы разобьем модель App\Models\User
на страницы и укажем, что планируем отображать 15 записей на странице. Как видите, синтаксис почти идентичен результатам разбиения на страницы query builder:
use App\Models\User; $users = User::paginate(15);
Конечно, вы можете вызвать метод paginate
после установки других ограничений запроса, таких как предложения where
:
$users = User::where('votes', '>', 100)->paginate(15);
Вы также можете использовать метод simplePaginate
для пагинации Eloquent моделей:
$users = User::where('votes', '>', 100)->simplePaginate(15);
Точно так же вы можете использовать метод cursorPaginate
для курсорной пагинации Eloquent моделей:
$users = User::where('votes', '>', 100)->cursorPaginate(15);
Несколько экземпляров Paginator на странице
Иногда вам может понадобиться визуализировать два отдельных пагинатора на одном экране, который отображается вашим приложением. Однако, если оба экземпляра пагинатора используют параметр строки запроса page
для хранения текущей страницы, два пагинатора будут конфликтовать. Чтобы разрешить этот конфликт, вы можете передать имя параметра строки запроса, который вы хотите использовать для хранения текущей страницы пагинатора, через третий аргумент, предоставляемый методам paginate
, simplePaginate
и cursorPaginate
:
use App\Models\User; $users = User::where('votes', '>', 100)->paginate( $perPage = 15, $columns = ['*'], $pageName = 'users');
Курсорная Пагинация
В то время как paginate
и simplePaginate
создают запросы с использованием SQL-предложения "offset", разбиение курсора на страницы работает путем создания предложений "where", которые сравнивают значения упорядоченных столбцов, содержащихся в запросе, обеспечивая наиболее эффективную производительность базы данных среди всех доступных. Методы пагинации Laravel. Этот метод разбивки на страницы особенно хорошо подходит для больших наборов данных и «бесконечных» пользовательских интерфейсов с прокруткой.
В отличие от пагинации на основе смещения, которая включает номер страницы в строку запроса URL-адресов, сгенерированных средством разбивки на страницы, нумерация на основе курсора помещает строку «курсор» в строку запроса. Курсор представляет собой закодированную строку, содержащую местоположение, с которого следующий запрос с разбивкой на страницы должен начать разбиение на страницы, и направление, в котором он должен разбивать страницы:
http://localhost/users?cursor=eyJpZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0
Вы можете создать экземпляр пагинатора на основе курсора с помощью метода cursorPaginate
, предлагаемого построителем запросов. Этот метод возвращает экземпляр Illuminate\Pagination\CursorPaginator
:
$users = DB::table('users')->orderBy('id')->cursorPaginate(15);
После того, как вы получили экземпляр разбивки на страницы курсора, вы можете отобразить результаты разбивки на страницы, как обычно при использовании методов paginate
и simplePaginate
. Для получения дополнительной информации о методах экземпляра, предлагаемых средством разбивки на страницы курсора, обратитесь к документации по методу экземпляра средства разбивки курсора.
{note} Ваш запрос должен содержать предложение «упорядочить по», чтобы воспользоваться преимуществами разбиения курсора на страницы.
Курсорная против пагинации смещения
Чтобы проиллюстрировать различия между разбиением на страницы со смещением и разбиением на страницы с помощью курсора, давайте рассмотрим несколько примеров SQL-запросов. Оба следующих запроса будут отображать «вторую страницу» результатов для таблицы users
, упорядоченной по 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;
Запрос на разбиение на страницы с помощью курсора предлагает следующие преимущества по сравнению с разбиением на страницы со смещением:
- Для больших наборов данных разбиение курсора на страницы будет более производительным, если столбцы «упорядочить по» будут проиндексированы. Это связано с тем, что предложение «смещение» сканирует все ранее сопоставленные данные.
- Для наборов данных с частой записью смещение страниц может пропускать записи или показывать дубликаты, если результаты были недавно добавлены или удалены со страницы, которую пользователь просматривает в данный момент.
Однако разбиение курсора на страницы имеет следующие ограничения:
- Как и
simplePaginate
, разбивка курсора на страницы может использоваться только для отображения ссылок «Следующая» и «Предыдущая» и не поддерживает создание ссылок с номерами страниц. - Требуется, чтобы порядок основывался как минимум на одном уникальном столбце или на комбинации уникальных столбцов. Столбцы с нулевыми значениями не поддерживаются.
- Выражения запроса в предложениях "order by" поддерживаются только в том случае, если они имеют псевдоним и также добавляются в предложение "select".
Создание пагинатора вручную
Иногда вы можете захотеть создать экземпляр разбиения на страницы вручную, передав ему массив элементов, которые у вас уже есть в памяти. Вы можете сделать это, создав экземпляр Illuminate\Pagination\Paginator
, Illuminate\Pagination\LengthAwarePaginator
или Illuminate\Pagination\CursorPaginator
, в зависимости от ваших потребностей.
Классам Paginator
и CursorPaginator
не нужно знать общее количество элементов в результирующем наборе; однако из-за этого у этих классов нет методов для получения индекса последней страницы. LengthAwarePaginator
принимает почти те же аргументы, что и Paginator
; однако для этого требуется подсчет общего количества элементов в результирующем наборе.
Другими словами, Paginator
соответствует методу simplePaginate
в query builder, CursorPaginator
соответствует методу cursorPaginate
, а LengthAwarePaginator
соответствует методу paginate
.
{note} При ручном создании экземпляра пагинатора вы должны вручную «нарезать» массив результатов, которые вы передаете в пагинатор. Если вы не знаете, как это сделать, ознакомьтесь с PHP-функцией array_slice.
Настройка URL-адресов пагинации
По умолчанию ссылки, сгенерированные пагинатором, будут соответствовать URI текущего запроса. Однако метод пагинатора withPath
позволяет вам настроить URI, используемый пагинатором при создании ссылок. Например, если вы хотите, чтобы пагинатор генерировал ссылки типа http://example.com/admin/users?page=N
, вы должны передать /admin/users
методу withPath
:
use App\Models\User; Route::get('/users', function () { $users = User::paginate(15); $users->withPath('/admin/users'); //});
Добавление значений строки запроса
Вы можете добавить к строке запроса ссылки на страницы, используя метод appends
. Например, чтобы добавить sort=votes
к каждой ссылке на страницу, вы должны сделать следующий вызов appends
:
use App\Models\User; Route::get('/users', function () { $users = User::paginate(15); $users->appends(['sort' => 'votes']); //});
Вы можете использовать метод withQueryString
, если хотите добавить все значения строки запроса текущего запроса к ссылкам на страницы:
$users = User::paginate(15)->withQueryString();
Добавление хеш-фрагментов
Если вам нужно добавить «хеш-фрагмент» к URL-адресам, сгенерированным пагинатором, вы можете использовать метод fragment
. Например, чтобы добавить #users
в конец каждой ссылки на страницу, вы должны вызвать метод fragment
следующим образом:
$users = User::paginate(15)->fragment('users');
Отображение результатов пагинации
При вызове метода paginate
вы получите экземпляр Illuminate\Pagination\LengthAwarePaginator
, а вызов метода simplePaginate
возвращает экземпляр Illuminate\Pagination\Paginator
. И, наконец, вызов метода cursorPaginate
возвращает экземпляр Illuminate\Pagination\CursorPaginator
.
Эти объекты предоставляют несколько методов, описывающих результирующий набор. В дополнение к этим вспомогательным методам экземпляры пагинатора являются итераторами и могут быть зациклены как массив. Таким образом, как только вы получили результаты, вы можете отобразить их и отобразить ссылки на страницы с помощью Blade:
<div class="container"> @foreach ($users as $user) {{ $user->name }} @endforeach</div> {{ $users->links() }}
Метод links
отобразит ссылки на остальные страницы в результирующем наборе. Каждая из этих ссылок уже будет содержать правильную переменную строки запроса page
. Помните, что HTML-код, сгенерированный методом links
совместим с фреймворком Tailwind CSS.
Настройка окна ссылок пагинации
Когда пагинатор отображает ссылки на страницы, отображается номер текущей страницы, а также ссылки на три страницы до и после текущей страницы. Используя метод onEachSide
, вы можете управлять количеством дополнительных ссылок, отображаемых с каждой стороны текущей страницы в среднем скользящем окне ссылок, сгенерированных пагинатором:
{{ $users->onEachSide(5)->links() }}
Преобразование результатов в JSON
Классы разбивки на страницы Laravel реализуют контракт интерфейса Illuminate\Contracts\Support\Jsonable
и предоставляют метод toJson
, поэтому очень легко преобразовать результаты разбивки на страницы в JSON. Вы также можете преобразовать экземпляр пагинатора в JSON, вернув его из маршрута или действия контроллера:
use App\Models\User; Route::get('/users', function () { return User::paginate();});
JSON из пагинатора будет включать метаинформацию, такую как total
, current_page
, last_page
и т. д. Записи результатов доступны через ключ data
в массиве JSON. Вот пример JSON, созданного путем возврата экземпляра пагинатора из маршрута:
{ "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":[ { // Record... }, { // Record... } ]}
Настройка представления пагинации
По умолчанию представления для отображения ссылок на страницы совместимы с фреймворком Tailwind CSS. Однако, если вы не используете Tailwind, вы можете определить свои собственные представления для отображения этих ссылок. При вызове метода links
для экземпляра пагинатора вы можете передать имя представления в качестве первого аргумента метода:
{{ $paginator->links('view.name') }} // Passing additional data to the view...{{ $paginator->links('view.name', ['foo' => 'bar']) }}
Однако самый простой способ настроить представления разбиения на страницы — экспортировать их в каталог resources/views/vendor
с помощью команды vendor:publish
:
php artisan vendor:publish --tag=laravel-pagination
Эта команда поместит представления в каталог resources/views/vendor/pagination
вашего приложения. Файл tailwind.blade.php
в этом каталоге соответствует представлению разбиения на страницы по умолчанию. Вы можете отредактировать этот файл, чтобы изменить HTML-разметку страницы.
Если вы хотите назначить другой файл в качестве представления разбиения на страницы по умолчанию, вы можете вызвать методы пагинатора defaultView
и defaultSimpleView
в методе boot
вашего класса App\Providers\AppServiceProvider
:
<?php namespace App\Providers; use Illuminate\Pagination\Paginator;use Illuminate\Support\Facades\Blade;use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider{ /** * Bootstrap any application services. * * @return void */ public function boot() { Paginator::defaultView('view-name'); Paginator::defaultSimpleView('view-name'); }}
Использование Bootstrap
Laravel включает представления разбиения на страницы, созданные с помощью Bootstrap CSS. Чтобы использовать эти представления вместо представлений Tailwind по умолчанию, вы можете вызвать метод useBootstrap
разбиения на страницы в методе boot
вашего класса App\Providers\AppServiceProvider
:
use Illuminate\Pagination\Paginator; /** * Bootstrap any application services. * * @return void */public function boot(){ Paginator::useBootstrap();}
Пагинатор и методы экземпляра пагинатора с учетом длины
Каждый экземпляр пагинатора предоставляет дополнительную информацию о разбиении на страницы с помощью следующих методов:
Метод | Описание |
---|---|
$paginator->count() |
Получить количество элементов для текущей страницы. |
$paginator->currentPage() |
Получить текущий номер страницы. |
$paginator->firstItem() |
Получить номер результата первого элемента в результатах. |
$paginator->getOptions() |
Получить параметры пагинатора. |
$paginator->getUrlRange($start, $end) |
Создайте диапазон URL-адресов разбивки на страницы. |
$paginator->hasPages() |
Определите, достаточно ли элементов для разделения на несколько страниц. |
$paginator->hasMorePages() |
Определите, есть ли еще элементы в хранилище данных. |
$paginator->items() |
Получить элементы для текущей страницы. |
$paginator->lastItem() |
Получить номер результата последнего элемента в результатах. |
$paginator->lastPage() |
Получить номер последней доступной страницы. (Недоступно при использовании simplePaginate ). |
$paginator->nextPageUrl() |
Получить URL следующей страницы. |
$paginator->onFirstPage() |
Определить, находится ли пагинатор на первой странице. |
$paginator->perPage() |
Количество элементов, которые должны отображаться на странице. |
$paginator->previousPageUrl() |
Получить URL предыдущей страницы. |
$paginator->total() |
Определите общее количество совпадающих элементов в хранилище данных. (Недоступно при использовании simplePaginate ). |
$paginator->url($page) |
Получить URL для заданного номера страницы. |
$paginator->getPageName() |
Получить переменную строки запроса, используемую для хранения страницы. |
$paginator->setPageName($name) |
Установите переменную строки запроса, используемую для хранения страницы. |
Методы экземпляра курсор пагинатора
Каждый экземпляр средства разбивки на страницы курсора предоставляет дополнительную информацию о разбивке на страницы с помощью следующих методов:
Метод | Описание |
---|---|
$paginator->count() |
Получить количество элементов для текущей страницы. |
$paginator->cursor() |
Получить текущий экземпляр курсора. |
$paginator->getOptions() |
Получить параметры пагинатора. |
$paginator->hasPages() |
Определите, достаточно ли элементов для разделения на несколько страниц. |
$paginator->hasMorePages() |
Определите, есть ли еще элементы в хранилище данных. |
$paginator->getCursorName() |
Получить переменную строки запроса, используемую для хранения курсора. |
$paginator->items() |
Получить элементы для текущей страницы. |
$paginator->nextCursor() |
Получить экземпляр курсора для следующего набора элементов. |
$paginator->nextPageUrl() |
Получить URL следующей страницы. |
$paginator->onFirstPage() |
Определить, находится ли пагинатор на первой странице. |
$paginator->perPage() |
Количество элементов, которые должны отображаться на странице. |
$paginator->previousCursor() |
Получить экземпляр курсора для предыдущего набора элементов. |
$paginator->previousPageUrl() |
Получить URL предыдущей страницы. |
$paginator->setCursorName() |
Установите переменную строки запроса, используемую для хранения курсора. |
$paginator->url($cursor) |
Получить URL для данного экземпляра курсора. |