Tecnologia em Sistemas para Internet
Componente Curricular: Desenvolvimento para Servidores I
015 – Programação Orientada a Objetos e PHP
Conexão com Bancos de Dados usando PDO – PHP Data Objects
Professor: Jorge Luís Gregório | e-mail: jorge.gregorio@fatec.sp.gov.br
@jlgregorio81 Jorge Luís Gregório
Um pouco de história...
• A comunidade PHP sempre foi muito grande e muito ativa no mundo todo,
desta forma, o PHP cresceu com uma grande diversidade de bibliotecas
construídas para resolver problemas muito específicos, principalmente
quando o assunto é banco de dados.
• Existem diversos SGBDs no mercado, entre eles, os mais populares são
MySQL, Firebird, Postgres, entre outros. Desta forma, o PHP, no ápice do
seu crescimento fornecia bibliotecas diferentes com funções diferentes
para bancos de dados diferentes.
• Apesar de resolver problemas de desenvolvedores de bancos de dados
específicos, essa solução limitava o PHP, pois, ao ser considerada a
mudança do SGBD de uma aplicação, o desenvolvedor teria que adaptar
e/ou alterar todo a lógica de acesso ao banco de dados, pois o PHP
fornecia funções específicas para cada banco.
• Face a essa limitação, surge o PDO – PHP Data Objects
PDO – PHP Data Objects
• O PDO fornece uma API limpa e consistente que visa
unificar a maioria das características e funções
presentes nas extensões dos bancos de dados aos
quais o PHP suporta (Dall’Oglio, 2009, pág. 159)
• A PDO unifica as chamadas de métodos e, de acordo
com o banco de dados selecionado, faz a delegação
para a extensão específica do banco de dados.
• A PDO é totalmente orientada a objetos, diferente das
extensões específicas dos bancos de dados que ainda
possui o modelo procedural de chamada de funções.
PDO e as extensões para acesso a
bancos de dados do PHP
PDO
Extensão do
MySQL
Extensão do
PostgreSQL
Extensão do SQLite
Banco de dados
Aplicação Web
Ativando extensões no WAMP
• Por padrão, a extensão para conexão com banco de
dados MySQL vem ativa no Wamp. Caso deseja usar o
Postgres, é necessário ativar a exetensão.
– Clique no ícone do WAMP na bandeja do sistema,
selecione a opção PHP, depos PHP Extensions e ative as
opções php_pdo_pgsql e php_pgsql
• Para fazer manualmente, é necessário abrir o arquivo
php.ini na pasta do servidor Apache e retire o
comentário (símbolo ;) das linhas onde se encontra
digitado
extension=php_pdo_pgsql.dll
extension=php_pgsql
Testando se o PDO/PGSQL está ativo
• Depois de ativar as extensões do Postgres no PHP é
necessário fazer um teste para verificar se estão ativas;
• Crie um arquivo index.php e digite o seguinte código
nele:
phpinfo();
A função phpinfo mostrará todas as configurações do
servidor Apache e quais drivers de conexão foram
carregados. Localize as palavras PDO, pdo_pgsql e pgsql.
Se todas estiverem presentes, tanto o driver de conexão
com o Posgres quanto o PDO estão ativos.
Verificando a configuração
Abrindo o index.php no browser
Erro persistente!
• Caso os drivers/extensões não tenham sido carregados, provavelmente será
necessário editar o arquivo de configuração do Apache inserindo uma linha de
comando para carregar a DLL (Dynamic Link Library) de conexão com o Postgres.
• Essa DLL fica na pasta do wamp no seguinte caminho:
binphp<versão_do_php>libpq.dll
Abra o arquivo de configuração do Apache (httpd.conf) que fica na pasta do wamp no
seguinte caminho:
binapache<versão_do_apacheconfhttpd.conf
Logo após a última linha com o comando LoadModule, adicione a seguinte linha de
comando:
LoadFile “<raiz_do_wamp>/bin/php/<versão_do_php>/libpq.dll”
Criando um banco de dados
• Abra o PgAdmin (Postgres) e crie um banco de
dados com o nome ‘database’ (sem aspas)
• Clique no link para baixar o script para a
criação das tabelas:
– Clique aqui!
Powered by:
String de conexão
Banco de
Dados
String de conexão
FireBird new PDO(“firebird:dbname=C:base.GDB”,
“SYSDBA”, “masterkey”);
MySQL new
PDO(‘mysql:unix_socket=/tmp/mysql.sock;host=loc
alhost;port3306;dbname=livro’,’user’,’senha’)
Postgres new
PDO(‘pgsql:dbname=example;user=user;password=se
nha;host=localhost);
Adaptado de Dall’Oglio, 2009, pág. 160
Criando uma classe de conexão
namespace util;
use PDO;
/**
* Description of Connection
*
* @author JorgeLuis
*/
class Connection {
//..constantes para conexão com o Postgres
const DBNAME = 'database';
const USER = 'postgres';
const PASSWORD='postdba';
const HOST = 'localhost';
const PORT = 5432;
/**
* Retorna um objeto do tipo PDO pronto para executar instruções SQL no banco de dados
* @return PDO
* @throws utilPDOException
*/
public static function getConnection(){
try {
return new PDO("pgsql:dbname=".self::DBNAME.";user=".self::USER .
";password=".self::PASSWORD.";host=".self::HOST .
";port=".self::PORT);
} catch (PDOException $ex) {
throw $ex;
}
}
}
Inserindo dados
O método exec da classe PDO é capaz de executar uma instrução SQL diretamente no banco de
dados. O retorno do método é um número inteiro contendo a qtde de linhas linhas que foram
atualizadas no banco de dados.
require_once 'autoload.php';
use utilConnection;
try {
//..pega um objeto PDO
$db = Connection::getConnection();
} catch (Exception $ex) {
//..trata a exceção
echo $ex->getMessage() . " - " . $ex->getCode();
}
//..inserindo na tabela cidade
$linhas = $db->exec("insert into cidade (nome, uf, cep) values('Urânia','SP','15760000')");
if ($linhas > 0)
echo 'Dados inseridos!<br>';
else
echo 'Erro!';
Atualizando registros
O comando exec pode ser usado também para comandos de update:
require_once 'autoload.php';
use utilConnection;
//..pega um objeto PDO
$db = Connection::getConnection();
//..executa o comando update
$linhas = $db->exec("update cidade set nome='Londrina', uf='PR' where id_cidade = 1");
if($linhas > 0)
echo 'Dados atualizados com sucesso!<br>';
else
echo 'Erro!<br>';
Excluindo registros
require_once 'autoload.php';
use utilConnection;
//..pega um objeto PDO
$db = Connection::getConnection();
//..executa o comando delete
$linhas = $db->exec("delete from cidade where id_cidade = 1");
if($linhas > 0)
echo 'Dados excluídos com sucesso!<br>';
else
echo 'Erro!<br>';
Listando registros
• Para listar registros, isto é, executar uma consulta no banco de dados, o método
query deverá ser invocado. Se não houver dados que satisfaçam a consulta, o
retorno do método será false, caso contrário, será retornado um objeto
PDOStatement que é um resultset no formato de um array composto de outros
arrays.
require_once 'autoload.php';
use utilConnection;
//..pega um objeto PDO
$db = Connection::getConnection();
//..executa a consulta
$resultSet = $db->query('select * from cidade order by nome');
//..se houver resultSet, então itera-o mostrando os campos da consulta
if($resultSet){
foreach ($resultSet as $reg) {
echo $reg['id_cidade'] . ' - ';
echo $reg['nome'] . ' - ';
echo $reg['uf'] . ' - ';
echo $reg['cep'] . '<br>';
}
}
Listando registros
• É possível determinar outros formatos para
retornar os dados usando a função FETCH e
passando um parâmetro de acordo com a
tabela:
Parâmetros Descrição
PDO::FETCH_ASSOC Retorna um array indexado pelo nome da coluna (padrão)
PDO::FETCH_NUM Retorna um array indexado pela posição numérica da coluna
PDO::FETCH_BOTH Retorna um array indexado pelo nome da coluna e pela
posição numérica da mesma.
PDO::FETCH_OBJ Retorna um objeto (StdClass), de modo que cada coluna é
acessada como um propriedade.
Adaptado de Dall’Oglio, 2009, pág. 162
Listando registros - objetos
require_once 'autoload.php';
use utilConnection;
//..pega um objeto PDO
$db = Connection::getConnection();
//..executa a consulta
$resultSet = $db->query('select * from cidade order by nome');
if($resultSet){
while ($reg = $resultSet->fetch(PDO::FETCH_OBJ)){
echo $reg->id_cidade . ' - ' .
$reg->nome . ' - ' .
$reg->uf . ' - ' .
$reg->cep . '<br>';
}
}
Listando registros – índice numérico
require_once 'autoload.php';
use utilConnection;
//..pega um objeto PDO
$db = Connection::getConnection();
//..executa a consulta
$resultSet = $db->query('select * from cidade order by nome');
if($resultSet){
while ($reg = $resultSet->fetch(PDO::FETCH_NUM)){
echo $reg[0] . ' - ' .
$reg[1] . ' - ' .
$reg[2] . ' - ' .
$reg[3] . '<br>';
}
}
Este modo é recomendável para simplificar a referência aos atributos quando estes
são conhecidos. O parâmetro PDO::BOTH permite que os atributos sejam
referenciados tanto por índices numéricos, quanto por chaves.
Tratamento de erros
• A classe PDO possui um método chamado setAttribute ao qual é possível
configurar, entre outros recursos avançados, o modo de como os erros
gerados pelo objeto serão tratados.
• É recomendável configurar a classe de conexão para gerar exceções, pois
assim é possível lançar e/ou tratar os erros de forma mais elegante através
dos já conhecidos blocos try..catch.
• A exceção gerada é uma instância de PDOException, isto é, uma exceção
específica para erros de bancos de dados.
• Exemplo:
//..pega um objeto PDO
$db = Connection::getConnection();
//..seta o modo de erros
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
A partir de agora, o objeto $db irá lançar exceções, caso aconteçam.
Exemplo completo
try {
//..pega um objeto PDO
$db = Connection::getConnection();
//..seta o modo de erros
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//..executa a consulta - nome da tabela cidade está errado – vai gerar erro!
$resultSet = $db->query('select * from cidades order by nome');
if ($resultSet) {
while ($reg = $resultSet->fetch(PDO::FETCH_BOTH)) {
echo $reg[0] . ' - ' .
$reg[1] . ' - ' .
$reg['uf'] . ' - ' .
$reg['cep'] . '<br>';
}
}
} catch (PDOException $ex) {
//..mostra a mensagem de erro
echo $ex->getMessage();
}
Modificando a classe Connection
• Para fazer com que a classe Connection retorne um objeto PDO pronto a gerar exceções, segue uma nova
proposta.
namespace util;
use PDO;
/**
* Description of Connection
*
* @author JorgeLuis
*/
class Connection {
//..constantes para conexão com o Postgres
const DBNAME = 'database';
const USER = 'postgres';
const PASSWORD='postdba';
const HOST = 'localhost';
const PORT = 5432;
/**
* Retorna um objeto do tipo PDO pronto para executar instruções SQL no banco de dados
* @return PDO
* @throws utilPDOException
*/
public static function getConnection(){
try {
//..pega um objeto PDO
$connection = new PDO("pgsql:dbname=".self::DBNAME.";user=".self::USER.
";password=".self::PASSWORD.";host=".self::HOST.";port=".self::PORT);
//..configura para gerar exceções sempre que um erro ocorrer
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//..retorna o objeto PDO;
return $connection;
} catch (PDOException $ex) {
throw $ex;
}
}
}
Exemplo de tratamento de erros
require_once 'autoload.php';
use utilConnection;
try {
//..pega um objeto PDO
$db = Connection::getConnection();
//..executa a consulta - nome da tabela cidade está errado – vai gerar Exceção
$resultSet = $db->query('select * from cidades order by nome');
if ($resultSet) {
while ($reg = $resultSet->fetch(PDO::FETCH_BOTH)) {
echo $reg[0] . ' - ' .
$reg[1] . ' - ' .
$reg['uf'] . ' - ' .
$reg['cep'] . '<br>';
}
}
} catch (PDOException $ex) {
echo $ex->getMessage();
}
Transações
Uma transação representa uma interação entre a
aplicação e o sistema de banco de dados tratada de
forma única e independente. Pense em uma
transação financeira de transferência de fundos.
Este tipo de transação necessita de um grande
cuidado pois, do contrário, uma conta pode ser
debitada e a outra não ser creditada, ou vice-versa.
Uma transação é uma sequência de trabalho que
tem um ponto de início e de fim bem definidos [...]”
DALL’OGLIO, 2009, pág. 206
Propriedades de Transações - ACID
• Atomicidade: uma transação pode envolver uma ou mais interações com
o banco de dados, porém deve ser vista como uma única operação. Se
uma delas falhar, os dados não refletirão o mundo real então, toda a
operação deverá ser revertida (rollback). Executa tudo ou nada. Sem
operações incompletas.
• Consistêcia: após a transação, os dados devem permanecer íntegros, ou
seja, com todas as suas restrições (chave primária, check, etc) intactas.
• Isolamento: as transações devem ser executadas isoladas de outras
transações, pois pode ser que um registro seja acessado por diversas
transações ao mesmo tempo (venda de um produto). O resultado da
transação só deve ser visível após o seu término.
• Durabilidade: deve haver a garantia de que os dados serão persistentes
após o término da transação, ou seja, ela não será desfeita e/ou perdida
por qualquer que seja o motivo.
Sintaxe
try{
//..inicia a transação
PDOObject->beginTransaction();
//..instrução SQL 01
//..instrução SQL 02
//..instrução SQL 03
//..instrução SQL n...
//..confirma a transação
PDOObject->commit();
}
catch(PDOException $ex){
//..retorna ao estado inicial caso aconteça algum erro
PDOObject->rollBack();
}
Exemplo
• No banco de dados, a tabela pessoafisica é uma
especialização da tabela pessoa, ou seja, para
cadastrar uma pessoa física é necessário primeiro
a inserção dos dados na tabela pessoa e, após
obter o nº do id inserido, é necessário inserir o
registro específico na tabela pessoafisica.
• Se qualquer uma das operações falhar no
momento da confirmação (commit), o sistema
deverá cancelar a transação (rollback).
• Os dados deverão ser inseridos nas duas tabelas
ou em nenhuma (atomicidade).
Código-fonte comentado
require_once 'autoload.php';
use utilConnection;
try{
//..pega uma conexão
$connection = Connection::getConnection();
//..inicia a transação
$connection->beginTransaction();
//..inicia as operações da transação
//..executa a instrução SQL para inserção em pessoa
$connection->exec("insert into pessoa(nome, id_cidade) values ('Peter Parker', 2);");
echo 'Pessoa Inserida! <br>';
//..pega o id do registro inserido em pessoa para inserí-lo em pessoafisica
$id = $connection->lastInsertId("seq_pessoa");
echo "ID inserido: $id <br>";
//..executa a instrução SQL para a inserção em pessoafisica
$connection->exec("insert into pessoafisica values ($id, 'M', '111','222','Rua XYZ','15999000');");
echo 'Pessoa Física Inserida! <br>';
//..confirma a transação
$connection->commit();
}
catch (PDOException $ex){
//..Se gerar exceção, mostra o erro e executa um rollback.
echo 'Erro na transação: ' . $ex->getMessage() . '<br>';
$connection->rollBack();
}
Dica: Para verificar se o controle de transação está realmente dando certo, crie um erro em uma
das instruções SQL, na primeira ou na segunda. Com erros, a lógica acima cairá no bloco catch e o
rollback será executado desfazendo as alterações.
Atividade Prática
• Criar uma aplicação simples que cadastre e liste
os dados de um formulário
• Dados:
– Nome (campo de texto)
– Sexo (campo select)
– Formação (campo select)
• Ensino fundamental
• Ensino médio
• Superior
• Pós graduação
• Outros
Mapeamento Objeto-Relacional
• Persistência
– Persistir quer dizer perdurar, resistir ao tempo. Em
uma aplicação, persistir significa fazer com que os
objetos do modelo de negócio sejam “gravados” em
um local externo à aplicação e que, principalmente,
permita sua posterior recuperação.
– Objetos existem apenas durante um certo período de
tempo dentro dos limites da aplicação, desta forma, é
extremamente importante seu armazenamento.
Mundo OO vs Mundo Relacional
[...] existem diversos conceitos da orientação a objetos
para os quais o modelo relacional simplesmente não
oferece suporte, então temos uma diferença de conceito.
Os bancos de dados foram construídos para armazenar
dados, ao passo que, no paradigma orientado a objetos,
além de dados (atributos), temos comportamento
(métodos) e outras estruturas complexas. Dessa forma, é
necessário utilizar alguma ferramenta de compatibilidade
entre os dois modelos, que geralmente implementam
algum técnica de mapeamento objeto-relacional. [...]
DALL’OGLIO, 2009, pág. 222
Mundo OO vs Mundo Relacional
• Mundo Relacional
– Tabelas: entidade que
armazena dados
– Registros: cada dado ou
conjunto de dados de uma
tabela real ou gerada por
SQL
– Chaves primárias:
responsáveis por:
• Fazer com que um registro
seja único
• Fazer com que as tabelas se
relacionem através de
ligação com chaves
estrangeiras
• Mundo OO
– Objetos: armazenam dados
e são capazes de realizar
tarefas
– Listas: conjuntos de
objetos
– Os relacionamentos são
feitos por associações:
• Associação simples
• Composição
• Agregação
Mundo OO vs Mundo Relacional
• Padrões para mapeamento objeto-relacional:
– Identity Field: campo autoincremento para chave primária/estrangeira
– Foreign Key Mapping: composição (relacionamento “forte” todo/parte) no
mundo OO pode ser realizada através de chaves estrangeiras.
– Association Table Mapping: agregação (relacionamento “fraco” todo/parte )
também pode ser mapeado como chaves estrangeiras.
– Herança
• Single Table Inheritance: as classes são mapeadas para uma única tabela contendo todos os
atributos comuns da hierarquia.
• Concrete Table Inheritance: as classes são mapeadas para diversas tabelas, cada classe possui
uma tabela de forma independente.
• Class Table Inheritance: e criada uma tabela para cada classe na estrutura da hierarquia. Após
isso, cria-se uma generalização/especialização através de pares de chaves primárias.
Maiores detalhes em Dall’Oglio, pág. 222-231.
DAO – Data Access Object
• O padrão de projeto DAO propõe a criação de uma camada de
acesso a dados independente de outras camadas da aplicação, ou
seja, os objetos DAO possui a responsabilidade de persistir objetos
em bancos de dados, realizando, o mapeamento objeto-relacional
(Object-Relational Mapping).
• Além da persistência (inserts e updates), os objetos DAO também
podem recuperar dados através de consultas SQL e retornar apenas
objetos de negócio (model) para a aplicação.
• Vantagens:
– Isolar a lógica de acesso e manipulação de dados de outros
componentes do sistema melhora a reusabilidade, escalabidade e
manutenabilidade do código.
DAO – Data Access Object
model
Classe1 Classe2
* *
Classe3 Classe4
1 *
+findById()
+persist()
+query()
+delete()
DAO
Banco de
dados
Objetos model Instruções SQL
Dados
Objetos
Exemplo
• Baixar o código-fonte comentado no link
abaixo:
– Clique aqui!
Powered by:
Discussão – a camada model
Discussão – a camada dao
Discussão – métodos DAO
• Os objetos DAO devem implementar a interface Idao, então,
surgem os seguintes métodos:
– persist($modelObject)
• Insere e/ou atualiza um registro no banco de dados mediante um objeto
model informado. O objeto deverá ser mapeado em dados relacionais e
persistido no Banco de Dados.
– delete($id)
• Exclui um registro baseado no id informado
– query($field = null, $like=null)
• Realiza uma query do tipo “selecionar tudo” ou usando um campo e uma
cláusula ‘like’ como filtros. Retorna um ArrayObject (array de objetos)
– findById($id)
• Recupera um registro mediante o id informado, mapeia-o em objeto e retorna
para a aplicação.
O que vem depois???
• Agora que a camada DAO está pronta, é
necessário integrá-la a sua aplicação.
• MVC – Model/View/Controller
– Padrão de Projeto (Design Pattern) que divide uma
aplicação em 3 camadas distintas.
– O padrão DAO combina muito bem com o MVC.
Bibliografia recomendada
DALL’OGLIO, Pablo. Capítulo 3: Manipulação de dados. In: ________. PHP:
programando com orientação a objetos. 2. ed. São Paulo: Novatec, 2009. p. 154-220.
Manual do PHP. PHP Data Objects. Disponível em <http://php.net/manual/pt_BR/
book.pdo.php> Acesso em 20 jan. 2015.
Manual do PHP. PHP::setAttribute. Disponível em <http://php.net/manual/pt_BR/
pdo.setattribute.php> Acesso em 20 jan. 2015.

