Sistema de paginação em PHP
Quando se tem um grande conjunto de resultados provenientes de uma consulta SQL, é útil apresentá-los de forma parcial, por questões de usabilidade ou até performance. Por exemplo, numa página de uma loja online, é comum que a apresentação de produtos após uma pesquisa esteja dividida em várias páginas. São inúmeras as vantagens de utilização de um sistema deste género, a título de exemplo:
- O utilizador não tem de esperar tanto tempo para carregar a página.
- Existe um menor volume de dados para processar por parte do servidor.
- O utilizador não fica perdido numa imensidão de resultados.
Vamos então ver como fazer um sistema destes em PHP.
Criação de uma tabela simples
Para exemplificar o tutorial, vamos construir uma pequena tabela de pessoas. Na verdade, é possível usar qualquer tabela ou conjunto de tabelas, porque o que realmente importa é conseguir contar quantos resultados obtivemos.
CREATE TABLE pessoa (
nome VARCHAR(50) NOT NULL
);
Introduzam alguns dados na vossa tabela, aqui fica um exemplo gerado com o GenerateData.com:
INSERT INTO pessoa (nome) VALUES ('Brody');
INSERT INTO pessoa (nome) VALUES ('Azalia');
INSERT INTO pessoa (nome) VALUES ('Fiona');
INSERT INTO pessoa (nome) VALUES ('Chantale');
INSERT INTO pessoa (nome) VALUES ('Sylvia');
INSERT INTO pessoa (nome) VALUES ('Hamilton');
INSERT INTO pessoa (nome) VALUES ('Colorado');
INSERT INTO pessoa (nome) VALUES ('Shelby');
INSERT INTO pessoa (nome) VALUES ('Julian');
INSERT INTO pessoa (nome) VALUES ('Hayfa');
INSERT INTO pessoa (nome) VALUES ('Nelle');
INSERT INTO pessoa (nome) VALUES ('Graiden');
INSERT INTO pessoa (nome) VALUES ('Jorden');
INSERT INTO pessoa (nome) VALUES ('Madeline');
INSERT INTO pessoa (nome) VALUES ('Hoyt');
INSERT INTO pessoa (nome) VALUES ('Paki');
INSERT INTO pessoa (nome) VALUES ('Bree');
INSERT INTO pessoa (nome) VALUES ('Russell');
INSERT INTO pessoa (nome) VALUES ('Victoria');
INSERT INTO pessoa (nome) VALUES ('Kaye');
Estratégia para paginação
Já temos a nossa tabela com alguns dados. Neste momento, se fizermos uma consulta à tabela, obtemos os 20 registos e podemos imprimir um a um na nossa página. Mas vamos supor que apenas pretendemos 5 registos por cada página. Como limitar os registos? O MySQL e a gereralidade dos SGBD têm a instrução LIMIT
, que como o nome sugere, permite limitar um determinado conjunto de resultados. Por exemplo, experimentem a seguinte consulta:
SELECT * FROM pessoa LIMIT 0,5
Como podem ver, a consulta anterior devolve os primeiros 5 resultados. Em português corrente, podemos traduzir a consulta para algo como: "Devolva-me todos os valores da tabela pessoa. Desses resultados, apenas quero 5 registos, a começar do primeiro (0)".
Vamos ver outro exemplo:
SELECT * FROM pessoa LIMIT 10,5
Esta consulta pode traduzir-se por: "Devolva-me todos os valores da tabela pessoa. Desses resultados, apenas quero 5 registos, a começar do décimo primeiro (ou alternativamente, a partir do décimo, exclusive)".
Então, se tivermos LIMIT X,Y
, X
é o primeiro registo que deve ser devolvido (que começa em 0
) e Y
é o total de resultados a que queremos limitar. Esta é a base para perceber a paginação.
Aplicar o LIMIT
Recorrendo ao LIMIT
, é fácil aplicarmos a paginação. Como sabemos, um sistema de paginação tem um número finito de páginas, que começam em 1
e a vão até N
. Assumindo que queremos 6 registos em cada página, temos em primeiro lugar de calcular o total de páginas que pretendemos: basta pegar no total de registos da tabela, correspondentes à consulta, e dividir pelo número de registos por página, ou seja:
20 registos / 6 por página = 3,3333...
Portanto, precisamos de 3 páginas. Mas como temos um número não inteiro de páginas, temos sempre de arredondar por excesso. Ou seja, para que não fique nenhum registo por visualizar, iremos precisar de 4 páginas, neste caso.
Já sabemos quantas páginas precisamos de mostrar, mas agora, estando numa certa página, como saber que conjunto de resultados apresentar? Vamos usar o que aprendemos sobre o LIMIT
para limitar os resultados. Neste caso, a consulta SQL genérica é:
SELECT * FROM pessoa LIMIT ((P - 1) * M), M
Em que:
M
é o total de registos que queremos obter para uma página (no exemplo, são6
).P
é o número da página actual, que varia no intervalo de1
até4
no exemplo
Código PHP
Se experimentarem o seguinte código, devem obter os nomes que inseriram na tabela divididos por diversas páginas (tudo no mesmo script). Reparem que usámos a consulta SQL do ponto anterior para obter os registos diferentes consoante o número de página que estamos a visualizar. Reparem ainda que é criada uma pequena lista no fim do documento que permite saltar entre as diversas páginas.
<?php
// ligação à base de dados (não esquecer de trocar pelos dados correctos)
mysql_connect('hostsql', 'username', 'password') or die(mysql_error());
mysql_select_db('basedados');
// definir a constante com quantos registos queremos por página
define('POR_PAGINA', 6);
// contar o total de registos da nossa tabela e total de páginas
$sqlTotalRegistos = mysql_query('SELECT COUNT(*) FROM pessoa') or die(mysql_query());
$totalRegistos = mysql_result($sqlTotalRegistos, 0, 0);
$totalPaginas = ceil($totalRegistos / POR_PAGINA);
// obter o número de página actual, é a primeira por omissão
$pagina = 1;
if( !empty($_GET['pagina']) ){
$p = intval($_GET['pagina']);
if( $p <= 0 || $p > $totalPaginas ){
header('Location: ?pagina=1');
exit();
}
$pagina = $p;
}
// obter os registos para esta página, usando a consulta SQL genérica
$sqlPagina = mysql_query('SELECT * FROM pessoa LIMIT '.(($pagina - 1) * POR_PAGINA).' , '.POR_PAGINA) or die(mysql_error());
echo '<ul>';
while( $linha = mysql_fetch_row($sqlPagina) )
echo '<li>'.$linha[0].'</li>';
echo '</ul>';
// gerar ligações para saltar entre páginas
for( $i = 1 ; $i <= $totalPaginas ; $i++ ){
// Não criar uma ligação para a própria página que estamos a visualizar
if( $i == $pagina )
echo $i.' ';
else
echo '<a href="?pagina='.$i.'">'.$i.'</a> ';
}
?>