PHP:: PDO – CRUD COMPLETO

php_code_1

php_logo2

CRUD COMPLETO COM PDO.

Nível iniciante.

Este artigo descreve detalhadamente e de forma simples em 7 etapas, como você pode criar uma aplicação CRUD. Vamos criar uma agenda de contatos, ou cadastro de contatos como preferir! Serão vistos as quatro operações do banco de dados em ação, utilizando a classe PDO. Além disso, a fim de que você se sinta mais a vontade com o foco do artigo, não vou entrar em detalhe técnico sobre orientação a objetos aqui, antes, meu objetivo é fazer você compreender como criar rapidamente o CRUD sem nenhum auxilio de qualquer Framework. Todavia, se você desejar um artigo mais avançado, depois de concluir sua leitura a esse artigo, não deixe de ver também um dos mais novos artigos: PHP::CRUD com MVC. Voltando ao tema presente, após concluir as 7 etapas, você terá uma visão bem abrangente da classe PDO e como utilizá-la em seus códigos.

Introdução

Em outros artigos sobre persistência, já abrangi sobre CRUD utilizando inclusive alguns padrões de projetos mas não eram aplicações completas. Entretanto, imagino que para quem está iniciando a programar em PHP e ainda não está acostumado a padrões de projetos, poderá estar com inúmeras dúvidas e precisa de algo simples, porém funcional. Por isso, decidi, criar este artigo que abrange de forma simples o CRUD em PHP fazendo uso do banco de dados MySQL. CRUD é um acrônimo para as quatro operações do Banco: CREATE (Criar), READ (Ler), Update (Atualizar) e DELETE (Excluir). Quando você cria uma aplicação que conte com todas estas operações, está desenvolvendo um CRUD.

Vamos então passa a passo, etapa por etapa entendendo como fazer uma aplicação CRUD (agenda de contatos) desde a conexão com banco de dados. Queri deixar claro que é importe se acostumar a programar conforme o paradigma Orientado a Objetos. Você até pode programar conforme o paradigma procedural, mas estará limitado em alguns aspectos e até irá se deparar com outros problemas que somente terão solução pela Orientação a Objetos. Não entraremos em detalhes sobre isso aqui. Além disso, é importante que você tenha noções da linguagem SQL a fim de ter um melhor aproveitamento.

Primeira etapa: Criando o banco de dados

Precisamos de um banco de dados e elegemos o MySQL como SGDB para gerenciá-lo.

Vamos criar uma agenda de contatos, com três colunas nome, e-mail e telefone.

1- Para criar o banco de dados execute o código:


CREATE DATABASE crudsimples DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;</span></pre>

2- Em seguida selecione o banco:


USE crudsimples;

3- Então crie a tabela contatos:


CREATE TABLE contatos (
    id INT NOT NULL AUTO_INCREMENT,
    nome VARCHAR(45) NOT NULL,
    email VARCHAR(45) NOT NULL,
    celular VARCHAR(15) DEFAULT NULL,
    PRIMARY KEY(id)
);

4- Para verificar se está tudo certo:


SELECT * FROM contatos;

Se você seguir a risca estas etapas acima, não deverá enfrentar nenhum problema.

Segunda etapa: Conexão com banco de dados

Não é novidade que atualmente se adotou a classe PDO, uma interface de conexão, que permite criar a abstração com o sistema de banco de dados. Sendo assim, vamos criando nosso objeto de conexão PDO.

1- Nesta etapa, vamos iniciar o projeto por criar um novo arquivo com extensão .php e, obviamente aqui o nome do arquivo é livre, ou seja, você poderá dar o nome de sua preferência 🙂 . Além disso, é claro, utilize a IDE de sua preferência ou até um editor de textos se assim preferir. Então como já foi dito, inicie com um arquivo limpo, e digitando apenas as tags de abertura e encerramento do php “<?php” e “?>”. Além disso, você pode pular algumas linhas entre elas para facilitar a digitação do código. Após isso, já estará apto para digitar os primeiros códigos entre as tags do php, e inicie esse trabalho por criar um bloco “try e cacth” onde, vamos instanciar o objeto de conexão com o banco de dados: PDO.


<?php

try {
    $conexao = new PDO("mysql:host=localhost; dbname=crudsimples", "root", "123456");
} catch (PDOException $erro) {

}

Note como que instanciamos o objeto PDO, sua sintaxe é:

<objeto PDO> = new PDO(String <Nome da fonte de dados>, String <usuário do banco>, String <senha do banco>);

Note que o objeto que será associado a variável $conexão será do tipo PDO, um objeto que representa a conexão com o banco e que será o nosso manipulador.

