Edição de clientes com Modal do Bootstrap e CodeIgniter

UPDATE 14/11/2014

Atenção, muitos visitantes têm reclamado de um erro que acontece ao rodar este projeto, mesmo baixando o arquivo zipado aqui do site. O erro que acontece é que a view não encontra a variável $clientes que vem do controller. Na verdade não é um problema no código.

Em meus projetos eu costumo trabalhar como short_open_tag PHP habilitado. Isso server para não precisar escrever <?php ?> no código, mas somente <? ?>.

Pra resolver o problema do projeto, basta habilitar essa função no seu PHP. Abra o php.ini e procure por short_open_tag, então, tire o comentário do começo da linha, salve e reinicie o apache. Ou então, troque no código tudo que tem <?  ?> por <?php ?>, tomando o cuidado para quando tiver assim: <?= ?>, trocar por isso: <?php echo ?>.

Olá

O post de hoje é especialmente importante pois é algo que eu sempre vejo pessoas tendo dúvidas em como fazer isto, ou em como integrar várias soluções juntas

Neste post eu vou explicar detalhadamente como funciona um pequeno cadastro de clientes que fiz, onde eu integrei diversas soluções.

Veja abaixo quais soluções estão presentes neste pequeno sistema:

Eu vou partir do princípio que você já saiba como Instalar o CodeIgniter, a como configurá-lo para acessar um Banco de Dados e como funciona o padrão MVC. Caso não sabia, recomendo que leia os posts antes.

Para não ficar tão grande o post, eu vou explicar as partes mais importantes de cada arquivo.

O sistema funciona assim: ao abri-lo, uma tabela é preenchida com os dados de vários clientes cadastrados no banco de dados, neste caso, somente os campos Nome e Email, e uma terceira coluna para a Ação, que somente fará a Edição dos dados do Clientes.

Não estou abordando aqui a inserção e a deleção, mas como a Edição é a parte mais complicada, acredito que você tenha condições em adaptar o sistema para inserir e excluir clientes.

Quando o usuário clica no botão Editar, abre-se uma janela Modal do Bootstrap com os dois campos Nome e Email já preenchidos com os dados do cliente escolhido.

Ao clicar no botão Salvar Alterações, estes dados são salvos no banco de dados.

Bem simples e objetivo, mas acredito que serve como base para muitos que estão patinando nesta área.

O código está bem comentado e é bem pequeno.

O código abaixo é o controller home.php, que é responsável para fazer aparecer a primeira página do sistema. É dentro da função index() deste controller que conecto ao banco de dados e atribuo à variável $clientes a lista de clientes, que será enviada à view:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Home extends CI_Controller {

	/*
	 * Esta função carrega a tela inicial com os dados da tabela clientes.
	 * Carrego o model de clientes, depois chamo função clientes() dentro do model que me traz os dados do cliente
	 */
	public function index()
	{
		$this->load->model("m_clientes", "clientes");
		
		$dados['clientes'] = $this->clientes->clientes();
		
		$this->load->view('home', $dados);
	}
}

 

Abaixo vemos a view home.php, que é responsável por carregar o Bootstrap, JavaScripts e mostrar os dados do cliente na tela:

<!DOCTYPE html>
<html lang="pt-br">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Mini cadastro de Clientes</title>

    <!-- Bootstrap core CSS -->
    <link href="<?= base_url('includes/bootstrap/css/bootstrap.min.css') ?>" rel="stylesheet">

	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="<?= base_url('includes/bootstrap/js/bootstrap.min.js') ?>"></script>
    <script src="<?= base_url('includes/js/jquery.forms/jquery.forms.js') ?>"></script>

    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
    <style>
    	.container {
    		margin-top: 50px;
    	}
    </style>
    <script>
    
    	/*
    	 * Função que carrega após o DOM estiver carregado.
    	 * Como estou usando o ajaxForm no formulário, é aqui que eu o configuro.
    	 * Basicamente somente digo qual função será chamada quando os dados forem postados com sucesso.
    	 * Se o retorno for igual a 1, então somente recarrego a janela.
    	 */
    	$(function(){
    		$('#formulario_clientes').ajaxForm({
    			success: function(data) {
    				if (data == 1) {
    					
    					//se for sucesso, simplesmente recarrego a página. Aqui você pode usar sua imaginação.
    					document.location.href = document.location.href;
				    	
    				}
    			}
    		});
    	});
    
    	//Aqui eu seto uma variável javascript com o base_url do CodeIgniter, para usar nas funções do post.
    	var base_url = "<?= base_url() ?>";
    	
	    /*
	     *	Esta função serve para preencher os campos do cliente na janela flutuante
	     * usando jSon.  
	     */
    	function carregaDadosClienteJSon(id_cliente){
    		$.post(base_url+'/index.php/clientes/dados_cliente', {
    			id_cliente: id_cliente
    		}, function (data){
    			$('#nome').val(data.nome);
    			$('#email').val(data.email);
    			$('#id_cliente').val(data.id_cliente);//aqui eu seto a o input hidden com o id do cliente, para que a edição funcione. Em cada tela aberta, eu seto o id do cliente. 
    		}, 'json');
    	}
    
    	function janelaEditarCliente(id_cliente){
    		
    		//antes de abrir a janela, preciso carregar os dados do cliente e preencher os campos dentro do modal
    		carregaDadosClienteJSon(id_cliente);
    		
	    	$('#modalEditarCliente').modal('show');
    	}
    	
    </script>
  </head>

  <body>

    <div class="container">

		<div class="panel panel-primary">
		  <div class="panel-heading">
		    <h3 class="panel-title">Meus Clientes Cadastrados</h3>
		  </div>
		  <div class="panel-body">
		    <table class="table">
		    	<tr>
		    		<th>Nome</th>
		    		<th>E-mail</th>
		    		<th>Ação</th>
		    	</tr>
		    	<? foreach ($clientes -> result() as $cliente): ?>
					<tr>
						<td><?= $cliente->nome ?></td>
						<td><?= $cliente->email ?></td>
						<td><a href="javascript:;" onclick="janelaEditarCliente(<?= $cliente->id ?>)">Editar</td>
					</tr>
				<? endforeach; ?>
		  </div>
		</div>		
      
    </div><!-- /.container -->

    
	<div class="modal fade bs-example-modal-lg" id="modalEditarCliente" >
	  <div class="modal-dialog">
	    <div class="modal-content">
	      <div class="modal-header">
	        <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Fechar</span></button>
	        <h4 class="modal-title">Editar Cliente</h4>
	      </div>
	      <div class="modal-body">
	      	
			<form role="form" method="post" action="<?= base_url('index.php/clientes/salvar')?>" id="formulario_clientes">
			  <div class="form-group">
			    <label for="nome">Nome</label>
			    <input type="text" class="form-control" id="nome" name="nome">
			  </div>
			  <div class="form-group">
			    <label for="email">E-mail</label>
			    <input type="email" class="form-control" id="email" name="email">
			  </div>
			  <input type="hidden" name="id_cliente" id="id_cliente" value="" />
			</form>	    
			    
	      </div>
	      <div class="modal-footer">
	        <button type="button" class="btn btn-default" data-dismiss="modal">Fechar</button>
	        <button type="button" class="btn btn-primary" onclick="$('#formulario_clientes').submit()">Salvar Alterações</button>
	      </div>
	    </div><!-- /.modal-content -->
	  </div><!-- /.modal-dialog -->
	</div><!-- /.modal -->  
	  
  </body>
</html>

O pulo do gato aqui é na função carregaDadosClienteJSon, que é chamada quando é clicado no botão Editar.

Esta função é responsável por buscar os dados do cliente através do seu ID, e depois preencher cada campo do formulário de edição. Como vários campos serão preenchidos, preferi utilizar jSon para esta função.

É nesta etapa também que muitos se perdem. Para que eu saiba com qual cliente estou lidando, eu criei um capo do tipo hidden no formulário que recebe o id_cliente, e este campo é preenchido em todas as vezes que alguém clica no botão Editar. Assim, eu garanto que estou trabalhando com aquele cliente.

O código abaixo é o model m_cilentes.php, que tem somente duas funções. Uma que carrega os dados de todos os clientes ou somente de um cliente caso seja passado com parâmetro o id deste cliente.

A outra função serve para atualizar os dados do cliente na tabela.

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class M_clientes extends CI_model {

	/*
	 * Recupero todos os clientes do cadastro.
	 * Se for passado o parâmetro ID do cliente, então recupero somente um cliente
	 */
	public function clientes($id_cliente = null) {
			
		if ($id_cliente != null) {
			$this->db->where("id", $id_cliente);
		}
		
		$this->db->order_by("nome");
		return $this->db->get("cad_clientes");
		
	}
	
	/*
	 * A função abaixo simplesmente salva os dados do cliente na tabela.
	 * Para utilizá-la, é preciso passar o id do cliente e também os dados do cliente já formatados. Veja no controller estes dados.
	 */
	 public function salvar($id_cliente = null, $dados_cliente = null){
	 	
		if ($this->db->where("id", $id_cliente)->update("cad_clientes", $dados_cliente))
			return true;
		else
			return false;
		
	 }
}

