Laravel 5

Cours Laravel 5.5 – les données – la pagination

La pagination consiste à limiter le nombre de données affichées et de prévoir des boutons de navigation entre les pages ainsi constituées. Laravel propose une pagination automatique facile à mettre en œuvre aussi bien au niveau du Query Builder que d’Eloquent. Nous allons vois dans ce chapitre comment faire.

Paginer (paginate) le résultat d’une requête

Dans l’application d’exemple en page d’accueil on a 6 articles présentés accompagnés d’une pagination :

On peut ainsi naviguer dans les pages avec facilité.

Si on regarde le code dans le contrôleur Front/PostController :

public function index()
{
    $posts = $this->postRepository->getActiveOrderByDate($this->nbrPages);

    return view('front.index', compact('posts'));
}

On voit qu’on fait appel à la méthode getActiveOrderByDate du repository PostRepository :

protected function queryActiveOrderByDate()
{
    return $this->model
        ->select('id', 'title', 'slug', 'excerpt', 'image')
        ->whereActive(true)
        ->latest();
}

...

public function getActiveOrderByDate($nbrPages)
{
    return $this->queryActiveOrderByDate()->paginate($nbrPages);
}

Dans la méthode queryActiveOrderByDate on :

  • sélectionne (select) les colonnes nécessaires,
  • filtre (whereActive) uniquement les articles actifs (true),
  • ordonne à partir du plus récent (latest).

Dans la méthode getActiveOrderByDate on reçoit en paramètre le nombre d’articles à afficher pour chaque page et on utilise la méthode paginate sur la requête pour avoir automatiquement le bon nombre d’enregistrements.

Au niveau de la vue front/index.blade.php on a ce code :

{{ $posts->links('front.pagination') }}

La méthode links génère la pagination. Par défaut elle ne nécessite pas de paramètre, on verra plus loin pourquoi ici on lui transmet une vue.

Si vous avez la curiosité de regarder comment sont constitués les liens de la pagination vous allez voir quelque chose de cette forme :

http://monsite.com/?page=2

Donc on a en paramètre de l’url le numéro de la page désirée.

Ajouter (appends) des paramètres à la pagination

Il arrive qu’on ai besoin d’ajouter des paramètres à l’url de la pagination. Regardez dans l’administration la liste des contacts en sélectionnant les nouveaux :

Pour la sélection des nouveaux on utilise un paramètre dans l’url :

http://monsite.com/admin/contacts?new=on

Du coup au niveau de la pagination il ne faut pas perdre ce paramètre :

http://monsite.com/admin/contacts?new=on&page=2

Voyons comment on fait ça…

On a vu que pour la gestion des pages d’index des différentes entités il est fait usage du trait Back/Indexable. Dans ce trait on a la méthode qui gère la liste des entités :

public function index(Request $request)
{
    $parameters = $this->getParameters ($request);

    // Get records and generate links for pagination
    $records = $this->repository->getAll (config ("app.nbrPages.back.$this->table"), $parameters);
    $links = $records->appends ($parameters)->links ('back.pagination');

    // Ajax response
    if ($request->ajax ()) {
        return response ()->json ([
            'table' => view ("back.$this->table.table", [$this->table => $records])->render (),
            'pagination' => $links->toHtml (),
        ]);
    }

    return view ("back.$this->table.index", [$this->table => $records, 'links' => $links]);
}

Comme ça concerne plusieurs entités aux paramètres variables on a une méthode getParameters qui va chercher ces paramètres. Ce qui nous intéresse pou ce chapitre c’est cette partie du code :

$records = $this->repository->getAll (config ("app.nbrPages.back.$this->table"), $parameters);
$links = $records->appends ($parameters)->links ('back.pagination');

On va chercher les enregistrements (getAll) dans le repository en transmettant le nombre de pages issu de la configuration (config (« app.nbrPages.back.$this->table »)) ainsi que les paramètres.

Comme on a affaire aux contacts c’est dans ce cas le repository ContactRepository :

public function getAll($nbrPages, $parameters)
{
    return Contact::with ('ingoing')
        ->latest()
        ->when ($parameters['new'], function ($query) {
            $query->has ('ingoing');
        })->paginate($nbrPages);
}

On voit qu’on :

  • charge une relation (with(‘ingoing’)) dont j’ai déjà parlé dans le chapitre sur le polymorphisme,
  • quand (when) on a le paramètre new on filtre (has) les nouveaux contacts,
  • on active la pagination (paginate).

Si on en revient au code du trait :

$links = $records->appends ($parameters)->links ('back.pagination');

On voit qu’on utilise la méthode appends pour ajouter le paramètre new, ensuite on utilise la méthode links qu’on a déjà vue ci-dessus.

Du coup dans la vue back/contacts/index.blade.php on a juste ce code pour générer la pagination :

{{ $links }}

La pagination en Ajax

