PHP e MySQL :: CRUD – Create, Read, Update, Delete

php_logo2

php_logo2

CRUD EM PHP UTILIZANDO DAO.

Nível Intermediário.

Neste artigo vamos criar umas classes que irão trabalhar com as quatro operações de Banco, utilizando um padrão comum. Em geral procura-se utilizar uma camada intermediária entre código que se refere à estrutura de negócio e o banco de dados. Caso esteja procurando um Design Pattern não deixe de conferir meu artigo sobre Table Data Gateway.

Antes de prosseguir, se o que você espera, seja um artigo de nível básico, sem criação de classes e também não necessita neste momento de nenhum exemplo com orientação a objetos, talvez o que você esteja procurando está neste outro artigo bem abrangente e de forma simples do CRUD em PHP: PHP:: PDO – CRUD COMPLETO

Conforme a Wikipedia:
CRUD (acrônimo de Create, Read, Update e Delete na língua Inglesa) para as quatro operações básicas utilizadas em bases de dados relacionais (RDBMS) ou em interface para utilizadores para criação, consulta, atualização e destruição de dados.

Hoje, sabemos muito bem que os bancos de dados são utilizados para armazenar diversos tipos de informações pelo mundo todo e de fato, não conseguimos imaginar nenhum sistema de informação sem eles.

Hoje em dia cada vez mais se tem procurado desenvolver padrões de projetos de forma eficaz, onde não apenas o desenvolvimento seja prático, mas também a sua manutenção. Além disso, como regras de negócios tem se tornado cada vez mais complexas, se faz necessário desenvolver métodos onde seja possível abstrair ao máximo em camadas as lógicas, cada parte de um projeto, as que se referem às regras de negócios e as partes mecânicas da aplicação, sendo mais específica a persistência de dados e visualização das informações geradas com os dados.

Enfim, CRUD em padrões de projetos tais como o MVC, tem sido utilizado para criar uma camada de abstração que interage com a parte lógica de controle do Sistema que contém as regras de negócio e os sistemas de bancos de dados. Utilizando Orientação a Objetos, costuma-se utilizar o CRUD dentro de objetos DAO gerados por classes DAO (Data Access Object) para criar a “interface” entre a parte de Controle e os dados persistentes no sistema de banco de Dados. Inclusive a parte de persistência de dados, no MVC faz parte da camada Modelo.
Neste post, vamos ver como funciona um CRUD utilizado a classe PDO. Esta classe provê uma interface padrão de comunicação entre o PHP e os sistemas de bancos de dados.

Vamos criar um aplicativo de cadastro de contatos bem simples , visando apresentar as quatro operações concentradas na ideia CRUD.

Primeiramente vamos criar o banco de dados simples para persistência dos dados de contatos:

CREATE DATABASE exemplocrud;

CREATE TABLE contatos (
   ID INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
   NOME VARCHAR(45) NOT NULL,
   EMAIL VARCHAR(45) NOT NULL,
   TELEFONE VARCHAR(15)
);

Agora vamos criar a classe que gera objetos para manipulação de contatos. O objeto deverá refletir um no formato da tabela para que a nossa futura classe DAO que atuará como CRUD, possa traduzir os objetos para dados persistentes e vice-versa.

  1. class Contato {
  2.     private $id = null;
  3.     private $nome;
  4.     private $email;
  5.     private $telefone;
  6.     public function __construct($nome, $emal, $telefone) {
  7.        $this->nome = $nome;
  8.        $this->emal = $email;
  9.        $this->telefone = $telefone;
  10.     }
  11.     public function getId() {
  12.        return $this->id;
  13.     }
  14.     public function getNome() {
  15.        return $this->nome;
  16.     }
  17.     public function getEmal() {
  18.        return $this->emal;
  19.     }
  20.     public function getTelefone() {
  21.        return $this->telefone;
  22.     }
  23.     public function setId($id) {
  24.        $this->id = $id;
  25.     }
  26.     public function setNome($nome) {
  27.        $this->nome = $nome;
  28.     }
  29.     public function setEmal($emal) {
  30.        $this->email = $email;
  31.     }
  32.     public function setTelefone($telefone) {
  33.        $this->telefone = $telefone;
  34.     }
  35. }

