Ir para conteúdo

POWERED BY:

Arquivado

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

cassiano óliver

[Resolvido] Classe de extensão PDO e funções MySQL

Recommended Posts

Olá pessoal,

 

Há algum tempo estou estudando POO, estou iniciando a criação de pequenas classes para fixação do que já estudei.

Inclusive vários arquivos / script aqui do fórum me ajudaram bastante. Abaixo estão algumas classes (extensão PDO), se puderem dar-me opiniões para melhorá-las, ficarei grato.

 

Classe de conexão (Basicamente é o meu arquivo conexao.php atualmente)

 

class.mysql.php
class Conexao extends PDO {
   private $cnx = NULL;
   private $host = '';
private $database = '';
private $usuario = '';
   private $senha = '';

public function __construct() {
       try {
           //Cria a conexão ao MySQL
           if($this->cnx == null) {
               $cnx = parent::__construct('mysql:host=' . $this->host . ';port=330;dbname=' . $this->database, $this->usuario, $this->senha, array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
			$cnx = parent::setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
			$cnx = parent::setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
               $this->cnx = $cnx;
               return $this->cnx;
           }
       }
       catch(PDOException $e) {
           echo 'Falha ao realizar conexão à base de dados.<br /><br />
		Erro técnico: ' . $e->getMessage() . '<br />
		Arquivo: ' . basename($e->getFile()) . '<br />
		Linha: ' . $e->getLine() . '<br />';
       }
   }

   //Função de encerramento da conexão
   public function fecha() {
       $this->cnx != NULL ? $this->cnx = NULL : NULL;   
   }
}

 

funcoes.mysql.php

class Funcao extends Conexao {
private $campos;
private $tabela;
private $where, $whereSQL;
private $order, $orderSQL;
private $limit, $limitSQL;

public function consulta($obj, $campos, $tabela, $where, $order, $limit) { // passo a instância da conexão para $obj
	$whereSQL = !empty($where) ? ' WHERE ' . $where : '';
	$orderSQL = !empty($order) ? ' ORDER BY ' . $order : '';
	$limitSQL = !empty($limit) ? ' ORDER BY ' . $limit : '';

	$query = $obj->query("SELECT " . $campos . " FROM " . $tabela . $whereSQL . $orderSQL . "");
	return $query;
}
}

 

Uso:

$cnx = new Funcao;
$query = $cnx->consulta($cnx, 'id, titulo', 'agenda', '', ' id DESC', '');

if($query) {
while($dados = $query->fetch()) {
	echo $dados->titulo . '<br>';
}
$cnx->fecha();
}
else {
echo 'Opa, falhou!';
}

 

Aguardo opiniões e melhorias se necessários.

Desde já obrigado.

Compartilhar este post


Link para o post
Compartilhar em outros sites

beleza,

 

Algum tempo postei uma classe PDO aqui no imasters ela me atende bem, teve boas recomendações para melhora-la

segue ai o link olha se te atende: http://forum.imasters.com.br/topic/448961-completa-classe-crud-com-validacao-de-dados/page__p__1775048__fromsearch__1#entry1775048

Compartilhar este post


Link para o post
Compartilhar em outros sites

Hmmmm... cheirou mal isso aí...

Dá uma lidinha neste tópico:

http://forum.imasters.com.br/topic/451067-myframework/

Compartilhar este post


Link para o post
Compartilhar em outros sites

Henrique,

 

Dei uma lida no tópico, e pelo que entendi não deveria estender a PDO. Minha intenção em estender a PDO, era poder personalizar algumas funções.

 

Como farei então para criar uma classe para manipular Agenda (por ex) e utilizar os métodos da PDO nesta classe sem obter sua instância (no caso acima $cnx)?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá Henrique,

 

Pesquisei bastante sobre Composição, e também, agregação, encapsulamento...

 

Seguindo sua sugestão, na composição eu teria de criar a classe de conexão, e nesta criar uma instância da PDO, certo?

 

E qual a vantagem em fazer isso ao invés de estender?

 

E aproveitando o meu caso inicial, caso se eu quisesse herdar a instância da PDO (para não ficar passando $cnx), como seria?

 

Lembrando que este caso, é apenas para fixação de estudo.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Hoje você está usando PDO, beleza... Mas se você algum dia desenvolver para um ambiente que não possui a extensão PDO instalada? Pense na quantidade de código que terá que alterar...

 

Você está tentando utilizar herança onde não há espaço para ela.

Dê uma pesquisada também sobre o Princípio de Substituição de Liskov. Ele diz que ao se derivar uma classe de outra, seria possível substituir todos os objetos da classe mãe pelos objetos da classe filha, sem perdas. Agora veja se isso é possível quando você restringe a conexão com o banco de dados aos valores que você seta.

 

Se por exemplo você tem uma aplicação que acessa 2 bancos de dados distintos, você estende PDO para ambos os bancos de dados? Mesmo que eles façam praticamente a mesma coisa? Olha a duplicação de código aí...

 

Lembre-se do princípio da responsabilidade única: não armazene os dados para conexão onde você FAZ a conexão. Faça com que a classe de conexão receba como parâmetro um array ou um objeto de configuração. Dessa forma, se você tiver acesso a 2 bancos diferentes, basta alterar os dados passados como parâmetro ao invés de duplicar o código, como você teria que fazer na sua implementação atual...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Entendi.

Principalmente sobre o acesso a bases diferentes, já fiz a duplicação de arquivo de conexão para este caso.

 

Concluindo, o correto é:

 

1) Criar um arquivo de configuração dos dados de acesso ao banco (conexao.php) por ex.

