+4

CRUD Genéricos em PHP. 1ª Parte: Create

criado por Marcio Alexandre em 02/05/2010 3:13pm
Primeramente explicando o que é CRUD: Create [criar], Retrieve [recuperar], Update [atualizar] e Delete [excluir].

Quero deixar registrado que o foco aqui não é a performance do sistema, ok?! Afinal de contas, as 'tags' que caracterizam esse artigo é bem específico ;)

Vamos iniciar, com este, um conjunto de 5 artigos explicando como fazer o famoso CRUD em php orientado à objetos, de forma que não precisemos criar este conjunto de ações a quantidade de vezes que houver funções de acesso a base. Ou seja, nossos objetos estarão mais enxutos e não importando a regra de negócio, poderemos obter as informações necessárias, puxadas no banco de dados, nas camadas acima, utilizando SEMPRE a mesma função, modificando apenas os parâmetros enviados.

Basicamente, nas estruturas DAO, já temos os dados do objeto em questão. Como já sabemos para cada objeto temos a estrutura que receberá cada dado referente à sua tabela no banco. Além disso temos também todas as ações deste objeto no sistema (inserts, updates, deletes, selects).
Sabendo que este objeto tem um estrutura semelhando à tabela do banco, podemos incrementar um pouco mais essas informações afim de que ela se comunique com nossas classes genéricas, e execute o que está sendo solicitado.

Por questão de organização e segurança, deixei as classes CRUD dentro do objeto de conexão com o banco. E nos objetos (DAO) nós importamos as classe e alimentamos os parâmetros.
Vamos lá, trazendo o código referente a um funcionário (funcionarioDAO.php), já no padrão de acesso às classes genéricas:
class funcionario{
private $nome_tabela	=	'tb_funcionario';
private $camposInsert	=	'fun_nome,fun_data';
var $id_funcionario;
var $fun_nome;		
var $fun_data;
public function setDados($id_funcionario,$fun_nome,$fun_data){
	if (isset($id_funcionario)){ $this->id_funcionario = $id_funcionario ; }else{$this->id_funcionario = null; }
	$this->fun_nome		=	$fun_nome	;
	$this->fun_data		=	$fun_data	;
}
public function getId(){ return $this->id_funcionario;}
public function getNome()	{ return $this->fun_nome; }
public function getDataBr()	{ /*modelo brasil (00/00/0000 00:00)*/ $temp = explode(' ',$this->fun_data); $temp_data = explode('-',$temp[0]); $data = $temp_data[2].'/'.$temp_data[1].'/'.$temp_data[0]; $hora = $temp[1];  return $data.' '.$hora ; }
public function getDataEn()	{ return $this->fun_data; }

public function getNomeTabela()	{ return $this->nome_tabela;	 }
public function getNomeCampos()	{ return $this->camposInsert; }
public function getValorCampos()	{ return "'".$this->fun_nome."','".$this->fun_data."' "; }

public function Salvar($objeto,$db){ $db->insertObjectToDB($objeto); }
public function Atualizar($objeto,$db){ $db->updateObjectToDB($objeto); }
public function Pegar($fields,$values,$db){ return $db->selectDataDb($this->getNomeTabela(),$fields,$values);}
public function PegarTodos($fields,$values,$db){ return $db->selectDatasDb($this->getNomeTabela(),$fields,$values); }
public function Deletar($fields,$values,$db){ $db->DeleteDataDb($this->getNomeTabela(), $fields,$values); }
}
Observe que adicionamos mais duas variáveis privadas, no objeto, uma que traz o nome da tabela no banco, e a outra trazendo os fields (campos), em sequência como utilizamos nos inserts em sql. Também inserimos duas funções para trazer os valores dessas duas variáveis.

Adicionamos também uma função ( getVAlorCampos() ) que retorna uma string com alguns dados na mesma seqüência da variável privada referente aos campos da tabela ($camposInsert), para inserir os dados.
A outras variáveis e funções são comuns aos DAOs.

Na função salvar nós enviamos o objeto em questão, já alimentado, e a variável de referencia ao banco, que traz as classes genéricas.

Observe que é necessário um padrão de nomenclaturas entre o objeto (nome dele mesmo) e o nome da tabela e seus campos. Para tornar o fluxo de informação viável numa classe genérica temos que usar estes padrões:
• Nome dos objetos: funcionarioDAO,clienteDAO,produtoDAO.
• Nome da classe:funcionario,cliente,produto (respectivamente)
• Nome das tabelas: tb_funcionario,tb_cliente,tb_produto (respectivamente).
• Nome das páginas: funcionario.php,cliente.php,produtos.php (respectivamente).

Adotando este padrão será possível acessar qualquer tabela baseada no objeto enviado, pois o nome será lido a partir do objeto inserido na classe, e o fluxo automático de páginas no sistema.

