Classes "extendue" de PDO

ViPHP
ViPHP | 1961 Messages

28 nov. 2006, 11:58

Si tu y penses, c'est très simple.

Pour ne pas changer, une petite indication.
C'est pas TA class qui retourne l'objet PDOStatment ?
Deux choses sont infinies, l'Univers et la sottise humaine!!
Mais je ne suis pas sur de ce que j'affirme au sujet de l'Univers.

A. Einstein

ViPHP
ViPHP | 3607 Messages

28 nov. 2006, 12:06

je croit que pour ce matin je vais un peu relacher le problème, mais simplement une dernière petite:
Donc c'est bien ma classe qui doit retourner l'objet,
Donc je redéfini la méthode prepare , mais là que dois-je retourner, parceque si je retourne parent::prepare, la j'aurai une instance de PDOStatement, on est d'accord déja là dessus?
donc si c'est bien ça la question reviens à :
Comment retourner une Instance de classe Différente...
Une réponse simple serait :
return new SQLStatement;
(en adméttant que SQLStatement est dérivé de PDOStatement...)
Seulement le problème c'est que dans la doc, il n'apparait pas de constructeur de PDOStatement, donc comment le redéfinir dans ma classe SQLStatement?

ViPHP
ViPHP | 1961 Messages

28 nov. 2006, 12:20

Tu te rapproches de plus en plus de la solution, elle est juste là, à mois de 1 mm.

Pense à QQ chose du style
class MyPDOStatment{
   private $monStatment = null;
   public function __construct (PDOStatment $leStatment){
      $this->monStatment = $leStatment;
   }
}
Pour le reste je laisse réfléchir.
Deux choses sont infinies, l'Univers et la sottise humaine!!
Mais je ne suis pas sur de ce que j'affirme au sujet de l'Univers.

A. Einstein

ViPHP
ViPHP | 3607 Messages

28 nov. 2006, 14:48

Bon ben là c'est l'échec... j'ai beau chercher et relire ton dernier commentaire... je trouve pas la solution :?
Bon simplifions la donne, pour résoudre ce bout de problème, on a besoin que des méthodes prepare et execute, alors voilà le point de départ:
class MyPDO extends PDO{
  public function prepare($q,$opt=NULL){
    // je fait pas non plus les try catch, pour simplifier
    return parent::prepare($q,$opt);
  }
}

class MyPDOStatement extends PDOStatement {
  public function execute($param=NULL){
    return parent::execute($param);
  }
}
Seulement si on laisse le code comme ça, ben MyPDO::prepare va retourner une instance PDOStatement
et si je comprend bien, dans la méthode PDO::prepare, il doit y avoir un appel du style new PDOStatement($statement)...
donc moi si je fait comme ceci:
class MyPDO extends PDO{
  public function prepare($q,$opt=NULL){
    // je fait pas non plus les try catch, pour simplifier
    parent::prepare($q,$opt);
    return new MyPDOStatement($q,$opt);
  }
}

class MyPDOStatement extends PDOStatement {

  private $statement=NULL;
  private $options=NULL;

  public function __construct($stat,$opt){
    $this->statement=$stat;
    $this->options=$opt;
  }

  public function execute($param=NULL){

  }
}
ça serait déja mieu non? mais je sai spas quoi mettre dans la méthode execute... :cry:
je pédale pas mal dans la semoule là #-o

ViPHP
ViPHP | 1961 Messages

28 nov. 2006, 15:07

non, tu t'égares.

Maintenant on ne va pa étendre la class PDOStatment mais la masquer pour l'utilisateur et y ajouter nos méthodes

Il-y-a d'autres choses à faire mais pour l'idée de départ
class MyPDOStatment{
   private $monStatment = null;
   public function __construct (PDOStatment $leStatment){
      $this->monStatment = $leStatment;
   }
   public function execute($param = null){
      return $this->monStatment->execute($param);
   }
}
et dans la class MyPDO
   public function prepare($param){
      return (new MyPDOStatment (parent::prepare($param)));
   }
N'oublie pas tous les try/catch, etc...
Deux choses sont infinies, l'Univers et la sottise humaine!!
Mais je ne suis pas sur de ce que j'affirme au sujet de l'Univers.

A. Einstein

ViPHP
ViPHP | 3607 Messages

28 nov. 2006, 15:32

Bon je comprend déja pas trop l'idée de départ... :oops:
en fait je comprend pas trop où est défini la méthode execute, quand tu faits $this->monstatement->execute?
mais je l'ai appliqué bêtement, pour voir si ça marchait, et ça fait des trucs bizarres...
voici les deux classe que j'ai et les appels:
<?php
/**
 * Compteur de requêtes.
 *
 * Classe étendue de PDO destinée à compter le nombre de requêtes envoyées.
 */
class SQL extends PDO
{
     /**
      *redéfinition de la méthode prepare
      */
      
      public function prepare($param){
        try{
          return (new SQLStatement (parent::prepare($param)));
        } catch (PDOException $e){
          throw $e;
        }
      }            
}

class SQLStatement {
   private $monStatment = null;
   
