CRUD Genéricos em PHP. 1ª Parte: Create
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:
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):
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:
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...
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); }
}
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
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á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...
Isso mesmo, Arruda!
Isso aconteceu pq antes eu não tinha o redirecionamento na minha classe, e depois optei em deixar isso tb dinâmico, e acabei esquecendo de reposicionar o unset() abaixo. Mas vc está certo, da forma como postei está errado, acusaria um erro logo no 'explode' e a variável não receberia o valor proposto, por fim, deve-se colocar conforme corrigido pelo Arruda.
Grato pela correção,
Isso aconteceu pq antes eu não tinha o redirecionamento na minha classe, e depois optei em deixar isso tb dinâmico, e acabei esquecendo de reposicionar o unset() abaixo. Mas vc está certo, da forma como postei está errado, acusaria um erro logo no 'explode' e a variável não receberia o valor proposto, por fim, deve-se colocar conforme corrigido pelo Arruda.
Grato pela correção,
21/07/2010 4:08pm
(~1 ano atrás)
Estou com uma dúvida nessa primeira parte.
Na Classe Banco, no metodo insertObjectToDB() há uma pequena falha...
unset($objeto);
$temp_id = explode('_',$objeto->getNomeTabela());
Não poderia dar utilizar o unset no objeto e logo em seguida chamar ele novamente, poderia usar como esta embaixo. Essa alteração gera algum outro problema????!!!
$temp_id = explode('_',$objeto->getNomeTabela());
unset($objeto);
Obrigado
Na Classe Banco, no metodo insertObjectToDB() há uma pequena falha...
unset($objeto);
$temp_id = explode('_',$objeto->getNomeTabela());
Não poderia dar utilizar o unset no objeto e logo em seguida chamar ele novamente, poderia usar como esta embaixo. Essa alteração gera algum outro problema????!!!
$temp_id = explode('_',$objeto->getNomeTabela());
unset($objeto);
Obrigado
21/07/2010 3:45pm
(~1 ano atrás)
Oi Adauto,
a condicional aí é para dar suporte à população do objeto tanto pelo banco de dados(rs) qt pelo formulário (digitado pelo usuário, antes de enviar para o banco). Se os dados vem do formúlario, o id vem vazio, e para não acusar erro, 'setamos' null.
No caso exposto, não temos população do objeto pelo banco de dados, mas nos demais artigos vc poderá entender melhor.
Grato, e qualquer dúvida é só postar.
a condicional aí é para dar suporte à população do objeto tanto pelo banco de dados(rs) qt pelo formulário (digitado pelo usuário, antes de enviar para o banco). Se os dados vem do formúlario, o id vem vazio, e para não acusar erro, 'setamos' null.
No caso exposto, não temos população do objeto pelo banco de dados, mas nos demais artigos vc poderá entender melhor.
Grato, e qualquer dúvida é só postar.
06/07/2010 8:38am
(~1 ano atrás)
Márcio, Estou gostando muito das práticas de programação utilizadas ! Porém estou tendo algumas dificuldades para entender esse teste na variável id_funcionario:
if (isset($id_funcionario)){ $this->id_funcionario = $id_funcionario ; }else{$this->id_funcionario = null; }
Pode dá um pálinha a mais ???
Obrigado.
if (isset($id_funcionario)){ $this->id_funcionario = $id_funcionario ; }else{$this->id_funcionario = null; }
Pode dá um pálinha a mais ???
Obrigado.
05/07/2010 10:48am
(~1 ano atrás)
E aih Gustavo, o artigo de consulta: http://www.phpbrasil.com/artigo/md0HwqKKrmOp/crud-genericos-em-php-2a-parte-retrieve-de-um-objeto
17/06/2010 5:16pm
(~1 ano atrás)
Muito bom esse teu artigo!
Estou ancioso pela próximas partes!
Se der, faz as consultas na segunda parte!
Abraço!
Estou ancioso pela próximas partes!
Se der, faz as consultas na segunda parte!
Abraço!
27/05/2010 10:07am
(~1 ano atrás)


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.