This document is for CakePHP's development version, which can be significantly different from previous releases.
You may want to read current stable release documentation instead.

Pagination

class Cake\Controller\Component\PaginatorComponent

Um dos principais obstáculos da criação de aplicativos Web flexíveis e fáceis de usar é o design de uma interface de usuário intuitiva. Muitos aplicativos tendem a crescer em tamanho e complexidade rapidamente, e designers e programadores acham que não conseguem lidar com a exibição de centenas ou milhares de registros. A refatoração leva tempo, e o desempenho e a satisfação do usuário podem sofrer.

A exibição de um número razoável de registros por página sempre foi uma parte crítica de todos os aplicativos e usada para causar muitas dores de cabeça aos desenvolvedores. O CakePHP facilita a carga para o desenvolvedor, fornecendo uma maneira rápida e fácil de paginar os dados.

A paginação no CakePHP é oferecida por um componente no controlador, para facilitar a criação de consultas paginadas. A View PaginatorHelper é usada para simplificar a geração de links e botões de paginação.

Usando Controller::paginate()

No controlador, começamos definindo as condições de consulta padrão que a paginação usará na variável do controlador $paginate. Essas condições servem como base para suas consultas de paginação. Eles são aumentados pelos parâmetros sort, direction, limit e page transmitidos a partir da URL. É importante notar que a chave order deve ser definida em uma estrutura de matriz como abaixo:

class ArticlesController extends AppController
{
    public $paginate = [
        'limit' => 25,
        'order' => [
            'Articles.title' => 'asc'
        ]
    ];

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

Você também pode incluir qualquer uma das opções suportadas por find(), como fields:

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

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

Enquanto você pode passar a maioria das opções de consulta da propriedade paginate, geralmente é mais fácil e simples agrupar suas opções de paginação em Personalizando Metódos de Consulta. Você pode definir o uso da paginação do localizador, definindo a opção finder:

class ArticlesController extends AppController
{
    public $paginate = [
        'finder' => 'published',
    ];
}

Como os métodos localizadores personalizados também podem receber opções, é assim que você passa as opções para um método find personalizado dentro da propriedade paginate:

class ArticlesController extends AppController
{
    // encontrar artigos por tag
    public function tags()
    {
        $tags = $this->request->getParam('pass');

        $customFinderOptions = [
            'tags' => $tags
        ];
        // o método find personalizado é chamado findTagged dentro de ArticlesTable.php,
        // e deve ter se parecer com: public function findTagged(Query $query, array $options) {
        // portanto, você usa tags como a chave
        $this->paginate = [
            'finder' => [
                'tagged' => $customFinderOptions
            ]
        ];
        $articles = $this->paginate($this->Articles);
        $this->set(compact('articles', 'tags'));
    }
}

Além de definir valores gerais de paginação, você pode definir mais de um conjunto de padrões de paginação no controlador, basta nomear as chaves da matriz após o modelo que deseja configurar:

class ArticlesController extends AppController
{
    public $paginate = [
        'Articles' => [],
        'Authors' => [],
    ];
}

Os valores das chaves Articles e Authors podem conter todas as propriedades que um modelo/chave menos a matriz $paginate.

Depois de definida a propriedade $paginate, podemos usar o método paginate() para criar os dados de paginação e adicionar o PaginatorHelper `` se ainda não foi adicionado. O método paginado do controlador retornará o conjunto de resultados da consulta paginada e definirá os metadados de paginação para a solicitação. Você pode acessar os metadados da paginação em ``$this->request->getParam('paging'). Um exemplo mais completo do uso de paginate() seria:

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

Por padrão, o método paginate() usará o modelo padrão para um controlador. Você também pode passar a consulta resultante de um método find:

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

Se você quiser paginar um modelo diferente, poderá fornecer uma consulta para ele, sendo o próprio objeto de tabela ou seu nome:

// Usando a query.
$comments = $this->paginate($commentsTable->find());

// Usando o nome do modelo.
$comments = $this->paginate('Comments');

// Usando um objeto de tabela.
$comments = $this->paginate($commentTable);

Usando o Paginator Diretamente

Se você precisar paginar os dados de outro componente, poderá usar o PaginatorComponent diretamente. O PaginatorComponent possui uma API semelhante ao método do controlador:

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

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

O primeiro parâmetro deve ser o objeto de consulta de um objeto de localização na tabela do qual você deseja paginar os resultados. Opcionalmente, você pode passar o objeto de tabela e permitir que a consulta seja construída para você. O segundo parâmetro deve ser a matriz de configurações a serem usadas para paginação. Essa matriz deve ter a mesma estrutura que a propriedade $paginate em um controlador. Ao paginar um objeto Query, a opção finder será ignorada. Supõe-se que você esteja passando a consulta que deseja paginar.

Paginando Múltiplas Queries

Você pode paginar vários modelos em uma única ação do controlador, usando a opção scope na propriedade $paginate do controlador e na chamada para o método paginate():

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

// Em um método do controlador
$articles = $this->paginate($this->Articles, ['scope' => 'article']);
$tags = $this->paginate($this->Tags, ['scope' => 'tag']);
$this->set(compact('articles', 'tags'));

A opção scope resultará na PaginatorComponent procurando nos parâmetros da string de consulta com escopo definido. Por exemplo, o URL a seguir pode ser usado para paginar tags e artigos ao mesmo tempo:

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

Veja a seção paginator-helper-multiple para saber como gerar elementos HTML com escopo e URLs para paginação.

Paginando o Mesmo Modelo Várias Vezes

Para paginar o mesmo modelo várias vezes em uma única ação do controlador, é necessário definir um alias para o modelo. Consulte table-registry-usage para obter detalhes adicionais sobre como usar o registro da tabela:

// Em um método do controlador
$this->paginate = [
    'ArticlesTable' => [
        'scope' => 'published_articles',
        'limit' => 10,
        'order' => [
            'id' => 'desc',
        ],
    ],
    'UnpublishedArticlesTable' => [
        'scope' => 'unpublished_articles',
        'limit' => 10,
        'order' => [
            'id' => 'desc',
        ],
    ],
];

// Registre um objeto de tabela adicional para permitir a diferenciação no componente de paginação
TableRegistry::getTableLocator()->setConfig('UnpublishedArticles', [
    'className' => 'App\Model\Table\ArticlesTable',
    'table' => 'articles',
    'entityClass' => 'App\Model\Entity\Article',
]);

$publishedArticles = $this->paginate(
    $this->Articles->find('all', [
        'scope' => 'published_articles'
    ])->where(['published' => true])
);

$unpublishedArticles = $this->paginate(
    TableRegistry::getTableLocator()->get('UnpublishedArticles')->find('all', [
        'scope' => 'unpublished_articles'
    ])->where(['published' => false])
);

Controlar Quais Campos Usados para Ordenamento

Por padrão, a classificação pode ser feita em qualquer coluna não virtual que uma tabela tenha. Às vezes, isso é indesejável, pois permite que os usuários classifiquem em colunas não indexadas que podem ser caras de solicitar. Você pode definir a lista de permissões dos campos que podem ser classificados usando a opção sortableFields. Essa opção é necessária quando você deseja classificar os dados associados ou os campos computados que podem fazer parte da sua consulta de paginação:

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

Quaisquer solicitações que tentem classificar campos que não estão na lista de permissões serão ignoradas.

Limitar o Número Máximo de Linhas por Página

O número de resultados que são buscados por página é exposto ao usuário como o parâmetro limit. Geralmente, é indesejável permitir que os usuários busquem todas as linhas em um conjunto paginado. A opção maxLimit afirma que ninguém pode definir esse limite muito alto do lado de fora. Por padrão, o CakePHP limita o número máximo de linhas que podem ser buscadas para 100. Se esse padrão não for apropriado para a sua aplicação, você poderá ajustá-lo como parte das opções de paginação, por exemplo, reduzindo-o para 10:

public $paginate = [
    // Outras chaves aqui.
    'maxLimit' => 10
];

Se o parâmetro de limite da solicitação for maior que esse valor, ele será reduzido ao valor maxLimit.

Juntando Associações Adicionais

Associações adicionais podem ser carregadas na tabela paginada usando o parâmetro contains:

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

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

Solicitações de Página Fora do Intervalo

O PaginatorComponent lançará uma NotFoundException ao tentar acessar uma página inexistente, ou seja, o número da página solicitada é maior que a contagem total de páginas.

Portanto, você pode permitir que a página de erro normal seja renderizada ou usar um bloco try catch e executar a ação apropriada quando um NotFoundException for capturado:

use Cake\Http\Exception\NotFoundException;

public function index()
{
    try {
        $this->paginate();
    } catch (NotFoundException $e) {
        // Faça algo aqui como redirecionar para a primeira ou a última página.
        // $this->request->getParam('paging') fornecerá as informações necessárias.
    }
}

Paginação na View

Verifique a documentação PaginatorHelper para saber como criar links para navegação de paginação.