   public function __construct (PDOStatment $leStatment){
      $this->monStatment = $leStatment;
   }
   
   public function execute($param = null){
    try{
      return $this->monStatment->execute($param);
    }catch (PDOException $e){
      throw $e;
    }
   } 
}

$user='xxx';
$pass='xxx';
try{
  $connec=new SQL('mysql:host=xxx;dbname=xxx', $user, $pass);
} catch (PDOException $e) {
  die("Erreur de connection: <br />".$e->getMessage());
}

$sql='SELECT * FROM `actions` LIMIT 0,10';
try{
  $resQrySel = $connec->query($sql);
} catch (PDOException $e){
  die("Erreur d'éxécution de la requête:<br />".$sql."<br />Erreur:<br />".$e->getMessage());
}
if($i == 0){
  try{
    $res = $resQrySel->fetchAll(PDO::FETCH_OBJ);
  } catch (PDOException $e){
    die("Erreur lors du traitement de la ressource: <br />".$e->getMessage());
  }
  foreach($res as $a=>$b){
    echo "<br />Enregistrement numéro ".$a."<br />";
    foreach($b as $cle=>$valeur){
      echo $cle." = ".$valeur."<br />";
    }
  }
}

$sql='SELECT * FROM `actions` WHERE `id_action` = ?';
try{
  $var=$connec->prepare($sql);
  $var->execute(array(5));
  $res=$var->fetchAll();
}catch(PDOException $e){
  die('Erreur d\'éxécution de la requête préparée: '.$e->getMessage());
}
print_r($res);


echo 'Nombre de requêtes préparées effectuées: '.$connec->getnbrQuery(PREPARED);