Como parâmetros, o construtor da classe exige:

  • uma DSN (Nome da fonte de dados), onde informamos o driver do banco, o nome do host e o nome do banco de dados e note que são separados por ponte e vírgula. Mas a DSN suporta diferentes métodos de argumentação. Caso tenha interesse dê uma olhada na documentação (http://php.net/manual/pt_BR/pdo.construct.php)
  • um nome de usuário para conexão com o banco de dados
  • a senha para o usuário informado.

Opcionalmente é possível passar um array associativo com opções de conexão, como um terceiro parâmetro, mas não vou abranger aqui.

Observação: deste momento em diante, não darei tanta ênfase as tags de abertura e fechamento do bloco de códigos php. Serão mencionadas apenas quando for necessário misturar código php com tags html ou adicionar em outro local no arquivo.

Perceba que o parâmetro de catch foi informado como um argumento do tipo PDOExecption. Esta classe do php estende RuntimeException e é específica para representar os erros gerados pela classe PDO. Para termos uma representação mais específica, a classe PDO nos apresenta um método setAttribute para o objeto PDO, note os blocos acima reescritos com o método, logo abaixo:


try {
    $conexao = new PDO("mysql:host=localhost; dbname=crudsimples", "root", "123456");
    $conexao->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $erro) {
    echo "Erro na conexão:" . $erro->getMessage();
}

O método setAttribute() nos permite adicionar atributos no objeto de conexão, sua sintaxe:

<valor boleano> = setAttribute(inteiro “Atributo”, misto “Valor”);

Note que o método devolve um valor booleano como resposta e assim você pode descobrir se tudo correu bem. Ainda, como atributos, há um do tipo inteiro e outro que pode ser de vários tipos. No caso do argumento inteiro, este método deve receber algum dos atributos válidos para o objeto de conexão. Estes objetos são representados por constantes, semelhantes a esta que estamos usando aí acima. Se você estiver interessado em saber quais são, veja a documentação: http://php.net/manual/pt_BR/pdo.setattribute.php. Por hora vamos utilizar PDO::ATTR_ERRMODE que indica como relatar o erro. Entenda que o segundo argumento deve ser compatível com o primeiro. No caso de PDO::ATTR_ERRMODE, espera-se receber um dos três modos disponíveis:

  • PDO::ERRMODE_SILENT: Só defina o código de erro
  • PDO::ERRMODE_WARNING: gerar um E_WARNING.
  • PDO::ERRMODE_EXCEPTION: Lance uma exceção.

Atento a isto, descobrimos que a última opção é a melhor por estarmos trabalhando com uma PDOException no nosso bloco catch. Sendo assim, agora será possível imprimir uma exceção lançada, por chamar o método getMessage() da PDOException. É exatamente isso que estamos fazendo dentro do bloco catch, como você pode ter notado.

Pois bem, será que já terminamos a parte de conexão? Talvez, mas poderemos melhorar algo aqui: lembre-se que estamos no Brasil, onde é comum utilizar acentos e, por isso, a codificação comum é UTF-8. Como é que informamos isso ao servidor de banco de dados? Note os blocos try e catch reescritos e terminados:


try {
    $conexao = new PDO("mysql:host=localhost; dbname=crudsimples", "root", "123456");
    $conexao->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $conexao->exec("set names utf8");
} catch (PDOException $erro) {
    echo "Erro na conexão:" . $erro->getMessage();
}

O que mudou? Foi adicionado uma linha com o método exec() da classe PDO, que executar uma instrução SQL e retornar o número de linhas afetadas. Neste caso, não esperamos nenhum retorno, mas queremos executar a instrução SQL direto no banco. Note que esta não é uma instrução da classe PDO e sim do banco de dados. Caso queira saber mais a respeito desta instrução no MySQL, consulte http://dev.mysql.com/doc/refman/5.7/en/charset-connection.html

Muito bem, terminado a segunda etapa de construção da aplicação, a próxima será criar um formulário simples e inserir dados nele, construindo assim a primeira função do CRUD.

Embora este artigo não tenha como meta apresentar a programação POO, pois se concentra na classe PDO, se você tiver interesse em saber como criar uma classe de conexão com o banco de dados, algo bem moderno usado em alguns frameworks modernos, não deixe de ver este meu artigo: PHP:: Conexão conforme os padrões singleton e Factory Method. Nele, é apresentado passo a passo como criar uma classe de conexão capaz de gerar objetos PDO para muitos bancos e ainda, manter uma única instancia ativa durante a conexão. Com a classe apresentado neste procedimento, todas as linhas acima, seriam substituídas apenas pela chamada:   $conexao =  connection::getInstance(‘nomeDoAquivo.INI’).

Terceira Etapa: Criando um formulário

Precisamos de um formulário, então vamos criá-lo por inserir este código HTML bem abaixo do código php que já criamos com a conexão. Lembre-se antes de fechar a tag PHP com um “?>” antes de inserir as tags seguintes, se você já não o fez. 😉


<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Agenda de contatos</title>
    </head>
    <body>
        <form action="?act=save" method="POST" name="form1" >
          <h1>Agenda de contatos</h1>
          <hr>
          <input type="hidden" name="id" />
          Nome:
          <input type="text" name="nome" />
          E-mail:
          <input type="text" name="email" />
          Celular:
         <input type="text" name="celular" />
         <input type="submit" value="salvar" />
         <input type="reset" value="Novo" />
         <hr>
       </form>
    </body>
</html>

Até aqui, se você abrir a página, vai ver o nosso formulário com 3 campos e dois botões, mas ainda não funciona.

Artigo sobre CRUD em PHP: Criando formulário
Artigo sobre CRUD em PHP: Criando formulário

Veja que também utilizamos uma tag input do tipo “hidden” e esta será utilizada para o recurso de Update. Visto que, já que mencionei o “Update”, vamos já preparar nosso formulário para a função este recurso. Então, dentro de cada tag input, antes do encerramento “/>”, vamos acrescentar um espaço e adicionar um código php para preenchimento automático. Este código, naturalmente deverá estar delimitado pelas tags do php “<?php” e “?>”. Então, leve o cursor até a área informada acima e adicione o código entre as tags do php. Ele deverá ser assim:


<html>
    <head>
        <meta charset="UTF-8">
        <title>Agenda de contatos</title>
    </head>
    <body>
        <form action="?act=save" method="POST" name="form1" >
            <h1>Agenda de contatos</h1>
            <hr>
            <input type="hidden" name="id" <?php
            // Preenche o id no campo id com um valor "value"
            if (isset($id) && $id != null || $id != "") {
                echo "value=\"{$id}\"";
            }
            ?> />
            Nome:
            <input type="text" name="nome" <?php
            // Preenche o nome no campo nome com um valor "value"
            if (isset($nome) && $nome != null || $nome != ""){
                echo "value=\"{$nome}\"";
            }
            ?> />
            E-mail:
            <input type="text" name="email" <?php
            // Preenche o email no campo email com um valor "value"
            if (isset($email) && $email != null || $email != ""){
                echo "value=\"{$email}\"";
            }
            ?> />
            Celular:
            <input type="text" name="celular" <?php
            // Preenche o celular no campo celular com um valor "value"
            if (isset($celular) && $celular != null || $celular != ""){
                echo "value=\"{$celular}\"";
            }
            ?> />
           <input type="submit" value="salvar" />
           <input type="reset" value="Novo" />
           <hr>
        </form>
    </body>
</html>

Novamente, até aqui se você abrir a página no browser, ainda não vai acontecer porque estas instruções de decisão apenas estão verificando se uma variável foi definida e se seu valor é diferente de nulo ou diferente de vazio. Todavia, as variáveis ainda não foram definidas e por isso nada acontece. Mas vamos adicionar estas novas instruções antes do bloco “try e catch” na primeira parte do nosso código, ou seja, ficará logo depois da primeira tag de abertura do php “<?php” do início e antes do bloco “try e catch”:


<?php
// Verificar se foi enviando dados via POST
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $id = (isset($_POST["id"]) && $_POST["id"] != null) ? $_POST["id"] : "";
    $nome = (isset($_POST["nome"]) && $_POST["nome"] != null) ? $_POST["nome"] : "";
    $email = (isset($_POST["email"]) && $_POST["email"] != null) ? $_POST["email"] : "";
    $celular = (isset($_POST["celular"]) && $_POST["celular"] != null) ? $_POST["celular"] : NULL;
} else if (!isset($id)) {
    // Se não se não foi setado nenhum valor para variável $id
    $id = (isset($_GET["id"]) && $_GET["id"] != null) ? $_GET["id"] : "";
    $nome = NULL;
    $email = NULL;
    $celular = NULL;
}

Agora, se você executar a página, poderá preencher o formulário e notar uma diferença ao clicar em “Salvar”. A diferença é quando clicar no botão “Salvar” e fazer o “submit”, pois, os dados permanecerão nos campos como se nada acontecesse.

Artigo sobre CRUD em PHP: Adicionando funcionalidade ao formulário
Artigo sobre CRUD em PHP: Adicionando funcionalidade ao formulário

Como assim? Esta é a nossa intenção neste momento, porque definimos e preenchemos as variáveis via POST, aquelas que são verificadas no código dentro das tags input dentro do formulário. Mesmo com refresh da página, os dados não sumirão, mas continuarão lá. Precisamos agora salvar estes dados no banco de dados e assim alcançar nosso primeiro objetivo. Esta é a nossa próxima etapa: Create! Você deve ter notado também que estamos trabalhando com uma variável $id, embora esta variável ainda não receba nenhum valor. Não se preocupe logo voltaremos nossa atenção a ela.

Quarta Etapa: Create – salvando novo registro no banco de dados

Nosso formulário contém dados que precisam ser persistidos no banco de dados. Para isso funcionar, vamos adicionar o código após a ultima chave que encerra o “try e catch” criado para a conexão. Ah, há mais um detalhe aqui que reforço: Estamos trabalhando no primeiro bloco de comandos php, então vamos inserir o seguinte código logo abaixo do “try e catch” de conexão. A frase foi repetida para reforçar a atenção! O código é este:


if (isset($_REQUEST["act"]) && $_REQUEST["act"] == "save" && $nome != "") {
    try {
        $stmt = $conexao->prepare("INSERT INTO contatos (nome, email, celular) VALUES (?, ?, ?)");
        $stmt->bindParam(1, $nome);
        $stmt->bindParam(2, $email);
        $stmt->bindParam(3, $celular);
        
        if ($stmt->execute()) {
            if ($stmt->rowCount() > 0) {
                echo "Dados cadastrados com sucesso!";
                $id = null;
                $nome = null;
                $email = null;
                $celular = null;
            } else {
                echo "Erro ao tentar efetivar cadastro";
            }
        } else {
               throw new PDOException("Erro: Não foi possível executar a declaração sql");
        }
    } catch (PDOException $erro) {
        echo "Erro: " . $erro->getMessage();
    }
}

Muito bem! se você rodar este código e clicar em salvar, as informações vão ser escritas no banco de dados e o formulário não retornará com mais nenhum valor.Além disso, uma mensagem “Dados cadastrados com sucesso!” será apresentada logo acima do formulário:

Artigo sobre CRUD em PHP: Etapa Create - formuláro
Artigo sobre CRUD em PHP: Etapa Create – formuláro

Agora note na próxima imagem que os dados podem ser recuperados no Banco de dados:

