Может войдёшь?
Черновики Написать статью Профиль

Страничный вывод

перевод документация 5.х

  1. 1. Настройка
  2. 2. Основы использования
    1. 2.1. Страничный вывод выборки из БД
    2. 2.2. Страничный вывод запросов Eloquent
    3. 2.3. Ручное создание экземпляра страничного вывода
  3. 3. Отображение результатов страничного вывода
    1. 3.1. Преобразование в JSON
  4. 4. Настройка представления страничного вывода
  5. 5. Методы экземпляра страничного вывода
Этот перевод актуален для англоязычной документации на (ветка 5.3) , (ветка 5.2) , (ветка 5.1) и (ветка 5.0). Опечатка? Выдели и нажми Ctrl+Enter.

Настройка

В некоторых фреймворках страничный вывод может быть большой проблемой. Страничный вывод в Laravel интегрирован с построителем запросов и Eloquent ORM и обеспечивает удобный, простой в использовании вывод результатов БД. Генерируемый HTML-код совместим с CSS-фреймворком Bootstrap.

Основы использования

Страничный вывод выборки из БД

Есть несколько способов разделения данных на страницы. Самый простой — используя метод PHPpaginate() на объекте-конструкторе запросов или на запросе Eloquent. Метод PHPpaginate() автоматически позаботится о задании правильных пределов и промежутков на основе текущей просматриваемой пользователем страницы. По умолчанию текущая страница определяется по значению аргумента ?page в HTTP-запросе. Само собой, Laravel автоматически определяет это значение, и так же автоматически вставляет его в ссылки, генерируемые для страничного вывода.

В этом примере единственный аргумент метода PHPpaginate() — число элементов на одной странице. Давайте укажем, что мы хотим выводить по 15 элементов на страницу:

PHP
<?php

namespace App\Http\Controllers;

use 
Illuminate\Support\Facades\DB;
//для версии 5.2 и ранее:
//use DB;
use App\Http\Controllers\Controller;

class 
UserController extends Controller
{
  
/**
   * Вывести всех пользователей приложения.
   *
   * @return Response
   */
  
public function index()
  {
    
$users DB::table('users')->paginate(15);

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

На данный момент операции страничного вывода, которые используют оператор PHPgroupBy, не могут эффективно выполняться в Laravel. Если вам необходимо использовать PHPgroupBy для постраничного набора результатов, рекомендуется делать запрос в БД и создавать экземпляр страничного вывода вручную.

«Простой страничный вывод»

Если вам необходимо вывести для страничного представления только ссылки «Далее» и «Назад», вы можете использовать метод PHPsimplePaginate() для более эффективных запросов. Для больших наборов данных очень полезно, когда вам не надо отображать номер каждой страницы в вашем представлении:

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

Страничный вывод запросов Eloquent

Можно также делать постраничный вывод запросов Eloquent. В этом примере мы разобьём на страницы модель User по 15 элементов на странице. Как видите, синтаксис практически совпадает со страничным выводом выборки из БД:

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

Разумеется, вы можете вызвать PHPpaginate() после задания других условий запроса, таких как where:

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

Также вы можете использовать метод PHPsimplePaginate() моделей Eloquent:

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

Ручное создание экземпляра страничного вывода

Иногда необходимо создать экземпляр страничного вывода вручную, передав ему массив данных. Это можно сделать создав либо экземпляр Illuminate\Pagination\Paginator, либо экземпляр Illuminate\Pagination\LengthAwarePaginator, в зависимости от ситуации.

Классу Paginator не надо знать общее количество элементов в конечном наборе, и поэтому класс не должен иметь методы для получения индекса последней страницы. LengthAwarePaginator принимает почти те же аргументы, что и Paginator, но ему требуется общее количество элементов в конечном наборе.

Другими словами, Paginator соответствует методу PHPsimplePaginate() на конструкторе запросов и Eloquent, а LengthAwarePaginator соответствует методу PHPpaginate().

При ручном создании экземпляра страничного вывода вы должны вручную «поделить» передаваемый в него массив результатов. Если вы не знаете, как это сделать, используйте PHP-функцию array_slice.

Отображение результатов страничного вывода

При вызове методов PHPpaginate() и PHPsimplePaginate() на конструкторе запросов или запросе Eloquent вы получите экземпляр страничного вывода. Для метода PHPpaginate() это будет экземпляр Illuminate\Pagination\LengthAwarePaginator. А для метода PHPsimplePaginate() это будет экземпляр Illuminate\Pagination\Paginator. Эти объекты предоставляют несколько методов для вывода конечного набора. В дополнение к этим вспомогательным методам экземпляры страничного вывода — итераторы, к ним можно обращаться как к массивам. Итак, когда вы получили результаты, вы можете вывести их и создать ссылки на страницы с помощью Blade:

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

{{ 
$users->links() }}
//для версии 5.1 и ранее:
//{!! $users->render() !!}
+ 5.0

добавлено в 5.0 ()

Итак, когда вы получили результаты, вы можете вывести их и создать ссылки на страницы методом PHPrender():

PHP
<div class="container">
  <?php foreach ($users as $user): ?>
    <?php echo $user->name?>
  <?php endforeach; ?>
</div>

<?php echo $users->render(); ?>

Метод PHPlinks() (для версии 5.1 и ранее PHPrender()) выведет ссылки на остальные страницы в конечном наборе. Каждая из этих ссылок уже будет содержать правильную переменную строки запроса page. Помните, сгенерированный методом PHPlinks() HTML-код совместим с CSS-фреймворком Bootstrap.

+ 5.1 5.0

добавлено в 5.1 () 5.0 ()

При вызове метода PHPrender() из Blade-шаблона не забудьте использовать синтаксис PHP{!! !!} для экранирования HTML-ссылок.

Настройка URI для вывода ссылок

Настроить URI для вывода ссылок на страницы можно с помощью метода PHPsetPath(). Например, если вы хотите получить ссылки вида http://example.com/custom/url?page=N, вам надо передать custom/url в метод PHPsetPath():

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

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

  
//
});

