Paginer une collection de model dans laravel est très simple. Il suffit d’appeler la méthode paginate() ou simplePaginate() depuis son model Eloquent .

$posts = \App\Post::paginate();

 

Et d’appeler la méthode $posts->links() là où on veut afficher les liens de pagination dans la vue.

Il arrive très souvent de récupérer les items non pas depuis le model Eloquent, mais par la création manuelle d’une collection d’autres objets .

<?php
//routes/web.php
//...
Route::get('/test', function(){
    $users = new \Illuminate\Support\Collection();
    foreach(range(10, 50) as $item)
    {
        $user = new stdClass();
        $user->id = $item;
        $user->name = 'User '. $item;
        $user->role = array_random(['admin', 'moderator', 'ordinary']);
        $users->push($user);
    }
});

 

Dans ce genre de situation, $users->paginate() générera une belle BadMethodCallException parce qu’aucune méthode paginate() n’est disponible dans la classe Illimunate\Support\Collection().

Decouvrons comment dans ce genre de situation créer manuellement la pagination.

Au coeur du système de pagination Laravel.

Il y a deux classes qui gèrent la pagination dans laravel.

\Illuminate\Pagination\LengthAwarePaginator qui génère la pagination indexée, l’équivalent de Model::paginate()

Et \Illuminate\Pagination\Paginator qui ne fait qu’afficher la page suivante et précédente. L’équivalent de Model::simplePaginate().

Essayons d’implémenter manuellement une pagination dans différents contexte qu’on peut être fasse.

SimplePaginate

La classe \Illuminate\Pagination\Paginator est celle qui est utilisée au coeur de laravel quand vous utilisez Model::simplePaginate(). Son constructeur accepte 4 arguments dont deux premiers sont obligatoires.

  • items : La collection de données à paginer. Ça peut être un array ou une collection. Cela doit être la collection d’items à afficher commençant par celle qui doit être affichée dans a page courante
  • perPage : Le nombre d’item à afficher par page.
  • currentPage : L’index actuel. Concrètement, c’est la valeur du paramètre ?page.
  • options : L’option est un tableau associatif qui peut contenir 4 éléments
    • pageName : Le nom du paramètre utilisé pour naviguer à travers currentPage. Par défaut c’est page
    • path : L’url courant, c’est l’url sur lequel la Paginator va utiliser pour ajouter le paramètre pageName. par défaut c’est la valeur de app.url
    • query : Un tableau associatif des paramètres additionnels dans l’url que vous pouvez ajouter.
    • fragment : Le lien ancré, un dièse ajouté à la fin de l’url. ex : https://informagenie.com/#list

On a tous les outils en mains pour créer notre pagination, allez, fonçons !

Route::get('/test', function(){
    $users = new \Illuminate\Support\Collection();
    foreach(range(10, 50) as $item)
    {
        $user = new stdClass();
        $user->id = $item;
        $user->name = 'User '. $item;
        $user->role = array_random(['admin', 'moderator', 'ordinary']);

        $users->push($user);
    }
    //Récupère le paramètre ?page
    $page = \Illuminate\Support\Facades\Input::get('page', 1);
    $perPage = 10;

    $users = new \Illuminate\Pagination\Paginator(
        $users->slice(($page - 1) * $perPage),
        $perPage,
        $page,
        [
            'path' => \Illuminate\Pagination\Paginator::resolveCurrentPath()
        ]
    );
    return view('user.index', compact('users'));
});

S’il y a une explication à donner, c’est au niveau du premier argument de Paginator. En effet, Paginator ne sait pas à partir de quel item commencer à afficher. Tout ce qu’il sait, c’est à partir d’où s’arrêter grâce à perPage. Dans le système de pagination, les items/éléments affichés dans la page 1 ne doivent pas être affichés dans la page 2. C’est justement ce que fait $users->slice(($page - 1) * $perPage). Enlever les items précédemment affichés (Plus d’infos sur la méthode slice).

Et avec une vue

@extends('layouts.default')

@section('content')

    <div class="list-group">
    @foreach($users as $user)
        <div class="list-group-item">
            {{ $user->name }}
        </div>
    @endforeach
    </div>
    {!! $users->links() !!}
@stop

On a ce résultat

paginations larave

Paginate

Quid de Model::paginate() ? Pas une si grande différence. LengthAwarePaginatorprend cependant 5 arguments dont les 3 premiers sont obligatoires. Je ne détaille que le trois premiers car le reste c’est la même chose que pour Paginator

  • items: La collection d’items à afficher. Cette fois ci, LengthAwarePaginatora besoin qu’on lui fournisse exactement ce qu’il va afficher dans la page courante.
  • total: Le nombre total d’items
  • perPage: Le nombre d’item à afficher par page. La même chose que pour Paginator.

Pour le code, c’est la même chose que le cas précédent, je me contente juste d’utiliser le constructeur de LengthAwarePaginator

$users = new \Illuminate\Pagination\LengthAwarePaginator(
        $users->slice(($page - 1) * $perPage, $perPage),
        $users->count(),
        $perPage,
        $page,
        [
            'path' => \Illuminate\Pagination\Paginator::resolveCurrentPath()
        ]
    );

Avec la même vue  que précédemment, j’ai cette fois ci ce résultat :

laravel pagination avancé

Fin de la citation.

Désolé, je n’ai pas la science infuse

  • https://laravel.com/docs/5.6/pagination#customizing-the-pagination-view

Catégorisé:

Étiqueté dans :

,