2) Criar uma classe de conexão, e nesta, criar uma instância de PDO.

Poderia mostrar-me um exemplo disto (se não for pedir demais é claro)?

3) Criar uma classe de funções básicas (consultas, retorno de registros, atualização, exclusão, etc...), esta, estensão da classe funções.

4) Criar uma classe para cada tabela do banco (agenda, noticias, etc..), esta, estenção da classe funções.

 

É mais ou menos por aí?

 

Mais uma vez obrigado pela atenção.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Veja este post aqui:

http://forum.imaster...ost__p__1784565

 

Tem um exemplo implementando os padrões Adapter e TablaDataGateway que favorecem a composição sobre a herança.

Herança amarra seu código, deve ser usada com sabedoria. Já a composição é um relacionamento muito mais flexível, muito mais fácil de tratar.

 

O código de exemplo é bem superficial, apenas para mostrar a idéia.

 

Para utilizar PDO, derive uma classe "Db_Adapter_PdoMysql" de Db_Adapter e implemente as funções específicas sobre a PDO. Essa classe TERÁ uma instância da classe PDO... Observe o código de "Db_Adapter_Mysqli" e você terá uma idéia.

Compartilhar este post


Link para o post
Compartilhar em outros sites

O Henrique está usando Adapter e Table Data Gateway. Se tem mais algum outro eu não sei! hheheh.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Na verdade eu também fiz uma releitura do padrão DataAccessObject.

Nos exemplos que eu já encontrei, ele se assemelha muito ao TableDataGateway. Só que pela nomenclatura não faz muito sentido. DAO, ao meu ver, é mais geral, serve como camada de acesso para dados salvos em qualquer lugar, não só em bancos de dados.

 

Por isso, fiz com que ele se resumisse somente a uma interface, que contém os métodos gerais necessários para as operações de CRUD. TableDataGateway estaria numa camada um nível abaixo e logo em seguida o Db_Adapter, que lida diretamente com as funções do banco de dados.

 

Se eu estive utilizando arquivos XML como armazenamento, poderia ter um XMLGateway e um XMLAdapter abstraindo o acesso aos dados. O que o programador precisaria enxergar seria apenas as funções da interface DataAccessObject. Para alterar o modo de armazenamento, basta passar uma instância diferente de DataAccessObject para o Model...

 

É nessas horas que vejo que programação se aproxima muito mais da poesia do que da matemática, apesar de escrever poesia ser muito mais fácil =P...

Compartilhar este post


Link para o post
Compartilhar em outros sites
É nessas horas que vejo que programação se aproxima muito mais da poesia do que da matemática, apesar de escrever poesia ser muito mais fácil =P...

 

E é nessas horas que o bixo pega! kkkkkkkkkk

Compartilhar este post


Link para o post
Compartilhar em outros sites

Segue nova classe, está melhor?

 

Classe de configuração de dados

abstract class ConfigDB {
protected $host = 'localhost';
protected $database = 'teste';
protected $usuario = 'root';
   protected $senha = '';
}

 

Classe de conexão

include 'class.config.php';