?> 
j'ai l'impression à l'appel de la page que le serveur ne répond pas....
si je comment la partie des requêtes préparées, tout s'affiche correctement, et rapidement, si je fait une faute dans ma requête préparée, une belle erreur m'est retournée, mais si j'ai une requête correcte, la page est en constant chargement, et rien ne s'affiche? :(

ViPHP
ViPHP | 1961 Messages

28 nov. 2006, 15:44

C'est normal.

Tu dois réecrire toutes les méthodes de PDOStatment dans MyPDOStatment avec la même "tête" que execute.
Quand je te disais "masquer" c'est vraiment masquer (on n'a pas fait de extend, donc on n'a pas hérité des propriétes et méthodes) il faut les redéfinir mais juste pour l'appel (elles ne servent que de rellais)
si tu utilises fetchAll() il va chercher où les valeurs.?
Deux choses sont infinies, l'Univers et la sottise humaine!!
Mais je ne suis pas sur de ce que j'affirme au sujet de l'Univers.

A. Einstein

ViPHP
ViPHP | 3607 Messages

28 nov. 2006, 15:54

ça n'a pas l'aire de marcher le $thi->->methode, car si j'enlève l'appel à fetchAll ou que je redéfinit fetchAll, j'ai le même problème que tout à l'heure Je suis de plus en plus embrouillé là :-s

ViPHP
ViPHP | 1961 Messages

28 nov. 2006, 15:57

Là je dois m'absenter, je regarderais ça à mon retour et te tiens au courant.
Deux choses sont infinies, l'Univers et la sottise humaine!!
Mais je ne suis pas sur de ce que j'affirme au sujet de l'Univers.

A. Einstein

ViPHP
ViPHP | 3607 Messages

28 nov. 2006, 16:03

c'est très aimable à toi de me prévenir :wink:
Bon absentage :!:

Mammouth du PHP | 983 Messages

28 nov. 2006, 21:41

Voilà comment je ferais. Désolé, c'est un peu long.
<?php
class SQL extends PDO
{
    /**
     * Statement des requêtes préparées
     *
     * @var PDOStatement
     */
	private $_statement = null;
    
    /**
     * Prépare une requête
     * 
     * @param string $sql requête SQL à préparer
     * @param array $params paramètres du driver PDO
     * 
     * @return PDOStatement le statement généré
     * @throws PDOException si une erreur se produit dans la préparation de la requête
     */
     public function prepare($sql, $params = null)
  	 {
  	     //si la requête est vide, on ne peut pas la préparer
  	     if( empty($sql) )
  	     {
  	         throw new PDOException(__METHOD__ . 'attend un chaîne SQL valide en 1er argument!');
  	     }
  	     // pas besoin d'entourer de try / catch, notre méthode lèvera une PDOException 
  	     // qu'il faudra rattraper lors de l'appel
  	     $this->_statement = parent::prepare($sql, $params);
  	     //ici on peut incrémenter le cpt de préparation de requête
         return $this->_statement; 
     }

     /**
      * Exécute une requête préparée
      *
      * @param array | mixed $bindParams valeurs des paramètre de la requête
      * 
      * @return bool true si la requête s'est bien exécutée, false sinon
      * @throws PDOException si aucune requête préparée, ou si il manque un paramètre nommé
      */
     public function execute($bindParams = array() )
     {
         // si la requête n'a pas été préparée, on ne peut pas l'exécuter
         if( is_null($this->_statement) )
         {
             throw new PDOException(__METHOD__ . ' doit être appelée après avoir 
				préparer une reqûete avec SQL->prepare()');
         }
         
         $res = $this->_statement->execute( (array) $bindParams );
         //ici on peut incrémenter le cpt de reqûete préparées exécutées
         return $res;
     }
     
     /**
      * Exécute la requpete SQL donnée et retourne le nb de lignes affectées.
      * 
      * @throws PDOException si la requête SQL est vide
      */
     public function exec($sql)
     {
         if( empty($sql) )
         {
             throw new PDOException('L\'argument attendu ne peut être vide');
         }
         
         $res = $this->exec($sql);
         //si tout s'est bien passé, on reoturne le nb de lignes affectées
         if( $res !== false)
         {
             //ici on peut incrémenter le cpt des requêtes non préparées
             return $res;
         }
         
         //si on arrive ici, une erreur s'est produite
         throw new PDOException('Une erreur s\'est produite : ' . print_r($this->errorInfo(), 1) );
     }
     
     //faire de même pour query
     
     /**
      * Retourne le statement de la dernière préparation de requête.
      *
      * @return PDOStatement
      */
     public function getStatement()
     {
         return $this->_statement;
     }
}

$user='xxx';
$pass='xxx';
try{
  $connec = new SQL('mysql:host=xxx;dbname=xxx', $user, $pass);
} catch (PDOException $e) {
  die("Erreur de connection: <br />".$e->getMessage());
}

$sql='SELECT * FROM `actions` LIMIT 0,10';
$resQrySel = 0;
try{
  $resQrySel = $connec->query($sql);
} catch (PDOException $e){
  die("Erreur d'éxécution de la requête:<br />".$sql."<br />Erreur:<br />".$e->getMessage());
}
if($resQrySel != 0){
  try{
    $res = $resQrySel->fetchAll(PDO::FETCH_OBJ);
  } catch (PDOException $e){
    die("Erreur lors du traitement de la ressource: <br />".$e->getMessage());
  }
  foreach($res as $a=>$b){
    echo "<br />Enregistrement numéro ".$a."<br />";
    foreach($b as $cle=>$valeur){
      echo $cle." = ".$valeur."<br />";
    }
  }
}

$sql='SELECT * FROM `actions` WHERE `id_action` = ?';
try{
  $var= $connec->prepare($sql);
  $res = $var->execute(array(5));
  
  if($res)
  {
  	$datas = $var->fetchAll();
  }
}catch(PDOException $e){
  die('Erreur d\'éxécution de la requête préparée: '.$e->getMessage());
}
print_r($res);
s
//echo 'Nombre de requêtes préparées effectuées: '.$connec->getnbrQuery(PREPARED);

?>  
Je maintiens que je ne vois pas l'intérêt de faire un try / catch pour faire seulement un throw dans le catch. autant laisser les méthode PDO de base lever une exception et les rattraper lors de l'appel des méthodes.

J'ai essayé de commenter un maximum pour dire ce que je fais. Le principe est de ne pas encapsuler PDOStatement dans une autre classe, car il faudrait alors router toutes ses méthodes dans la classe qui l'encapsule.
Je n'ai pas fait les compteurs, je te laisse le soin de les faire, mais j'ai indiqué là où je les mettrais.

N'hésites pas si tu as des questions

ViPHP
ViPHP | 3607 Messages

28 nov. 2006, 22:13

Alors tout d'abord merci d'avoir pris le temps de développer une solution... c'est gentil!
Mais par contre la solution ne fonctionne pas lorsque l'on fait une requête préparée...
lorsque je test la requête préparée, elle ne me retourne que les enregistrement dont l' `id_action` est égal à 0, et si je remplace directement dans la requête le ? par 5, j'ai bien les bon enregistrements...
donc il y a un soucis au niveau du prepare ou du execute...

ViPHP
ViPHP | 1961 Messages

28 nov. 2006, 22:20

Re,

J'ai pas eu le temps de voir ce qu'a fait rami mais juste par curiosité

As-tu essayé une simple query() avec des erreurs de synthaxe SQL ?

Si le fait de ne pas faire transmettre l'exception fonctionne, il va faloir que je revoi toute ma théorie.

Si tu as essayé dis moi ce que ça donne.
Deux choses sont infinies, l'Univers et la sottise humaine!!
Mais je ne suis pas sur de ce que j'affirme au sujet de l'Univers.

A. Einstein

ViPHP
ViPHP | 3607 Messages

28 nov. 2006, 22:26

Dsl pour toi rami, mais en effet si l'on ne fait pas de try catch dans la classe, les erreurs ne sont pas transmises...
Un point pour Ajoloca

ViPHP
ViPHP | 1961 Messages

28 nov. 2006, 22:31

Oufff....
Tu me rassures !
Je dinne et regarde le PB de execute().
Deux choses sont infinies, l'Univers et la sottise humaine!!
Mais je ne suis pas sur de ce que j'affirme au sujet de l'Univers.

A. Einstein