+7

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> </td>
     
<td> </td>
   
</tr>
   
<tr>
     
<td> </td>
     
<td><input type="submit" name="Submit" value="Enviar"></td>
   
</tr>
   
<tr>
     
<td> </td>
     
<td> </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 17 comentários
kaizen disse:
Thanks for your sharing. Hope you can contribute more quality posts to this page. Thank you!
http://colour-switch.com
27/02/2018 3:57am (~7 anos atrás)

João Assef disse:
Boa noite,

Você segue SOLID?

Att.
24/06/2014 10:32pm (~10 anos 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 (~11 anos 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 (~11 anos atrás)

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

www.cupom.net
18/06/2013 1:36am (~11 anos 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 (~12 anos 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 (~12 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 (~12 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 (~12 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 (~13 anos atrás)

Novo Comentário:

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