Параметры в ссылках

Вы можете добавить параметры запросов к ссылкам страниц с помощью метода PHPappends(). Например, чтобы добавить &sort=votes к каждой страничной ссылке, вам надо вызвать PHPappends() вот так:

PHP
{{ $users->appends(['sort' => 'votes'])->links() }}
//для версии 5.1 и ранее:
//{!! $users->appends(['sort' => 'votes'])->render() !!}

Код выше создаст ссылки наподобие:

http://example.com/something?page=2&sort=votes

Если вы хотите добавить «хэш-фрагмент» в URL-адреса страничного вывода, вы можете использовать метод PHPfragment(). Например, чтобы добавить #foo к каждой страничной ссылке, вам надо вызвать PHPfragment() вот так:

PHP
{{ $users->fragment('foo')->links() }}
//для версии 5.1 и ранее:
//{!! $users->fragment('foo')->render() !!}

Вызов этого метода сгенерирует URL-адреса наподобие:

http://example.com/something?page=2#foo

Преобразование в JSON

Классы страничного вывода Laravel реализуют контракт интерфейса Illuminate\Contracts\Support\Jsonable и предоставляют метод PHPtoJson(), поэтому можно очень легко конвертировать ваш страничный вывод в JSON. Вы также можете преобразовать экземпляр страничного вывода в JSON, просто вернув его из маршрута или действия контроллера.

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

JSON-форма экземпляра будет включать некоторые «мета-данные», такие как total, current_page, last_page и другие. Данные экземпляра будут доступны через ключ data в массиве JSON. Вот пример JSON, созданного при помощи возврата экземпляра страничного вывода из маршрута:

PHP
{
 
"total"50,
 
"per_page"15,
 
"current_page"1,
 
"last_page"4,
 
"next_page_url""http://laravel.app?page=2",
 
"prev_page_url"null,
 
"from"1,
 
"to"15,
 
"data":[
    {
      
// Объект вывода
    
},
    {
      
// Объект вывода
    
}
 ]
}
+ 5.3

добавлено в 5.3 ()

Настройка представления страничного вывода

По умолчанию отрисованные представления для отображения ссылок страничного вывода совместимы с CSS-фреймворком Bootstrap. Но если вы не используете Bootstrap, вы можете определить свои собственные представления для отрисовки этих ссылок. При вызове метода PHPlinks() на экземпляре страничного вывода передайте первым аргументом имя представления:

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