Agora vamos criar uma classe que gera uma conexão com banco de dados. Esta classe não precisa construir objetos e seguindo o padrão Singleton, só pode ser instanciada de dentro para fora. Por isso você nota que o método construtor, de clonagem e o de serializar, possuem uma restrição máxima “private” impedindo seu acesso. Além disso, como único meio de acesso público a classe, usará um método estático getInstancia(). Este método se encarrega de verificar se já existe uma instância de conexão ativa e se houver, apenas retorna esta instância. Caso contrário instancia um novo objeto de conexão PDO e retorna este. Faz sentido usar este método de conexão que sempre certificará se já existe uma instância de conexão ativa com o banco de dados e talvez você já esteja imaginando porque. Em geral, não precisamos de uma nova conexão com o banco de dados a cada operação realizada com o banco. Assim, este projeto Singleton, visa resolver este tipo de problema, quando só precisamos de uma única instância de um determinado objeto durante a execução da aplicação.

  1. /**
  2. * Description of PdoConexao – Singleton pattern
  3. *
  4. * @author Alexandre Bezerra Barbosa
  5. */
  6. class PdoConexao {
  7.     private static $instancia;
  8.    
  9.     // Impedir instanciação
  10.     private function __construct() { }
  11.     // Impedir clonar
  12.     private function __clone() { }
  13.    
  14.     //Impedir utilização do Unserialize
  15.     private function __wakeup() { }
  16.    
  17.     /**
  18.     *
  19.     * @return object PDO connection
  20.     *
  21.     */
  22.     public static function getInstancia() {
  23.         if(!isset(self::$instancia)) {
  24.              try {
  25.                  $dsn = “mysql:host=localhost;dbname=exemplocrud”;
  26.                  $usuario = “root”;
  27.                  $senha = “”; // Preencha aqui com a senha do seu servidor de banco de dados.
  28.                  
  29.                  // Instânciado um novo objeto PDO informando o DSN e parâmetros de Array
  30.                  self::$instancia = new PDO( $dsn, $usuario, $senha );
  31.                  
  32.                  // Gerando um excessão do tipo PDOException com o código de erro
  33.                  self::$instancia->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
  34.              
  35.              } catch ( PDOException $excecao ){
  36.                  echo $excecao->getMessage();
  37.                  // Encerra aplicativo
  38.                  exit();
  39.              }
  40.          }
  41.          return self::$instancia;
  42.         }
  43.    }

Já vimos que com essa classe é possível instanciar um objeto de conexão, mas ela em si não serve para nada se não houver a interface da aplicação com o banco de dados. Vamos criar então a classe DaoContatos que refletirá as quatro operações do banco e será o script que comunica a aplicação com o banco de dados.

