Page 1 sur 1

PDO et query exécuté

Posté : 13 avr. 2010, 15:17
par Yosh
Bonjour à tous,

Cela fait un moment que j'utilise PDO que je couple avec un mode DEBUG afin d'afficher toutes les requêtes exécuté dans un script, tout fonctionne bien sauf le principal à savoir comment récupérer la query généré par PDO avec les paramètres.

Avez-vous déjà fait ça?

Une idée?

Ci-dessous, la surcharge PDO que j'utilie pour sqlserver:
class mssqlPDO extends PDO {
		
		/*
		public function __autoload() { }		
		public function __construct() {	}		
		public function __destruct() { }		
		public function __clone() {	}		
		public function __call($method, $arguments) {	}		
		public function __set($nom, $valeur) { }		
		public function __get($nom) {	}
		*/
		
		//redefine method for sqlserver
		public function lastInsertId($name = '') {
			$sql_scope = "select CONVERT(INT, SCOPE_IDENTITY()) as lastInsertId";
			$stmt_scope = parent::prepare($sql_scope);
			//exec sql
			if($stmt_scope->execute()) {
				return $stmt_scope->fetch(PDO::FETCH_OBJ)->lastInsertId;
			}
			return false;
		}
		
		//log des query prepare
		public function prepare($sql, $driver_options = array()) {
			global $GROUPES_LIBELLE;
			if(DEBUG) {
				echo "<div style=\"background-color:#5298d4; color:#FFFFFF; margin:10px; padding:5px\"><strong>DEBUG:</strong><hr>$sql</div>";	
			}	
			return parent::prepare($sql, $driver_options = array());
		}
	}
Et le code HTML généré lors d'un simple SELECT:
SELECT id, nom, prenom, email FROM [user] WHERE id = :id;
Concrètement, j'aimerais affiché:
SELECT id, nom, prenom, email FROM [user] WHERE id = 845; //par exemple

Re: PDO et query exécuté

Posté : 13 avr. 2010, 15:35
par stealth35
	
$query 	= $pdo->prepare("SELECT * FROM test WHERE id = :id AND test LIKE ':test'");
	
$data 	= array(':id' => 4, ':test' => 'hello');
$result	= $query->execute($data);
	
echo str_replace(array_keys($data), array_values($data), $query->queryString);

//SELECT * FROM test WHERE id = 4 AND test LIKE 'hello'
pas tiptop mais bon... a creuser

Re: PDO et query exécuté

Posté : 13 avr. 2010, 15:37
par Yosh
$query 	= $pdo->prepare("SELECT * FROM test WHERE id = :id");
	
$data 	= array(':id' => 4);
$result	= $query->execute($data);
	
echo str_replace(array_keys($data), array_values($data), $query->queryString);

//SELECT * FROM test WHERE id = 4
pas tiptop mais bon... a creuser
J'y avais déjà pensé, mais ça me va pas...

Le but est de surchrager une des méthode de PDO pour arriver au résultat escompter, comme ça je ne le fais QUE dans ma class, je ne veux pas alourdir toutes mes class.

Re: PDO et query exécuté

Posté : 13 avr. 2010, 15:40
par stealth35
sauf que c'est pas au moment de 'prepare' qu'il faut le faire mais au moment de 'execute' :wink:

Re: PDO et query exécuté

Posté : 13 avr. 2010, 15:48
par Yosh
sauf que c'est pas au moment de 'prepare' qu'il faut le faire mais au moment de 'execute' :wink:
Oui, je sais aussi... :/

Pour le moment j'essaye simplement de surcharger la méthode execute de ma classe mssqlPDO comme ceci:
public function execute($input_parameters = array()) {
			print_r($input_parameters);
			
			return parent::execute($input_parameters);
		}
Mais ça fait rien.

EDIT: bon déjà je dois surcharger PDOStatement et non pas ma class PDO apparemment.

Re: PDO et query exécuté

Posté : 13 avr. 2010, 15:59
par stealth35
EDIT: bon déjà je dois surcharger PDOStatement et non pas ma class PDO apparemment.
yep j'allais te le dire :wink:

Re: PDO et query exécuté

Posté : 13 avr. 2010, 16:06
par Yosh
EDIT: bon déjà je dois surcharger PDOStatement et non pas ma class PDO apparemment.
yep j'allais te le dire :wink:
J'avance un tout petit peu,