Artigo sobre CRUD em PHP: Visualizando os dados inseridos no banco de dados
Artigo sobre CRUD em PHP: Visualizando os dados inseridos no banco de dados

Vamos entender o que foi feito até aqui:

Primeiro, note que iniciamos um bloco “if” para descobrir se há uma ação “act” para salvar “save”, se sim, então entra em um novo bloco try e catch. Neste bloco try e catch, utilizamos o objeto de conexão do PDO que está associado a variável $conexao. Assim, temos a nossa disposição alguns métodos do objeto PDO para atender as nossas necessidade. O primeiro método é o prepare(), note a linha:


$stmt = $conexao->prepare("INSERT INTO contatos (nome, email, celular) VALUES (?, ?, ?)");

Este método transforma uma declaração SQL na forma de um “objeto declaração” que pode ser manipulado por alguns métodos específicos. Entre estes métodos, o bindParam() que vincula uma variável a um espaço demarcado na declaração.


$stmt->bindParam(1, $nome);
$stmt->bindParam(2, $email);
$stmt->bindParam(3, $celular);

O método bindParam() recebe ainda outros argumentos, mas não vamos abrangê-los aqui. Se desejar descobrir mais sobre isso, não deixe de conferir a documentação do php: http://php.net/manual/pt_BR/pdostatement.bindparam.php

A declaração estando pronta, ou seja, o novo objeto PDO Statement, então poderá ser executada. Neste momento que chamamos o método execute() do próprio objeto Statement:


if ($stmt->execute()) {

Você até poderia deixar de usar o método bindParam e definir as variáveis dentro de um array passando-os como argumento diretamente ao método execute(), todavia isto será valido apenas para tipos String. Além disso, você também poderia colocar a variável diretamente na declaração recebida pelo método prepare(), mas estaria vulnerável a problemas de segurança que também não vou destacar neste artigo. Em resumo, procure sempre usar o bindParam().

Ainda, veja que chamamos o método execute() dentro de um bloco “if”, pois ele retornará um valor booleano true se a instrução for executada com êxito. E por isso, temos um recurso para darmos o início ao tratamento de erros. Visando refinar esse tratamento de erros, aproveitamos para fazer uso de mais um método da PDO Statement que fica disponível após o execute, que é o rowCount():


if ($stmt->rowCount() > 0) {

O rowCount() retornará o número de linhas afetadas na tabela por uma última instrução DELETE, INSERT ou UPDATE executada pelo objeto PDOStatement correspondente. Em nosso caso, até agora foi um INSERT. Já que estamos inserindo uma linha, esperamos que como resposta haja um número maior que zero “0”. Logo, temos uma segunda etapa para tratar erros que nos permite fazer mais alguma coisa em caso de êxito ou não. E é isso que acontece:

Primeiro, imprimimos uma mensagem informando que tudo correu bem:


echo "Dados cadastrados com sucesso!";

Em seguida, limpamos as variáveis para que o formulário não seja preenchido novamente nesta etapa:


$id = null;
$nome = null;
$email = null;
$celular = null;

Concluímos a etapa Create do CRUD. Agora vamos passar para próxima etapa que é o Read.

Quinta Etapa: Read – Lendo os registros no banco

A funcionalidade “Read” pode ser construída de algumas maneiras: por usar um filtro para ler um registro por vez e em seguida o apresentar na tela ou mesmo utilizar algum filtro para ler vários registros e listá-los na tela, ou ainda, chamando uma listagem inteira por trazer todos os registros de uma tabela. Vamos chamar uma listagem inteira, embora isto seja verdade apenas de forma acadêmica. Vamos seguir adiante, criando uma tabela html com a tag table. Você deve posicionar esta tag table logo depois da tag de fechamento do formulário “</form>” que criamos dentro das tags “<body>” e “</body>” em nosso html e antes da tag de fechamento “</body>”. Este é o código:


<table border="1" width="100%">
    <tr>
        <th>Nome</th>
        <th>E-mail</th>
        <th>Celular</th>
        <th>Ações</th>
    </tr>
</table>

Se você abrir a página, vai perceber apenas o cabeçalho da tabela, mas nada é impresso abaixo dele e esta é nossa intenção até este momento.

Artigo sobre CRUD em PHP: Desenhando a listagem de registros - cabeçalho
Artigo sobre CRUD em PHP: Desenhando a listagem de registros – cabeçalho

Mas, agora vamos então gerar uma listagem dos registros abaixo deste cabeçalho e para isso, você deverá abrir e fechar as tags do php “<?php” e “?>” logo abaixo da tag de fechamento da linha da tabela “</tr>” e, antes da tag de fechamento da tabela “</table>”. Dentro deste bloco de código php, precisamos adicionar um novo bloco “try e catch”:


<?php
try {

    $stmt = $conexao->prepare("SELECT * FROM contatos");

        if ($stmt->execute()) {
            while ($rs = $stmt->fetch(PDO::FETCH_OBJ)) {
                echo "<tr>";
                echo "<td>".$rs->nome."</td><td>".$rs->email."</td><td>".$rs->celular
                           ."</td><td><center><a href=\"\">[Alterar]</a>"
                           ."&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
                           ."<a href=\"\">[Excluir]</a></center></td>";
                echo "</tr>";
            }
        } else {
            echo "Erro: Não foi possível recuperar os dados do banco de dados";
        }
} catch (PDOException $erro) {
    echo "Erro: ".$erro->getMessage();
}
?>

Dentro da tabela entre as tags “<table>” e “</table>”, ficará assim:


<table border="1" width="100%">
    <tr>
        <th>Nome</th>
        <th>E-mail</th>
        <th>Celular</th>
        <th>Ações</th>
    </tr>
    <?php
    // Bloco que realiza o papel do Read - recupera os dados e apresenta na tela
    try {
        $stmt = $conexao->prepare("SELECT * FROM contatos");
            if ($stmt->execute()) {
                while ($rs = $stmt->fetch(PDO::FETCH_OBJ)) {
                    echo "<tr>";
                    echo "<td>".$rs->nome."</td><td>".$rs->email."</td><td>".$rs->celular
                               ."</td><td><center><a href=\"\">[Alterar]</a>"
                               ."&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
                               ."<a href=\"\">[Excluir]</a></center></td>";
                    echo "</tr>";
                }
            } else {
                echo "Erro: Não foi possível recuperar os dados do banco de dados";
            }
    } catch (PDOException $erro) {
        echo "Erro: ".$erro->getMessage();
    }
    ?>
</table>

Abrindo a página, você perceberá que já é possivel ver um registro salvo anteriormente. Criamos este registro no teste da quarta etapa.

Artigo sobre CRUD em PHP: Apresentando registros na tela
Artigo sobre CRUD em PHP: Apresentando registros na tela

O que foi feito lá no código inserido?

Notou que preparamos mais uma declaração com o método prepare()? Sim, é exatamente para convertermos nossa declaração SQL em um objeto PDO Statement. Depois disto, logo utilizamos o método execute() do objeto PDO Statement mas, desta vez, não precisamos informar nenhum parâmetro e por isso não utilizamos o método bindParam(). Mas se fôssemos utilizar um filtro, seria ideal utilizar o método bindParam(), como já dito anteriormente. Na próxima etapa, vamos precisar construir um “Read” desta forma e você irá compreender o porquê.

Depois de executar o método execute(), precisamos recuperar o resultado de alguma forma, então iterar sobre cada registro resultante e apresentá-lo na tela. Por isso, criamos uma variável $rs de “result set” que receberá a cada iteração de loop como sendo um objeto de registro. O método fetch() do novo objeto “result set”, “busca” o resultado obtido pelo método execute() de PDO Statement. Perceba que um argumento é passado ao método fetch, o PDO::FETCH_OBJ, a fim de informar ao método que queremos obter os registros como objetos. O loop utiliza a função while, que talvez você já tenha entendido o motivo, entretanto, apenas para ficar claro, aqui estamos informamos que as iterações deverão continuar enquanto um valor seja verdadeiro para while. Enquanto for possível iterar pelo “result set”, será verdadeiro. Assim, dentro do bloco while poderemos nos referir ao objeto em $rs por seus atributos. Mas, que atributos são estes? São os nomes das colunas na tabela contatos do banco de dados. Então, isso se torna interessante porque trabalhar com um registro de forma orientado a objetos tornam os nossos projetos bem mais interessantes. É claro que você pode iterar o “result set” e trabalhar com array, assim como as antigas técnicas e se desejar saber mais sobre isso leia mais sobre isso, consulte a documentação do php em http://php.net/manual/pt_BR/pdostatement.fetch.php. Entretanto, se estiver criando um sistema totalmente orientado a objetos, o ideal será manipular os resultados como objetos.

Uma vez sabendo como recuperar o valor de cada coluna de um “result set”, é fácil imprimi-los na tela e fazemos isso simplesmente com o construtor de linguagem “echo”, como foi visto nas linhas seguintes:


echo "<tr>";
echo "<td>".$rs->nome."</td><td>".$rs->email."</td><td>".$rs->celular
           ."</td><td><center><a href=\"\">[Alterar]</a>"
           ."&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
           ."<a href=\"\">[Excluir]</a></center></td>";
echo "</tr>";

Sexta Etapa: Update – alterando registros salvos no banco.

Até aqui, você deve ter notado que ao trabalhar com a classe PDO seguimos um certo padrão e por isso, adicionar os recursos finais ao nosso aplicativo, será relativamente fácil a você compreender, mesmo agora antes de implementá-los. Note que já deixamos previamente preparados dois links para cada registo que são impressos na tabela html, que apresenta nossos registros. Mas estes links não possuem uma âncora para nenhum lugar. Se você clicar sobre eles, não farão absolutamente nada. Faremos uso do primeiro link para implementar o “Update” mas nada tão complexo assim. Para começar, precisamos informar um filtro logo alí, qual registro será que queremos alterar. Então, logo nos lembramos que para cada registro, temos um campo numérico e que é a chave primária do mesmo. Este campo é o id. Além disso, precisamos nos lembrar que nossa aplicação tendenciosamente decide tudo no “refresh de tela”, assim precisaremos indicar uma ação “act” que será interpretada neste momento. Por isso, volte sua atenção para estas linhas:


echo "<td>".$rs->nome."</td><td>".$rs->email."</td><td>".$rs->celular
           ."</td><td><center><a href=\"\">[Alterar]</a>"
           ."&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
           ."<a href=\"\">[Excluir]</a></center></td>";

Dentro da tag “<a>” com rótulo a frente “[Alterar]”, preencha ente as duas “aspas escapadas” (\”) a seguinte informação:


?act=upd&id=" . $rs->id . "

Difícil? Não, não é! Note o que muda:


echo "<td>".$rs->nome."</td><td>".$rs->email."</td><td>".$rs->celular
           ."</td><td><center><a href=\"?act=upd&id=" . $rs->id . "\">[Alterar]</a>"
           ."&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
           ."<a href=\"\">[Excluir]</a></center></td>";

O que fizemos alí foi indicar na âncora “href” do link os parâmetros “act” e “id” que serão lidos pela mesma página no refresh. Note também que não indicamos uma página alvo para âncora e sim apenas deixamos o sinal de interrogação “?”. Se você abrir a página no navegador e levar ponteiro acima do link “Alterar” de cada registro, vai notar na barra de status inferior do browser que agora um link é informado. Além disso, também já apresenta o id para cada registro. Já que estamos mexendo alí, podemos também já deixar pronto o outro link para “Delete”. Então, no dentro da tag “<a>” com rótulo “[Excluir]” logo a frente, preencha ente as duas “aspas escapadas” (\”) a seguinte informação:


 ?act=del&id=" . $rs->id . "

Veja agora o que muda:


echo "<td>".$rs->nome."</td><td>".$rs->email."</td><td>".$rs->celular
           ."</td><td><center><a href=\"?act=upd&id=" . $rs->id . "\">[Alterar]</a>"
           ."&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
           ."<a href=\"?act=del&id=" . $rs->id . "\">[Excluir]</a></center></td>";
echo "</tr>";

O que fizemos alí, também foi indicar na âncora do link os parâmetros “act” e “id” que serão lidos pela mesma página no refresh. Novamente, se você abrir a página no navegador e levar ponteiro até o link “Excluir” de cada registro, vai notar na barra de status inferior do browser que agora também há um link sendo informado. Além disso, já apresenta o id para cada registro.

Certo, até aqui preparamos o nosso aplicativo para receber os novos recursos que precisam ser implementados. Na verdade, apenas a parte de interação com o usuário está pronta, mas não a sua funcionalidade. Então vamos a lógica!

Para alterar um registro, precisamos primeiro recuperar este registro no formulário para dar ao usuário exatamente o registro salvo. E então como faremos isso? Você se lembra das variáveis $id, $nome, $email e $celular? Sim, estas variáveis precisam receber os dados filtrados para preencherem o formulário. Então vamos fazer o seguinte: logo após o final do bloco “if” que foi criado lá na quarta etapa “Create”, ou seja, o bloco que faz a persistência dos dados (Lembra-se?), será necessário adicionar este novo bloco “if” logo abaixo:


if (isset($_REQUEST["act"]) && $_REQUEST["act"] == "upd" && $id != "") {
    try {
        $stmt = $conexao->prepare("SELECT * FROM contatos WHERE id = ?");
        $stmt->bindParam(1, $id, PDO::PARAM_INT);
        if ($stmt->execute()) {
            $rs = $stmt->fetch(PDO::FETCH_OBJ);
            $id = $rs->id;
            $nome = $rs->nome;
            $email = $rs->email;
            $celular = $rs->celular;
        } else {
            throw new PDOException("Erro: Não foi possível executar a declaração sql");
        }
    } catch (PDOException $erro) {
        echo "Erro: ".$erro->getMessage();
    }
}

Mais uma vez, quando você abrir a página novamente e clicar no Update, note que os dados daquele registro serão recuperados no formulário, semelhante ao início, quando estavamos enviando via POST para testar o preenchimento do formulário. A diferença desta vez é o processo dos dados serem recuperados não de uma origem via POST, mas agora diretamente do banco de dados.

Artigo sobre CRUD em PHP: Recuperando dados no formulário
Artigo sobre CRUD em PHP: Recuperando dados no formulário

Percebeu lá no código que inserimos agora que este bloco “if” também é muito semelhante a aquele anterior na quinta etapa onde listamos os registros na tabela? Sim, mas com duas diferenças sutis:

Primeira: Utilizamos um filtro na instrução SQL pelo id e novamente fazemos uso do bindParam() para adicioná-lo ao objeto PDO Statement. Além disso, também informamos agora mais um novo parâmetro no método bindParam(), que informa qual é o tipo de dado na variável $id. Este parâmetro é indicado pela constante PDO::PARAM_INT.

Segunda: Não utilizamos mais o laço de repetição While! E isso faz sentido aqui, pois se estamos filtrando pela coluna chave primária, esperamos é claro recuperar apenas um único registro.

Na sequencia, são recuperados os atributos do “result set” para cada variável correspondente, que são lidas logo em seguida durante a construção do formulário. Assim, os campos são preenchidos com os dados das variáveis, “alimentado-os com os valores” em “value”. Interessante? 😀

Ok mas, recuperamos os dados no formulário, alteramos e … e agora para salvar os dados atualizados novamente no banco? Porque se você clicar no botão salvar, o resultado será um novo registro logo abaixo:

Artigo sobre CRUD em PHP: Está duplicando os dados ao invés de atualizá-los
Artigo sobre CRUD em PHP: Está duplicando os dados ao invés de atualizá-los

Falhamos em nosso projeto? Precisamos adicionar mais um botão para “Update“? Claro que não! Mas fica evidente que precisamos fazer uma alteração na lógica para atender a nova funcionalidade. Afinal, os nossos objetivos anteriores estavam sendo alcançados, mas agora estamos em uma nova etapa! 😉

Esta mudança será feita no bloco “if” que criamos na Quarta Etapa: Create. Então, esteja antento as mudanças seguintes:

Primeiro, olhe atentamente a linha abaixo:


$stmt = $conexao->prepare("INSERT INTO contatos (nome, email, celular) VALUES (?, ?, ?)");

Coloque esta linha dentro do bloco “else” de um novo bloco “if” que criaremos para fazer teste da variável $id, para checar se a mesma recebeu algum valor. O quê? Sim, desta forma:


if ($id != "") {

} else {
    $stmt = $conexao->prepare("INSERT INTO contatos (nome, email, celular) VALUES (?, ?, ?)");
}

Muito bem! então, alí a decisão recai sobre condição em que, se a variável $id estiver vazia, será feito um Insert, como já estava sendo feito antes. Mas e se a variável $id possuir um valor diferente de vazio?

Neste caso, faremos um “Update”! Aqui está a grande sacada! 😀 Então, o bloco deverá receber uma nova preparação de declaração para “Update”, fincando portando, assim:


if ($id != "") {
    $stmt = $conexao->prepare("UPDATE contatos SET nome=?, email=?, celular=? WHERE id = ?");
    $stmt->bindParam(4, $id);
} else {
    $stmt = $conexao->prepare("INSERT INTO contatos (nome, email, celular) VALUES (?, ?, ?)");
}

Notou que, caso seja recebido um valor em $id, estaremos executando um “UPDATE” para aquele valor armazenado na variável $id? 😉

Além disso, como vamos lidar com um quarto parâmetro a ser inserido no objeto PDO Statement, ele também já o é informado logo na linha abaixo da instrução contendo o método prepare(), dentro do mesmo do bloco “if”:


 $stmt->bindParam(4, $id);

Agora a aplicação está funcionando como esperado! Já é possível criar novos registros e atualizá-los! Faça o teste! 😀

Sétima Etapa: Delete – Excluíndo registros do banco de dados

Você já deve estar se amarrando em tudo isso até aqui! 😀 😀 😀

Mas ainda falta um recurso para concluirmos nosso projeto do CRUD: Delete. Se você foi acompanhando o passo a passo e testando o aplicativo, neste momento já deve contar com um monte de registros que pensa em excluir:

Artigo sobre CRUD em PHP: Avaliando registros criados
Artigo sobre CRUD em PHP: Avaliando registros criados

Você deve se lembrar de que na etapa anterior, preparamos a interface com usuário, deixando basicamente pronto o Link de exclusão de registro, se lembra? Portanto, falta apenas implementar a funcionalidade para este link! Para isso, logo abaixo do ultimo bloco “if” e antes da tag de encerramento do primiero bloco php “?>” e que se localiza antes das tags html, inclua este novo bloco if:


if (isset($_REQUEST["act"]) && $_REQUEST["act"] == "del" && $id != "") {
    try {
        $stmt = $conexao->prepare("DELETE FROM contatos WHERE id = ?");
        $stmt->bindParam(1, $id, PDO::PARAM_INT);
        if ($stmt->execute()) {
            echo "Registo foi excluído com êxito";
            $id = null;
        } else {
            throw new PDOException("Erro: Não foi possível executar a declaração sql");
        }
    } catch (PDOException $erro) {
        echo "Erro: ".$erro->getMessage();
    }
}

Veja que estes códigos já se tornaram muito familiares, mas com certas semelhanças e sutis diferenças:

Primeira observação: nossa declaração é um Delete e recebe um parâmetro id que será associado ao objeto PDO Statement utilizando o método bindParam(), novamente com o novo parâmetro PDO::PARAM_INT.

Segunda observação: agora não utilizamos mais um método fetch() para “juntar” alguma coisa, mas apenas o método execute(). Sim, é muito óbvio o motivo disso: porque não precisamos recuperar nenhum valor mas apenas executar o método execute() que já o é suficiente para cumprir o objetivo.

Perceba que dentro do bloco “if” do método execute() acima, deixamos uma instrução para imprimir na tela uma mensagem, informando que o registro foi excluído com êxito. Além disso, após a exclusão, precisamos anular qualquer valor na variável $id, para que o nosso formulário retorne livre e pronto para receber novos registros. Se você iniciar a página no browser, verá que o recurso de exclusão agora também funciona perfeitamente!

Conclusão

Pronto! Agora temos um CRUD completo, contendo as quatro operações do banco de dados em funcionamento: Create, Read, Update e Delete! Acredito que por seguir este passo a passo a risca, lendo e relendo se for o caso, você estará apto a criar aplicações com CRUD. Poderá criar até outras aplicações mais complexas do que esta deste artigo!

Artigo sobre CRUD em PHP Agenda de Contatos
Artigo sobre CRUD em PHP Agenda de Contatos

Abaixo está o código completo para que você possa conferir. Além disso, você também poderá baixar o projeto “com alguns leves aprimoramentos” no Github por clicar AQUI.

Dica importante: Nunca recomendo que você seja forte seguidor do uso das teclas CTRL+C e CTRL+V quando está aprendendo, mas o ideal é ir digitando caractere a caractere! Todavia, se preferir fazê-lo a fim de conferir a funcionalidade do código, a decisão está em suas mãos! have a fun! 😀


<?php
/**
 * Projeto de aplicação CRUD utilizando PDO - Agenda de Contatos
 *
 * Alexandre Bezerra Barbosa
 */

// Verificar se foi enviando dados via POST
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $id = (isset($_POST["id"]) && $_POST["id"] != null) ? $_POST["id"] : "";
    $nome = (isset($_POST["nome"]) && $_POST["nome"] != null) ? $_POST["nome"] : "";
    $email = (isset($_POST["email"]) && $_POST["email"] != null) ? $_POST["email"] : "";
    $celular = (isset($_POST["celular"]) && $_POST["celular"] != null) ? $_POST["celular"] : NULL;
} else if (!isset($id)) {
    // Se não se não foi setado nenhum valor para variável $id
    $id = (isset($_GET["id"]) && $_GET["id"] != null) ? $_GET["id"] : "";
    $nome = NULL;
    $email = NULL;
    $celular = NULL;
}

// Cria a conexão com o banco de dados
try {
    $conexao = new PDO("mysql:host=localhost;dbname=crudsimples", "root", "123456");
    $conexao->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $conexao->exec("set names utf8");
} catch (PDOException $erro) {
    echo "Erro na conexão:".$erro->getMessage();
}

// Bloco If que Salva os dados no Banco - atua como Create e Update
if (isset($_REQUEST["act"]) && $_REQUEST["act"] == "save" && $nome != "") {
    try {
        if ($id != "") {
            $stmt = $conexao->prepare("UPDATE contatos SET nome=?, email=?, celular=? WHERE id = ?");
            $stmt->bindParam(4, $id);
        } else {
            $stmt = $conexao->prepare("INSERT INTO contatos (nome, email, celular) VALUES (?, ?, ?)");
        }
        $stmt->bindParam(1, $nome);
        $stmt->bindParam(2, $email);
        $stmt->bindParam(3, $celular);

        if ($stmt->execute()) {
            if ($stmt->rowCount() > 0) {
                echo "Dados cadastrados com sucesso!";
                $id = null;
                $nome = null;
                $email = null;
                $celular = null;
            } else {
                echo "Erro ao tentar efetivar cadastro";
            }
        } else {
            throw new PDOException("Erro: Não foi possível executar a declaração sql");
        }
    } catch (PDOException $erro) {
        echo "Erro: ".$erro->getMessage();
    }
}

// Bloco if que recupera as informações no formulário, etapa utilizada pelo Update
if (isset($_REQUEST["act"]) && $_REQUEST["act"] == "upd" && $id != "") {
    try {
        $stmt = $conexao->prepare("SELECT * FROM contatos WHERE id = ?");
        $stmt->bindParam(1, $id, PDO::PARAM_INT);
        if ($stmt->execute()) {
            $rs = $stmt->fetch(PDO::FETCH_OBJ);
            $id = $rs->id;
            $nome = $rs->nome;
            $email = $rs->email;
            $celular = $rs->celular;
        } else {
            throw new PDOException("Erro: Não foi possível executar a declaração sql");
        }
    } catch (PDOException $erro) {
        echo "Erro: ".$erro->getMessage();
    }
}

// Bloco if utilizado pela etapa Delete
if (isset($_REQUEST["act"]) && $_REQUEST["act"] == "del" && $id != "") {
    try {
        $stmt = $conexao->prepare("DELETE FROM contatos WHERE id = ?");
        $stmt->bindParam(1, $id, PDO::PARAM_INT);
        if ($stmt->execute()) {
            echo "Registo foi excluído com êxito";
            $id = null;
        } else {
            throw new PDOException("Erro: Não foi possível executar a declaração sql");
        }
    } catch (PDOException $erro) {
        echo "Erro: ".$erro->getMessage();
    }
}
?>
<!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>Agenda de contatos</title>
        </head>
        <body>
            <form action="?act=save" method="POST" name="form1" >
                <h1>Agenda de contatos</h1>
                <hr>
                <input type="hidden" name="id" <?php
                
                // Preenche o id no campo id com um valor "value"
                if (isset($id) && $id != null || $id != "") {
                    echo "value=\"{$id}\"";
                }
                ?> />
                Nome:
               <input type="text" name="nome" <?php

               // Preenche o nome no campo nome com um valor "value"
               if (isset($nome) && $nome != null || $nome != "") {
                   echo "value=\"{$nome}\"";
               }
               ?> />
               E-mail:
               <input type="text" name="email" <?php

               // Preenche o email no campo email com um valor "value"
               if (isset($email) && $email != null || $email != "") {
                   echo "value=\"{$email}\"";
               }
               ?> />
               Celular:
               <input type="text" name="celular" <?php

               // Preenche o celular no campo celular com um valor "value"
               if (isset($celular) && $celular != null || $celular != "") {
                   echo "value=\"{$celular}\"";
               }
               ?> />
               <input type="submit" value="salvar" />
               <input type="reset" value="Novo" />
               <hr>
            </form>
            <table border="1" width="100%">
                <tr>
                    <th>Nome</th>
                    <th>E-mail</th>
                    <th>Celular</th>
                    <th>Ações</th>
                </tr>
                <?php

                // Bloco que realiza o papel do Read - recupera os dados e apresenta na tela
                try {
                    $stmt = $conexao->prepare("SELECT * FROM contatos");
                    if ($stmt->execute()) {
                        while ($rs = $stmt->fetch(PDO::FETCH_OBJ)) {
                            echo "<tr>";
                            echo "<td>".$rs->nome."</td><td>".$rs->email."</td><td>".$rs->celular
                                       ."</td><td><center><a href=\"?act=upd&id=".$rs->id."\">[Alterar]</a>"
                                       ."&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
                                       ."<a href=\"?act=del&id=".$rs->id."\">[Excluir]</a></center></td>";
                            echo "</tr>";
                        }
                    } else {
                        echo "Erro: Não foi possível recuperar os dados do banco de dados";
                    }
                } catch (PDOException $erro) {
                    echo "Erro: ".$erro->getMessage();
                }
                ?>
            </table>
        </body>
    </html>

Se você gostou deste artigo não deixe de se expressar. Deixe o seu “Curtir” e desde já muito obrigado!

[]’s

40 comentários

  1. Muito bom o artigo, eu estive procurando conteúdos que fossem “limpos” de framework para aprender essa parte do PHP e esse me ajudou bastante, ótima didática, parabéns.Como vi no outro comentário aqui, seria interessante um conteúdo de MVC no PHP também. Abraços.

    1. Obrigado Andrei, fico muito satisfeito com seu feedback sendo positivo e que de fato tenha alcançado meu objetivo: Ajudar! É verdade que ainda não tenho um artigo com uma aplicação exemplo em MVC ou totalmente orientado a objetos. Mas enquanto este artigo não ficar pronto, tenho mais dois artigos sobre CRUD que apresentam conceitos através de classes. Um deles utiliza um padrão de projeto “Table Data Gateway” e o outro apresenta uma ideia simplificada com DAO. Espero que possa aproveitar este material também!

  2. Ótimo artigo, parabéns! No entanto, fiquei com uma dúvida: pelo que entendi o celular não é um campo obrigatório já que no BD aceita valores NULL, no entanto na verificação de preenchimento do formulário é feita a verificação se o campo está nulo, exigindo seu preenchimento. Estou com um problema aqui para criar um CRUD justamente porque o campo deve aceitar valores nulos, mas pelo que estou lendo o NULL do PHP é diferente do NULL do MySQL.

    1. Olá Altair! Obrigado pelo feedback e fico satisfeito de ver que você pode tirar proveito! Você fez esta ótima observação por causa da linha:
      $celular = (isset($_POST[“celular”]) && $_POST[“celular”] != null) ? $_POST[“celular”] : “”;
      Muito boa sua consideração, porque de valor NULL causa muita confusão para todos iniciantes em SQL, visto que NULL não é a mesma coisa que uma string vazia “”. E este é até o caso de estar fazendo uma correção no artigo. Neste caso você pode alterar tranquilamente os “” por NULL e vai funcionar:
      $celular = (isset($_POST[“celular”]) && $_POST[“celular”] != null) ? $_POST[“celular”] : NULL;

      Além disso, adicione no começo do script algumas linhas (Abaixo em negrito) para evitar o erro de falta de variável:
      // Verificar se foi enviando dados via POST
      if ($_SERVER[‘REQUEST_METHOD’] == ‘POST’) {
      $id = (isset($_POST[“id”]) && $_POST[“id”] != null) ? $_POST[“id”] : “”;
      $nome = (isset($_POST[“nome”]) && $_POST[“nome”] != null) ? $_POST[“nome”] : “”;
      $email = (isset($_POST[“email”]) && $_POST[“email”] != null) ? $_POST[“email”] : “”;
      $celular = (isset($_POST[“celular”]) && $_POST[“celular”] != null) ? $_POST[“celular”] : NULL;
      } else if (!isset($id)) {
      // Se não se não foi setado nenhum valor para variável $id
      $id = (isset($_GET[“id”]) && $_GET[“id”] != null) ? $_GET[“id”] : “”;
      $nome = NULL;
      $email = NULL;
      $celular = NULL;

      }

      Abraço

  3. Alexandre, quero agradecer por este trabalho muito bem explicado e direcionado a um objetivo concreto. Como citou o Andrei estou buscando orientação para criar um framework que me sirva para meus projetos, onde possa entender e resolver de imediato, desta forma uma oportunidade de nos ajudar com um sistema MVC, PHPOO e PDO.

    1. Rogério, muito obrigado pelo seu feedback e fico muito feliz de saber que está ajudando. Então segue pra você em primeira mão o meu novo artigo PHP::MVC-CRUD COMPLETO . Acredito que este vai dar uma grande força no seus estudos. Este artigo foi desenvolvido exatamente na estrutura MVC, POO e PDO! Caso encontre falhas na escrita ou se torne muito complexo de entender, não deixe de dar seu feedback! Se você ainda não estiver me seguindo no blog, lhe incentivo, pois futuramente colocarei mais exemplos. Abraço!

  4. Alexandre, boa tarde! Muito bom o seu artigo! Aprendi muito!! Parabéns!!

    No final do meu projeto eu tive um pequeno problema, depois de inserir o contato, quando clico em alterar ele mantem o contato atual e cria um novo.
    É isso msm ou era para ele de fato ele substituir o antigo?

    PS.: Já comecei a ler seu novo artigo!!!! hehehe

    Desde já muito obrigado!!

    Um abraço

    1. Olá Diego, obrigado pelo seu feedback! Espero que possa evoluir bastante, há outros artigos sobre Persistência que poderão te dar uma visão bem ampla! Sobre a sua dúvida, entenda que a decisão no projeto está sendo feita em cima do id, então se for passado um id ele decide que é um update, caso contrário será um insert. Verifique estas linhas:

      
      if ($id != "") {
          $stmt = $conexao->prepare("UPDATE contatos SET nome=?, email=?, celular=? WHERE id = ?");
          $stmt->bindParam(4, $id);
      } else {
          $stmt = $conexao->prepare("INSERT INTO contatos (nome, email, celular) VALUES (?, ?, ?)");
      }
      
      

      Acredito que corrigindo isso, irá funcionar perfeitamente! Abraço!

  5. Olá Alexandre, parabéns pelo excelente material. Estou em busca de aprendizado e vou testar seu material pois sempre me perco em trabalhar com várias tabelas, ou módulos, preciso criar um app de cadastro de suportes para atendimento e vi que esse tutorial vai me ajudar muito.

  6. Olá Alexandre, Primeiramente quero lhe parabenizar pelo trabalho. funcionou direitinho aqui pra mim e acabei aprendendo muito sobre o pdo com o seu post. mas mesmo assim ainda fiquei com algumas duvidas referente alguns pontos. você por acaso teria algum canal no youtube com video aulas explicando os conceitos do PDO? estudei o outro artigo sobre MVC com PDO e POO mas no fim das contas a aplicação não funcionou na minha maquina. Segui todos os passos exatamente como vc explica no tutorial mas não consegui rodar a aplicação. li 3 vezes e escrevi o script de todas as camadas do MVC mas sem sucesso. gostaria muito de ver algum video explicativo para dominar melhor o conteúdo. inclusive estou estudando profundamente POO. aproveito pra dizer que estou ansioso pelo desenvolvimento do framework que prometeu desenvolver em breve. de qualquer forma deixa minha gratidão pelo esforço. forte abraço e sucesso.

    1. Olá Diones, fico feliz de saber que você pode tirar proveito do artigo sobre PDO e isso de fato mostra que o artigo alcançou seu objetivo. No meu blog na página “Sobre”, têm o meu e-mail. Envie um print de tela com as mensagens de erro, ou dê algum exemplo sobre o que você não conseguiu fazer. Antes, aproveito para dizer e até acredito que vou ter de adicionar essa informação no artigo, é que a versão foi toda desenvolvida para PHP 7 e não funcionará no PHP 5, a menos que, seja feito alterações, por exemplo, referente a imposição do tipo de retorno, a imposição dos tipos aceitos em alguns métodos, etc. De toda forma, não deixe de enviar suas dúvidas pois isso contribui muito para que o artigo se torne melhor, visto que posso re-avaliar a didática utilizada. Ainda não tenho um canal, mas já está em projeto! Abraço!

  7. Olá Amigo boa tarde, sou principiante como programador web, fui até a quarta etapa do tutorial. Quando o formulário é preenchido e consecutivamente salvo no banco de dados, os campos do formulário ficam em branco, o erro se dá ao atualizar a página, caso você atualize a página, mesmo em branco os campos, é inserida outra entrada no banco de dados conforme o último preenchimento. Percebi que mesmo setando as variáveis como null em algum ponto do código fica salvo esta informação que é enviado para o banco quantas vezes atualizar a página.

    1. Ola Nilson, você tem razão! Porque os dados estão no cache do navegador e um F5 forçará um novo submit quando a página tem refresh. Se este procedimento for em testes que você mesmo estiver executando, talvez por teclar F5 para atualizar a tela visualizar uma mudança no código, considere, clicar no campo da Uri e teclar Enter. Desse jeito você estará forçando o recarregamento da página. Mas se o que você busca é evitar registro duplicado, ou seja, um nome não pode aparecer duas vezes, considere alterar a coluna nome para conter apenas dados únicos, e talvez para evitar o erro de SQL, fazer uma consulta ao banco para certificar que os dados enviados não sejam repetidos! Se você não souber como fazer, me mande um e-mail sobre isso. Abraço!

      1. Olá Alexandre, obrigado pela pronta resposta e consecutivamente pela dica, setar um dos campos do BD como unique resolveu o problema. Mas fiquei em dúvida o que seria clicar no campo da Uri? A opção de se realizar uma consulta automática no BD (validação Front End) antes de adicionar um novo registro seria bacana, porém este não sei fazer, seria mais comodo para o usuário. Mas para o caso de atualizar a página sera que não teria uma forma de limpar a memória após gravar no banco?

  8. Boa noite Alexandre.
    Pode fazer um exemplo de uso de uma segunda tabela relacionada neste crud.
    Por exemplo tbl_tipocontato (tip_id, tip_descricao)

    1. Olá Nilton, Seja Bem Vindo!

      Você precisa ter cadastros dos tipos para relacionar as chaves, como você mesmo já sujere, por exemplo um cadastro para os tipos de contatos, onde provavelmente haveria um campo id e um campo “tipo_contato” ou “nome” ou “descricao”, como você mesmo está construíndo. Todas as vezes que carregar o formulário, precisa adicionar um componente select e preenche-lo com o resultado da consulta ao banco. Cada option terá o id no value e o tipo a ser impresso na tela, por exemplo Telefone. O processo de construção é simples, nada muito diferente do que você já fez. Supondo que você tenha uma tabela tipos_contatos, (tirei os prefixos que você sujere para simplificar):

      
      $stmt_tp_contato->prepare("SELECT * FROM tipos_contatos");
      
      if ($stmt_tp_contato->execute()) {
          while ($rs_tp_contatos = $stmt_tp_contato->fetch(PDO::FETCH_OBJ)) {
      ?><option value="<?= $rs_tp_contatos->tipo_contato_id ?>" <?php 
      if ($rs_tp_contatos->tipo_contato_id == $tipo_contato_id) {
          echo "selected";
      }?> ><?= $rs_tp_contatos->tipo_contato_descricao ?> >
      

      De onde vêm a variável $tipos_contatos e $tipo_contato_id ? A tabela contato deverá ter uma chave extrangeira com um nome como esse do exemplo: tipo_contato_id . Essa chave estrangeira se refere a chave primária na tabela de tipos de contatos que você deve criar e elaborar um CRUD para ela, semelhante ao do exercício ou preencher os dados, inserindo direto no banco.
      No create, você vai passar o valor do elemento HTML select e capturar como os outros campos:

      $stmt = $conexao->prepare("INSERT INTO contatos (..., tipo_contato_id...) VALUES (...?, ...)");
      $stmt->bindParam(4, $tipo_contato_id); // Esse número 4 é um exemplo, mas deve estar de acordo com o comando Insert que você criar
      
      if ($stmt->execute()) {
          if ($stmt->rowCount() > 0) {
              echo "Dados cadastrados com sucesso!";
                      ...
              $tipo_contato_id = null;
                      ...
              } else {
                  echo "Erro ao tentar efetivar cadastro";
              }
      

      Então no Update você já deve ter entendido que tera uma variável semelhante a essa na lista:

      
      $tipo_contato_id = $rs->tipo_contato_id;
      
      

      Note que toda operação sempre é em cima dos valores de chaves primária e estrangeira, porque outros campos como descrição servem apenas para conter informações para o usuário, neste caso. Por isso ele não é usado num insert ou update.

      Nilton, acredido que você vai acertar na primeira! Se você tiver o projeto no Github poste aí com a dúvida!

      abraço!

  9. Estava com dúvida na criação de CRUD, mas o passo a passo foi muito esclarecedor.
    Estou deixando a área de infra e migrando para DEV, afinal hoje crio, altero e deleto a estrutura de servidores via código pelo Terraform/Ansible.

  10. Boa tarde Alexandre,
    Tirar esta dúvida do arquivo conexao.php, nesta linha :
    try {
    $conexao = new PDO(“mysql:host=localhost; dbname=crudsimples”, “root”, “123456”);

    Pode ser feita assim:
    $dblocal = “localhost”;
    $dbuser = “root”;
    $dbpass = “123456”;
    $dbname = “crudsimples”;
    try {
    $conexao = new PDO(“mysql:host=localhost; dbname=crudsimples”, $dbuser, $dbpass);

    E nos arquivos faço o include ‘conexao.php’; e uso a variável nos arquivos .php:
    $conexao

    Aqui tentei colocar todas as variáveis, mas não consegui:
    $conexao = new PDO(“mysql: ” $dblocal, $dbname, $dbuser, $dbpass);

      1. Bom dia Alexandre,

        Eu aqui novamente. Queria saber se vc pode me ajudar em uma parte do meu projeto. Você me passa o valor que te pago. Venho tentando esta parte, ate fiz várias buscas, mas não obtive algo que me ajudasse.

        A questão é sobre listar os registros da tabela clientes onde existe as duas tabelas relacionadas. Uma faço o select do setor e a outra o local. Preciso listar assim: Local: A Setor: A-101 id -nome 1 cliente fulano de tal 2 cliente sicrano de tal

        Setor: A-102 3 – xxxxx 4 – zzzzzzzz Local: B Setor: B-101 5 – dddddddd 6 – ppppppp

        E assim por diante.

        Tabelas tbCliente (idCliente, nomeCliente, idLocal, idSetor)

        Tabela tbLocal idLocal – nomeLocal 1 – A 2 – B 3 – C

        Tabela tbSetor idSetor – nomeSetor – idLocal 1 – A-101 – 1 2 – A-102 – 1 3 – A-103 – 1 4 – B-101 – 2 5 – B-102 – 2

        6 – C-101 – 3 7 – C-102 – 3 8 – C-103 – 3

        A parte do select, já consegui. Está funcionando, mas no PHP que tenho dificuldade para mostrar.

        Estou no trabalho, por isto que escrevi do celular.

        Qualquer detalhe, só informar.

        Atenciosamente,

        Nilton

        Em ter, 14 de jul de 2020 23:12, Alexandre Bezerra Barbosa escreveu:

        > Alexandre Bezerra Barbosa commented: “Olá Nilton! Tem de fazer um pequeno > ajuste! Tente assim: $conexao = new PDO(“mysql:host={$dblocal}; > dbname={$dbname}”, $dbuser, $dbpass); Acredito que desta maneira dará > certo! Abraço!” >

      2. Olá de novo Nilton!

        Desculpe, talvez eu não tenha entendido sua dúvida, mas com base na suas informações de tabela, seria assim?

        
        /** Conexão com banco de dados */
        $conn = new \PDO("mysql:host=localhos; dbname=dbclientes", 'root', 'Su@S3nh@');
        
        /** String da declaração criada com herodoc */
        $sql = <<<SQL
        SELECT 
            `nomeCLiente` as `cliente`,
            `nomeLocal` as `local`,
            `nomeSetor` as `setor`
        FROM 
            `tbCliente` `tCli`
        LEFT JOIN 
            `tbSetor` `tS` ON `tCli`.`idSetor` = `tS`.`idSetor`
        LEFT JOIN
            `tbLocal` `tL` ON `tCli`.`idLocal` = `tL`.`idLocal`
        LIMIT 10,1;"; 
        SQL;
        
        $stmt = $conn->prepare($sql);
        
        /** Se executou */
        if ($stmt->execute()) {
        
            /** Se encontrou resultados */
            if ($stmt->rowCount() > 0) {
                
                $recordSet = $stmt->fetchAll(\PDO::FETCH_ASSOC);
        	
                /** Iterar pelos resultados *
                foreach ($recordSet as $row) {
                    echo "Setor: {$row["setor"]} - Local: {$row["local"]} Cliente: {$row["cliente"]} <br />";
                }
            }
        }  
        

        Aí acima também pode substituir os LEFT JOIN por JOIN, mas nesse caso só trará resultados se nas três tabelas existirem os dados relacionados com suas chaves. Com LEFT JOIN sempre trará resultados desde que haja um setor, local e por fim cliente.

        Espero ter ajudado amigo!

        Abraço!!

      3. Fiz um print da listagem no Access para ver de como é feito. Pensei que dava para enviar neste email. Mas postei aqui: https://ibb.co/MN9yWH5

        Em qui., 16 de jul. de 2020 às 00:12, Alexandre Bezerra Barbosa escreveu:

        > Alexandre Bezerra Barbosa commented: “Olá de novo Nilton! Desculpe, talvez > eu não tenha entendido sua dúvida, mas com base na suas informações de > tabela, seria assim? $conn = new \PDO(“mysql:host=localhos; > dbname=dbclientes”, ‘root’, ‘Su@S3nh@’); $sql = “SELECT nomeCLiente as c” >

  11. Alexandre, desculpe, mas interpretei mal esta parte. Na verdade isto é um relatório, ou seja a listagem para ser impresso conforme o total de cada local. Acredito que terei que procurar nos tutoriais de mpdf.

  12. Olá, Alexandre, muito obrigado pelo material disponibilizado!
    Como ficaria para recuperar as informações no formulário em elementos select? Estou trabalhando com PDO e seu artigo tirou muitas dúvidas, só não consegui resolver isso.
    Poderia me ajudar? obrigado =)

    1. Olá Kleber, obrigado por prestigiar o artigo do blog.
      Para você recuperar informações de um select em um formulário, precisa ter uma consulta que para preencher o select [ou uma coleção em um array] e outra, naturalmente que retorna os dados do formulário.

      Veja o exemplo abaixo. Sua consulta para preencher o select deveria trazer ao menos duas chaves por resultado obtido. Neste exemplo suponhamos: funcionario_id e nome. Então quando construisse o código, deveria ser algo assim:

      <b>Funcionário:</b>
      <select name="funcionario_id" >
          <?php foreach ($funcionarios as $funcionario) : ?>
              <option value="<?php echo $funcionario['funcionario_id']; ?>"
                  <?php if ($funcionario['funcionario_id'] == $dados_form['funcionario_id']) : ?>
                      selected
                  <?php endif; ?>
              ><?php echo $funcionario['nome']; ?></option>
          <?php endforeach; ?>
      </select>
      

      Neste exemplo do código acima, imagine que a variável $dados_form, contenha todos os dados que serão recuperados no formulário. Provavelmente um deles poderia ter uma chave “funcionario_id”. Então basta fazer uma comparação desta chave $dados_form[“funcionario_id”] com cada resultado iterado no laço foreach.
      Quando o valor for verdadeiro em if, ou seja, quando os dados casarem, ele irá imprimir “selected”
      Feito isso, você terá recuperado no formulário, exatamente a opção marcada!

      Espero ter ajudado em sua dúvida.

      []’s

      1. Com certeza ajudou, e muito, Alexandre!
        Muito obrigado pelo apoio, acabei de testar e funcionou perfeitamente!
        Parabéns pelo trabalho e o apoio prestado aos leitores.

  13. Obrigado pelo conteúdo Alexandre, comecei a estudar PHP junto com o MySQL e o seu material foi muito útil, minha única dúvida é quando atualizo (F5) o navegador verifico que o registro anterior é inserido novamente mesmo com o formulário em branco. Li os comentários vi que alguns usuários também tem a mesma dúvida porém não encontrei a solução.

    1. Olá André, obrigado por prestigiar o material. Fico feliz de poder colaborar com seu aprendizado.
      Realmente esse é um bug comum em algumas aplicações inclusive em um grande sistema que trabalho atualmente: Quando enviar a requisição post, novamente inserir como se fossem novos dados enviados pelo próprio usuário. Existem sim algumas soluções para isso, contudo elas nem sempre serão tão simples ou práticas. Por exemplo: (1) criar uma consulta ao banco para validar se os dados que estão sendo submetidos já existem no banco. Neste cenário com poucos dados funcionará bem sem muita complexidade, mas em um cenário utilizando um formulário com mais dados, poderá não ser a solução ideal. Até poderá se a consulta for feita em cima de campos obrigatórios e que não podem ser repetidos. (2) Uma outra maneira não prática é após salvar, dar um reload para própria página usando uma instrução javascript. E para essa segunda sugestão, o ideal ainda seria dividir o projeto em duas páginas, uma que recebe as solicitações e salvam os dados e a uma outra que contém o formulário que submete o dados. Então ao salvar fazer um redirect para página anterior. Espero que possa ajudar com essas duas sugestões!
      []’s

Deixar mensagem para Alexandre Bezerra Barbosa Cancelar resposta

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