Vejamos como a classe de inserção é construída, esta classe estará dentro do objeto ‘banco.php’ (que traz consigo também a abertura de fechamento do banco Mysql):
class Banco{
	private $local;
	private $user;
	private $senha;
	private $msg0;
	private $msg1;
	private $nome_db;
	private $db;
public function __construct(){
	$this->local 	=	'localhost';
	$this->user  	=	'root';
	$this->senha 	=	'';
	$this->msg0  	=	'Conexão falou, erro: '.mysql_error();
	$this->msg1  	=	'Não foi possível selecionar o banco de dados!';
	$this->nome_db 	=	'db_sistemaqualquer';
	}
public function abrir(){
	$this->db = mysql_connect($this->local,$this->user,$this->senha) or die($this->msg0);
	mysql_select_db($this->nome_db,$this->db) or die($this->msg1);
	}
public function fechar(){
	//analisar se o mysql_close precisa ser colocado numa variável
	$closed = mysql_close($this->db);
$closed = NULL;
}
public function insertObjectToDB($objeto){ 
	$db = new Banco();
	$db->abrir();
	$sql = "INSERT INTO ".$objeto->getNomeTabela()."(".$objeto->getNomeCampos().") VALUES ( ".$objeto->getValorCampos().")";
	$query = mysql_query($sql) or die ($sql.' '.mysql_error());
	$db->fechar(); 
	unset($objeto);
	$temp_id = explode('_',$objeto->getNomeTabela());
	header('location: '.$temp_id[1].'.php?msg=Inserido');
}
} //class
Simples assim, a classe recebe via parâmetro o objeto que quer inserir no banco. A string SQL é montada automaticamente de acordo com os dados que já existem no objeto (neste caso sem wheres, mas nos próximos artigos mostraremos como montar as strings SQL com 1 ou mais wheres).
E com os próprios dados que vem do objeto, obedecendo os padrões de nomenclaturas adotados previamento já direciona para próxima página após a inserção.

Agora o mais simples, o formulário de inserção:
<html>
<head>
<title>Cadastro de Funcion&aacute;rio</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<?php if (!$_POST){ 
$msg	= @$_REQUEST['msg'];
if (isset($msg)){
echo '<font color="red"> '.$msg.'</font><br><br>';
}
$link = explode('/',$_SERVER ['REQUEST_URI']);
$qtd = count($link); echo '<br>';
?>
<form action="<?php echo $link[$qtd-1]; ?>" method="post">
<table width="50%" border="0" cellspacing="0" cellpadding="0">
    <tr> 
      <td width="17%">Nome</td>
      <td width="49%"><input name="txtNome" type="text" id="txtNome" size="50"></td>
    </tr>
    <tr>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
    </tr>
    <tr> 
      <td>&nbsp;</td>
      <td><input type="submit" name="Submit" value="Enviar"></td>
    </tr>
    <tr> 
      <td>&nbsp;</td>
      <td>&nbsp;</td>
    </tr>
  </table>
</form>
<?php
}else{ 
require('uses/banco.php');
$db = new Banco();
require('uses/funcionarioDAO.php');
$fun_nome	=	$_POST['txtNome'];
$fun_data	=	date('Y-m-d H:i:s');
$func = new funcionario();
$func->setDados(null,$fun_nome,$fun_data);
$func->salvar($func,$db);
 } 
?>
</body>
</html>

Portanto, instanciamos o $func, onde alimentamos o objeto com os dados fornecidos pelo formulário, e depois salvamos enviando ele mesmo ($func) e a instância do objeto do banco ($db), via parâmetro.

Só para clarear, utilizamos o $_SERVER ['REQUEST_URI'] para dar o refresh automático, para não precisar se preocupar com mais este campo do formulário, deixando mais dinâmico.

Bom, é isso aí, espero ter contribuído com uma programação mais prática e sem frameworks pesados e muitas vezes desnecessários.
Até a 2ª Parte...

Comentários:

Mostrando 1 - 10 de 16 comentários
João Assef disse:
Boa noite,

Você segue SOLID?

Att.
24/06/2014 10:32pm (~2 meses atrás)

Obrigado pela contribuição, Victor Azevedo.

Esse artigo postei há uns 3 anos, quando eu engatinhava no php. Mts melhorias já forma sugeridas, aqui mesmo. Dá uma lida, e sucesso!!
28/08/2013 7:33am (~1 ano atrás)

Meus parabéns. Acho que pra melhorar, deve-se usar PDO e blocos try catch no CRUD.
Segue um pequeno exemplo da implantação do PDO e tratamento de erro.

try{
$stmte = $pdo->prepare("INSERT INTO cliente(idcliente, nome) VALUES (?, ?)");
$stmte->bindParam(1, $codigo);
$stmte->bindParam(2, $nome);
$executa = $stmte->execute();

if($executa){
echo 'Dados inseridos com sucesso';
}
else{
throw new Exception();
}
}
catch(Exception$e){
echo $e->getMessage();
}
28/08/2013 7:19am (~1 ano atrás)

Thyago Silva disse:
Concordo com o Carlos, parabéns pelo tutorial.

www.cupom.net
18/06/2013 1:36am (~1 ano atrás)

Teu código ta show, eu só alteraria poucas coisas como utilizar o operador ternário ?.
Ao invés de :
if (isset($id_funcionario)){ $this->id_funcionario = $id_funcionario ; }else{$this->id_funcionario = null; }

eu usaria:

$this->id_funcionario = (isset($id_funcionario)) ? $id_funcionario : null;
03/12/2012 8:22am (~1 ano atrás)

percebe-se que dedução não é o seu forte!

=)

Olhando a classe, fica fácil... lição de casa, ok?! ;)
06/07/2012 8:46pm (~2 anos atrás)

Cerebro disse:
Como é que você quer que a gente salve se vc não nos deu a estrutura do banco de dados?
06/07/2012 8:45pm (~2 anos atrás)

Cerebro disse:
Como é que você quer que a gente salve se vc não nos deu a estrutura do banco de dados?
06/07/2012 8:17pm (~2 anos atrás)

Mazza,

Todos os meus projetos faço utilizando este prática. Portanto, são vários e vários...
A diferença é que hoje utilizo interfaces e classes abstratas, e logicamente um conceito OO mais interessante.
25/01/2012 12:51pm (~2 anos atrás)

Bom dia!

Temos em algum local estes exemplo funcionando ??
27/09/2011 8:39am (~3 anos atrás)

Novo Comentário:

(Você pode usar tags como <b>, <i> ou <code>. URLs serão convertidas para links automaticamente.)