Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Alexandre Carmo

Melhorar Técnicos

Recommended Posts

Boa tarde

 

Pessoal estou querendo melhorar as técnicas que uso em PDO, vou postar um pequeno exemplo de como trabalho, gostaria que vocÊs comentem e me informem se esta ok, ou se existe forma melhor para se trabalhar. Como venho do php3 estruturado ainda tenho alguns vicios e o PDO é algo novo que estou usando é bem provável que preciso de melhorias

Minha idéia é a seguinte, tenho a minha class de conexão, ela faz o tramento da conexão com banco e joga exceção se tiver problemas, tenho uma outra classe (ExecutaQuery) que herda a conexão e executa tudo o que for referente a CRUD, basicamente ela tem 2 funções uma para insert, update e delete e outra apenas para consultas. Com isso resolvo todo o processo de conexão e CRUD, então entro com a criação da aplicação e suas tarefas, por exemplo se eu precisar inserir algo em algum tabela, como por exemplo um cadastro de cliente, eu terei 2 arquivos por exemplo, um deles recebe os dados enviado pelo usuário, trata eles e manda para um outro aquivo DAO que recebe os valores enviados pelo cliente cria uma query e enviar para a classe e envia para a classe ExecutaQuery, finalizar o processo.

Esta funcionando mas não sei se esta ideal, segue abaixo as classes por favor me informem o que devo melhorar:

Classe de conexão:

<?php
class Conexao 
{
   // private function __construct(){}

    public static function open()
    {
       //verifica se existe arquivo de configuração para esta banco de dados
       if(file_exists("mysql.ini"))
       {
           //lê o arquivo ini e retorna um array
           $db = parse_ini_file("mysql.ini");
       }
       else
       {
           //se não existir, lança um erro
           throw new Exception("Arquivo mysql.ini não encontrado");
       }

       //lê as informações contidas no arquivo
       $user = isset($db['user']) ? $db['user'] : NULL;
       $pass = isset($db['pass']) ? $db['pass'] : NULL;
       $name = isset($db['name']) ? $db['name'] : NULL;
       $host = isset($db['host']) ? $db['host'] : NULL;
       $type = isset($db['type']) ? $db['type'] : NULL;
       $port = isset($db['port']) ? $db['port'] : NULL;

       //conecta o banco
       $port = $port ? $port : '3306';
       $conn = new PDO("mysql:host={$host};port={$port};dbname={$name}", $user, $pass);


       //define para que o PDO lance exceções na ocorrência de erros
       $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

       //retorna objeto instanciado
       return $conn;
   }
}

?>

Classe ExecutaQuery

<?php
class ExecutaQuery extends Conexao 
{
   function executa($query,$valores)
   {
       $conn = $this->open(); //conecta o banco
       $stmt = $conn->prepare($query); //herda as propriedades de PDO e recebe a query
       $armazena = $stmt->execute($valores); //recebe o array com os valores que serão usados pelas query e executa a query
   }
}
?>
Classe de camada DAO
[code]
<?php
class CamadaPDO 
{
   function __autoload($classe)
   {
       if(file_exists("{$classe}.class.php"))
       {
           include_once "{$classe}.class.php";
       }
   }

   function armazena($valor1,$valor2)
   {
       $executaQuery = new ExecutaQuery();
       $query = "INSERT INTO testes (texto,texto2) VALUES (:txt1, :txt2)";
       $dados = array(':txt1' => $valor1, ':txt2' => $valor2);
       $executa = $executaQuery->executa($query, $dados);
   }
}
?>

Classe que trata os dados recebidos e envia para DAO:

<?php
function __autoload($classe)
{
   if(file_exists("{$classe}.class.php"))
   {
       include_once "{$classe}.class.php";
   }
}
$enviaDados = new CamadaPDO();
$teste = $enviaDados->armazena('wwww', '123465');
?>

Compartilhar este post


Link para o post
Compartilhar em outros sites

Conceituamente falando, o teu objeto Conexão, faz uma conexão realmente, mas não é apenas isso que ele representa.

 