No código abaixo está o controller clientes, que é responsável por tratar funções relacionadas aos clientes. Ele também tem duas funções apenas. A primeira que traz os dados do cliente e a segunda, que trata os campos a serem atualizados na tabela e faz o salvamento das informações no banco de dados.

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Clientes extends CI_Controller {

	/*
	 * A função abaixo recebe o id_cliente como parâmetro e retorna os dados
	 * do cliente em formato jSon para a função $.post() do jquery lá na view.
	 */
	public function dados_cliente(){
		
		//recebo o id_cliente da view para trazer os dados somente daquele cliente
		$id_cliente = $this->input->post("id_cliente");
		
		//carrego o model responsável pelos clientes
		$this->load->model("m_clientes", "clientes");
		
		//chamo a função clientes() dentro do model que me traz somente os dados de um cliente, pois estou passando o id_cliente como parãmetro
		$consulta = $this->clientes->clientes($id_cliente);
		
		//antes de continuar, verifico se alguma informação foi retornada, para não dar erro.
		if ($consulta->num_rows() == 0) {
			die("Cliente não encontrado");
		}
		
		//como eu vou retornar os dados para a view em formato jSon, aqui eu crio os índices para serem acessados dentro da função $.post()
		$array_clientes = array(
		
			"id_cliente" => $consulta->row()->id,
			"nome" => $consulta->row()->nome,
			"email" => $consulta->row()->email
			
		);
		
		/*
		 * Após os índices criados para o formato jSon, dou um echo no jsonEcode da array acima.
		 */
		echo json_encode($array_clientes);
		
	}

	/*
	 * Função que recebe os dados via post do formulário.
	 */
	
	public function salvar()
	{
		//Carrego o model clientes
		$this->load->model("m_clientes", "clientes");
		
		$id_cliente = $this->input->post("id_cliente");
		$nome= $this->input->post("nome");
		$email = $this->input->post("email");
		
		
		//Aqui eu seto cada campo da tabela com seu respectivo valor para o update no model.
		$dados_cliente = array(
		
			"nome" => $nome,
			"email" => $email
		
		);
		
		//Agora eu chamo a função salvar() dentro do model passando o id_cliente e os dados do cliente como parâmetro
		//Se tiver sucesso, então retorno com o código 1, pois recupero as informações via ajax na view.
		if ($this->clientes->salvar($id_cliente, $dados_cliente))
			echo 1;
		else
			echo 0;		
	}
}

Estes são os arquivos principais do nosso sistema. Vale lembrar que eu também alterei o arquivo config/autoload.php para carregar a biblioteca database  e o helper url.

Configurei também o meu controller padrão dentro do arquivo /config/routes.php.

E por último, segue o dump do banco de dados para você poder testar aí no seu computador:

-- phpMyAdmin SQL Dump
-- version 3.3.9
-- http://www.phpmyadmin.net
--
-- Servidor: localhost
-- Tempo de Geração: Jul 22, 2014 as 06:38 PM
-- Versão do Servidor: 5.5.8
-- Versão do PHP: 5.3.5

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

--
-- Banco de Dados: `clientes`
--

-- --------------------------------------------------------

--
-- Estrutura da tabela `cad_clientes`
--

CREATE TABLE IF NOT EXISTS `cad_clientes` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `nome` varchar(200) NOT NULL,
  `email` varchar(200) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=21 ;

--
-- Extraindo dados da tabela `cad_clientes`
--

INSERT INTO `cad_clientes` VALUES
(1, 'Tiago', 'tiago@email.com'),
(2, 'Fabio', 'fabio@email.com.br'),
(3, 'Manoel', 'manoel@email.com'),
(4, 'José', 'jose@uol.com'),
(5, 'Maria Carey', 'maria@dominio.com'),
(6, 'Epaminondas', 'epaminondas@gmail.com'),
(7, 'Pedro', 'pedro@email.com'),
(8, 'Eduardo', 'eduardo@gmail.com'),
(9, 'Carlos', 'carlos@provedor.com'),
(10, 'Maria', 'maria@dominio.com'),
(11, 'Dirce', 'dirce@email.com'),
(12, 'Renan', 'renan@email.com'),
(13, 'Maicon', 'maicon@email.com'),
(14, 'Augusto', 'augusto@email.com'),
(15, 'Luciana', 'luciana@email.com'),
(16, 'Gislaine', 'gislaine@bol.com'),
(17, 'Paulo', 'paulo@email.com'),
(18, 'João', 'joao@bol.com.br'),
(19, 'Luana', 'luana@email.com'),
(20, 'Thaís', 'thais@email.com');

Bom, então é isto.

No link abaixo você pode baixar o sistema completo e testar no seu computador ou no seu servidor. Espero que seja útil e que sirva de base para suas aplicações.

-> Download do Mini Cadastro de Clientes

Veja o projeto funcionando ao clicar no link abaixo:

>>>Testar o Projeto – Versão 2

>>> Veja um vídeo mostrando como colocar um botão Novo Cadastro no projeto.

P.S. Se tiver alguma dúvida ou sugestão de post, use a área de comentários abaixo.

Fábio S. Reszko

Sou Programador PHP desde 2006 e eu acredito sinceramente que programar usando um Framework PHP é a solução para os problemas de códigos desorganizados, difíceis de entender e de dar manutenção no futuro. Se você também acredita nisto, então fique à vontade em explorar meu blog.