Pagination

class Cake\Controller\Component\PaginatorComponent

Les principaux défis lors de la création d’une application flexible et ergonomique sont le design et d’avoir une interface utilisateur intuitive. De nombreuses applications ont tendance à augmenter rapidement en taille et en complexité, et les designers ainsi que les programmeurs trouvent même qu’ils sont incapables de faire face a l’affichage de centaines ou de milliers d’enregistrements. Réécrire prend du temps, et les performances et la satisfaction des utilisateurs peut en pâtir.

Afficher un nombre raisonnable d’enregistrements par page a toujours été une partie critique dans toutes les applications et cause régulièrement de nombreux maux de tête aux développeurs. CakePHP allège le fardeau des développeurs en fournissant un moyen rapide et facile pour paginer les données.

La pagination dans CakePHP se fait par un Component dans le controller, pour faciliter la création des requêtes de pagination. Dans la Vue, PaginatorHelper est utilisé pour faciliter la génération de la pagination, des liens et des boutons.

Utiliser Controller::paginate()

Dans le controller, nous commençons par définir les conditions de la requête de pagination qui seront utilisées par défaut dans la variable $paginate du controller. Ces conditions, vont servir de base à vos requêtes de pagination. Elles sont complétées par les paramètres sort, direction, limit et page passés dans l’URL. Ici, il est important de noter que la clé order doit être définie dans une structure en tableau comme ci-dessous:

class ArticlesController extends AppController
{

    public $paginate = [
        'limit' => 25,
        'order' => [
            'Articles.title' => 'asc'
        ]
    ];

    public function initialize()
    {
        parent::initialize();
        $this->loadComponent('Paginator');
    }
}

Vous pouvez aussi inclure d’autres options find(), comme fields:

class ArticlesController extends AppController
{

    public $paginate = [
        'fields' => ['Articles.id', 'Articles.created'],
        'limit' => 25,
        'order' => [
            'Articles.title' => 'asc'
        ]
    ];

    public function initialize()
    {
        parent::initialize();
        $this->loadComponent('Paginator');
    }
}

Alors que vous pouvez passer la plupart des options de query à partir de la propriété paginate, il est souvent plus propre et simple de mettre vos options de pagination dans une Méthodes Finder Personnalisées. vous pouvez définir l’utilisation de la pagination du finder en configurant l’option findType:

class ArticlesController extends AppController
{

    public $paginate = [
        'finder' => 'published',
    ];
}

Comme les méthodes finder personnalisées peuvent aussi être prises en options, voici comment vous pouvez passer des options dans une méthode de finder personnalisée dans la propriété paginate:

class ArticlesController extends AppController
{

    // trouve les articles selon les tags
    public function tags()
    {
        $tags = $this->request->getParam('pass');

        $customFinderOptions = [
            'tags' => $tags
        ];
        // la méthode de finder personnalisée est appelée findTagged dans
        // ArticlesTable.php
        // elle devrait ressembler à ceci:
        // public function findTagged(Query $query, array $options) {
        // ainsi vous utilisez tagged en clé
        $this->paginate = [
            'finder' => [
                'tagged' => $customFinderOptions
            ]
        ];

        $articles = $this->paginate($this->Articles);

        $this->set(compact('articles', 'tags'));
    }
}

En plus de définir les valeurs de pagination générales, vous pouvez définir plus d’un jeu de pagination par défaut dans votre controller, vous avez juste à nommer les clés du tableau d’après le model que vous souhaitez configurer:

class ArticlesController extends AppController
{

    public $paginate = [
        'Articles' => [],
        'Authors' => [],
    ];
}

Les valeurs des clés Articles et Authors peuvent contenir toutes les propriétés qu’un model/clé sans $paginate peut contenir.

Une fois que la variable $paginate à été définie, nous pouvons utiliser la méthode paginate() pour créer les données paginées et ajouter le PaginatorHelper s’il n’a pas déjà été ajouté. La méthode paginate du controller va retourner l’ensemble des résultats de la requête paginée, et définir les meta-données de pagination de la requête. Vous pouvez accéder aux meta-données de pagination avec $this->request->getParam('paging'). un exemple plus complet de l’utilisation de paginate() serait:

class ArticlesController extends AppController
{

    public function index()
    {
        $this->set('articles', $this->paginate());
    }
}

Par défaut la méthode paginate() va utiliser le model par défaut pour un controller. Vous pouvez aussi passer la requête résultante d’une méthode find:

public function index()
{
   $query = $this->Articles->find('popular')->where(['author_id' => 1]);
   $this->set('articles', $this->paginate($query));
}

Si vous voulez paginer un model différent, vous pouvez lui fournir une requête l’objet table lui-même, ou son nom:

//Utiliser une query
$comments = $this->paginate($commentsTable->find());

