(vale a pena conferir o post sobre autenticação, para restringir o acesso a esses boletos {ou qualquer outra informação})
Quando isso é utilizado? ao se criar uma view(página,tabela ou tela) que mostrará uma grande quantidade de dados.
Imagine carregar 2.000 linhas de uma consulta e mostrar em uma página ? Além da página ficar grande e pesada(em kbs), está sujeito o usuário ter que usar o recurso "Localizar" do navegador para encontrar o que procura.
P/ evitar isso (que é muito feio), o que sugiro é uma técnica bastante utilizada de dividir a consulta em blocos ou páginas. Exemplo os 2.000 ficariam :
Registros por página : 100 --> Nº de páginas : 20
Registros por página : 50 --> Nº de páginas : 40
Além do mecanismo de paginação, pode-se implementar filtros para restringir os resultados. Logo, precisamos manter os mesmos filtros durante a navegação dos registros. A busca do Google é um bom exemplo.
O exemplo apresentado será com uma tabela p/ armazenar boletos bancários. Não vou entrar nos detalhes da geração do boleto.Basta saber o que o boleto foi gerado usando BoletoPhp , que na minha opinião é uma das maneiras mais simples e completas p/ gerar boletos com PHP.
Este exemplo ainda utiliza o variáveis tipo $_GET e mantém os valores na URL.
Esse não é o melhor jeito.A melhor maneira de fazer é com formulários usando $_POST, e os links postarem os valores necessários, e um ajax trocar o conteúdo da tabela de dados dentro de uma tag <tbody>, o que mostrarei num posso próximo post, pois tive q fazer isso p/ uma base ORACLE.
Então o que precisamos? (além do que já foi citado nos dois posts anteriores)
- Banco de Dados
-Tabela p/ armazenar os boletos: boleto - MVC
-Model-> Boleto.php
-View-> /pages/*(seção pública que monta a tela),/app/view/Boleto/{index,add}.php
-Controller-> BoletoControler.php, PostController.php (para tratar os formulários postados que não sejam de consulta) - DAO
-BoletoDAO.php - Arquivos de função, costumo chamar de lib ou /lib
-Conexao.php
-Utils.php - EXTRA: /ajax/clientes.php, /app/model/Cliente.php /app/controller/ClienteController, /app/dao/ClienteDAO.php
Estrutura de arquivos :
![]() |
| Figura 1 - Estrutura de arquivos no Projeto do Netbeans |
Diagrama do Banco
![]() |
| Figura 2 - Diagrama do Banco, a tabela boleto_seq serve apenas p/ controlar o campo nosso_num dentro da aplicação. |
Codigo da tabela do Mysql :
CREATE TABLE IF NOT EXISTS `mydb`.`boleto` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`nosso_num` VARCHAR(16) NOT NULL ,
`data_vencimento` DATE NOT NULL ,
`data_documento` DATETIME NOT NULL ,
`valor` DECIMAL(10,2) NOT NULL ,
`nota_fiscal` VARCHAR(30) NULL DEFAULT NULL ,
`discriminacao` TEXT NOT NULL ,
`id_cliente` INT(11) NOT NULL ,
`sacado` VARCHAR(225) NULL DEFAULT NULL ,
`linha_digitavel` VARCHAR(54) NULL DEFAULT NULL ,
`pago` TINYINT(1) NULL DEFAULT '0' , -- ao ser criado não pode ter sido pago, certo (0_o)?
PRIMARY KEY (`id`) ,
INDEX `boleto_cliente_FK` (`id_cliente` ASC) ,
CONSTRAINT `boleto_cliente_FK`
FOREIGN KEY (`id_cliente` )
REFERENCES `mydb`.`cliente` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci
-- table cliente
CREATE TABLE IF NOT EXISTS `mydb`.`cliente` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`nome` VARCHAR(255) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,
`email` VARCHAR(130) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,
`ddd` VARCHAR(3) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NULL DEFAULT NULL ,
`fone` VARCHAR(15) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,
`ramal` VARCHAR(6) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NULL DEFAULT NULL ,
`endereco` VARCHAR(255) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,
`numero` VARCHAR(7) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,
`complemento` VARCHAR(30) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NULL DEFAULT NULL ,
`bairro` VARCHAR(150) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NULL DEFAULT NULL ,
`cidade_id` INT(11) NOT NULL ,
`estado_id` INT(11) NOT NULL ,
`cep` VARCHAR(9) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,
`tipo_end` ENUM('Res','Com','Cor') CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL DEFAULT 'Res' ,
`tipo_fone` ENUM('Res','Com','Cel') CHARACTER SET 'utf8' COLLATE 'utf8_bin' NULL DEFAULT 'Res' ,
`tipo_cliente` ENUM('pf','pj') CHARACTER SET 'utf8' COLLATE 'utf8_bin' NULL DEFAULT NULL ,
`cnpj` VARCHAR(20) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NULL DEFAULT NULL ,
`cpf` VARCHAR(15) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NULL DEFAULT NULL ,
`inscr_estadual` VARCHAR(15) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NULL DEFAULT NULL ,
`senha` VARCHAR(8) NULL DEFAULT NULL ,
`ativo` TINYINT(1) NOT NULL DEFAULT '1' ,
`contato` VARCHAR(150) NULL DEFAULT NULL ,
PRIMARY KEY (`id`) ,
INDEX `cidade_cliente_FK` (`cidade_id` ASC) ,
INDEX `estado_cliente_FK` (`estado_id` ASC) ,
CONSTRAINT `cidade_cliente_FK`
FOREIGN KEY (`cidade_id` )
REFERENCES `mydb`.`cidade` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `estado_cliente_FK`
FOREIGN KEY (`estado_id` )
REFERENCES `mydb`.`estado` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci
Veja a tela como ficará após o login :
![]() |
| Lista dos boletos com paginação e pesquisa |
![]() |
| Explicação das seções da página |
Vamos aos arquivos. obs: as datas ficam no formato brasileiro dia/mes/ano
Modelos
<?php
//@arquivo /app/model/Boleto.php
class Boleto {
var $id;
var $nossoNum;
var $dataVencimento;
var $dataDocumento;
var $valor;
var $notaFiscal;
var $discriminacao;
var $idCliente;
var $linhaDigitavel;
var $sacado;
var $pago;
public function Boleto() { // contrutor
$this->pago=false; //ao ser criado ele não pode ter sido pago, certo ?(0_o)
$this->nossoNum=NULL;
$this->valor=NULL;
$this->dataDocumento=NULL;
$this->dataVencimento=NULL;
$this->idCliente=NULL;
}
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getNossoNum() {
return $this->nossoNum;
}
public function setNossoNum($nossoNum) {
$this->nossoNum = $nossoNum;
}
public function getDataVencimento() {
return $this->dataVencimento;
}
public function setDataVencimento($dataVencimento) {
$this->dataVencimento = $dataVencimento;
}
public function getDataDocumento() {
return $this->dataDocumento;
}
public function setDataDocumento($dataDocumento) {
$this->dataDocumento = $dataDocumento;
}
public function getValor() {
return $this->valor;
}
public function setValor($valor) {
$this->valor = $valor;
}
public function getNotaFiscal() {
return $this->notaFiscal;
}
public function setNotaFiscal($notaFiscal) {
$this->notaFiscal = $notaFiscal;
}
public function getDiscriminacao() {
return $this->discriminacao;
}
public function setDiscriminacao($discriminacao) {
$this->discriminacao = $discriminacao;
}
public function getIdCliente() {
return $this->idCliente;
}
public function setIdCliente($idCliente) {
$this->idCliente = $idCliente;
}
public function getLinhaDigitavel() {
return $this->linhaDigitavel;
}
public function setLinhaDigitavel($linhaDigitavel) {
$this->linhaDigitavel = $linhaDigitavel;
}
public function getSacado() {
return $this->sacado;
}
public function setSacado($sacado) {
$this->sacado = $sacado;
}
public function isPago() {
return $this->pago;
}
public function setPago($pago) {
$this->pago = $pago;
}
}
?>
Controller<?php
//@arquivo /app/controller/BoletoController.php
// observe que o controler nao faz include do conexao. quem faz isso é o DAO
require_once($_SERVER['DOCUMENT_ROOT'] . '/app/model/Boleto.php');
require_once($_SERVER['DOCUMENT_ROOT'] . '/app/dao/BoletoDAO.php');
class BoletoController {
// funcao p/ gerar o proximo nosso numero que é sequencia e de controle da empresa
public function getNextNossoNumero() {
$boleto = new BoletoDAO();
$numRetorno = $boleto->getNextNossoNum();
return $numRetorno;
}
// veja como passar um TIPO de objeto p/ uma função. isso sim é moderno :)
public function salvarBoleto(Boleto $Boleto) {
$boletoC = new BoletoDAO();
$salvarBoleto = $boletoC->salvarBoleto($Boleto);
return $salvarBoleto;
}
public function listarBoletos() {
$boletoD = new BoletoDAO();
$boletoArr = $boletoD->getBoletos();
return $boletoArr; // retorna um array de Objetos Boletos
}
// aqui que é feita a divisão dos registros em blocos.
// Observe que passaremos um objeto Boleto para utilizar na busca
public function getDadosPaginados($primeiroRegistro, $numPorPagina, Boleto $buscaBoleto) {
$boletoD = new BoletoDAO();
$boletoArr = $boletoD->getClientesPaginados($primeiroRegistro, $numPorPagina, $buscaBoleto);
return $boletoArr; // retorna um array de Objetos Boletos
}
// essa funcao é usada pegar o total de registros p/ fazer a paginacao.
// é o mesmo objeto, passado p/ a função getDadosPaginados
public function getTotalBoletos(Boleto $buscaBoleto) {
$boletoD = new BoletoDAO();
$total = $boletoD->contaTotalBoletos($buscaBoleto);
return $total;
}
}
?>
DAO<?php
//@arquivo /app/dao/BoletoDAO.php
require_once($_SERVER['DOCUMENT_ROOT'] . '/lib/Conexao.php');
require_once($_SERVER['DOCUMENT_ROOT'] . '/app/model/Boleto.php');
class BoletoDAO {
public function BoletoDAO() { }
// essa funcao sera utilizada qdo for criado um novo boleto
public function getNextNossoNum() {
$numRetorno = 1000001; // nº inicial
$sqlQuery = "select max(valor) + 1 as valor from boleto_seq ";
$conexao = new Conexao();
$conexao->conecta();
$rs = $conexao->executeQuery($sqlQuery);
if ($row = mysql_fetch_array($rs)) { // parece estranho. mas só preciso de 1 registro
$numRetorno = $row['valor'];
}
$conexao->desconecta();
return $numRetorno;
}
public function salvarBoleto(Boleto $Boleto) {
$sqlQueryInsert = "INSERT INTO `mydb`.`boleto`
(
`nosso_num`,
`data_vencimento`,
`data_documento`,
`valor`,
`nota_fiscal`,
`discriminacao`,
`id_cliente`,
`sacado`,
`linha_digitavel`)
VALUES
(
'" . $Boleto->getNossoNum() . "',
STR_TO_DATE('" . $Boleto->getDataVencimento() . "','%d/%m/%Y') ,
STR_TO_DATE('" . $Boleto->getDataDocumento() . "','%d/%m/%Y') ,
" . $Boleto->getValor() . ",
'" . $Boleto->getNotaFiscal() . "',
'" . $Boleto->getDiscriminacao() . "',
" . $Boleto->getIdCliente() . ",
'" . $Boleto->getSacado() . "',
'" . $Boleto->getLinhaDigitavel() . "'
);";
// die($sqlQueryInsert);
$conexao = new Conexao();
$conexao->conecta();
$rsInsert = $conexao->executeUpdate($sqlQueryInsert);
// se inseriu, precisa incrementar a tabela que controla os NossoNumº
// poderia fazer uma trigger, mas nao vem ao caso
if ($rsInsert) {
$sqlQuery = "select max(valor) + 1 as valor from boleto_seq ";
$rs = $conexao->executeQuery($sqlQuery);
while ($row = mysql_fetch_array($rs)) {
$numRetorno = $row['valor'];
}
$sqlIncrement = "INSERT into boleto_seq (valor) values($numRetorno) ";
// die($sqlIncrement);
$rsInsert2 = $conexao->executeUpdate($sqlIncrement);
}
// apos realizar 2 inserts e uma consulta, pode fechar a conexao
$conexao->desconecta();
return true;
}
//lista simples dos boletos
public function getBoletos() {
// $sqlQuery = "Select * from boleto"; // apenas p/ ilustrar , nunca use SELECT *
$sqlQuery = "SELECT
`boleto`.`id`,
`boleto`.`nosso_num`,
`boleto`.`data_vencimento`,
`boleto`.`data_documento`,
`boleto`.`valor`,
`boleto`.`nota_fiscal`,
`boleto`.`discriminacao`,
`boleto`.`id_cliente`,
`boleto`.`sacado`,
`boleto`.`linha_digitavel`,
`boleto`.`pago`
FROM `mydb`.`boleto`"; //
$conexao = new Conexao();
$conexao->conecta();
$boletoArr = array(); // esse é o Array de boletos
$cnt = 0; // criei p/ controlar o indice, poderia usar array_push($boletoArr, $boleto)
$rsInsert = $conexao->executeQuery($sqlQuery);
while ($row = mysql_fetch_array($rsInsert)) {
$boleto = new Boleto();
$boleto->setId($row['id']);
$boleto->setNossoNum($row['nosso_num']);
$boleto->setDataVencimento($row['data_vencimento']);
$boleto->setDataDocumento($row['data_documento']);
$boleto->setValor($row['valor']);
$boleto->setNotaFiscal($row['nota_fiscal']);
$boleto->setDiscriminacao($row['discriminacao']);
$boleto->setIdCliente($row['id_cliente']);
$boleto->setSacado($row['sacado']);
$boleto->setLinhaDigitavel($row['linha_digitavel']);
$boleto->setPago($row['pago']);
//array_push($boletoArr, $boleto); // se eu nao estivesse usando um indice
$boletoArr[$cnt] = $boleto;// armazena um objeto Boleto no array
$cnt++;
}
$conexao->desconecta();
return $boletoArr; // retorna o array de boletos
}
/*
* Em vez de ficar verificando se ja existe WHERE na consulta
* inicio as duas consultas com o parametro : "WHERE id is not null" que sempre
* será verdadeiro, ae sim acrescento os filtros usando AND e como o filtro das duas
* consultas será o mesmo criei a funcao montaFiltroPaginacao que recebe um boleto
* como parametro, e retorna o SQL complementar as consultas base
*/
// essa funcao é usada pegar o total de registros p/ fazer a paginacao.
public function contaTotalBoletos(Boleto $boleto) {
$conexao = new Conexao();
$conexao->conecta();
$sqlQuery = "SELECT COUNT(*) as total FROM mydb.boleto B WHERE id is not null ";
$sqlQuery .= $this->montaFiltroPaginacao($boleto);
$rs = $conexao->executeQuery($sqlQuery);
$total = 0;
while ($row = mysql_fetch_array($rs)) {
$total = $row['total'];
}
$conexao->desconecta();
return $total;
}
// essa funcao é usada p/ fazer a paginacao.
public function getClientesPaginados($primeiroRegistro, $numPorPagina, Boleto $boleto) {
$sqlQuery = "Select B.*,
DATE_FORMAT(B.data_documento,'%d/%m/%Y') as data_documento,
DATE_FORMAT(B.data_vencimento,'%d/%m/%Y') as data_vencimento
from boleto B WHERE id is not null ";
$sqlQuery .= $this->montaFiltroPaginacao($boleto);
$sqlQuery.= " LIMIT " . $primeiroRegistro . "," . $numPorPagina; // esse é segredo da divisao
$conexao = new Conexao();
$conexao->conecta();
$rs = $conexao->executeQuery($sqlQuery);
$boletoArr = array();
$cnt = 0;
while ($row = mysql_fetch_array($rs)) {
$B = new Boleto();
$B->setId($row['id']);
$B->setNossoNum($row['nosso_num']);
$B->setDataVencimento($row['data_vencimento']);
$B->setDataDocumento($row['data_documento']);
$B->setValor($row['valor']);
$B->setNotaFiscal($row['nota_fiscal']);
$B->setDiscriminacao($row['discriminacao']);
$B->setIdCliente($row['id_cliente']);
$B->setSacado($row['sacado']);
$B->setLinhaDigitavel($row['linha_digitavel']);
$B->setPago($row['pago']);
$boletoArr[$cnt] = $B;
$cnt++;
}
$conexao->desconecta();
return $boletoArr; //retorna o array de boletos de acordo com a pagina que sera controlada na view
}
//funcao utilizada para aplicar o filtro na pesquisa
public function montaFiltroPaginacao(Boleto $boleto){
$sqlQuery="";
if ($boleto->getNossoNum() != NULL) {
$sqlQuery.=" AND B.nosso_num like '%" . $boleto->getNossoNum() . "%' ";
}
if ($boleto->getValor() != NULL) {
$sqlQuery.=" AND B.valor =" . $boleto->getValor() . " ";
}
if ($boleto->getDataDocumento() != NULL) {
$sqlQuery.=" AND B.data_documento = STR_TO_DATE('" . $boleto->getDataDocumento() . "','%d/%m/%Y') ";
}
if ($boleto->getDataVencimento() != NULL) {
$sqlQuery.=" AND B.data_vencimento = STR_TO_DATE('" . $boleto->getDataVencimento() . "','%d/%m/%Y') ";
}
if ($boleto->getIdCliente() != NULL) {
$sqlQuery.=" AND B.id_cliente = " . $boleto->getIdCliente() . " ";
}
if ($boleto->isPago()) {
$sqlQuery.=" AND B.pago = 1 ";
}
return $sqlQuery;
}
}
?>
VIEWAssumindo que você já viu os 2 posts anteriores, e o cliente já está logado, com a estrutura acima explicada, precisamos apenas definir na view
o nº de Registros por página, a página em que está, e objeto Boleto que será mantido na busca durante a paginacao.
Lembre-se que essa página privado.php já fez os includes necessários de todas as classes que utilizaremos abaixo.
codigo necessário para fazer a paginação: obs: não vou incluir a parte da pesquisa para focar na paginação e no final eu mostro o arquivo inteiro
<?
//@arquivo=/app/view/Boleto/index.php
/* arquivo q ja estao sendo incluidos
require_once($_SERVER['DOCUMENT_ROOT'] . '/app/model/Boleto.php');
require_once($_SERVER['DOCUMENT_ROOT'] . '/app/controller/BoletoController.php');
*/
session_start();
error_reporting('E_ALL');
// define registros por pagina
$numPorPagina = 5;
//base p/ gerar os links
$basePage = $_SESSION['user']['view'] . "?section=boletos&action=index";
// acrescenta o parametro pagina no link, o valor sera gerado ao carregar
$basePage .="&pagina=";
if (isset($_GET['pagina'])) {
$pagina = $_GET['pagina'];
} else {
$pagina = 1;
}
//trava palhaçadas, como tentar passar numeros negativos na url
if ($pagina <= 0) {
header("Location:" . $basePage . "1");
}
// 1º registro do Bloco
$primeiroRegistro = ($pagina * $numPorPagina) - $numPorPagina;
// observe o objeto boletoBusca usado nas duas funcoes
$BoletoC = new BoletoController();
$cache = $BoletoC->getDadosPaginados($primeiroRegistro, $numPorPagina, $boletoBusca); // carrega os registros do array
$totalRegistros = $BoletoC->getTotalBoletos($boletoBusca); // pega o total de boletos
$totalPaginas = ceil($totalRegistros / $numPorPagina); // ceil arredonda p/ maior , exemplo 1.65 sao 2 paginas
$anterior = $pagina - 1;
$proximo = $pagina + 1;
//trava palhaçadas , tipo colocar um nº maior do que o total de paginas
if ($pagina > $totalPaginas) {
header("Location:" . $basePage . $totalPaginas);
}
?>
<!-- SECAO DADOS-->
<table width="85%" border="0" cellspacing="2" cellpadding="0">
<tr>
<th>ID</th>
<th>SACADO</th>
<th>NOSSO NUM</th>
<th>DATA DOC</th>
<th>DATA VENC</th>
<th>VALOR</th>
<th>ações</th>
</tr>
<? if (count($cache) > 0) {
for ($i = 0; $i < count($cache); $i++) {
$B = new Boleto();
$B = $cache[$i];
$idBoleto = $B->getId();
?>
<tr>
<td><? echo $idBoleto; ?></td>
<td><? echo $B->getSacado(); ?></td>
<td><? echo $B->getNossoNum(); ?></td>
<td><? echo $B->getDataDocumento(); ?></td>
<td><? echo $B->getDataVencimento(); ?></td>
<td><? echo $B->getValor(); ?></td>
<td class="actions">
<a href="<? echo $_SESSION['user']['view']; ?>?section=boletos&action=view&id=<? echo $idBoleto; ?>"><img src="/images/search-menor.png"></a>|
</td>
</tr>
<? } ?>
<tr>
<td colspan="7"><hr width="100%" size="1" /></td>
</tr>
<tr>
<td colspan="7"><? echo $primeiro = ($primeiroRegistro <= 0) ? "1" : $primeiroRegistro; ?> até <?
echo $ultimo = ($totalRegistros <= ($primeiroRegistro + $numPorPagina) ? $totalRegistros : ($primeiroRegistro + $numPorPagina));
?> de <? echo $totalRegistros; ?></td>
</tr>
</table>
<!-- SECAO BARRA DE NAVEGACAO -->
<div class="paging">
<? if ($pagina <= 1) { ?>
<span class="prev disabled">< anterior</span>
<? } else { ?>
<span class="prev"><a href=" <? echo $basePage . $anterior; ?>"><anterior</a></span>
<? } ?>
<?
for ($z = 1; $z <= $totalPaginas; $z++) {
if ($z != $pagina) {
?> <a href="<? echo $basePage . $z; ?>"><? echo $z; ?></a>
<? } else { ?>
<? echo $z; ?>
<? } ?>
<? } ?>
<? if ($pagina == $totalPaginas) { ?>
<span class="next disabled">próxima ></span>
<? } else { ?>
<span class="next"><a href="<? echo $basePage . $proximo; ?>">próxima ></a></span>
<? } ?>
</div>
<!-- FIM SECAO BARRA DE NAVEGACAO -->
</div>
<? } else {// se a consulta retornar 0 registros ?>
<tr>
<td colspan="5">Boleto não econtrado.</td>
</tr>
</table>
</div>
<? } ?>
<!-- FIM SECAO DADOS-->
Simples hein ? agora vamos adicionar a parte php da carga do boletoBusca e a parte html da busca em cima da seção DADOS.PHP
<?
// apenas usado p/ realizar a busca, caso seja utilizada
$boletoBusca = new Boleto();
if ((isset($_GET['nosso_num'])) && ($_GET['nosso_num'] != "")) {
$boletoBusca->setNossoNum($_GET['nosso_num']);
$basePage.="&nosso_num=" . $_GET['nosso_num'];
}
if ((isset($_GET['valor'])) && ($_GET['valor'] != "")) {
$boletoBusca->setValor($_GET['valor']);
$basePage.="&valor=" . $_GET['valor'];
}
if ((isset($_GET['data_doc'])) && ($_GET['data_doc'] != "")) {
$boletoBusca->setDataDocumento($_GET['data_doc']);
$basePage.="&data_doc=" . $_GET['data_doc'];
}
if ((isset($_GET['data_venc'])) && ($_GET['data_venc'] != "")) {
$boletoBusca->setDataVencimento($_GET['data_venc']);
$basePage.="&data_venc=" . $_GET['data_venc'];
}
if ((isset($_GET['clienteId'])) && ($_GET['clienteId'] != 'todos')) {
$boletoBusca->setIdCliente($_GET['clienteId']);
$basePage.="&clienteId=" . $_GET['clienteId'];
}
if ((isset($_GET['pago']))) {
$boletoBusca->setPago(1);
$basePage.="&pago=1";
}
?>
HTML, observe que os campos já vem preenchidos com os parâmetros da busca<!-- SECAO BUSCA -->
<div id="busca">
<fieldset>
<form id="formBusca" name="formBusca" method="GET" action="<? echo $_SESSION['user']['view']; ?>">
<table style="width: auto;">
<tr>
<th colspan="2">Localizar Boleto:<th>
</tr>
<tr>
<td>Nosso Nº:</td><td><input type="text" name="nosso_num" id="nossoNum" value="<? echo $boletoBusca->getNossoNum(); ?>"></td>
</tr>
<tr>
<td>
Valor:</td><td><input type="text" name="valor" id="valor" value="<? echo $boletoBusca->getValor(); ?>">
</td>
</tr>
<tr>
<td>
Data Doc:</td><td><input type="text" name="data_doc" id="dataDoc" size="16" value="<? echo $boletoBusca->getDataDocumento(); ?>">
</td>
</tr>
<tr>
<td>
Pago:</td><td><input type="checkbox" name="pago" id="pago" <? if ($boletoBusca->isPago()) {
echo "checked=\"checked\"";
} ?> value="<? echo $boletoBusca->isPago(); ?>">
</td>
</tr>
<tr>
<td>
Data Venc:</td><td><input type="text" name="data_venc" id="dataVenc" size="16" value="<? echo $boletoBusca->getDataVencimento(); ?>">
</td>
</tr>
<tr>
<td>
Cliente:</td><td>
<input name="data[OS][busca_cliente]" maxlength="30" type="text" id="buscaCliente" />
<span class="actions">
<input type="button" value="Buscar Cliente" id="busca2"/>
</span>
</td>
</tr>
<tr>
<td>Cliente Selecionado</td>
<td>
<select name="clienteId" id="clienteId">
<option value="todos">todos</option>
<? // essa parte apenas enche o combo com os clientes retornados da consulta
if ($boletoBusca->getIdCliente() != NULL) {
$clienteC = new ClienteController();
$clienteC->loadOptions($boletoBusca->getIdCliente());
}
?>
</select>
</td>
</tr>
<tr>
<td colspan="2">
<input type="hidden" name="section" id="section" value="boletos">
<input type="hidden" name="action" id="action" value="index">
<input type="hidden" name="pagina" id="pagina" value="1">
<!-- ao clicar no botao pesquisar sempre iniciará uma nova pesquisa por isso
pagina=1 -->
<div class="submit">
<input type="submit" value="Buscar">
</div>
</td>
</tr>
</table>
</form>
</fieldset>
</div>
<!-- FIM SECAO BUSCA-->
E está feita a paginação de registros. Porém existe uma particularidade nessa busca. Não faz sentido nessa busca, pesquisar nomes de clientes que não existam, Então ao preencher o campo busca_cliente ou clicar no botão "buscar cliente" um ajax busca uma lista de clientes e enche o combo com os resultados, realizando o objetivo de filtrar os boletos por Cliente.
Porque isso? imagine se tivesse 3000 clientes o tamanho q essa lista ficaria. ... então é melhor filtrar ;)
cuidado ao utilizar ajax p/ não expor dados sigilosos. pesquise no google "cross-site scripting ajax" ou "Cross-site request forgery"
parte do ajax
<?
session_start();
require_once($_SERVER['DOCUMENT_ROOT'] . '/lib/block.php');
/*
@arquivo = /ajax/clientes.php
MVC : model
objeto : Cliente
tabela : clientes
obs : responde a requisições ajax e monta as options do combo clientes
*/
require_once($_SERVER['DOCUMENT_ROOT'] . '/app/model/Cliente.php');
require_once($_SERVER['DOCUMENT_ROOT'] . '/app/controller/ClienteController.php');
//jeito inseguro
//
//if (isset($_GET['busca'])) {
// $busca = $_GET['busca'];
// $cliente = new ClienteController();
// if (isset($_GET['incluirOpcao']) && $_GET['incluirOpcao'] == 'todos') {
// echo "<option value=\"todos\" selected=\"selected\" >todos</option>";
// }
// if ($busca != "") {
// $cliente->buscaOptions($busca);
// }
//}
//jeito mais seguro
if (isset($_POST['busca'])) {
$busca = $_POST['busca'];
$clienteC = new ClienteController();
$todos = false;
if (isset($_POST['incluirOpcao']) && $_POST['incluirOpcao'] == 'todos') {
// echo "<option value=\"todos\" selected=\"selected\" >todos</option>";
$todos = true;
$primeiroCliente= new Cliente();
$primeiroCliente->setId('todos');
$primeiroCliente->setNome('todos');
}
if ($busca != "") {
$arrClientes= $clienteC->getListaClientesAjax($busca);
}
// ternary way
// $increment=$todos==true?array_shift($arrClientes,$primeiroCliente):null;
// if ($todos){array_shift($arrClientes,$primeiroCliente);}
$conta=0;
if ($todos){
$arrtmp[$conta]=
(array(
"id"=>$primeiroCliente->getId(),
"nome"=>$primeiroCliente->getNome()
));
$conta++;
}
foreach ($arrClientes as $cliente) {
$arrtmp[$conta]=
(array(
"id"=>$cliente->getId(),
"nome"=>$cliente->getNome()
));
$conta++;
}
echo json_encode($arrtmp);
}
// like a beam , but not java
if (isset($_POST['cliente_id'])){
$clienteId=$_POST['cliente_id'];
$clienteC = new ClienteController();
$cliente = new Cliente();
$cliente = $clienteC->loadDados($clienteId);
echo json_encode(array(
"id"=>$cliente->getId(),
"nome"=>$cliente->getNome(),
"tipo_cliente"=>$cliente->getTipoCliente(),
"cpf"=>$cliente->getCpf(),
"cnpj"=>$cliente->getCnpj()
));
}
?>
//complementar ao ajax :o clienteCOntroller
<?
/*
@arquivo = /app/controller/ClienteController.php
MVC : controller
objeto : Cliente
*/
require_once($_SERVER['DOCUMENT_ROOT'] . '/app/model/Cliente.php');
require_once($_SERVER['DOCUMENT_ROOT'] . '/app/dao/ClienteDAO.php');
Class ClienteController {
public function buscaOptions($busca) {
$clienteDAO = new ClienteDAO();
$clientes = $clienteDAO->getClientesBusca($busca);
$conta = 0;
foreach ($clientes as $cliente) {
echo "<option value=\"" . $cliente->getId() . "\" >" . $cliente->getNome() . "</option> \n";
$conta++;
}
if ($conta == 0) {
echo "<option value=\"0\" selected=\"selected\" > cliente não encontrado </option> \n";
}
}
public function getListaClientesAjax($busca) {
$clienteDAO = new ClienteDAO();
$arrClientes = $clienteDAO->getClientesBusca($busca);
if (count($arrClientes)==0){
return NULL;
}else {
return $arrClientes;
}
}?>
e o clienteDAO
<?php
// @arquivo = /app/dao/ClienteDAO.php
// MVC : controller
// objeto : Cliente
require_once($_SERVER['DOCUMENT_ROOT'] . '/app/model/Cliente.php');
require_once($_SERVER['DOCUMENT_ROOT'] . '/lib/Conexao.php');
class ClienteDAO {
public function ClienteDAO() {
}
public function getClientesBusca($busca) {
$arrClientes = array();
$indice = 0;
$sqlQuery = "Select id,nome from cliente where nome like '%" . $busca . "%' order by nome";
$conexao = new Conexao();
$conexao->conecta();
$rs = $conexao->executeQuery($sqlQuery);
while ($row = mysql_fetch_array($rs)) {
$cliente = new Cliente();
$cliente->setId($row['id']);
$cliente->setNome($row['nome']);
$arrClientes[$indice] = $cliente;
$indice++;
}
$conexao->desconecta();
return $arrClientes;
}
}?>
Agora vejamos pagina completa :
<?
session_start();
error_reporting('E_ALL');
require_once($_SERVER['DOCUMENT_ROOT'] . '/app/controller/ClienteController.php');
// define registros por pagina
$numPorPagina = 5;
//base p/ gerar os links
$basePage = $_SESSION['user']['view'] . "?section=boletos&action=index";
// apenas usado p/ realizar a busca, caso seja utilizada
$boletoBusca = new Boleto();
if ((isset($_GET['nosso_num'])) && ($_GET['nosso_num'] != "")) {
$boletoBusca->setNossoNum($_GET['nosso_num']);
$basePage.="&nosso_num=" . $_GET['nosso_num'];
}
if ((isset($_GET['valor'])) && ($_GET['valor'] != "")) {
$boletoBusca->setValor($_GET['valor']);
$basePage.="&valor=" . $_GET['valor'];
}
if ((isset($_GET['data_doc'])) && ($_GET['data_doc'] != "")) {
$boletoBusca->setDataDocumento($_GET['data_doc']);
$basePage.="&data_doc=" . $_GET['data_doc'];
}
if ((isset($_GET['data_venc'])) && ($_GET['data_venc'] != "")) {
$boletoBusca->setDataVencimento($_GET['data_venc']);
$basePage.="&data_venc=" . $_GET['data_venc'];
}
if ((isset($_GET['clienteId'])) && ($_GET['clienteId'] != 'todos')) {
$boletoBusca->setIdCliente($_GET['clienteId']);
$basePage.="&clienteId=" . $_GET['clienteId'];
}
if ((isset($_GET['pago']))) {
$boletoBusca->setPago(1);
$basePage.="&pago=1";
}
// acrescenta o parametro pagina no link, o valor sera gerado ao carregar
$basePage .="&pagina=";
if (isset($_GET['pagina'])) {
$pagina = $_GET['pagina'];
} else {
$pagina = 1;
}
//trava palhaçadas, como tentar passar numeros negativos na url
if ($pagina <= 0) {
header("Location:" . $basePage . "1");
}
// 1º registro do Bloco
$primeiroRegistro = ($pagina * $numPorPagina) - $numPorPagina;
// observe o objeto boletoBusca usado nas duas funcoes
$BoletoC = new BoletoController();
$cache = $BoletoC->getDadosPaginados($primeiroRegistro, $numPorPagina, $boletoBusca); // carrega os registros do array
$totalRegistros = $BoletoC->getTotalBoletos($boletoBusca); // pega o total de boletos
$totalPaginas = ceil($totalRegistros / $numPorPagina); // ceil arredonda p/ maior , exemplo 1.65 sao 2 paginas
$anterior = $pagina - 1;
$proximo = $pagina + 1;
//trava palhaçadas , tipo colocar um nº maior do que o total de paginas
if ($pagina > $totalPaginas) {
header("Location:" . $basePage . $totalPaginas);
}
?>
<div class="index">
<h3>Seção : boletos:</h3>
<!-- SECAO BUSCA -->
<div id="busca">
<fieldset>
<form id="formBusca" name="formBusca" method="GET" action="<? echo $_SESSION['user']['view']; ?>">
<table style="width: auto;">
<tr>
<th colspan="2">Localizar Boleto:<th>
</tr>
<tr>
<td>Nosso Nº:</td><td><input type="text" name="nosso_num" id="nossoNum" value="<? echo $boletoBusca->getNossoNum(); ?>"></td>
</tr>
<tr>
<td>
Valor:</td><td><input type="text" name="valor" id="valor" value="<? echo $boletoBusca->getValor(); ?>">
</td>
</tr>
<tr>
<td>
Data Doc:</td><td><input type="text" name="data_doc" id="dataDoc" size="16" value="<? echo $boletoBusca->getDataDocumento(); ?>">
</td>
</tr>
<tr>
<td>
Pago:</td><td><input type="checkbox" name="pago" id="pago" <? if ($boletoBusca->isPago()) {
echo "checked=\"checked\"";
} ?> value="<? echo $boletoBusca->isPago(); ?>">
</td>
</tr>
<tr>
<td>
Data Venc:</td><td><input type="text" name="data_venc" id="dataVenc" size="16" value="<? echo $boletoBusca->getDataVencimento(); ?>">
</td>
</tr>
<tr>
<td>
Cliente:</td><td>
<input name="data[OS][busca_cliente]" maxlength="30" type="text" id="buscaCliente" />
<span class="actions">
<input type="button" value="Buscar Cliente" id="busca2"/>
</span>
</td>
</tr>
<tr>
<td>Cliente Selecionado</td>
<td>
<select name="clienteId" id="clienteId">
<option value="todos">todos</option>
<? // essa parte apenas enche o combo com os clientes retornados da consulta
if ($boletoBusca->getIdCliente() != NULL) {
$clienteC = new ClienteController();
$clienteC->loadOptions($boletoBusca->getIdCliente());
}
?>
</select>
</td>
</tr>
<tr>
<td colspan="2">
<input type="hidden" name="section" id="section" value="boletos">
<input type="hidden" name="action" id="action" value="index">
<input type="hidden" name="pagina" id="pagina" value="1">
<div class="submit">
<input type="submit" value="Buscar">
</div>
</td>
</tr>
</table>
</form>
</fieldset>
</div>
<!-- FIM SECAO BUSCA-->
<!-- SECAO DADOS-->
<table width="85%" border="0" cellspacing="2" cellpadding="0">
<tr>
<th>ID</th>
<th>SACADO</th>
<th>NOSSO NUM</th>
<th>DATA DOC</th>
<th>DATA VENC</th>
<th>VALOR</th>
<th>ações</th>
</tr>
<? if (count($cache) > 0) {
for ($i = 0; $i < count($cache); $i++) {
$B = new Boleto();
$B = $cache[$i];
$idBoleto = $B->getId();
?>
<tr>
<td><? echo $idBoleto; ?></td>
<td><? echo $B->getSacado(); ?></td>
<td><? echo $B->getNossoNum(); ?></td>
<td><? echo $B->getDataDocumento(); ?></td>
<td><? echo $B->getDataVencimento(); ?></td>
<td><? echo $B->getValor(); ?></td>
<td class="actions">
<a href="<? echo $_SESSION['user']['view']; ?>?section=boletos&action=view&id=<? echo $idBoleto; ?>"><img src="/images/search-menor.png"></a>|
</td>
</tr>
<? } ?>
<tr>
<td colspan="7"><hr width="100%" size="1" /></td>
</tr>
<tr>
<td colspan="7"><? echo $primeiro = ($primeiroRegistro <= 0) ? "1" : $primeiroRegistro; ?> até <?
echo $ultimo = ($totalRegistros <= ($primeiroRegistro + $numPorPagina) ? $totalRegistros : ($primeiroRegistro + $numPorPagina));
?> de <? echo $totalRegistros; ?></td>
</tr>
</table>
<!-- SECAO BARRA DE NAVEGACAO -->
<div class="paging">
<? if ($pagina <= 1) { ?>
<span class="prev disabled">< anterior</span>
<? } else { ?>
<span class="prev"><a href=" <? echo $basePage . $anterior; ?>"><anterior</a></span>
<? } ?>
<?
for ($z = 1; $z <= $totalPaginas; $z++) {
if ($z != $pagina) {
?> <a href="<? echo $basePage . $z; ?>"><? echo $z; ?></a>
<? } else { ?>
<? echo $z; ?>
<? } ?>
<? } ?>
<? if ($pagina == $totalPaginas) { ?>
<span class="next disabled">próxima ></span>
<? } else { ?>
<span class="next"><a href="<? echo $basePage . $proximo; ?>">próxima ></a></span>
<? } ?>
</div>
<!-- FIM SECAO BARRA DE NAVEGACAO -->
</div>
<? } else {// se a consulta retornar 0 registros ?>
<tr>
<td colspan="5">Boleto não econtrado.</td>
</tr>
</table>
</div>
<? } ?>
<!-- FIM SECAO DADOS-->
<!-- SECAO NOVO -->
<div class="actions">
<h3>Ações</h3>
<ul>
<li><a style="width: 80px;" href="<? echo $_SESSION['user']['view']; ?>?section=boletos&action=add">Novo Boleto</a></li>
</ul>
</div>
<!-- FIM SECAO NOVO -->
e no final da pagina
<script type="text/javascript">
$(document).ready(function() {
$(function(){
$("#dataDoc").mask("99/99/9999");
$("#dataVenc").mask("99/99/9999");
});
$('#buscaCliente').change(function(){
// JEITO INSEGURO
// $('#clienteId').load('/ajax/clientes.php?incluirOpcao=todos&busca='+$('#buscaCliente').val(),function(){
// $('#clienteId').each(function(){
// if (this.value==""){
// alert('cliente nao econtrado');
// }
// });
//
// }) ;
// JEITO SEGURO
if ( $('#buscaCliente').val()!='') {
var dataString='incluirOpcao=todos&busca='+$('#buscaCliente').val();
$('#clienteId').empty(); // limpa o select
$.post("/ajax/clientes.php", dataString,
function(data) {
var conta=0;
$.each(data,function(){
$('#clienteId').append("<option value="+this['id']+">"+this['nome']+"</option>");
// alert(data);
// alert(this);
conta++;
})
if (conta==1){ // o 1º é o todos
alert('nenhum cliente econtrado');
}
},"json");
}
});
});
</script>
E assim está concluída nossa paginação registros com opções de filtragem/busca. Para complementar vou mostrar os principais trechos das duas paginas que salvam os boletos. Eis o formulário após a geração do boleto.
<br> <form action="/app/controller/PostController.php" method="post"> <input type="hidden" name="data[boleto][operacao]" value="novo"/> <input type="hidden" name="data[boleto][id_cliente]" value="<? echo $_POST['id_cliente'];?>"/> <input type="hidden" name="data[boleto][nossoNum]" value="<? echo $dadosboleto["nosso_numero"]; ?>"/> <input type="hidden" name="data[boleto][dataVencimento]" value="<? echo $dadosboleto["data_vencimento"] ;?>"/> <input type="hidden" name="data[boleto][dataDocumento]" value="<? echo $dadosboleto["data_documento"];?>"/> <input type="hidden" name="data[boleto][valorBoleto]" value="<? echo number_format($dadosboleto["valor_boleto"],2,'.','') ;?>"/> <input type="hidden" name="data[boleto][sacado]" value="<? echo $dadosboleto["sacado"] ;?>"/> <input type="hidden" name="data[boleto][nf]" value="<? echo $dadosboleto["nu_doc"] ;?>"/> <input type="hidden" name="data[boleto][discriminacao]" value="<? echo $dadosboleto["demonstrativo1"] ;?>"/> <input type="hidden" name="data[boleto][doc_cliente]" value="<? echo $dadosboleto["cnpj_sacado"];?>"/> <input type="hidden" name="data[boleto][linha_digitavel]" value="<? echo $dadosboleto["linha_digitavel"];?>"/> <button>Salvar</button> </form>
e o PostController que recebe e trata os formularios, esta seção abaixo salva o boleto.
<?php
session_start();
require_once($_SERVER['DOCUMENT_ROOT'] . '/app/model/Boleto.php');
require_once($_SERVER['DOCUMENT_ROOT'] . '/app/controller/BoletoController.php');
//echo "<pre>";
//print_r($_POST);
//echo "</pre>";
if (isset($_POST['data']['boleto']['operacao'])) {
$nossoNum=$_POST['data']['boleto']['nossoNum'];
$dataVencimento=$_POST['data']['boleto']['dataVencimento'];
$dataDocumento=$_POST['data']['boleto']['dataDocumento'];
$valor=$_POST['data']['boleto']['valorBoleto'];
$notaFiscal=$_POST['data']['boleto']['nf'];
$discriminacao=$_POST['data']['boleto']['discriminacao'];
$idCliente =$_POST['data']['boleto']['id_cliente'];
$sacado = $_POST['data']['boleto']['sacado'];
$linhaDigitavel = $_POST['data']['boleto']['linha_digitavel'];
$B= new Boleto();
$B->setNossoNum($nossoNum);
$B->setDataVencimento($dataVencimento);
$B->setDataDocumento($dataDocumento);
$B->setValor($valor);
$B->setNotaFiscal($notaFiscal);
$B->setDiscriminacao($discriminacao);
$B->setIdCliente($idCliente);
$B->setSacado($sacado);
$B->setLinhaDigitavel($linhaDigitavel);
$boletoC = new BoletoController();
$boletoC->salvarBoleto($B);
$urlToGo = $_SESSION['user']['view']."?section=boletos&action=index&flash=boleto&resultado=3";
header("Location: $urlToGo");
}
?>
Até a próxima...




4 comentários:
Como sempre, otimo material professor.
Marcello Nicollette
Otimo material, tem como enviar ele completo para o meu email para que possa estudar, inclusive as partes de crud num pagina php, na hora de inserir, remover e edita e listar
marcela@gmail.com
Pesquisando sobre o MVC encontrei os seus artigos e achei muito interessante. Você poderia enviar o material completo para facilitar o entendimento, visualizar melhor a estrutura de diretório, etc. marcospmsantos@gmail.com
Postar um comentário