Toujours avec la vue d’administration des contacts vous avez sans doute remarqué que le changement de page se fait en Ajax, c’est juste la liste des contacts qui est régénérée.

Toujours dans la méthode index du trait qu’on a vu ci-dessus on a ce code :

if ($request->ajax ()) {
    return response ()->json ([
        'table' => view ("back.$this->table.table", [$this->table => $records])->render (),
        'pagination' => $links->toHtml (),
    ]);
}

Si la requête est en Ajax (ajax) alors on retourne une réponse JSON (response()->json) avec deux éléments :

  • la liste (table) issu de la vue dont on génère le code HTML (render),
  • la pagination (pagination) avec les liens dont on a vu la génération ci-dessus et qu’on envoie au format HTML (toHtml).

Il suffit côté client de régénérer les parties de la page correspondantes :

$('#pannel').html(data.table)
$('#pagination').html(data.pagination)

Je parlerai plus en détail de l’utilisation d’Ajax avec Laravel dans un chapitre ultérieur.

La personnalisation de la vue de la pagination

Par défaut la vue de génération des liens de la pagination correspondant à une mise en forme pour Bootstrap. Quand on l’utilise c’est parfait et on n’a rien à faire. Par contre quand on désire une autre mise en forme, comme c’est le cas pour l’application d’exemple on a un peu plus de travail.

Une solution consiste à publier les vues de Laravel avec la commande :

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

On se retrouve avec les vues dans le dossier resources/views/vendor/pagination et il ne reste plus qu’à les modifier.

Une autre solution que j’ai adoptée pour l’application est de passer le nom de la vue à la méthode links. Par exemple pour la page d’accueil on a ce code dans la vue :

{{ $posts->links('front.pagination') }}

Ce qui signifie qu’on utilise la vue front/pagination pour la mise en forme des liens de pagination :

@if ($paginator->hasPages())
    <nav class="pagination">
        {{-- Previous Page Link --}}
        @if ($paginator->onFirstPage())
            <span class="page-numbers prev inactive">@lang('pagination.previous')</span>
        @else
            <a href="{{ $paginator->previousPageUrl() }}" class="page-numbers prev" rel="prev">@lang('pagination.previous')</a>
        @endif

        {{-- Pagination Elements --}}
        @foreach ($elements as $element)
            {{-- "Three Dots" Separator --}}
            @if (is_string($element))
                <span class="page-numbers current">{{ $element }}</span>
            @endif

            {{-- Array Of Links --}}
            @if (is_array($element))
                @foreach ($element as $page => $url)
                    @if ($page == $paginator->currentPage())
                        <span class="page-numbers current">{{ $page }}</span>
                    @else
                        <a href="{{ $url }}" class="page-numbers">{{ $page }}</a>
                    @endif
                @endforeach
            @endif
        @endforeach

        {{-- Next Page Link --}}
        @if ($paginator->hasMorePages())
            <a href="{{ $paginator->nextPageUrl() }}"  class="page-numbers next" rel="next">@lang('pagination.next')</a>
        @else
            <span class="page-numbers next inactive">@lang('pagination.next')</span>
        @endif
    </nav>
@endif

Pour la partie administration on a une autre mise en forme et donc une autre vue back/pagination :

@if ($paginator->hasPages())
    <ul class="pagination pagination-sm no-margin pull-right">
        {{-- Previous Page Link --}}
        @if ($paginator->onFirstPage())
            <li class="disabled"><a href="#">&laquo;</a></li>
        @else
            <li><a href="{{ $paginator->previousPageUrl() }}" rel="prev">&laquo;</a></li>
        @endif

        {{-- Pagination Elements --}}
        @foreach ($elements as $element)
            {{-- "Three Dots" Separator --}}
            @if (is_string($element))
                <li class="disabled"><a href="#">{{ $element }}</a></li>
            @endif

            {{-- Array Of Links --}}
            @if (is_array($element))
                @foreach ($element as $page => $url)
                    @if ($page == $paginator->currentPage())
                        <li class="active"><a href="#">{{ $page }}</a></li>
                    @else
                        <li><a href="{{ $url }}">{{ $page }}</a></li>
                    @endif
                @endforeach
            @endif
        @endforeach

        {{-- Next Page Link --}}
        @if ($paginator->hasMorePages())
            <li><a href="{{ $paginator->nextPageUrl() }}" rel="next">&raquo;</a></li>
        @else
            <li class="disabled"><a href="#">&raquo;</a></li>
        @endif
    </ul>
@endif

On a toujours la même structure mais ce sont les classes utilisées qui changent selon l’aspect voulu.

En résumé

  • La pagination avec Laravel se fait simplement avec la méthode paginate.
  • On peut ajouter des paramètres aux urls de pagination avec la méthode appends.
  • On peut facilement réaliser une pagination en Ajax.
  • Il faut créer une vue particulière pour la pagination si on n’utilise pas Bootstrap.
Print Friendly, PDF & Email

4 commentaires

Laisser un commentaire