// Utiliser le nom du model.
$comments = $this->paginate('Comments');

// Utiliser un objet table.
$comments = $this->paginate($commentTable);

Utiliser Directement Paginator

Si vous devez paginer des données d’un autre component, vous pouvez utiliser directement PaginatorComponent. Il fournit une API similaire à la méthode du controller:

$articles = $this->Paginator->paginate($articleTable->find(), $config);

// Ou
$articles = $this->Paginator->paginate($articleTable, $config);

Le premier paramètre doit être l’objet query à partir d’un find sur l’objet table duquel vous souhaitez paginer les résultats. En option, vous pouvez passer l’objet table et laisser la query être construite pour vous. Le second paramètre doit être le tableau des configurations à utiliser pour la pagination. Ce tableau doit avoir la même structure que la propriété $paginate dans un controller. Quand on pagine un objet Query, l’option finder sera ignorée. Il faut que vous passiez la query que vous souhaitez voir paginée.

Requêtes de Paginating Multiple

Vous pouvez paginer plusieurs models dans une unique action de controller en utilisant l’option scope, à la fois via la propriété $paginate d’un controller et dans l’appel à la méthode paginate():

// Paginate property
public $paginate = [
    'Articles' => ['scope' => 'article'],
    'Tags' => ['scope' => 'tag']
];

// Dans une action de controller
$articles = $this->paginate($this->Articles, ['scope' => 'article']);
$tags = $this->paginate($this->Tags, ['scope' => 'tag']);
$this->set(compact('articles', 'tags'));

L’option scope va faire que PaginatorComponent va regarder les paramètres de query string scopés. Par exemple, l’URL suivante pourrait être utilisée pour paginer les tags et les articles en même temps:

/dashboard?article[page]=1&tag[page]=3

Consulter la section Paginer Plusieurs Résultats pour savoir comment générer les elements HTML scopés et les URLS pour la pagination.

Nouveau dans la version 3.3.0: Pagination multiple a été ajoutée dans la version 3.3.0

Contrôler les Champs Utilisés pour le Tri

Par défaut le tri peut être fait sur n’importe quelle colonne d’une table. Ceci n’est parfois pas souhaité puisque cela permet aux utilisateurs de trier sur des colonnes non indexées qui peuvent être compliquées à trier. Vous pouvez définir la liste blanche des champs qui peut être triée en utilisant l’option sortWhitelist. Cette option est nécessaire quand vous voulez trier sur des données associées, ou des champs calculés qui peuvent faire parti de la requête de pagination:

public $paginate = [
    'sortWhitelist' => [
        'id', 'title', 'Users.username', 'created'
    ]
];

Toute requête qui tente de trier les champs qui ne sont pas dans la liste blanche sera ignorée.

Limiter le Nombre Maximum de Lignes par Page

Le nombre de résultat qui sont récupérés et montrés à l’utilisateur est configuré par le paramètre limit. En général on ne souhaite pas permettre aux utilisateurs de récupérer toutes les lignes d’un ensemble paginé. L’option maxLimit permet à ce que personne ne puisse définir cette limite trop haute depuis l’extérieur. Par défaut, CakePHP limite le nombre maximum de lignes qui peuvent être récupérées à 100. Si cette valeur par défaut n’est pas approprié pour votre application, vous pouvez l’ajuster dans les options de pagination, par exemple en le réduisant à 10:

public $paginate = [
    // Autres clés ici.
    'maxLimit' => 10
];

Si le paramètre de limite de la requête est plus grand que cette valeur, elle sera réduite à la valeur maxLimit.

Faire des Jointures d’Associations Supplémentaires

Des associations supplémentaires peuvent être chargées à la table paginée en utilisant le paramètre contain:

public function index()
{
    $this->paginate = [
        'contain' => ['Authors', 'Comments']
    ];

    $this->set('articles', $this->paginate($this->Articles));
}

Requêtes de Page Out of Range

PaginatorComponent va lancer une NotFoundException quand on essaie d’accéder à une page non existante, par exemple le nombre de page demandé est supérieur au total du nombre de pages.

Ainsi vous pouvez soit laisser s’afficher la page d’erreur normale, soit utiliser un bloc try catch et faire des actions appropriées quand une NotFoundException est attrapée:

// Prior to 3.6 use Cake\Network\Exception\NotFoundException
use Cake\Http\Exception\NotFoundException;

public function index()
{
    try {
        $this->paginate();
    } catch (NotFoundException $e) {
        // Faire quelque chose ici comme rediriger vers la première ou dernière page.
        // $this->request->getParam('paging') vous donnera les infos demandées.
    }
}

Pagination dans la Vue

Consultez la documentation PaginatorHelper pour savoir comment créer des liens de navigation paginés.