Dsi 015 - poo e php - conexão com bancos de dados usando pdo

  • 1.
    Tecnologia em Sistemaspara Internet Componente Curricular: Desenvolvimento para Servidores I 015 – Programação Orientada a Objetos e PHP Conexão com Bancos de Dados usando PDO – PHP Data Objects Professor: Jorge Luís Gregório | e-mail: jorge.gregorio@fatec.sp.gov.br @jlgregorio81 Jorge Luís Gregório
  • 2.
    Um pouco dehistória... • A comunidade PHP sempre foi muito grande e muito ativa no mundo todo, desta forma, o PHP cresceu com uma grande diversidade de bibliotecas construídas para resolver problemas muito específicos, principalmente quando o assunto é banco de dados. • Existem diversos SGBDs no mercado, entre eles, os mais populares são MySQL, Firebird, Postgres, entre outros. Desta forma, o PHP, no ápice do seu crescimento fornecia bibliotecas diferentes com funções diferentes para bancos de dados diferentes. • Apesar de resolver problemas de desenvolvedores de bancos de dados específicos, essa solução limitava o PHP, pois, ao ser considerada a mudança do SGBD de uma aplicação, o desenvolvedor teria que adaptar e/ou alterar todo a lógica de acesso ao banco de dados, pois o PHP fornecia funções específicas para cada banco. • Face a essa limitação, surge o PDO – PHP Data Objects
  • 3.
    PDO – PHPData Objects • O PDO fornece uma API limpa e consistente que visa unificar a maioria das características e funções presentes nas extensões dos bancos de dados aos quais o PHP suporta (Dall’Oglio, 2009, pág. 159) • A PDO unifica as chamadas de métodos e, de acordo com o banco de dados selecionado, faz a delegação para a extensão específica do banco de dados. • A PDO é totalmente orientada a objetos, diferente das extensões específicas dos bancos de dados que ainda possui o modelo procedural de chamada de funções.
  • 4.
    PDO e asextensões para acesso a bancos de dados do PHP PDO Extensão do MySQL Extensão do PostgreSQL Extensão do SQLite Banco de dados Aplicação Web
  • 5.
    Ativando extensões noWAMP • Por padrão, a extensão para conexão com banco de dados MySQL vem ativa no Wamp. Caso deseja usar o Postgres, é necessário ativar a exetensão. – Clique no ícone do WAMP na bandeja do sistema, selecione a opção PHP, depos PHP Extensions e ative as opções php_pdo_pgsql e php_pgsql • Para fazer manualmente, é necessário abrir o arquivo php.ini na pasta do servidor Apache e retire o comentário (símbolo ;) das linhas onde se encontra digitado extension=php_pdo_pgsql.dll extension=php_pgsql
  • 6.
    Testando se oPDO/PGSQL está ativo • Depois de ativar as extensões do Postgres no PHP é necessário fazer um teste para verificar se estão ativas; • Crie um arquivo index.php e digite o seguinte código nele: phpinfo(); A função phpinfo mostrará todas as configurações do servidor Apache e quais drivers de conexão foram carregados. Localize as palavras PDO, pdo_pgsql e pgsql. Se todas estiverem presentes, tanto o driver de conexão com o Posgres quanto o PDO estão ativos.
  • 7.
  • 8.
    Erro persistente! • Casoos drivers/extensões não tenham sido carregados, provavelmente será necessário editar o arquivo de configuração do Apache inserindo uma linha de comando para carregar a DLL (Dynamic Link Library) de conexão com o Postgres. • Essa DLL fica na pasta do wamp no seguinte caminho: binphp<versão_do_php>libpq.dll Abra o arquivo de configuração do Apache (httpd.conf) que fica na pasta do wamp no seguinte caminho: binapache<versão_do_apacheconfhttpd.conf Logo após a última linha com o comando LoadModule, adicione a seguinte linha de comando: LoadFile “<raiz_do_wamp>/bin/php/<versão_do_php>/libpq.dll”
  • 9.
    Criando um bancode dados • Abra o PgAdmin (Postgres) e crie um banco de dados com o nome ‘database’ (sem aspas) • Clique no link para baixar o script para a criação das tabelas: – Clique aqui! Powered by:
  • 10.
    String de conexão Bancode Dados String de conexão FireBird new PDO(“firebird:dbname=C:base.GDB”, “SYSDBA”, “masterkey”); MySQL new PDO(‘mysql:unix_socket=/tmp/mysql.sock;host=loc alhost;port3306;dbname=livro’,’user’,’senha’) Postgres new PDO(‘pgsql:dbname=example;user=user;password=se nha;host=localhost); Adaptado de Dall’Oglio, 2009, pág. 160
  • 11.
    Criando uma classede conexão namespace util; use PDO; /** * Description of Connection * * @author JorgeLuis */ class Connection { //..constantes para conexão com o Postgres const DBNAME = 'database'; const USER = 'postgres'; const PASSWORD='postdba'; const HOST = 'localhost'; const PORT = 5432; /** * Retorna um objeto do tipo PDO pronto para executar instruções SQL no banco de dados * @return PDO * @throws utilPDOException */ public static function getConnection(){ try { return new PDO("pgsql:dbname=".self::DBNAME.";user=".self::USER . ";password=".self::PASSWORD.";host=".self::HOST . ";port=".self::PORT); } catch (PDOException $ex) { throw $ex; } } }
  • 12.
    Inserindo dados O métodoexec da classe PDO é capaz de executar uma instrução SQL diretamente no banco de dados. O retorno do método é um número inteiro contendo a qtde de linhas linhas que foram atualizadas no banco de dados. require_once 'autoload.php'; use utilConnection; try { //..pega um objeto PDO $db = Connection::getConnection(); } catch (Exception $ex) { //..trata a exceção echo $ex->getMessage() . " - " . $ex->getCode(); } //..inserindo na tabela cidade $linhas = $db->exec("insert into cidade (nome, uf, cep) values('Urânia','SP','15760000')"); if ($linhas > 0) echo 'Dados inseridos!<br>'; else echo 'Erro!';
  • 13.
    Atualizando registros O comandoexec pode ser usado também para comandos de update: require_once 'autoload.php'; use utilConnection; //..pega um objeto PDO $db = Connection::getConnection(); //..executa o comando update $linhas = $db->exec("update cidade set nome='Londrina', uf='PR' where id_cidade = 1"); if($linhas > 0) echo 'Dados atualizados com sucesso!<br>'; else echo 'Erro!<br>';
  • 14.
    Excluindo registros require_once 'autoload.php'; useutilConnection; //..pega um objeto PDO $db = Connection::getConnection(); //..executa o comando delete $linhas = $db->exec("delete from cidade where id_cidade = 1"); if($linhas > 0) echo 'Dados excluídos com sucesso!<br>'; else echo 'Erro!<br>';
  • 15.
    Listando registros • Paralistar registros, isto é, executar uma consulta no banco de dados, o método query deverá ser invocado. Se não houver dados que satisfaçam a consulta, o retorno do método será false, caso contrário, será retornado um objeto PDOStatement que é um resultset no formato de um array composto de outros arrays. require_once 'autoload.php'; use utilConnection; //..pega um objeto PDO $db = Connection::getConnection(); //..executa a consulta $resultSet = $db->query('select * from cidade order by nome'); //..se houver resultSet, então itera-o mostrando os campos da consulta if($resultSet){ foreach ($resultSet as $reg) { echo $reg['id_cidade'] . ' - '; echo $reg['nome'] . ' - '; echo $reg['uf'] . ' - '; echo $reg['cep'] . '<br>'; } }
  • 16.
    Listando registros • Épossível determinar outros formatos para retornar os dados usando a função FETCH e passando um parâmetro de acordo com a tabela: Parâmetros Descrição PDO::FETCH_ASSOC Retorna um array indexado pelo nome da coluna (padrão) PDO::FETCH_NUM Retorna um array indexado pela posição numérica da coluna PDO::FETCH_BOTH Retorna um array indexado pelo nome da coluna e pela posição numérica da mesma. PDO::FETCH_OBJ Retorna um objeto (StdClass), de modo que cada coluna é acessada como um propriedade. Adaptado de Dall’Oglio, 2009, pág. 162
  • 17.
    Listando registros -objetos require_once 'autoload.php'; use utilConnection; //..pega um objeto PDO $db = Connection::getConnection(); //..executa a consulta $resultSet = $db->query('select * from cidade order by nome'); if($resultSet){ while ($reg = $resultSet->fetch(PDO::FETCH_OBJ)){ echo $reg->id_cidade . ' - ' . $reg->nome . ' - ' . $reg->uf . ' - ' . $reg->cep . '<br>'; } }
  • 18.
    Listando registros –índice numérico require_once 'autoload.php'; use utilConnection; //..pega um objeto PDO $db = Connection::getConnection(); //..executa a consulta $resultSet = $db->query('select * from cidade order by nome'); if($resultSet){ while ($reg = $resultSet->fetch(PDO::FETCH_NUM)){ echo $reg[0] . ' - ' . $reg[1] . ' - ' . $reg[2] . ' - ' . $reg[3] . '<br>'; } } Este modo é recomendável para simplificar a referência aos atributos quando estes são conhecidos. O parâmetro PDO::BOTH permite que os atributos sejam referenciados tanto por índices numéricos, quanto por chaves.
  • 19.
    Tratamento de erros •A classe PDO possui um método chamado setAttribute ao qual é possível configurar, entre outros recursos avançados, o modo de como os erros gerados pelo objeto serão tratados. • É recomendável configurar a classe de conexão para gerar exceções, pois assim é possível lançar e/ou tratar os erros de forma mais elegante através dos já conhecidos blocos try..catch. • A exceção gerada é uma instância de PDOException, isto é, uma exceção específica para erros de bancos de dados. • Exemplo: //..pega um objeto PDO $db = Connection::getConnection(); //..seta o modo de erros $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); A partir de agora, o objeto $db irá lançar exceções, caso aconteçam.
  • 20.
    Exemplo completo try { //..pegaum objeto PDO $db = Connection::getConnection(); //..seta o modo de erros $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //..executa a consulta - nome da tabela cidade está errado – vai gerar erro! $resultSet = $db->query('select * from cidades order by nome'); if ($resultSet) { while ($reg = $resultSet->fetch(PDO::FETCH_BOTH)) { echo $reg[0] . ' - ' . $reg[1] . ' - ' . $reg['uf'] . ' - ' . $reg['cep'] . '<br>'; } } } catch (PDOException $ex) { //..mostra a mensagem de erro echo $ex->getMessage(); }
  • 21.
    Modificando a classeConnection • Para fazer com que a classe Connection retorne um objeto PDO pronto a gerar exceções, segue uma nova proposta. namespace util; use PDO; /** * Description of Connection * * @author JorgeLuis */ class Connection { //..constantes para conexão com o Postgres const DBNAME = 'database'; const USER = 'postgres'; const PASSWORD='postdba'; const HOST = 'localhost'; const PORT = 5432; /** * Retorna um objeto do tipo PDO pronto para executar instruções SQL no banco de dados * @return PDO * @throws utilPDOException */ public static function getConnection(){ try { //..pega um objeto PDO $connection = new PDO("pgsql:dbname=".self::DBNAME.";user=".self::USER. ";password=".self::PASSWORD.";host=".self::HOST.";port=".self::PORT); //..configura para gerar exceções sempre que um erro ocorrer $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //..retorna o objeto PDO; return $connection; } catch (PDOException $ex) { throw $ex; } } }
  • 22.
    Exemplo de tratamentode erros require_once 'autoload.php'; use utilConnection; try { //..pega um objeto PDO $db = Connection::getConnection(); //..executa a consulta - nome da tabela cidade está errado – vai gerar Exceção $resultSet = $db->query('select * from cidades order by nome'); if ($resultSet) { while ($reg = $resultSet->fetch(PDO::FETCH_BOTH)) { echo $reg[0] . ' - ' . $reg[1] . ' - ' . $reg['uf'] . ' - ' . $reg['cep'] . '<br>'; } } } catch (PDOException $ex) { echo $ex->getMessage(); }
  • 23.
    Transações Uma transação representauma interação entre a aplicação e o sistema de banco de dados tratada de forma única e independente. Pense em uma transação financeira de transferência de fundos. Este tipo de transação necessita de um grande cuidado pois, do contrário, uma conta pode ser debitada e a outra não ser creditada, ou vice-versa. Uma transação é uma sequência de trabalho que tem um ponto de início e de fim bem definidos [...]” DALL’OGLIO, 2009, pág. 206
  • 24.
    Propriedades de Transações- ACID • Atomicidade: uma transação pode envolver uma ou mais interações com o banco de dados, porém deve ser vista como uma única operação. Se uma delas falhar, os dados não refletirão o mundo real então, toda a operação deverá ser revertida (rollback). Executa tudo ou nada. Sem operações incompletas. • Consistêcia: após a transação, os dados devem permanecer íntegros, ou seja, com todas as suas restrições (chave primária, check, etc) intactas. • Isolamento: as transações devem ser executadas isoladas de outras transações, pois pode ser que um registro seja acessado por diversas transações ao mesmo tempo (venda de um produto). O resultado da transação só deve ser visível após o seu término. • Durabilidade: deve haver a garantia de que os dados serão persistentes após o término da transação, ou seja, ela não será desfeita e/ou perdida por qualquer que seja o motivo.
  • 25.
    Sintaxe try{ //..inicia a transação PDOObject->beginTransaction(); //..instruçãoSQL 01 //..instrução SQL 02 //..instrução SQL 03 //..instrução SQL n... //..confirma a transação PDOObject->commit(); } catch(PDOException $ex){ //..retorna ao estado inicial caso aconteça algum erro PDOObject->rollBack(); }
  • 26.
    Exemplo • No bancode dados, a tabela pessoafisica é uma especialização da tabela pessoa, ou seja, para cadastrar uma pessoa física é necessário primeiro a inserção dos dados na tabela pessoa e, após obter o nº do id inserido, é necessário inserir o registro específico na tabela pessoafisica. • Se qualquer uma das operações falhar no momento da confirmação (commit), o sistema deverá cancelar a transação (rollback). • Os dados deverão ser inseridos nas duas tabelas ou em nenhuma (atomicidade).
  • 27.
    Código-fonte comentado require_once 'autoload.php'; useutilConnection; try{ //..pega uma conexão $connection = Connection::getConnection(); //..inicia a transação $connection->beginTransaction(); //..inicia as operações da transação //..executa a instrução SQL para inserção em pessoa $connection->exec("insert into pessoa(nome, id_cidade) values ('Peter Parker', 2);"); echo 'Pessoa Inserida! <br>'; //..pega o id do registro inserido em pessoa para inserí-lo em pessoafisica $id = $connection->lastInsertId("seq_pessoa"); echo "ID inserido: $id <br>"; //..executa a instrução SQL para a inserção em pessoafisica $connection->exec("insert into pessoafisica values ($id, 'M', '111','222','Rua XYZ','15999000');"); echo 'Pessoa Física Inserida! <br>'; //..confirma a transação $connection->commit(); } catch (PDOException $ex){ //..Se gerar exceção, mostra o erro e executa um rollback. echo 'Erro na transação: ' . $ex->getMessage() . '<br>'; $connection->rollBack(); } Dica: Para verificar se o controle de transação está realmente dando certo, crie um erro em uma das instruções SQL, na primeira ou na segunda. Com erros, a lógica acima cairá no bloco catch e o rollback será executado desfazendo as alterações.
  • 28.
    Atividade Prática • Criaruma aplicação simples que cadastre e liste os dados de um formulário • Dados: – Nome (campo de texto) – Sexo (campo select) – Formação (campo select) • Ensino fundamental • Ensino médio • Superior • Pós graduação • Outros
  • 29.
    Mapeamento Objeto-Relacional • Persistência –Persistir quer dizer perdurar, resistir ao tempo. Em uma aplicação, persistir significa fazer com que os objetos do modelo de negócio sejam “gravados” em um local externo à aplicação e que, principalmente, permita sua posterior recuperação. – Objetos existem apenas durante um certo período de tempo dentro dos limites da aplicação, desta forma, é extremamente importante seu armazenamento.
  • 30.
    Mundo OO vsMundo Relacional [...] existem diversos conceitos da orientação a objetos para os quais o modelo relacional simplesmente não oferece suporte, então temos uma diferença de conceito. Os bancos de dados foram construídos para armazenar dados, ao passo que, no paradigma orientado a objetos, além de dados (atributos), temos comportamento (métodos) e outras estruturas complexas. Dessa forma, é necessário utilizar alguma ferramenta de compatibilidade entre os dois modelos, que geralmente implementam algum técnica de mapeamento objeto-relacional. [...] DALL’OGLIO, 2009, pág. 222
  • 31.
    Mundo OO vsMundo Relacional • Mundo Relacional – Tabelas: entidade que armazena dados – Registros: cada dado ou conjunto de dados de uma tabela real ou gerada por SQL – Chaves primárias: responsáveis por: • Fazer com que um registro seja único • Fazer com que as tabelas se relacionem através de ligação com chaves estrangeiras • Mundo OO – Objetos: armazenam dados e são capazes de realizar tarefas – Listas: conjuntos de objetos – Os relacionamentos são feitos por associações: • Associação simples • Composição • Agregação
  • 32.
    Mundo OO vsMundo Relacional • Padrões para mapeamento objeto-relacional: – Identity Field: campo autoincremento para chave primária/estrangeira – Foreign Key Mapping: composição (relacionamento “forte” todo/parte) no mundo OO pode ser realizada através de chaves estrangeiras. – Association Table Mapping: agregação (relacionamento “fraco” todo/parte ) também pode ser mapeado como chaves estrangeiras. – Herança • Single Table Inheritance: as classes são mapeadas para uma única tabela contendo todos os atributos comuns da hierarquia. • Concrete Table Inheritance: as classes são mapeadas para diversas tabelas, cada classe possui uma tabela de forma independente. • Class Table Inheritance: e criada uma tabela para cada classe na estrutura da hierarquia. Após isso, cria-se uma generalização/especialização através de pares de chaves primárias. Maiores detalhes em Dall’Oglio, pág. 222-231.
  • 33.
    DAO – DataAccess Object • O padrão de projeto DAO propõe a criação de uma camada de acesso a dados independente de outras camadas da aplicação, ou seja, os objetos DAO possui a responsabilidade de persistir objetos em bancos de dados, realizando, o mapeamento objeto-relacional (Object-Relational Mapping). • Além da persistência (inserts e updates), os objetos DAO também podem recuperar dados através de consultas SQL e retornar apenas objetos de negócio (model) para a aplicação. • Vantagens: – Isolar a lógica de acesso e manipulação de dados de outros componentes do sistema melhora a reusabilidade, escalabidade e manutenabilidade do código.
  • 34.
    DAO – DataAccess Object model Classe1 Classe2 * * Classe3 Classe4 1 * +findById() +persist() +query() +delete() DAO Banco de dados Objetos model Instruções SQL Dados Objetos
  • 35.
    Exemplo • Baixar ocódigo-fonte comentado no link abaixo: – Clique aqui! Powered by:
  • 36.
    Discussão – acamada model
  • 37.
    Discussão – acamada dao
  • 38.
    Discussão – métodosDAO • Os objetos DAO devem implementar a interface Idao, então, surgem os seguintes métodos: – persist($modelObject) • Insere e/ou atualiza um registro no banco de dados mediante um objeto model informado. O objeto deverá ser mapeado em dados relacionais e persistido no Banco de Dados. – delete($id) • Exclui um registro baseado no id informado – query($field = null, $like=null) • Realiza uma query do tipo “selecionar tudo” ou usando um campo e uma cláusula ‘like’ como filtros. Retorna um ArrayObject (array de objetos) – findById($id) • Recupera um registro mediante o id informado, mapeia-o em objeto e retorna para a aplicação.
  • 39.
    O que vemdepois??? • Agora que a camada DAO está pronta, é necessário integrá-la a sua aplicação. • MVC – Model/View/Controller – Padrão de Projeto (Design Pattern) que divide uma aplicação em 3 camadas distintas. – O padrão DAO combina muito bem com o MVC.
  • 40.
    Bibliografia recomendada DALL’OGLIO, Pablo.Capítulo 3: Manipulação de dados. In: ________. PHP: programando com orientação a objetos. 2. ed. São Paulo: Novatec, 2009. p. 154-220. Manual do PHP. PHP Data Objects. Disponível em <http://php.net/manual/pt_BR/ book.pdo.php> Acesso em 20 jan. 2015. Manual do PHP. PHP::setAttribute. Disponível em <http://php.net/manual/pt_BR/ pdo.setattribute.php> Acesso em 20 jan. 2015.