Pour surcharger le PDOStatement, il faut utiliser l'attribut:
setAttribute(PDO::ATTR_STATEMENT_CLASS, array('myPDOStatement', array($this)));
Le hic, c'est que j'utilise un multiton, donc j'adapte mon code, comme ci-dessous:
self::$instance[$name]->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('myPDOStatement', array(self::$instance[$name])));
Jusque la tout va bien, si je test, je me retrouve avec l'erreur suivante:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: user-supplied statement does not accept constructor arguments' in C:\site\wwwroot_ieo\GestionPortailClient\class\db.class.php:83 Stack trace: #0 C:\site\wwwroot_ieo\GestionPortailClient\class\db.class.php(83): PDO->prepare('SELECT T1.id, n...', Array) #1 C:\site\wwwroot_ieo\GestionPortailClient\class\user.class.php(193): mssqlPDO->prepare('SELECT T1.id, n...') #2 C:\site\wwwroot_ieo\GestionPortailClient\index.php(78): user->getUser('POLIYO00') #3 {main} thrown in C:\site\wwwroot_ieo\GestionPortailClient\class\db.class.php  on line 83
Et donc apparement, il faut surcharger la méthode __construct de la class myPDOStatement comme suis:
public $dbh;
    protected function __construct($dbh) {
        $this->dbh = $dbh;
    }
Et la ça fonctionne, le seul hic est que je vais de voir reprendre toute mes class, car j'utilise bindParam au lieu de passer le tableau des clés / valeurs à la méthode execute :/

Re: PDO et query exécuté

Posté : 13 avr. 2010, 16:11
par stealth35
pas mal le coup du PDO::ATTR_STATEMENT_CLASS

Re: PDO et query exécuté

Posté : 13 avr. 2010, 16:14
par Yosh
pas mal le coup du PDO::ATTR_STATEMENT_CLASS
Vi, je connaissais pas ^^

Mais bon un peu galère quand il faut se retaper 50 class...

Re: PDO et query exécuté

Posté : 13 avr. 2010, 16:38
par Yosh
Finalement, c'est pas résolut, enfin la surcharge fonctionne, mais maintenant, toutes les query eécuté avec bindParam ne fonctionne plus :/

Je cherche...

Re: PDO et query exécuté

Posté : 13 avr. 2010, 16:42
par stealth35
ton MyPDOStatement etend PDOStatement ?

Re: PDO et query exécuté

Posté : 13 avr. 2010, 16:50
par Yosh
ton MyPDOStatement etend PDOStatement ?
oui

Re: PDO et query exécuté

Posté : 13 avr. 2010, 16:53
par stealth35
ducoup je vois pas bien ton soucis avec le bindParam :roll:

Re: PDO et query exécuté

Posté : 14 avr. 2010, 11:10
par Yosh
ducoup je vois pas bien ton soucis avec le bindParam :roll:
Je suis finalement arrivé à mes fins.

Le problème du bindParam venait du faite que la méthode execute avec comme paramètre $input_parameters plantait quand ce paramètre était vide (d'ailleurs pas bien normal mais bon), je le répète le but n'était pas de modifier toutes mes classes, mais d'adapté mes class PDO pour pouvoir logguer la query final avec les valeurs.

Ce que j'ai fait, j'ai créé une class myPDOStatement avec un paramètre privé $preBindingStatement qui va stocker la query puis la modifié au fur et à mesure que je bind les paramètre, si jamais, les paramètres sont passés directement dans la méthode execute, c'est quasiment pareil, puisque je parcours les paramètres et fais la même opération que pour le bind.

Voici donc la class final myPDOStatement:
class myPDOStatement extends PDOStatement {
		
		private $preBindingStatement;

		private function __construct($stmt) {
    	$this->stmt = $stmt;
			$this->preBindingStatement = $this->queryString;
    }
		
		public function bindParam($stmt_parameter, $stmt_value, $dataType = PDO::PARAM_STR) {        
        $this->preBindingStatement = str_replace("{$stmt_parameter}", "'{$stmt_value}'", $this->preBindingStatement);
				return parent::bindParam($stmt_parameter, $stmt_value, $dataType);
    }
		
		private function logQuery() {
			echo "<div style=\"background-color:#5298d4; color:#FFFFFF; margin:10px; padding:5px\"><strong>DEBUG:</strong><hr>".$this->preBindingStatement."</div>";
		}
		
		public function execute($input_parameters = array()) {
			
			if(count($input_parameters)>0) {
				$this->preBindingStatement = $this->queryString;
				foreach($input_parameters as $stmt_parameter => $stmt_value) {
					$this->preBindingStatement = str_replace("{$stmt_parameter}", "'{$stmt_value}'", $this->preBindingStatement);
				}
				$result = parent::execute($input_parameters);
			} else {
				$result = parent::execute();
			}			
			
			if(DEBUG) {
				$this->logQuery();
			}
			
			return $result;
		}
	}
Ce qui me permet d'avoir visuellement toutes les requêtes d'une page si j'active le mode DEBUG, pratique pour optimiser l'ensemble.

http://yfrog.com/72testmg

En passant vous avez des techniques de ce genre?