Eu que sempre utilizo PDO (PHP Data Object) em meus scripts PHP, logo percebi que esta classe não possui um sistema de paginação. Para resolver esse problema, a solução que encontrei foi desenvolver minha própria classe que implementasse o recurso de paginação no PDO.
Vejam o código, eu comento ele abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
class PDOPaginator extends PDO{ public $sessionName; public $maxNavigationLinks = 20; //quantidade de links de páginas public $maxRegistriesPerPage = 10; //Quantidade de registros por página private $startPage = 0; private $query = null; private $allBindParams = null; private $sql=null; private $resultLength = null; function __construct($dsn, $user, $pass=null, $driver_options=null){ parent::__construct($dsn,$user,$pass,$driver_options); } function prepareLimit($sql,$maxReg=10,$maxNav=20, $sessionName, $driver_options=array()){ $this->sessionName = $sessionName; $this->maxNavigationLinks = $maxNav; $this->maxRegistriesPerPage = $maxReg; $this->allBindParams = null; $this->startPage = 0; $this->sql = $sql; $sql = $sql . " LIMIT " . ":pg" . "," . $this->maxRegistriesPerPage; $this->query = parent::prepare($sql, $driver_options); } function bindParam($param1, $param2,$dataType){ if($param1==":pg"){ $this->startPage = $param2; $param2*=$this->maxRegistriesPerPage; $this->query->bindParam($param1,$param2,$dataType); return; } $this->query->bindParam($param1, $param2, $dataType); $this->allBindParams[] = array($param1,$param2,$dataType); } function execute(){ $this->query->execute(); return $this->query; } function getQueryResultLength(){ //Pega a quantidade de registros total, sem filtros if($this->resultLength!=null) return $this->resultLength; $tempQuery = parent::prepare($this->sql); for($i=0;$i<count($this->allBindParams);$i++){ $tempQuery->bindParam($this->allBindParams[$i][0],$this->allBindParams[$i][1],$this->allBindParams[$i][2]); } $tempQuery->execute(); $this->resultLength = count($tempQuery->fetchAll(PDO::FETCH_COLUMN,0)); return $this->resultLength; } function getLinks($tipo, $target=""){ //Pega os links da paginação $_SESSION[$this->sessionName] = isset($_SESSION[$this->sessionName])?$_SESSION[$this->sessionName]:((int)($this->getQueryResultLength()/$this->maxRegistriesPerPage)+($this->getQueryResultLength()%$this->maxRegistriesPerPage==0?-1:0)); if($_SESSION[$this->sessionName]<0) return "A consulta não retornou nenhum registro! <br>(0/0 páginas)"; if (empty($PHP_SELF)) $PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); // htmlspecialchars() to prevent XSS attacks $linksAround = (int)($this->maxNavigationLinks/2); $firstLink = $this->startPage - $linksAround<0?0:$this->startPage - $linksAround; $lastLink = $this->startPage + $linksAround>$_SESSION[$this->sessionName]?$_SESSION[$this->sessionName]:$this->startPage+$linksAround; $lastLink = $firstLink == 0?($firstLink+$this->maxNavigationLinks>$_SESSION[$this->sessionName]?$_SESSION[$this->sessionName]:$firstLink+$this->maxNavigationLinks): $lastLink; $firstLink = $lastLink==$_SESSION[$this->sessionName]?($lastLink-$this->maxNavigationLinks<0?0:$lastLink-$this->maxNavigationLinks):$firstLink; $numeralLinks = ""; $fullParams = ""; for($i=0;$i<count($this->allBindParams);$i++){ if($this->allBindParams[$i][0]==":pg") continue; $fullParams.= ",".str_replace(":","",$this->allBindParams[$i][0]) . ":'" .str_replace("%","",$this->allBindParams[$i][1]) . "'"; } switch($tipo){ case "ajax": //Retorna Links Ajax; for($i=$firstLink;$i<=$lastLink;$i++){ //Cria os links numéricos $tmp = $i; $tmp++; if($this->startPage==$i){ $numeralLinks.= $tmp . " ";continue; } $numeralLinks.= "<a href='#' onclick=\"javascript:\$('". $target ."').html(loading);$.post('". $PHP_SELF ."',{p: '". $i . "'" . $fullParams . "},function (data, textStatus) { $('" . $target . "').html(data)});\">". $tmp . "</a> "; } //Cria links << >> $first = $this->startPage!=0?"<a href='#' onclick=\"javascript:\$('". $target ."').html(loading);$.post('". $PHP_SELF ."',{p: '0'". $fullParams ."},function (data, textStatus) { $('" . $target . "').html(data)});\">inicio </a>":"inicio "; $last = $this->startPage!=$_SESSION[$this->sessionName]?"<a href='#' onclick=\"javascript:\$('". $target ."').html(loading);$.post('". $PHP_SELF ."',{p: '" . $_SESSION[$this->sessionName] . "'". $fullParams ."},function (data, textStatus) { $('" . $target . "').html(data)});\"> fim</a>":" fim"; $next = $this->startPage!=$_SESSION[$this->sessionName]?"<a href='#' onclick=\"javascript:\$('". $target ."').html(loading);$.post('". $PHP_SELF ."',{p: '" . ($this->startPage + 1) . "'". $fullParams ."},function (data, textStatus) { $('" . $target . "').html(data)});\">>></a>":">>"; $back = $this->startPage!=0?"<a href='#' onclick=\"javascript:\$('". $target ."').html(loading);$.post('". $PHP_SELF ."',{p: '" . ($this->startPage - 1) . "'". $fullParams ."},function (data, textStatus) { $('" . $target . "').html(data)});\"><<</a>":"<<"; return "(". ($this->startPage + 1) ."/" . ($_SESSION[$this->sessionName] + 1) . " paginas) ". $first ." ". $back . " " . $numeralLinks . " " . $next . " " . $last; break; case "friendlyUrl": $fullParams=str_replace(" ","", $fullParams); $fullParams=str_replace("'", "", $fullParams); $fullParamsArray = split(",",$fullParams); $fullParams = ""; $totalParams = count($fullParamsArray); for($i=0;$i<$totalParams;$i++){ $fullParams.= substr($fullParamsArray[$i], (strpos($fullParamsArray[$i],":")+1)) . "/"; } for($i=$firstLink;$i<=$lastLink;$i++){ //Cria os links numéricos $tmp = $i; $tmp++; if($this->startPage==$i){ $numeralLinks.= $tmp . " ";continue; } $numeralLinks.= "<a href='http://". $_SERVER['HTTP_HOST'] . $fullParams . $i .".html'>". $tmp . "</a> "; } $first = $this->startPage!=0?"<a href='http://". $_SERVER['HTTP_HOST'] . $fullParams ."0.html'>inicio </a>":"inicio "; $last = $this->startPage!=$_SESSION[$this->sessionName]?"<a href='http://". $_SERVER['HTTP_HOST'] . $fullParams . $_SESSION[$this->sessionName] .".html'> fim</a>":" fim"; $next = $this->startPage!=$_SESSION[$this->sessionName]?"<a href='http://". $_SERVER['HTTP_HOST'] . $fullParams . ($this->startPage + 1) . ".html'>>></a>":">>"; $back = $this->startPage!=0?"<a href='http://". $_SERVER['HTTP_HOST'] . $fullParams . ($this->startPage - 1) . ".html'><<</a>":"<<"; return "(". ($this->startPage + 1) ."/" . ($_SESSION[$this->sessionName] + 1) . " paginas) ". $first ." ". $back . " " . $numeralLinks . " " . $next . " " . $last; break; default: //Retorna links comuns com ancoras $fullParams = str_replace(":", "=",$fullParams); $fullParams = str_replace("'","",$fullParams); $fullParams = str_replace(",","&",$fullParams); for($i=$firstLink;$i<=$lastLink;$i++){ //Cria os links numéricos $tmp = $i; $tmp++; if($this->startPage==$i){ $numeralLinks.= $tmp . " ";continue; } $numeralLinks.= "<a href='". $PHP_SELF . "?p=" . $i . $fullParams . "'>". $tmp . "</a> "; } //Cria Links << > $first = $this->startPage!=0?"<a href='". $PHP_SELF . "?p=0". $fullParams ."'>inicio </a>":"inicio "; $last = $this->startPage!=$_SESSION[$this->sessionName]?"<a href='". $PHP_SELF . "?p=" . $_SESSION[$this->sessionName] . $fullParams . "'> fim</a>":" fim"; $next = $this->startPage!=$_SESSION[$this->sessionName]?"<a href='". $PHP_SELF . "?p=" . ($this->startPage + 1) . $fullParams . "'>>></a>":">>"; $back = $this->startPage!=0?"<a href='". $PHP_SELF . "?p=" . ($this->startPage - 1) .$fullParams . "'><<</a>":"<<"; return "(". ($this->startPage + 1) ."/" . ($_SESSION[$this->sessionName] + 1) . " paginas) ". $first ." ". $back . " " . $numeralLinks . " " . $next . " " . $last; } } } |
class PDOPaginator extends PDO{ public $sessionName; public $maxNavigationLinks = 20; //quantidade de links de páginas public $maxRegistriesPerPage = 10; //Quantidade de registros por página private $startPage = 0; private $query = null; private $allBindParams = null; private $sql=null; private $resultLength = null; function __construct($dsn, $user, $pass=null, $driver_options=null){ parent::__construct($dsn,$user,$pass,$driver_options); } function prepareLimit($sql,$maxReg=10,$maxNav=20, $sessionName, $driver_options=array()){ $this->sessionName = $sessionName; $this->maxNavigationLinks = $maxNav; $this->maxRegistriesPerPage = $maxReg; $this->allBindParams = null; $this->startPage = 0; $this->sql = $sql; $sql = $sql . " LIMIT " . ":pg" . "," . $this->maxRegistriesPerPage; $this->query = parent::prepare($sql, $driver_options); } function bindParam($param1, $param2,$dataType){ if($param1==":pg"){ $this->startPage = $param2; $param2*=$this->maxRegistriesPerPage; $this->query->bindParam($param1,$param2,$dataType); return; } $this->query->bindParam($param1, $param2, $dataType); $this->allBindParams[] = array($param1,$param2,$dataType); } function execute(){ $this->query->execute(); return $this->query; } function getQueryResultLength(){ //Pega a quantidade de registros total, sem filtros if($this->resultLength!=null) return $this->resultLength; $tempQuery = parent::prepare($this->sql); for($i=0;$i<count($this->allBindParams);$i++){ $tempQuery->bindParam($this->allBindParams[$i][0],$this->allBindParams[$i][1],$this->allBindParams[$i][2]); } $tempQuery->execute(); $this->resultLength = count($tempQuery->fetchAll(PDO::FETCH_COLUMN,0)); return $this->resultLength; } function getLinks($tipo, $target=""){ //Pega os links da paginação $_SESSION[$this->sessionName] = isset($_SESSION[$this->sessionName])?$_SESSION[$this->sessionName]:((int)($this->getQueryResultLength()/$this->maxRegistriesPerPage)+($this->getQueryResultLength()%$this->maxRegistriesPerPage==0?-1:0)); if($_SESSION[$this->sessionName]<0) return "A consulta não retornou nenhum registro! <br>(0/0 páginas)"; if (empty($PHP_SELF)) $PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); // htmlspecialchars() to prevent XSS attacks $linksAround = (int)($this->maxNavigationLinks/2); $firstLink = $this->startPage - $linksAround<0?0:$this->startPage - $linksAround; $lastLink = $this->startPage + $linksAround>$_SESSION[$this->sessionName]?$_SESSION[$this->sessionName]:$this->startPage+$linksAround; $lastLink = $firstLink == 0?($firstLink+$this->maxNavigationLinks>$_SESSION[$this->sessionName]?$_SESSION[$this->sessionName]:$firstLink+$this->maxNavigationLinks): $lastLink; $firstLink = $lastLink==$_SESSION[$this->sessionName]?($lastLink-$this->maxNavigationLinks<0?0:$lastLink-$this->maxNavigationLinks):$firstLink; $numeralLinks = ""; $fullParams = ""; for($i=0;$i<count($this->allBindParams);$i++){ if($this->allBindParams[$i][0]==":pg") continue; $fullParams.= ",".str_replace(":","",$this->allBindParams[$i][0]) . ":'" .str_replace("%","",$this->allBindParams[$i][1]) . "'"; } switch($tipo){ case "ajax": //Retorna Links Ajax; for($i=$firstLink;$i<=$lastLink;$i++){ //Cria os links numéricos $tmp = $i; $tmp++; if($this->startPage==$i){ $numeralLinks.= $tmp . " ";continue; } $numeralLinks.= "<a href='#' onclick=\"javascript:\$('". $target ."').html(loading);$.post('". $PHP_SELF ."',{p: '". $i . "'" . $fullParams . "},function (data, textStatus) { $('" . $target . "').html(data)});\">". $tmp . "</a> "; } //Cria links << >> $first = $this->startPage!=0?"<a href='#' onclick=\"javascript:\$('". $target ."').html(loading);$.post('". $PHP_SELF ."',{p: '0'". $fullParams ."},function (data, textStatus) { $('" . $target . "').html(data)});\">inicio </a>":"inicio "; $last = $this->startPage!=$_SESSION[$this->sessionName]?"<a href='#' onclick=\"javascript:\$('". $target ."').html(loading);$.post('". $PHP_SELF ."',{p: '" . $_SESSION[$this->sessionName] . "'". $fullParams ."},function (data, textStatus) { $('" . $target . "').html(data)});\"> fim</a>":" fim"; $next = $this->startPage!=$_SESSION[$this->sessionName]?"<a href='#' onclick=\"javascript:\$('". $target ."').html(loading);$.post('". $PHP_SELF ."',{p: '" . ($this->startPage + 1) . "'". $fullParams ."},function (data, textStatus) { $('" . $target . "').html(data)});\">>></a>":">>"; $back = $this->startPage!=0?"<a href='#' onclick=\"javascript:\$('". $target ."').html(loading);$.post('". $PHP_SELF ."',{p: '" . ($this->startPage - 1) . "'". $fullParams ."},function (data, textStatus) { $('" . $target . "').html(data)});\"><<</a>":"<<"; return "(". ($this->startPage + 1) ."/" . ($_SESSION[$this->sessionName] + 1) . " paginas) ". $first ." ". $back . " " . $numeralLinks . " " . $next . " " . $last; break; case "friendlyUrl": $fullParams=str_replace(" ","", $fullParams); $fullParams=str_replace("'", "", $fullParams); $fullParamsArray = split(",",$fullParams); $fullParams = ""; $totalParams = count($fullParamsArray); for($i=0;$i<$totalParams;$i++){ $fullParams.= substr($fullParamsArray[$i], (strpos($fullParamsArray[$i],":")+1)) . "/"; } for($i=$firstLink;$i<=$lastLink;$i++){ //Cria os links numéricos $tmp = $i; $tmp++; if($this->startPage==$i){ $numeralLinks.= $tmp . " ";continue; } $numeralLinks.= "<a href='http://". $_SERVER['HTTP_HOST'] . $fullParams . $i .".html'>". $tmp . "</a> "; } $first = $this->startPage!=0?"<a href='http://". $_SERVER['HTTP_HOST'] . $fullParams ."0.html'>inicio </a>":"inicio "; $last = $this->startPage!=$_SESSION[$this->sessionName]?"<a href='http://". $_SERVER['HTTP_HOST'] . $fullParams . $_SESSION[$this->sessionName] .".html'> fim</a>":" fim"; $next = $this->startPage!=$_SESSION[$this->sessionName]?"<a href='http://". $_SERVER['HTTP_HOST'] . $fullParams . ($this->startPage + 1) . ".html'>>></a>":">>"; $back = $this->startPage!=0?"<a href='http://". $_SERVER['HTTP_HOST'] . $fullParams . ($this->startPage - 1) . ".html'><<</a>":"<<"; return "(". ($this->startPage + 1) ."/" . ($_SESSION[$this->sessionName] + 1) . " paginas) ". $first ." ". $back . " " . $numeralLinks . " " . $next . " " . $last; break; default: //Retorna links comuns com ancoras $fullParams = str_replace(":", "=",$fullParams); $fullParams = str_replace("'","",$fullParams); $fullParams = str_replace(",","&",$fullParams); for($i=$firstLink;$i<=$lastLink;$i++){ //Cria os links numéricos $tmp = $i; $tmp++; if($this->startPage==$i){ $numeralLinks.= $tmp . " ";continue; } $numeralLinks.= "<a href='". $PHP_SELF . "?p=" . $i . $fullParams . "'>". $tmp . "</a> "; } //Cria Links << > $first = $this->startPage!=0?"<a href='". $PHP_SELF . "?p=0". $fullParams ."'>inicio </a>":"inicio "; $last = $this->startPage!=$_SESSION[$this->sessionName]?"<a href='". $PHP_SELF . "?p=" . $_SESSION[$this->sessionName] . $fullParams . "'> fim</a>":" fim"; $next = $this->startPage!=$_SESSION[$this->sessionName]?"<a href='". $PHP_SELF . "?p=" . ($this->startPage + 1) . $fullParams . "'>>></a>":">>"; $back = $this->startPage!=0?"<a href='". $PHP_SELF . "?p=" . ($this->startPage - 1) .$fullParams . "'><<</a>":"<<"; return "(". ($this->startPage + 1) ."/" . ($_SESSION[$this->sessionName] + 1) . " paginas) ". $first ." ". $back . " " . $numeralLinks . " " . $next . " " . $last; } } }
Talvez, para os iniciantes, essa classe possa gerar muitas dúvidas, então vejam o quiz que fiz para ajudar os leigos:
Paginação no PHP PDO: Como instanciar a classe PDOPaginator
Você pode criar um arquivo chamado config.php, onde deverá informar os dados para conexão com o banco de dados. Algo parecido com isso:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//Informe o servidor do mysql $servidor_mysql = "localhost"; //Informe o usuário do banco de dados $usuario_banco = "root"; //informe a senha do banco de dados $senha_banco = ""; //Informe eo nome do banco de daos $nome_banco = "livrophp"; $_DATABASE= array('dbdriver' =>'mysql','dbhostname'=>$servidor_mysql,'dbusername'=>'$usuario_banco,'dbpassword'=>$senha_banco,'dbname'=>$nome_banco); |
//Informe o servidor do mysql $servidor_mysql = "localhost"; //Informe o usuário do banco de dados $usuario_banco = "root"; //informe a senha do banco de dados $senha_banco = ""; //Informe eo nome do banco de daos $nome_banco = "livrophp"; $_DATABASE= array('dbdriver' =>'mysql','dbhostname'=>$servidor_mysql,'dbusername'=>'$usuario_banco,'dbpassword'=>$senha_banco,'dbname'=>$nome_banco);
Com isso, temos uma variavel do tipo array contendo todos os dados necessários para efetuar a conexão com o banco de dados. Agora, crie outro arquivo chamado connection.php e inclua o config.php. Ficaria mais ou menos isso:
1 2 3 |
require_once('config.php'); $conn = new PDOPaginator($_DATABASE["dbdriver"].":host=".$_DATABASE["dbhostname"].";dbname=".$_DATABASE["dbname"],$_DATABASE["dbusername"],$_DATABASE["dbpassword"]); $conn->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); |
require_once('config.php'); $conn = new PDOPaginator($_DATABASE["dbdriver"].":host=".$_DATABASE["dbhostname"].";dbname=".$_DATABASE["dbname"],$_DATABASE["dbusername"],$_DATABASE["dbpassword"]); $conn->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
Agora, já temos uma instância da classe PDOPaginator, então, sempre que quiser utilizar ela, basta incluir o arquivo conection.php em suas páginas PHP.
Paginação no PHP PDO: Como executar um sql usando a classe PDOPaginator
Para executar um sql, você deve primeiramente invocar o método: prepareLimit($sql,$maxReg=10,$maxNav=20, $sessionName, $driver_options=array())
O método prepareLimit possui 5 parâmetros, sendo que:
– o primeiro é a string sql a ser executada,
– o segundo é número máximo de registros que devem ser exibidas por página
– o terceiro é o número de links de navegação, ex: (1,2,3…)
– o quarto parâmetro é o nome de uma variável de sessão que irá armazenar o número total de registros (esse recurso é útil em bancos com grande número de registros para tornar as consultas mais rápidas a partir da segunda vez, visto que não será necessário percorrer todos os registros de uma tabela para saber a quantidade total). Mas porque precisamos desse número? Bem, ele é utilizado para criar a paginação.
– o último parâmetro é um array com as opções de driver, utilize esse parâmetro do mesmo modo que utilizaria na classe PDO. Esse parâmetro é opcional.
Veja um exemplo:
1 |
$conn->prepareLimit("select * from usuarios",300,20,"sessionUsers"); |
$conn->prepareLimit("select * from usuarios",300,20,"sessionUsers");
Após isso, você deve chamar o método execute(), veja como ficaria:
1 2 |
$conn->prepareLimit("select * from usuarios",300,20,"sessionUsers"); $usuarios = $conn->execute(); |
$conn->prepareLimit("select * from usuarios",300,20,"sessionUsers"); $usuarios = $conn->execute();
Paginação no PHP PDO: Como percorrer os registros da classe PDOPaginator
Após executar o método execute(), você pode utilizar o método fetch para percorrer os registros, veja um exemplo prático:
1 2 3 4 5 6 |
$conn->prepareLimit("select * from usuarios",300,20,"sessionUsers"); $usuarios = $conn->execute(); while($linha = $usuarios->fetch(PDO::FETCH_ASSOC);){ echo $linha["nm_usuario"]; } |
$conn->prepareLimit("select * from usuarios",300,20,"sessionUsers"); $usuarios = $conn->execute(); while($linha = $usuarios->fetch(PDO::FETCH_ASSOC);){ echo $linha["nm_usuario"]; }
Paginação no PHP PDO: Como criar a Paginação
A paginação é criada automaticamente, você só precisa chamar o método getLinks(), lembrando que PDOPaginator suporte três tipos de links, conforme o parâmetro que você passar no método getLinks(), um determinado tipo de link será criado. Esse método tem ainda um segundo parâmetro, que é útil quando você for utilizar links ajax, nesse caso, passe como segundo parâmetro o identificador o elemente aonde os links devem ser inseridos. Vejamos:
1- Links Normais:
1 |
echo $conn->getLinks("default"); |
echo $conn->getLinks("default");
2- Links Ajax:
1 |
echo $conn->getLinks("ajax"); |
echo $conn->getLinks("ajax");
3- Links com Urls Amigáveis:
1 |
echo $conn->getLinks("friendlyUrl"); |
echo $conn->getLinks("friendlyUrl");
Paginação no PHP PDO: Conclusão
Com esta classe você pode criar paginação facilmente utilizando PDO. A classe suporta três tipos de links de paginação, links comuns, links ajax e links com urls amigáveis. Além disse, a classe permite você definir uma variável de sessão que irá armazenar a quantidade total de registros, tornando a consulta no banco de dados, a partir da segunda, bem mais rápida. Caso você utilize um sistema que sofra modificações no banco de dados constantemente, como por exemplo um painel de administração onde o administrador exclua usuários, você pode simplesmente destruir a variável de sessão como comando unset(variavel aqui) para que o sistema volte a calcular o total de registros novamente.
Se tiver alguma dúvida, deixe aqui nos comentários.
Até o próximo artigo aqui no blog.