+3

CRUD Genéricos em PHP. 4ª Parte: Update

criado por Marcio Alexandre em 02/04/2012 5:12pm
Hellow Comunidade!

Depois de quase dois anos após a implementação dos códigos, e confecção do primeiro artigo sobre CRUD Genérico em PHP, aqui estou!!!

Vamos comentar sobre o Update do assunto abordado no título.

Bom, alerto que por inexperiência, talvez, não usufruí de alguns conceitos OO (herança, overload, overinding, abstract, interface), enfim... o objetivo aqui é outro! Mas, desde já, quem tiver os conceitos solidificados, corrijam em seus códigos. =)

Tornarei a repetir algumas conceitos teóricos, para deixar os artigos independentes.

Como já sabemos, para cada objeto temos a estrutura que receberá cada dado referente à sua tabela no banco, ou seja, este objeto tem um estrutura semelhando à tabela do banco.

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 importaremos as classe e alimentamos os parâmetros (aqui estará o segredo de manipulação das wheres).

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. Tudo deve ser analisado, inclusive segurança.

Utilizaremos, portanto, nas camadas superiores a função ‘Atualizar’.

Nos artigos anteriores eu expliquei os parâmetos, ‘$fields’ e ‘$values’ que seriam vetores que trazem os campos e seus valores, com os quais filtraríamos nossos dados no banco (refiro-me à where). Estraríamos aqui um dos pontos principais dos artigos anteriores, pois sendo assim, a where poderia ser determinada pelo desenvolvedor sem problemas, e poderia ser 01 ou mais filtros, bastando informar campo e valor, respectivamente, nos vetores.
Neste artigo não precisamos abordar os campos e seus valores. Basicamente, o que teremos é uma lista de objetos sendo exibida na tela (no caso, serão os funcionários, para exemplificar) e ao clicar em uma opção, carregaremos de imediato aquele objeto (utilizando a função “Pegar”, conforme já entendemos no segundo artigo desta série). Após carregar nosso objeto, exibimos os dados no HTML, alteramos o que achamos necessário, e o retornamos para a função “Atualizar” da classe “funcionário”.

Pergunta provável: Como o banco vai saber qual tupla atualizar, onde está o id?

Ao ser exibida a lista de funcionários, o link para alterá-lo deverá enviar o id do objeto escolhido, ou enviar via ‘hidden’. Muito simples de se entender, concorda?
Na página de exibição dos dados a serem alterados, teríamos a seguinte estrutura:

//instancio o banco, onde tem minhas funções genéricas
require('uses/banco.php');
$db = new Banco();
//Instancio minha classe funcionario
require('uses/funcionario_.php');
$fun = new funcionario();

//Aqui digo que se não for um ‘post’, então é para exibir os dados do funcionário escolhido
if (!$_POST){ //verifica se é uma submissão de formulário ou não
// recebo o id do funcionario
$fields[1] 	= 'id_funcionario';
$values[1] 	= $_REQUEST['id'];
$objeto 	= $fun->Pegar($fields,$values,$db);
Para tornar toda estrutura o mais dinâmico possível:
// mensagem que informará se foi atualizado, uma vez que é dado o refresh
$msg		= @$_REQUEST['msg'];
if (isset($msg)){
echo '<font color="red"> '.$msg.'</font><br><br>';
}
//captura do link da página para que o refresh seja automático
$link = explode('/',$_SERVER ['REQUEST_URI']);
$qtd = count($link); echo '<br>';

Feito isso, inicializamos o formulário de atualização:

<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" value="<?php echo $objeto->getNome(); ?>"></td>
    </tr>
    <tr>
      <td>
      	<input type="hidden" name="id_funcionario" id="id_funcionario" value="<?php echo $objeto->getId(); ?>">
      	<input type="hidden" name="fun_data" id="fun_data" value="<?php echo $objeto->getDataEn(); ?>">
      </td>
      <td>&nbsp;</td>
    </tr>
    <tr> 
      <td>&nbsp;</td>
      <td><input type="submit" name="Submit" value="Atualizar"></td>
    </tr>
    <tr> 
      <td>&nbsp;</td>
      <td>&nbsp;</td>
    </tr>
  </table>
</form>

Caso submeta o formulário, os dados serão processados (refresh):

<?php }else{ 
//buscando os dados REQUEST
$id_funcionario	= $_POST['id_funcionario']; 
if (!isset($id_funcionario) || $id_funcionario != ''){
	$fun_nome	= $_POST['txtNome']	;
	$fun_data	= $_POST['fun_data'];
            
            //inserindo no objeto
	$fun->id_funcionario	= $id_funcionario;
	$fun->fun_nome	= $fun_nome;
	$fun->fun_data	= $fun_data;
            
            //chamando função para envio dos dados dinâmicamente                        
            $fun->Atualizar($fun,$db);
}else{ ?>
	<script language="javascript">
                alert('Identificador do conteúdo não especificado');
                location.href='index.php';
             </script>
<?php 
 } // else do if (!isset($id_funcionario) ...
} // else do if (!$_POST){ 
?>