Essa class, devolve um objeto PDO completo, ou seja, devolve algo que vai além de uma conexão.

conexão por assim dizer, é apenas um dos passos, apenas uma das coisas que essa class faz.

 

Acho ruim esse nome.

 

O teu outro ExecutaQuery, é 'meio inutil'.. que tal apenas uma class chamada: Db (um objeto para representar o banco de dados, e tudo o que ele faz) ?

 

 

O problema do teu ->armazena(), é que ele cria uma nova instancia de ExecutaQuery, cada vez que é chamado, e portanto, cria uma nova conexão ao banco, cada vez que é chamado.

Na prática, se eu tiver que armazenar 3 registros consecutivamente:

 

$enviaDados = new CamadaPDO();
$teste = $enviaDados->armazena('wwww', '123465');
$teste = $enviaDados->armazena('xxxx', '67890');
$teste = $enviaDados->armazena('yyyy', '23234');

eu tive que usar 3 classes, sendo que criei 7 objetos, e abri 3 conexões com o banco.

Entendeu ?

 

 

se não, vamos tentar 'ser o compilador' (exercicio interessante, que o meu professor de Java fazia com agente:

$enviaDados = new CamadaPDO();

Okay, crio 1 objeto.

$teste = $enviaDados->armazena('wwww', '123465');

Okay, crio outro objeto

 $executaQuery = new ExecutaQuery();

que por sua vez

$conn = new PDO("mysql:host={$host};port={$port};dbname={$name}", $user, $pass);

cria outro, e abre uma conexão.

...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Opa beleza, valeu pela atenção.

Sim estou ciente que o meu objto de conexão retorna outra informações. Só não comentei porque não achei necessário.

Achei interessante o que você informou no demonstração que vocÊ fez no uso da minha classe, se ela esta fazendo conexões atoa o ideal é reduzir mesmo:

O problema do teu ->armazena(), é que ele cria uma nova instancia de ExecutaQuery, cada vez que é chamado, e portanto, cria uma nova conexão ao banco, cada vez que é chamado.

Na prática, se eu tiver que armazenar 3 registros consecutivamente:

 

$enviaDados = new CamadaPDO();

$teste = $enviaDados->armazena('wwww', '123465');

$teste = $enviaDados->armazena('xxxx', '67890');

$teste = $enviaDados->armazena('yyyy', '23234');

eu tive que usar 3 classes, sendo que criei 7 objetos, e abri 3 conexões com o banco.

Entendeu ?

 

Só não entendi muito bem a solução que vocÊ apresentou logo em seguida. As duas primeiras linhas faz exatamente o que coloquei no código, a terceira e quarta linha, ficaram sem significa para mim, onde devo colocarr e usar, a última linha já esta carregada na classe que faz a conexão então a classe que executar o pdo já chama ela.

Fiquei um pouco perdido vocÊ poderia me explicar melhor a sua idéia?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Só não entendi muito bem a solução que vocÊ apresentou logo em seguida.

não apresentei solução ainda. Apenas expliquei 'novamente' o problema.

 

A solução seria:

-> ter um unica class Db para representar o banco.

Essa class faria a conexão, e executaria queries.

 

-> o objeto $db deve ser um atributo|parâmetro da class DAO, para ser usado, sem precisar ser novamente instanciado a cada execução.

No teu contexto, faz sentido usar o construtor da classe CamadaPDO() para instanciar o objeto do banco, e então, em forma de atributo da class CamadaPDO, os metodos dessa class, apenas usariam o objeto do banco.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ok, como o William Bruno já falou, essa conexão sua com o banco de dados

tem que ser reaproveitável, como podemos fazer isso ? dá pra você fazer de duas maneiras

Mais temos que analisar umas coisas, se você precisa de trabalhar com 2 bancos de dados

Uma dessas maneiras não é aconselhável, caso você não precise trabalhar com 2 banco de dados

Uma das maneiras também não é aconselhável, então vejamos

  • Singleton - uma única instancia em toda aplicação

  • Registry - Array Object, um array que armazena vários objetos

 

O Singleton, permite uma única instancia em toda a aplicação, isso quer dizer que você

vai criar sua conexção com o banco de dados uma única vez, no caso não é banco de dados

e sim o objeto do 'PDO'.. mais como funciona ?

Você tem uma variavel estatica que irá armazenar esse objeto, e você ao acessar um metodo

ele vai verificar se já existe uma instancia\algo setado nela para poder criar uma nova instancia

caso contrario apenas retorna a existente ..

 

O Registry, permite varias instâncias com nomes diferentes, o próprio nome já diz 'Registry'

você registra vários objetos em um array, aonde você pode acessar esses objetos em qualquer lugar da aplicação

e bom usar registry quando se trabalha com 2 banco de dados, assim você pode registrar 2 objetos do pdo

em uma única variável .. porem o Índice para você pegar esse objeto do banco² é diferente

 

Agora, vamos imaginar a seguinte estrutura das pastas:

srt.jpg

 

Em DataObject, você vai guardar todos seus DAO's, todos poderam usar o namespace

onde é guardado as classes que fazer uma conexção com o banco de dados

Então cada arquivo Com o nome da Tabela dentro dessa pasta ira representar um DAO( No caso )

 

Em Database, você vai guardar todos suas classes para conexções com varios Drivers de banco de dados

seja ele Firebird, SQLite, MySQL, PgSQL, ORACLE.

 

Então um pequeno exemplo:

 

index.php

<!doctype html>
<html>
   <head>
       <meta http-equiv="content-type" content="text/html;charset=utf-8" />
   </head>
   <body>
       <?php
             require_once 'Config.php';
             use \Database\MySQL;
             use \DataObject\Usuarios;
             $Usuarios = new Usuarios();
       ?>
   </body>
</html>

 

Config.php

<?php
/**
* Adiciona a pasta app ao include_path
*/
$include_path = ini_get( 'include_path' ) . PATH_SEPARATOR . realpath( './app' );
ini_set( 'include_path' , implode( PATH_SEPARATOR , array_unique( explode( PATH_SEPARATOR , $include_path ) ) ) );

/**
* Registra a função para carregar as classes automaticamente
*/
function loader( $class ) {
require sprintf( '%s.php' , implode( DIRECTORY_SEPARATOR , explode( '\\' , $class ) ) );
}

spl_autoload_register( 'loader' , true );

 

DataObject\Usuarios.php

<?php
       /**
        * Define um namespace para os DAO's
        */
       namespace DataObject;
       /**
        * Usa o namespace que armazena a instancia do PDO
        */
       use \Database\MySQL;

       class Usuarios extends \Database\MySQL{
                   /**
                    * Armazena a instancia do PDO
                    * @access Private
                    * @var Object
                    */
                   private $db;
                   /**
                    * Faz a instancia da classe MySQL
                    * @method __construct
                    * @access Public
                    */
                   public function __construct(){
                          $this->db = MySQL::getInstance();
                   }

       }

 

\Database\MySQL.php

<?php
           /**
            * Define um namespace para ser usado
            */
           namespace Database;

           class MySQL{
                       /**
                        * Armazena a instancia de um objeto
                        * @access Private
                        * @var Object
                        */
                       private static $instance;
                       /**
                        * Cria uma nova instancia do PDO
                        * ou retorna uma se a mesma já não existir
                        * @return PDO Object
                        */
                       public static function getInstance(){
                              if(!isset( self::$instance )){
                                   self::$instance = new \PDO( 'mysql:host=localhost;dbname=..' , 'root' , '***' );
                                   if( self::$instance instanceOf \PDO ){
                                         self::$instance->setAttribute( \PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION );
                                         self::$instance->setAttribute( \PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC );
                                         self::$instance->setAttribute( \PDO::ATTR_AUTOCOMMIT, true );
                                         self::$instance->setAttribute( \PDO::ATTR_TIMEOUT, 5 );
                                   }
                              }
                              return self::$instance;
                       }


           }

 

Ao executar o código, o retorno:

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[28000] [1045] 
Access denied for user 'root'@'localhost' (using password: YES)' 

 

Perceba no index.php, a classe que eu faço a chamada ..

Então você vai entender como você pode realizar suas transações com banco de dados

e sobre a váriavel que o William falou

Compartilhar este post


Link para o post
Compartilhar em outros sites

bacana @Andrey, eu só não acho interessante isso aqui:

class Usuarios extends \Database\MySQL{

 

Usuario é usuario, e Banco é Banco.

Não vejo sentido em um usuario extender um banco.

 

A DAO de usuario, deve usar o banco, e não ser ele.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom dia

 

Obrigado a todos pela ajuda. Estou estudando o que vocÊ me passaram. Agradeço a ajuda.

No caso o William achou desinteressante o uso de um detalhe passado pelo Adrey no caso o usuário extender o banco, onde ele informou que esta seguinda minha idéia, se fosse necessário qual seria a forma correta então para corrigir esse último detalhe?

Ainda fiquei com um pouco de dúvidas na lógica de uso do seu arquivo config. VocÊ poderia me explicar ele por favor.

Outra detalhes é que não estou conseguindo implementar a idéia que vocÊ deixou, apesar de estar analisando ela não consegui usar o conceito, vocÊ poderia colocar junto com essa seu exemplo um modelo usando CRUD? Dessa forma posso analisar melhor o funcionamento e entender. Se você tiver como fazer isso e explicar ficao grato

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Alexandre Carmo, para o usuario não herdar do banco, basta seguir isso aqui:

 

-> o objeto $db deve ser um atributo|parâmetro da class DAO, para ser usado, sem precisar ser novamente instanciado a cada execução.

e para o config, basta incluir ele em cada página tua, onde você vai precisar trabalhar com classes.

Compartilhar este post


Link para o post
Compartilhar em outros sites

beleza William, entendi.

Estou estudando melhor as técnicas montei uma que acredito ter ficado legal, baseado na idéia que vocÊs me passaram e pegando algumas informações na net, montei um modelo e vou trabalhar suando ele.

Porém ele esta dando um erro na hora que vou consultar, o insert esta ok, se eu tirar o insert e deixar só o select que no caso é o lista vai funcionar. Será que preciso fechar a conexão ou algo do tipo?

O erro é esse:

Fatal error: Call to a member function query() on a non-object in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\teste\pdo\AgendaDAO.class.php on line 56

A linha informada e é essa, não entendo o motivo do erro:

$stmt = $this->p->query("SELECT * FROM agenda");}

que fina na class AgendaDAO, na seguinte função

public function Lista($query=null){
       try{
           if( $query == null ){
               $stmt = $this->p->query("SELECT * FROM agenda");}
           else{$stmt = $this->p->query($query);}
           $this->p = null;
           return $stmt;
       }
       catch ( PDOException $ex ){  echo "Erro: ".$ex->getMessage(); }
   }

A classe completa é essa:

<?php
class AgendaDAO 
{
   // irá receber uma conexão
   public $p = null;
   // construtor
   public function AgendaDAO(){
       $this->p = new Conexao();
   }
   // realiza uma inserção
   public function Insere( $agenda ){
       try{
           $stmt = $this->p->prepare("INSERT INTO agenda (nome, email, telefone) VALUES (?, ?, ?)");
           $stmt->bindValue(1, $agenda->getNome() );
           $stmt->bindValue(2, $agenda->getEmail() );
           $stmt->bindValue(3, $agenda->getTelefone() );
           $stmt->execute();
           // fecho a conexão
           $this->p = null;
           // caso ocorra um erro, retorna o erro;
       }
       catch ( PDOException $ex ){  echo "Erro: ".$ex->getMessage(); }
   }
   // realiza um Update
   public function Update( $agenda, $condicao ){
       try{
           // preparo a query de update – Prepare Statement
           $stmt = $this->p->prepare("UPDATE agenda SET nome=?, email=?, telefone=? WHERE id=?");
           $this->p->beginTransaction();
           $stmt->bindValue(1, $agenda->getNome() );
           $stmt->bindValue(2, $agenda->getEmail() );
           $stmt->bindValue(3, $agenda->getTelefone() );
           $stmt->bindValue(4, $condicao);
           // executo a query preparada
           $stmt->execute();
           $this->p->commit();
           // fecho a conexão
           $this->p = null;
       }
       catch ( PDOException $ex ){  echo "Erro: ".$ex->getMessage(); }
   }
   // remove um registro
   public function Deleta( $id ){
       try{
           $num = $this->p->exec("DELETE FROM agenda WHERE id=$id");
           // caso seja execuado ele retorna o número de rows que foram afetadas.
           if( $num >= 1 ){return $num;}
           else {return 0;}
           // caso ocorra um erro, retorna o erro;
       }
       catch ( PDOException $ex ){  echo "Erro: ".$ex->getMessage(); }
   }
   public function Lista($query=null){
       try{
           if( $query == null ){
               $stmt = $this->p->query("SELECT * FROM agenda");}
           else{$stmt = $this->p->query($query);}
           $this->p = null;
           return $stmt;
       }
       catch ( PDOException $ex ){  echo "Erro: ".$ex->getMessage(); }
   }
}
?>

 

A classe de conexão:

<?php
//ela herdará os métodos e atributos do PDO através da palavra-chave extends
class Conexao extends PDO
{
   private $dsn = 'mysql:host=servidor;port=3306;dbname=agenda';
   private $user = 'root';
   private $password = '123456';
   public $handle = null;
   function __construct() {
       try {
           //aqui ela retornará o PDO em si, veja que usamos parent::_construct()
           if ( $this->handle == null ) {
               $dbh = parent::__construct( $this->dsn , $this->user , $this->password );
               $this->handle = $dbh;
               return $this->handle;
           }
       }
       catch ( PDOException $e ) {
           echo 'Conexão falhou. Erro: ' . $e->getMessage( );
           return false;
       }
   }
   //aqui criamos um objeto de fechamento da conexão
   function __destruct( ) {
       $this->handle = NULL;   
   }
}
?>

A classe Agenda

<?php
class Agenda 
{
   private $id;
   private $nome;
   private $email;
   private $telefone;

   // construtor da classe pode utilizar o nome da classe ou a palavra reservada __construct() 
   public function Agenda(){}

   public function setId( $id ){$this->id = $id;}
   public function setNome( $nome ){$this->nome = $nome;}
   public function setEmail( $email ){$this->email = $email;}
   public function setTelefone( $telefone ){$this->telefone = $telefone;}

   public function getId(){return $this->id;}
   public function getNome(){return $this->nome;}
   public function getEmail(){return $this->email;}
   public function getTelefone(){return $this->telefone;}
}
?>

E o arquivo de teste:

<?php
include_once 'Conexao.class.php';
include_once 'AgendaDAO.class.php';
include_once 'Agenda.class.php';
// instancio a classe Agenda
$agenda = new Agenda();
//setando os dados de contato
$agenda->setNome("xxxx");
$agenda->setEmail("xxxx@gmail.com");
$agenda->setTelefone("9999-9999");
// instancio a classe Data Access Object para Agenda
$DAO = new AgendaDAO();
// inserir contato na agenda
$DAO->Insere($agenda);
//para listar nome e email de todos os contatos
foreach ($DAO->Lista() as $contato){
echo $contato["nome"]." – ".$contato["email"]."<br/>";
}

}

?>


Compartilhar este post


Link para o post
Compartilhar em outros sites

Você não entendeu nada sobre o reaproveitamento da conexão, lê oque eu postei de novo

foreach ($DAO->Lista() as $contato){
echo $contato["nome"]." – ".$contato["email"]."<br/>";
}

 

Você não executa nenhum fetch, por isso você nunca vai conseguir listar esses dados

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.