Conforme a Wikipedia:
Objeto de acesso a dados (ou simplesmente DAO, acrônimo de Data Access Object), é um padrão para persistência de dados que permite separar regras de negócio das regras de acesso a banco de dados. Podemos até dizer que é uma camada intermediária entre código de estrutura de negócios e o banco de dados. Numa aplicação que utilize a arquitetura MVC, todas as funcionalidades de bancos de dados, tais como obter as conexões, mapear objetos Java para tipos de dados SQL ou executar comandos SQL, devem ser feitas por classes DAO.
(https://pt.wikipedia.org/wiki/Objeto_de_acesso_a_dados – Acesso em 11/01/2016)

Claro que ali apenas foi mencionada a linguagem de programação Java, mas podemos dizer que todas as linguagens de programação que são orientadas a objeto ou dão suporte a este paradigma, suportam o objeto DAO. Vamos então criar a nossa classe DAO, mas para seguir o padrão a risca, criaremos antes uma interface que reflete a ideia deste post, impondo os métodos para nos ajudar chegar ao nosso objetivo. Talvez nesse momento, usar uma interface não parece necessário, mas em um artigo posterior, vou detalhar mais motivos ao usar estas mesmas classes.

  1. interface iDaoModeCrud {
  2.     public function create( $object );
  3.     public function read( $param );
  4.     public function update( $object );
  5.     public function delete( $param );
  6. }

Pronto, então vamos criar a classe de persistência implementando a interface iDaiModeCrud para criar cada um dos métodos declarados nela. A nova classe precisa sempre gerar um novo objeto DAO para cada execução da aplicação. Isso faz sentido existir dessa forma porque imagine por um momento, quando você construir uma aplicação que conecte com muitos usuários simultaneamente, se todos estes utilizarem um único objeto instanciado para fazer interface com o banco? Diversas inconsistências poderiam ocorrer, então cada sessão deve ter seu próprio objeto DAO. Além disso para cada contexto de um sistema que vou me referir como um “tipo de módulo” que interage com o banco, precisaremos de uma classe DAO específica. Módulo? Sim, por exemplo um módulo de cadastro de clientes, um outro de cadastro de produtos, um outro para operações de vendas, etc. Estando claro isso e seguindo com nosso objetivo de criar um cadastro de contatos, segue nossa classe Dao:

  1. class DaoContato implements iDaoModeCrud {
  2.    
  3.     private $instanciaConexaoPdoAtiva;
  4.     private $tabela;
  5.    
  6.     public function __construct() {
  7.        $this->instanciaConexaoPdoAtiva = PdoConexao::getInstancia();
  8.        $this->tabela = “contatos”;
  9.     }
  10.     /**
  11.     *
  12.     * create: Insere informações no banco de dados
  13.     *
  14.     * @param object $objeto
  15.     * @return boolean
  16.     */
  17.     public function create( $objeto ) {
  18.        $id = $this->getNewIdContato();
  19.        $nome = $objeto->getNome();
  20.        $email = $objeto->getEmail();
  21.        $telefone = $objeto->getTelefone();
  22.        $sqlStmt = “INSERT INTO {$this->tabela} (ID, NOME, EMAIL, TELEFONE) VALUES (:id, :nome, :email, :telefone)”;
  23.        try {
  24.           $operacao = $this->instanciaConexaoPdoAtiva->prepare($sqlStmt);
  25.           $operacao->bindValue(“:id”, $id, PDO::PARAM_INT);
  26.           $operacao->bindValue(“:nome”, $nome, PDO::PARAM_STR);
  27.           $operacao->bindValue(“:email”, $email, PDO::PARAM_STR);
  28.           $operacao->bindValue(“:telefone”, $telefone, PDO::PARAM_STR);
  29.           if($operacao->execute()){
  30.                 if($operacao->rowCount() > 0) {
  31.                    $objeto->setID($id);
  32.                    return true;
  33.                 } else {
  34.                    return false;
  35.                 }
  36.              } else {
  37.                 return false;
  38.           }
  39.        } catch( PDOException $excecao ) {
  40.              echo $excecao->getMessage();
  41.        }
  42.     }
  43.     /**
  44.     *
  45.     * read: Retorna um objeto refletindo um contato
  46.     *
  47.     * @param int $id
  48.     * @return object
  49.     */
  50.     public function read( $id ) {
  51.        $sqlStmt = “SELECT * from {$this->tabela} WHERE ID=:id”;
  52.        try {
  53.           $operacao = $this->instanciaConexaoPdoAtiva->prepare($sqlStmt);
  54.           $operacao->bindValue(“:id”, $id, PDO::PARAM_INT);
  55.           $operacao->execute();
  56.           $getRow = $operacao->fetch(PDO::FETCH_OBJ);
  57.           $nome = $getRow->NOME;
  58.           $email = $getRow->EMAIL;
  59.           $telefone = $getRow->TELEFONE;
  60.           $objeto = new Contato( $nome, $email, $telefone );
  61.           $objeto->setId($id);
  62.           return $objeto;
  63.        } catch( PDOException $excecao ){
  64.           echo $excecao->getMessage();
  65.        }
  66.     }
  67.    
  68.     /**
  69.     *
  70.     * update: atualiza um contato
  71.     *
  72.     * @param object $objeto
  73.     * @return boolean
  74.     */
  75.     public function update( $objeto ) {
  76.        $id = $objeto->getId();
  77.        $nome = $objeto->getNome();
  78.        $email = $objeto->getEmail();
  79.        $telefone = $objeto->getTelefone();
  80.        $sqlStmt = “UPDATE {$this->tabela} SET NOME=:nome, EMAIL=:email, TELEFONE=:telefone WHERE ID=:id”;
  81.        try {
  82.           $operacao = $this->instanciaConexaoPdoAtiva->prepare($sqlStmt);
  83.           $operacao->bindValue(“:id”, $id, PDO::PARAM_INT);
  84.           $operacao->bindValue(“:nome”, $nome, PDO::PARAM_STR);
  85.           $operacao->bindValue(“:email”, $email, PDO::PARAM_STR);
  86.           $operacao->bindValue(“:telefone”, $telefone, PDO::PARAM_STR);
  87.           if($operacao->execute()){
  88.              if($operacao->rowCount() > 0){
  89.                 return true;
  90.              } else {
  91.                 return false;
  92.              }
  93.           } else {
  94.              return false;
  95.           }
  96.        } catch ( PDOException $excecao ) {
  97.           echo $excecao->getMessage();
  98.        }
  99.     }
  100.     /**
  101.     *
  102.     * DELETE exclui um contato no banco de dados conforme informado por id
  103.     *
  104.     * @param int $id
  105.     * @return boolean
  106.     */
  107.     public function delete( $id ) {
  108.         $sqlStmt = “DELETE FROM {$this->tabela} WHERE ID=:id”;
  109.        try {
  110.           $operacao = $this->instanciaConexaoPdoAtiva->prepare($sqlStmt);
  111.           $operacao->bindValue(“:id”, $id, PDO::PARAM_INT);
  112.           if($operacao->execute()){
  113.              if($operacao->rowCount() > 0) {
  114.                    return true;
  115.              } else {
  116.                    return false;
  117.              }
  118.           } else {
  119.              return false;
  120.           }
  121.        } catch ( PDOException $excecao ) {
  122.           echo $excecao->getMessage();
  123.        }
  124.     }
  125.    
  126.     /**
  127.     *
  128.     * getNewIdContato retorna um novo Id para novos registros
  129.     *
  130.     * @return int
  131.     * @throws Exception
  132.     */
  133.     private function getNewIdContato(){
  134.           $sqlStmt = “SELECT MAX(ID) AS ID FROM {$this->tabela}”;
  135.           try {
  136.              $operacao = $this->instanciaConexaoPdoAtiva->prepare($sqlStmt);
  137.              if($operacao->execute()) {
  138.                 if($operacao->rowCount() > 0){
  139.                    $getRow = $operacao->fetch(PDO::FETCH_OBJ);
  140.                    $idReturn = (int) $getRow->ID + 1;
  141.                    return $idReturn;
  142.                 } else {
  143.                    throw new Exception(“Ocorreu um problema com o banco de dados”);
  144.                    exit();
  145.                 }
  146.              } else {
  147.                 throw new Exception(“Ocorreu um problema com o banco de dados”);
  148.                 exit();
  149.               }
  150.           } catch (PDOException $excecao) {
  151.              echo $excecao->getMessage();
  152.           }
  153.        }
  154.     }

As classes funcionais estão prontas! Agora podemos criar um novo arquivo php para realizar alguns testes. Por exemplo, abaixo criei um arquivo php com uma função de auto loader para classes que se encontram no mesmo caminho (OBS: Salvar arquivos de bibliotecas de classes no mesmo diretório da aplicação principal não é uma prática recomendada, está sendo usado aqui apenas para fins didáticos), note as explicações acima de cada linha definido como comentário:

  1. header(“Content-Type: text/html; charset=utf-8”,true);
  2. function __autoload( $classe ){
  3. if(file_exists( “{$classe}.php” )) {
  4.           include_once “{$classe}.php”;
  5.        } else {
  6.           echo “O arquivo {$classe}.php da classe {$classe} não foi encontrado”;
  7.        }
  8.     }
  9.    
  10. // Nesta etapa criamos um objeto de contato e logo em seguida vamos fazer destes dados persistentes no banco de dados
  11. $contato1 = new Contato( “Alexandre Barbosa”, “teste@teste.com.br”, “11999999999”);
  12. // Então primeiro criamos um novo objeto DAO
  13. $PersitenciaContato1 = new DaoContato();
  14. // Para persistencia de dados do objeto contato, usamos o método create passando o nosso objeto de contato como parâmetro
  15. if($PersitenciaContato1->create($contato1)){
  16.        echo ‘Inseridos no banco com Êxito’;
  17. }
  18. // Agora podemos testar outra funcionalidade, recuperar os dados persistidos no dados no banco para um novo objeto de contatos, usamos o método read do nosso DAO. O
  19. var_dump está sendo usado apenas para facilitar a visualização do objeto sem precisar inserir mais códigos
  20. var_dump($PersitenciaContato1->read(1));
  21. //Note que poderíamos criar um novo objeto com os dados de contato apenas desta forma:
  22. $contato2 = $PersitenciaContato1->read(1);
  23. // O número 1, indica o ID do registro no banco de dados.
  24. //Agora para atualizar os dados, primeiro “setamos” os novos valores no objeto de contato com os dados carregados. Vamos usar o primeiro objeto identificado como $contato1:
  25. $contato1->setNome(“João Silva”);
  26. $contato1->setEmail(“joao@teste.com.br”);
  27. // Então chamamos o método de update do nosso DAO passando o objeto de contato.
  28. if($PersitenciaContato1->update($contato1)){
  29.        echo ‘Atualizado no banco com Êxito’;
  30. }
  31. //Vamos conferir a atualização realizada com o método read do nosso DAO
  32. var_dump($PersitenciaContato1->read(1));
  33. // E para excluirmos? usamos o método delete do nosso DAO, informando o ID como parâmetro
  34. if($PersitenciaContato1->delete(1)){
  35.     echo ‘Excluído do banco com Êxito’;
  36. }

Note que não precisamos mais agora nos preocupar como obter ou inserir dados no banco de dados porque todo processo será realizado pela classe de persistência. Precisamos apenas saber que temos quatro métodos de operação e quais são os parâmetros necessários para invocar estes métodos, uma vez que instanciamos um objeto DAO.

Este post já ficou bem extenso. Então vou encerrar por aqui. Mas estou preparando um novo artigo separado em que criamos um pequeno aplicativo usando estas classes junto com as classes (com algumas melhorias) criadas em um post anterior sobre o Factory Pattern.

Reconheço que o layout do meu blog ainda não está ajudando muito para área de desenvolvimento e estou trabalhando nisso. Mas eu gostaria que você me ajuda-se curtindo este post caso você tenha gostado. Alguns me enviam e-mails parabenizando, e não há problema, mas a sua “curtida aqui” é muito importante para que eu possa continuar meu trabalho.
[]’s

11 comentários

    1. Parabéns pelo blog e o conteúdo abordado aqui. Sou iniciante em PHP mas com muito entusiasmo de aprender essa linguagem apaixonante.
      Veleu.

  1. Muito bom este tutorial amigo, muito bem explicado, parabens…
    Fiz uma adaptação ao meu estudo, e a parte de update nao esta funcionando, ele inclui um novo registro.. já olhei os codigos e nao encontro o erro. se puder me dar um help!!!

    1. Olá Marlon, primeiramente obrigado pelo seu feedback! O método update está semelhante ao do artigo? Se estiver, você pode começar a analisar primeiro o método read da classe DaoContato. Note que o read, obviamente recebe um id como argumento, que será utilizado na consulta a ser executada a seguir. O resultado virá como um objeto de onde capturamos o atributos e, os passamos como argumentos na criação de um novo objeto Contato. (OBS: Esse código é didático, por isso tem mais linhas do que precisa, portanto pode ser melhorado! 🙂 ). Continuando…: Então note que uma vez que temos o objeto criado, chamamos o método setId e passamos o Id como argumento para o objeto Contato, que adicionará ao atributo Id do objeto contato. Em seguida retornamos o objeto Contato para o código. Quando você vau utilizar o método update da classe DaoContato, ele precisa receber um objeto contato como argumento, então poderá extrair tudo que precisa para efetivar a persistência no banco, inclusive o Id. Avalie se é isto que está acontecendo: o id está sendo obtido normalmente pelo método getId do objeto Contato e se antes disso, o método update está obtendo o Id através do método getId. Caso contrário, poderão ocorrer efeitos indesejados. Repare se a declaração recebida pela variável $sqlStmt está informando corretamente os dados: “UPDATE {$this->tabela} SET NOME=:nome, EMAIL=:email, TELEFONE=:telefone WHERE ID=:id”. Veja aí, caso ainda não encontre a falha me passe o seu código por email com titulo: duvida no artigo CRUD. Meu email está na sessão “sobre”. Abraço

  2. Olá, primeiro parabéns por estes e outros de seus tutos…. Sou um iniciante, mas resolvi testar e estudar este crud. Ao invés do autoload, como eu subtituo as linhas abaixo e uso o meu formulário para inserir os dados?
    $contato1 = new Contato( “Alexandre Barbosa”, “teste@teste.com.br”, “11999999999”);
    $PersitenciaContato1 = new DaoContato();
    if($PersitenciaContato1->create($contato1)){
    echo ‘Inseridos no banco com Êxito’;

    Partindo da premissa que os nomes dos inputs são semelhantes aos deste crud. Sempre usei o post no modo procedural, sem classes e nem objetos….Pode dar uma dica aí?

  3. Queria agradecer você! Eu estava há muito tempo sem programar em php e recebi a missão de reescrever um sistema antigo e sem OO em php, estava perdida sem saber por onde começar e o seu tutorial foi tudo!!! Fiz umas alterações para diminuir o código, mas da forma como colocou fica mais facil para entender o que está sendo feito. Imagino q seja essa a ideia mesmo. 🙂 Já estou de vento em popa reescrevendo o sistema. Muito obrigada!

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.