Como vimos nos artigos anteriores... a função/método ‘Atualizar’ da classe Funcionario, evoca o método ‘updateObjectToDB’do banco enviado, enviando o objeto já populado. Como não haverá retorno (o que poderia, a critério do programador, trazer um true ou false, correspondendo a algum critério de controle de try - catch, enfim, possibilidades são inúmeras).

Pronto! Entendido estas arestas que não tratei na época...vamos ao coração deste artigo!

Vamos entrar na classe do banco e entender. As explicações vem no código, e é de fácil entendimento considerando o nome intuitivo dos métodos.

### Updater	
	
	public function updateObjectToDB($objeto){ //15abr2010
		// Processando, em execução, a obtenção de dados do objeto passado!
		$temp_id		=	explode('_',$objeto->getNomeTabela());
		$id_nome		=	'id_'.$temp_id[1]; //criando variável que será representará o id do objeto passado. Aqui é válido informar que há uma padronização no banco de dados em todas as tabelas, no que se refere à nomenclatura
		$temp_campos 	=	explode(',',$objeto->getNomeCampos()); // Aqui teremos os nomes dos campos da tabela, conforme foi alimentado no objeto.
		$temp_valores		=	explode(',',$objeto->getValorCampos()); // Novos dados (ou não) que serão substituidos no banco. Vale lembrar que todos os campos serão substituído, por mais que os dados novos e antigos sejam os mesmos. Um brecha aqui para futuras melhorias, para não perder no quesito processo.
		$qtd_campos		=	count($temp_campos); //Variável que armazenará a qtd de campos, afim de nortear a criação dinâmica da string SQL.
		//MONTANDO STRING SQL Dinamicamente--------------------------------
		$new_string = 'UPDATE '.$objeto->getNomeTabela().' set ';
		for ($i=0;$i <= $qtd_campos-1;$i++){ 
			// concatenação de valores
			$new_string .= $temp_campos[$i].' = '.$temp_valores[$i];
			if ($i < $qtd_campos-1){ $new_string .= ','; }
		}
		// concatena a SQL com a cláusula where.
		$new_string .= ' WHERE '.$id_nome.' = '.$objeto->getId().'';
		//-----------------------------------------------------
		//echo $new_string; break; // caso queria imprimir a string SQL para algum teste (e somente para isto), desabilitar.
		//abre o banco submete à mysql_query e fecha
		$db = new Banco(); 
		$db->abrir();
		$sql = $new_string;
		$query = mysql_query($sql) or die ($sql.' '.mysql_error());
		$db->fechar(); 
		//Redirecionando para página de atualização referida		header('Location:'.$temp_id[1].'_update.php?id='.$objeto->getId().'&msg=Atualizado');
	}


Bom, é isso!! Espero que seja útil à comunidade, a intenção é somente esta.

* Estou pensando em hospedar estes codes em algum site controlador de versões, que trabalhe com open source. A ideia é construímos, juntos, esta camada CRUD, baseada em collections (arrays), de maneira simples e segura. Isto pode facilitar muito a vida de alguns analistas/programadores, que prefiram trabalhar com SQL Dinâmicas, e não fazer mais 'n' funções para gerenciar o fluxo de dados entre o banco e a aplicação, e vice-versa.
Acredito que com esta despretensiosa solução, podemos atender melhor (quesito: tempo) a gerencia de requisitos e sua manipulação, atendendo inclusive aos conceitos de "metodologias agéis", pois TODA aplicação estaria em cima de cinco funções somente, ou seja, qualquer alteração ou nova implementação, seria rápida e facilmente gerenciável.


Outros artigos relacionados a este assunto:

1ª Parte - Create: http://www.phpbrasil.com/artigo/3crtg-4F_MGw/crud-genericos-em-php-1a-parte-create

2ª Parte - Retrieve (de um objeto): http://www.phpbrasil.com/artigo/md0HwqKKrmOp/crud-genericos-em-php-2a-parte-retrieve-de-um-objeto

3ª Parte - Retrieve (coleção de objetos): http://www.phpbrasil.com/artigo/ajN7IQp9AcZd/crud-genericos-em-php-3a-parte-retrieve-de-varios-objetos

Comentários:

Mostrando 1 - 2 de 2 comentários
Obrigado, José Sousa.

Em 2009, eu precisei dessa ideia para implementar um sistema, e não encontrei nada nos fóruns PHP, na época. Tive a ideia de compartilhar o que tinha feito. Mas alerto que n tinha muito domínio sobre os recursos da linguagem (era algo novo pra mim). Contudo, a ideia era montar uma primeira versão e ir incrementando junto com a comunidade...e deu certo! Muitas melhorias foram sugeridas, nos comentários dos outros artigos. Dê uma olhada.
28/08/2013 7:48am (~11 meses atrás)

Muito bom, comecei a ler da quarta parte, porém por ser muitissimo interessante com certeza estarei lendo as outras, o que precisa para poder hospedar ? Acho interessante e se puder ajudar estou a disposição.


Parabéns , código limpo e claro, gostei das técnicas de identação e organização.

11/01/2013 6:37am (~1 ano atrás)

Novo Comentário:

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