Но самый простой способ изменить представления страничного вывода — экспортировать их в ваш каталог resources/views/vendor с помощью команды shvendor:publish:

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

Эта команда поместит представления в папку resources/views/vendor/pagination. Файл default.blade.php в этой папке является стандартным представлением страничного вывода. Просто отредактируйте этот файл, чтобы изменить HTML страничного вывода.

Методы экземпляра страничного вывода

Каждый экземпляр страничного вывода предоставляет дополнительную информацию с помощью этих методов:

  • PHP$results->count()
  • PHP$results->currentPage()
  • PHP$results->firstItem() (для версии 5.2 и выше)
  • PHP$results->hasMorePages()
  • PHP$results->lastItem() (для версии 5.2 и выше)
  • PHP$results->lastPage() (недоступен при использовании simplePaginate)
  • PHP$results->nextPageUrl()
  • PHP$results->perPage()
  • PHP$results->previousPageUrl()
  • PHP$results->total() (недоступен при использовании simplePaginate)
  • PHP$results->url($page)
+ 5.0

добавлено в 5.0 ()

  • PHPfirstItem()
  • PHPlastItem()

Комментарии (3)

mcrack

А подскажите пожалуйста как сделать ссылки такого вида http://localhost/page-1 или например такого http://localhost/page/1?

FreeWebber

Laravel 5.2.42. Сделал так: создал свой класс пагинации на основе \Illuminate\Pagination\LengthAwarePaginator и в ней изменил public function url($page) под себя.

<?php

use Illuminate\Pagination\LengthAwarePaginator;

namespace App\Models;

class Paginator extends \Illuminate\Pagination\LengthAwarePaginator
{
    public function url($page)
    {
        if ($page <= 0) {
            $page = 1;
        }

        return
            $this->pageName
            .$page
            .$this->buildFragment();


    }
}

А так же в контроллере беру данные о странице и из них строю запросы, а потом передаю в пагинатор, который и создаёт ссылки.

public function index(Post $postModel, Request $request, $page=1){ // если нет данных о странице, то по-умолчанию - первая

    $perpage = 2; // новостей на страницу
    $total = DB::table('posts')->where('published', '=', '1')->count(); // кол-во новостей
    if($page > ceil($total/$perpage)) return redirect()->route('posts'); // если страница больше чем последняя, то редиректим

    $posts = DB::table('posts')
                ->select('posts.*','users.name as author',DB::raw('GROUP_CONCAT(tags.tag) as tags'))
                ->leftjoin('post_tag', 'post_tag.post_id', '=', 'posts.id')
                ->leftjoin('tags', 'tags.id', '=', 'post_tag.tag_id')
                ->leftJoin('users', 'users.id', '=', 'user_id')
                ->where('published', '=', '1')
                ->groupBy('posts.id')
                ->orderBy('published_at', 'desc')->skip(($page-1)*2)->take(2)->get(); // посты с тегами и авторами

    if(strpos($request->getPathInfo(),'blog/page')) $pageName=''; else $pageName='blog/page/'; // если не на главной, то не надо добавлять 'blog/page/'
    $posts=new Paginator($posts, $total, $perpage, $page, ['path'=>'path','pageName'=>$pageName]);

Ну и во вьюхе:

 {{ $posts->render() }}

Роуты:

Route::get('blog/page/{page}',['as'=>'blog','uses'=>'PostController@index']);
Route::get('/',['as'=>'posts','uses'=>'PostController@index']);

В итоге у меня получилось что на главной всегда первая страница, а при переходе на другую адрес уже становится site.ru/blog/page/2. Можно убрать blog/ и тогда получится просто site.ru/page/1 По-хорошему может даже надо разделить контроллеры со страницами и бе3. В планах ещё изучить render() и сделать свой. Может я не совсем правильно делаю, но пока только учусь...

DmitryNsk

Здравствуйте.

Такая проблема: вызов вида $preparedQuery->paginate($count)->appends($options) возвращает объект, не являющийся итератором (Invalid argument supplied for foreach()). Laravel версии 5.5.2. Как мне получить результат построчно в этом случае?

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.