abstract class Conexao extends ConfigDB {
protected $conexao;

public function __construct() {
       try {
           //Cria a conexão ao MySQL
           if($this->conexao == NULL) {
               $this->conexao = new PDO('mysql:host=' . $this->host . ';port=3306;dbname=' . $this->database, $this->usuario, $this->senha, array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
			$this->conexao->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
			$this->conexao->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
               return $this->conexao;
           }
       }
       catch(PDOException $e) {
           echo 'Falha ao realizar conexão à base de dados.<br /><br />
		Erro técnico: ' . $e->getMessage() . '<br />
		Arquivo: ' . basename($e->getFile()) . '<br />
		Linha: ' . $e->getLine() . '<br />';
       }
   }

public function closeCnx() {
	$this->conexao = NULL;
}
}

 

Classe para manipulação Agenda(testes)

Percebam que, neste arquivo, há uma função fora da classe, a função é para exibição de possíveis erros.

Onde e como eu poderia criar um método ou classe para isso?

 

Outra dúvida, os métodos: consulta, cadastrar, setCampos, setValores, totalRegistros e outros são basicamente comuns a qualquer acesso a tabelas do Banco. Poderia criar uma classe "Funções" e criar estes métodos nela, e estender estes às classes para os acessos a outros conteúdos (notícias, etc...)?

include 'class.conexao.php';

function exibeErro($obj) {
echo 'Falha ao realizar conexão à base de dados.<br /><br />
Erro técnico: ' . $obj->getMessage() . '<br />
Arquivo: ' . basename($obj->getFile()) . '<br />
Linha: ' . $obj->getLine() . '<br />';
}

class Agenda extends Conexao {
private $campos;
private $valores;
private $tabela = 'agenda';
public $camposValores = array();

public function setCampos($camposValores) {
	foreach($camposValores as $campo => $valor) {
		$this->campos .= $campo . ', ';
	}
	$this->campos = substr($this->campos, 0, -2);
}

public function setValores($camposValores) {
	foreach($camposValores as $campo => $valor ){
		$this->valores .= $this->conexao->quote($valor) . ', ';
	}
	$this->valores = substr($this->valores, 0, -2);
}

public function consulta($sql) {
	if(!empty($sql)) {
		return $this->conexao->query($sql);
	}
}

public function totalRegistros() {
	return $this->conexao->query("SELECT id FROM " . $this->tabela . "")->rowCount();
}

public function cadastrar() {
	if(!empty($this->campos) && !empty($this->valores)) {
		return $this->conexao->query("INSERT INTO " . $this->tabela . " (" . $this->campos . ") VALUES (" . $this->valores . ")");
	}
	else {
		echo 'Campos e/ou seus respectivos valores não foram informados.';
	}
}
}

try {
$camposValores = array(
	'dataInicio' => '2011-12-14',
	'dataFim' => '2011-12-17',
	'titulo' => 'Teste 05',
	'descricao' => 'Teste teste teste teste teste',
	'dataCadastro' => '2011-12-14',
);

$eventos = new Agenda;
$eventos->setCampos($camposValores);
$eventos->setValores($camposValores);
//$query = $eventos->consulta("SELECT CONCAT(titulo, ' - ', descricao) AS evento FROM agenda ORDER BY id DESC");
echo $eventos->totalRegistros();

//echo $query ? 'Cadastro ok' : 'Ih! Deu erro aí!';

/*$campos = array('titulo', 'dataInicio', 'descricao');
$eventos = new Agenda;
$eventos->setCampos($campos);
$query = $eventos->consulta("SELECT ");
while($dados = $query->fetch()) {
	echo $dados->titulo . '<br />';
}
$eventos->closeCnx();*/
}
catch(Exception $e) {
exibeErro($e);
}

 

Exemplo de uso do método cadastrar():

$camposValores = array(
	'dataInicio' => '2011-12-14',
	'dataFim' => '2011-12-17',
	'titulo' => 'Teste 05',
	'descricao' => 'Teste teste teste teste teste',
	'dataCadastro' => '2011-12-14',
);

$eventos = new Agenda;
$eventos->setCampos($camposValores);
$eventos->setValores($camposValores);

$query = $eventos->cadastrar();

Compartilhar este post


Link para o post
Compartilhar em outros sites

Segue nova classe, está melhor?

 

Classe de configuração de dados

abstract class ConfigDB {
protected $host = 'localhost';
protected $database = 'teste';
protected $usuario = 'root';
   protected $senha = '';
}

 

Classe de conexão

include 'class.config.php';

abstract class Conexao extends ConfigDB {

 

Nem olhei o resto do código, mas isto aí em cima está errado. Não existe herança entre configuração e conexão. Uma conexão NÃO É uma configuração. Uma conexão TEM uma configuração. A configuração não precisa ter uma classe para ela. Você pode usar um arquivo .ini para guardar estas informações de conexão e receber estas informações na classe Conexao. Da forma que você fez, você continua tendo o problema de só poder conectar a um banco de cada vez.

 

Vale a pena dar uma estudada nos conceitos básicos de orientação a objetos para entender melhor a questão da herança.

 

Carlos Eduardo

Compartilhar este post


Link para o post
Compartilhar em outros sites

No momento, meu intuito é utilizar apenas para uma conexão mesmo. Quero poder ter uma boa estrutura inicial para ir desenvolvendo aos poucos, até porque sou iniciante em OO.

 

Estou paralelamente estudando através do livro PHP com Orientação a Objetos 2ª edição.

 

Para os dados de conexão, posso então criar um arquivo .php ou .ini e simplemente incluí-lo na classe de conexão?

Quanto aos métodos básicos de acesso ao banco, estes devem ficar em uma classe específica (funções por ex) ou juntamente com a classe responsável por cada módulo (notícias, agenda, etc...)?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não utilize herança, ela não cabe aí.

Faça assim:

 

class ConnectionConfig {
private $_host, $_user, $_pswd, $_dbname;
public function __construct($host, $user, $pswd, $dbname){
	$this->_host = $host;
	$this->_user = $user;
	$this->_pswd = $pswd;
	$this->_dbname = $dbname;
}
}

class Conection {
private $_config;
public function __construct(ConnectionConfig $config){
   	$this->_config = $config;
}
}

Compartilhar este post


Link para o post
Compartilhar em outros sites

Obrigado Henrique.

 

Referente aos métodos para acesso às base de dados, estou fazendo o seguinte, criei uma classe "FuncoesDB".

Nela criei os métodos básicos (cadastrar, consultar, etc...), e nestes, passos os parametros necessários (tabela, campos, valores, etc...), assim está correto?

 

class FuncoesDB extends Conexao {
private $campos;
private $valores;
private $condicao;
private $ordem;
private $limiteInicio;
private $limiteFim;
public $tabela;

/*
 * tabela_qualquer
 *
 * @param string
*/
public function setTabela($tabela) {
	$this->tabela = $tabela;
}

/*
 * array('campo1', 'campo2', 'campo3')
 *
 * @param array
*/
public function setCampos($campos) {
	if(is_array($campos)) {
		foreach($campos as $campo) {
			$this->campos .= $campo . ', ';
		}
		$this->campos = substr($this->campos, 0, -2);
	}
	else {
		$this->campos = $campos;
	}
}

/*
 * array('campo1' => 'valor1', 'campo2' => 'valor2', 'campo3' => 'valor3')
 *
 * @param array
*/
public function setValores($valores) {
	if(is_array($valores)) {
		foreach($valores as $campo => $valor ){
			$this->valores .= $this->conexao->quote($valor) . ', ';
		}
		$this->valores = substr($this->valores, 0, -2);
	}
	else {
		$this->valores = $valores;
	}
}

public function consultaSimples($condicao, $ordem, $limiteInicio, $limiteFim) {
	$this->condicao = !empty($condicao) && !is_null($condicao) ? ' WHERE ' . $condicao : '';
	$this->ordem = !empty($ordem) && !is_null($ordem) ? ' ORDER BY ' . $ordem : '';
	$this->limite = $limiteInicio != '' && $limiteFim != '' && !is_null($limiteInicio) && !is_null($limiteFim) ? ' LIMIT ' . $limiteInicio . ', ' . $limiteFim : '';

	return $this->conexao->query("SELECT " . $this->campos . " FROM " . $this->tabela . $this->condicao . $this->ordem . $this->limite . "");
}
}

 

 

Um problema que prevejo, é em caso de consultas compostas (JOINs). Só vejo fazer desta forma informando a SQL completa, ex: consulta("SQL completa").

 

É melhor utilizando parâmetros no método consulta ou informar somente a instução SQL?

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.