Abstraction pdo

Soyez le premier à donner votre avis sur cette source.

Vue 6 390 fois - Téléchargée 324 fois

Description

Bonjour,
Cette classe permet d'étendre le module PDO.
La classe PdoManager ouvre la connexion en fonction de l'adapter passé.
Toutes les méthodes de PDO sont accessibles via la classe PdoManager grace a la fonction __call

Ex : appel de la méthode query
$oPdo = new DaoFactory::factory($aParams);
$oPdo->query('SELECT tata_yoyo FROM chapeau');

L'avantage est d'avoir des nom de méthode standardisé pour récupérer par exemple la liste des tables, la description des tables. Dans les classes PdoMysql et PdoPgsl on peut facilement ajouter des méthodes qui demandes des syntaxes SQL différentes selon les SGBD
Pour rajouter le support d'autre bdd il suffit par exemple de créer une class PdoMssql et d'y implémenter les méthodes obligatoires.
Voila c'est pas une classe très compliqué mais elle me sert beaucoup.
J'attend vaut critique et idées d'amélioration

Source / Exemple :


<?php
/**

  • @abstract
  • @name PdoManager
  • @author aberthelot
  • @since 11/10/2008
  • @package Dao::Pdo
  • @version 4.0.0 - AXB - 11/10/2008
  • @version 4.0.1 - AXB - 14/11/2008 - Déportation de la méthode connect dans les classes filles
  • /
abstract class PdoManager { /**
  • Host de connexion
*
  • @access protected
  • @var string
  • /
protected $_sHostname; /**
  • Nom d'utilisateur
*
  • @access protected
  • @var string
  • /
protected $_sUsername; /**
  • Password de connexion
*
  • @access protected
  • @var string
  • /
protected $_sPassword; /**
  • Adapter connexion
  • Ex : mysql, pgsql
  • @access protected
  • @var string
  • /
protected $_sAdapter; /**
  • Nom de la base de données
*
  • @access protected
  • @var string
  • /
protected $_sBasename; /**
  • Port de connexion
*
  • @access protected
  • @var integer
  • /
protected $_iPort; /**
  • Encodage de la base de données
*
  • @access protected
  • @var string
  • /
protected $_sEncoding; /**
  • Connexion base de données
*
  • @access protected
  • @var object
  • /
protected $_oPdoInstance = null; /**
  • Constructeur de la classe
  • Initialise les variables de connexion
  • Test si l'extension pdo est chargée
*
  • @param array $aParams
  • @return void
  • /
public function __construct($aParams) { $this->_sAdapter = ( isset($aParams['adapter']) ) ? $aParams['adapter'] : null; $this->_sHostname = ( isset($aParams['hostname']) ) ? $aParams['hostname'] : null; $this->_sPassword = ( isset($aParams['password']) ) ? $aParams['password'] : null; $this->_sUsername = ( isset($aParams['username']) ) ? $aParams['username'] : null; $this->_sBasename = ( isset($aParams['basename']) ) ? $aParams['basename'] : null; $this->_iPort = ( isset($aParams['port']) ) ? $aParams['port'] : null; $this->_sEncoding = ( isset($aParams['encoding']) ) ? $aParams['encoding'] : null; if( false === $this->checkExtensionPDo() ) { throw new Exception('L\'extension "pdo" ou "pdo_'.$this->_sAdapter.'" ne sont pas activées.', E_ERROR); } } /**
  • Connexion à la base de données
  • Passe la gestion des erreurs en exception
  • Si mysql on active l'émulation des requêtes préparés
  • Initialisation de l'encodage de la connexion
*
  • @access public
  • @return void
  • /
public function connect() { if( is_null($this->_oPdoInstance) ) { $this->_oPdoInstance = new PDO($this->_getDsn(), $this->_sUsername, $this->_sPassword); $this->_oPdoInstance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); if( $this->_oPdoInstance->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql' ) { $this->_oPdoInstance->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); } $this->_setConnectionEncoding(); } } /**
  • Mapping des fonction PDO
*
  • @access public
  • @param string $sMethod
  • @param array $aArguments
  • @return mixed|boolean
  • /
public function __call($sMethod, $aArguments) { if( method_exists(get_class($this->_oPdoInstance), $sMethod) ) { return call_user_func_array(array($this->_oPdoInstance, $sMethod), $aArguments); } return false; } /**
  • Retourne la liste des drivers disponible
*
  • @static
  • @access public
  • @return array
  • /
public static function getAvailableDrivers() { return PDO::getAvailableDrivers(); } /**
  • Ferme la connexion à la base de données
*
  • @access public
  • @return void
  • /
public function close() { $this->_oPdoInstance = null; } /**
  • Test si l'extension pdo est activé
*
  • @access private
  • @return boolean
  • /
private function checkExtensionPDo() { if ( extension_loaded('pdo') ) { if( extension_loaded('pdo_'.$this->_sAdapter) ) { return true; } } return false; } /**
  • Retourne le driver de connexion
*
  • @abstract
  • @access protected
  • @return void
  • /
abstract protected function _getDsn(); /**
  • Modifie l'encodage de la connexion
*
  • @abstract
  • @access protected
  • @return void
  • /
abstract protected function _setConnectionEncoding(); /**
  • Retourne la description de la table
*
  • @abstract
  • @access public
  • @param string $sNameTable
  • @param string $sSchema
  • @return array
  • /
abstract public function describe($sNameTable, $sSchema = null); /**
  • Retourne la liste des tables de la base
*
  • @abstract
  • @access public
  • @return array
  • /
abstract public function listTable(); } ?> <?php /**
  • @name PdoMysql
  • @author aberthelot
  • @since 11/10/2008
  • @package Dao::Pdo
  • @version 4.0.0 - AXB - 11/10/2008
  • /
class PdoMysql extends PdoManager { /**
  • Constructeur de la classe
  • Initialise les variables de connexion
  • Test si l'extension pdo est chargée
*
  • @param array $aParams
  • @return void
  • /
public function __construct($aParams) { parent::__construct($aParams); } /**
  • Retourne la description de la table
*
  • @access public
  • @param string $sNameTable
  • @param string $sSchema
  • @return array
  • /
public function describe($sNameTable, $sSchema = null) { $aData = array(); $sSql = 'SHOW COLUMNS FROM '.$sNameTable.';'; $aRes = $this->query($sSql); $aRows = $aRes->fetchAll(); foreach($aRows as $iKey => $sValue) { $aData[$sValue['Field']]['name'] = $sValue['Field']; $aData[$sValue['Field']]['type'] = $sValue['Type']; $aData[$sValue['Field']]['null'] = ($sValue['Null'] == 'YES') ? true : false; $aData[$sValue['Field']]['key'] = ($sValue['Key'] == 'PRI') ? true : false; $aData[$sValue['Field']]['default'] = $sValue['Default']; $aData[$sValue['Field']]['extra'] = $sValue['Extra']; } return $aData; } /**
  • Retourne la liste des tables de la base
*
  • @access public
  • @return array
  • /
public function listTable() { $aData = array(); $sSql = 'SHOW TABLES;'; $aRes = $this->query($sSql); $aRows = $aRes->fetchAll(); foreach($aRows as $iKey => $sValue) { $aData[$iKey] = $sValue['Tables_in_'.$this->_sBasename]; } return $aData; } /**
  • Retourne le driver de connexion
*
  • @abstract
  • @access protected
  • @return void
  • /
protected function _getDsn() { return 'mysql:host='.$this->_sHostname.';dbname='.$this->_sBasename; } /**
  • Modifie l'encodage de la connexion
*
  • @access protected
  • @return void
  • /
protected function _setConnectionEncoding() { if(! is_null($this->_sEncoding) ) { $sStmt = $this->_oPdoInstance->prepare('SET CHARACTER SET ?'); $this->execute(array($this->_sEncoding)); } } } ?> <?php /**
  • @name PdoPgsql
  • @author aberthelot
  • @since 11/10/2008
  • @package Dao::Pdo
  • @version 4.0.0 - AXB - 11/10/2008
  • /
class PdoPgsql extends PdoManager { /**
  • Constructeur de la classe
  • Initialise les variables de connexion
  • Test si l'extension pdo est chargée
*
  • @param array $aParams
  • @return void
  • /
public function __construct($aParams) { parent::__construct($aParams); } /**
  • Retourne la description de la table
*
  • @access public
  • @param string $sNameTable
  • @param string $sSchema
  • @return array
  • /
public function describe($sNameTable, $sSchema = null) { $aData = array(); $sSql = "SELECT a.attnum, n.nspname, c.relname, a.attname AS colname, t.typname AS type, a.atttypmod, "; $sSql .= "FORMAT_TYPE(a.atttypid, a.atttypmod) AS complete_type, d.adsrc AS default_value, "; $sSql .= "a.attnotnull AS notnull, a.attlen AS length, co.contype, ARRAY_TO_STRING(co.conkey, ',') AS conkey "; $sSql .= "FROM pg_attribute AS a "; $sSql .= "JOIN pg_class AS c ON a.attrelid = c.oid "; $sSql .= "JOIN pg_namespace AS n ON c.relnamespace = n.oid "; $sSql .= "JOIN pg_type AS t ON a.atttypid = t.oid "; $sSql .= "LEFT OUTER JOIN pg_constraint AS co ON (co.conrelid = c.oid "; $sSql .= "AND a.attnum = ANY(co.conkey) AND co.contype = 'p') "; $sSql .= "LEFT OUTER JOIN pg_attrdef AS d ON d.adrelid = c.oid AND d.adnum = a.attnum "; $sSql .= "WHERE a.attnum > 0 AND c.relname = '".$sNameTable."' "; $sSql .= ( is_null($sSchema) ) ? '' : " AND n.nspname = '".$sSchema."' "; $sSql .= "ORDER BY a.attnum;"; $aRes = $this->query($sSql); $aRows = $aRes->fetchAll(); foreach($aRows as $iKey => $sValue) { $aData[$sValue['colname']]['name'] = $sValue['colname']; $aData[$sValue['colname']]['type'] = $sValue['complete_type']; $aData[$sValue['colname']]['null'] = ($sValue['notnull'] == 1) ? true : false; $aData[$sValue['colname']]['key'] = ($sValue['contype'] == 'P') ? true : false; $aData[$sValue['colname']]['default'] = $sValue['default_value']; } return $aData; } /**
  • Retourne la liste des tables de la base
*
  • @access public
  • @return array
  • /
public function listTable() { $aData = array(); $sSql = "SELECT c.relname AS table_name "; $sSql .= "FROM pg_class c, pg_user u "; $sSql .= "WHERE c.relowner = u.usesysid AND c.relkind = 'r' "; $sSql .= "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) "; $sSql .= "AND c.relname !~ '^(pg_|sql_)' "; $sSql .= "UNION "; $sSql .= "SELECT c.relname AS table_name "; $sSql .= "FROM pg_class c "; $sSql .= "WHERE c.relkind = 'r' "; $sSql .= "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) "; $sSql .= "AND NOT EXISTS (SELECT 1 FROM pg_user WHERE usesysid = c.relowner) "; $sSql .= "AND c.relname !~ '^pg_';"; $aRes = $this->query($sSql); $aRows = $aRes->fetchAll(); foreach($aRows as $iKey => $sValue) { $aData[$iKey] = $sValue['table_name']; } return $aData; } /**
  • Retourne le driver de connexion
*
  • @abstract
  • @access protected
  • @return void
  • /
protected function _getDsn() { return 'pgsql:host='.$this->_sHostname.';dbname='.$this->_sBasename; } /**
  • Modifie l'encodage de la connexion
*
  • @access protected
  • @return void
  • /
protected function _setConnectionEncoding() { if(! is_null($this->_sEncoding) ) { $stmt = $this->_oPdoInstance->prepare('SET client_encoding TO ?'); $this->execute(array($this->_sEncoding)); } } } ?> <?php namespace Dao; /**
  • @name DaoFactory
  • @author aberthelot
  • @since 11/10/2008
  • @package Dao
  • @version 4.0.0 - AXB - 11/10/2008
  • /
class DaoFactory { /**
  • Factory
  • Retourne une instance de la classe désigné par $sType
*
  • @param array $aParams
  • @return object
  • /
public static function factory(array $aParams) { if( isset($aParams['adapter']) ) { $sClass = 'Pdo'.ucfirst(strtolower($aParams['adapter'])); $oReflection = new ReflectionClass($sClass); if(! $oReflection->isSubclassOf('PdoManager') ) { throw new InvalidArgumentException($sClass.' n\'est pas une classe enfant de "PdoManager".', E_ERROR); } $oInstance = new $sClass($aParams); return $oInstance; } else { throw new Exception('Aucun type de base de données spécifié.', E_ERROR); } } } ?> ##### EXEMPLES ##### <?php $oPdo = new DaoFactory::factory($aParams); $sStmt = $oPdo->query('SELECT tata_yoyo FROM chapeau'); $aRes = $sStmt->fetchAll(); print '<pre>'; print_r($aRes); print '</pre>'; ?>

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

Messages postés
60
Date d'inscription
lundi 1 décembre 2008
Statut
Membre
Dernière intervention
3 janvier 2011

hum, euh désolé, j'ai PDO avec PHP 5.2.9, en oubliant que PDO est natif seulement à partir de PHP5.3
Messages postés
60
Date d'inscription
lundi 1 décembre 2008
Statut
Membre
Dernière intervention
3 janvier 2011

Bonjour,

Plutôt initié que débutant, en tous cas pour moi :-)
Je n'ai pas la compétence pour juger si c'est bien codé mais en ts cas, le code est clair.

Juste une question: pour quelle raison précise PHP5.3 est-il requis ?
Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
15
Salut,

La question sur __call() est intéressante.
En terme de design pattern (motif de conception), la méthode magique __call() permet d'écrire une classe proxy (ou un wrapper). Si les performances peuvent en pâtir, il faut quand même rester réaliste : c'est pas ça qui va ralentir un serveur, même mutualisé. Et puis quand on développe en OO, qu'on respecte des design patterns, etc, les performances sont toujours un peu détériorées. Par contre, on gagne en lecture de code, en maintenabilité, évolutivité, modularité, etc.
Et puis si PDO évolue et que de nouvelles méthodes sont créées, il ne sera pas nécessaire de mettre à jours la source, alors qu'avec des méthodes réécrites, si.
Messages postés
1
Date d'inscription
dimanche 21 septembre 2008
Statut
Membre
Dernière intervention
22 mars 2009

Bonsoir,

J'ai trouvé ta source très intéressante, j'ai décidé de changer la mienne en gardant certaines options mais en prenant ton système comme base de travail.
Je me posais en revanche une question, est-ce que l'utilisation de __call n'est-elle pas lourde à la longue ?
Une solution serait de re-déclarer toutes les fonctions, un peu redondants et chiant mais sûrement plus efficace, enfin je suis pas à 3 millièmes près :)

Je vais faire des tests et j'essaierai de donner un petit feedback par la suite.
Messages postés
35
Date d'inscription
vendredi 15 septembre 2006
Statut
Membre
Dernière intervention
4 mai 2010

Bonsoir,

je viens de tester ta classe parce que j'ai décidé d'enfin passer par pdo.

Par contre en voulant faire ton exemple j'obtiens des erreurs et ça ne marche pas :
"Warning: get_class() expects parameter 1 to be object, null given in C:\wamp\www\pdo\class.pdo_manager.php on line 137

Fatal error: Call to a member function fetchAll() on a non-object in C:\wamp\www\pdo\index.php on line 18"

Je pense que ça viens de la connexion, et donc de la création de l'objet car j'arrive pas à trouvé ou la connexion ce fait dans les class.
Afficher les 47 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.