[POO] Debut avec des classes SQL

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : [POO] Debut avec des classes SQL

par agité » 23 mai 2008, 10:06

Pour la 2ème partie je pense avoir compris et c'est ce que j'ai ajouter maintenant pour pouvoir faire des requêtes, et aussi renvoyer une erreur assez explicite. Par contre je bloque sur les throw new exception et les try / catch qui allourdissent clairement les pages !!

Si a chaque appel de la classe je dois tester s'il y a des exception j'ai pas finis :roll:

du coup j'ai fais un méthode simple qui teste la requete dans la classe de cette manière :
class dbquery  {

 protected $config = array(
 'host' => 'localhost',
 'user' => 'root',
 'pass' => '',
 'dbname' => 'test_admin'
 );

 // Connection a la bdd
 function __construct() {
 
 		$this->dbconnect = @mysql_connect($this->config['host'],
																			$this->config['user'],
																			$this->config['pass']);
																			
		$this->dbtable = @mysql_select_db($this->config['dbname'],$this->dbconnect);	

									
		if(!$this->dbconnect)
		{
 			echo "<b>- Impossible de se connecter a la base de donnée</b><br />";
		}
									
			
		if(!$this->dbtable)
		{
			echo "<b>- La base de donnée : '".$this->config['dbname']."' n'éxiste pas</b><br />";
		}
									
 }
 
 // Deconnection de la bdd
 function __destruct() {
	
		mysql_close($this->dbconnect);
 }


 // Fonction requete select sur la bdd
 public function req_query($req) {

		if($this->query_error($req)){ 
		
		return mysql_query ($req);
		
		}
 }
 
 public function fetchrows_query($req) {
 
		return mysql_fetch_row ($req);
		
 }
  
 public function numrows_query($req) {
 
		return  @mysql_num_rows ($req);
 
 }
 
  public function fetcharray_query($req) {

		return  mysql_fetch_array ($req);

 }
 
	
 // Retourner l'erreur sql
 public function query_error($req) {
 	
	if(!mysql_query($req))
	{
		echo "Erreur sql n°".mysql_errno()." : ".mysql_error()." <br /><br /> ".$req."<br /><br />";
		return false;
	}else{
		return true;
	}	
 
 }

}
donc la j'utilise bien les retour d'erreur pour les query, pour les autres je ne vois pas comment les tester et retourner les erreurs.

Par contre pour la 1ère partie de ce que tu éxplique j'avoue que je suis un peu perdu, en fait ce que je voudrais c'est justement eviter le procédurale, donc avoir une classe que j'ai fait par moi même (donc que je comprends et adaptée a mes besoins) en restant orienté POO.

Et la je pense que je suis bien partis je viens de commencer ma 2ème classe qui gère des programmes, elle est donc dans la continuitée de l'utiliation POO et me permet de faire appel a la première classe pour l'utiliser. Donc je pense être aller plus loin que le procédurale.

Merci pour vos conseils et explications.

par caroube » 22 mai 2008, 18:45

Oui, ça pourrait ressembler à ça. Mais il faut aller un peu plus loin.
Tout tes objets utilisent la même connexion : imagine que tu crées un objet 1, un objet 2, puis que tu détruises l'objet 2 et que tu essayes de faire une requête avec l'objet 1 : la connexion est fermée et donc ... erreur

Il faut donc que chaque objet soit indépendant et que tu utilises la possiblilté d'avoir plusieurs connexions. Quelque chose comme :

class dbquery  { 

 protected $link;

 function __construct() { 
  
        $this->link = mysql_connect($this->config['host'], 
                                    $this->config['user'], 
                                    $this->config['pass']); 
                                     
        mysql_select_db($this->config['dbname'], $this->link);                             
  //Idem utilisation de link dans le query et dans le close                                   
 } 
Deuxième point : non aux constantes dans la classe, du moins à ce niveau le plus bas. Ton objet doit être capable de se connecter à n'importe quelle base de données MySQL (qui te dit que tu n'auras pas un jour un besoin de transférer des données d'une base vers une autre).

Donc là, deux solutions :
1) Quand tu crées l'objet, tu lui passes les paramètres de connexion
2) Tu utilises l'héritage : la connexion à la base test_admin est bien une sorte de connexion à une base de données et donc tu crées un objet dbquery_test_admin qui étend dbquery avec juste les variables de connexion positionnées (toutes les méthodes étant définies au niveau de l'objet générique). Mais c'est quand même très limite : une voiture rouge est bien une sorte de voiture, mais on préfèrera quand même instancier un objet voiture en positionnant la variable couleur.

Enfin, faire de l'objet c'est bien beau, mais si c'est juste pour faire la même chose qu'en procédural classique, cela ne sert pas à grand chose. Je sais bien que la bibliothèque Pear:DB n'est plus maintenue (http://pear.php.net/manual/en/package.database.db.php) mais tu peux t'inspirer d'elle si tu veux créer ta propre classe. Crée une méthode pour exécuter des requêtes "sans réponse" (type insert), une méthode pour exécuter des requêtes qui renvoie une seule valeur, une méthode pour exécuter des requêtes en récupérant les valeurs sous forme de tableau associatif, une méthode pour exécuter des requêtes en récupérant les valeurs sous forme d'un XML, ...
Même si à l'intérieur de l'objet, c'est la même chose (un mysql_query), ça fait plus propre dans ton code d'avoir des noms de méthodes explicites :
  mydbquery->query ("insert ...");
  $max = mydbquery->getRow ("select max(jour) from evenement");
  $tableau = mydbquery->getAll ("select * from evenement");

par agité » 22 mai 2008, 11:19

Il y a un problème de conception dans tes classes. Ta classe dbquery ne peut pas hériter de ta classe dbconnect. La notion d'héritage est une notion de caractérisation "est une sorte de".
Exemple : tu pars d'une classe véhicule, puis tu dis qu'un aéronef est une sorte de véhicule, puis qu'un avion est une sorte d'aéronef, tout comme un hélicoptère est une sorte d'aéronef.

Là, dbquery n'est pas une sorte de dbconnect.

Par contre, tu peux ajouter des variables dans une classe : un avion va comporter des variables de type "objet aile", "objet moteur", "objet roue", ...

Donc, ta classe dbquery va comporter une variable de type dbconnect que tu pourras initialiser lors du constructeur de dbquery. Par la suite, tes requêtes pourront se faire par rapport à cette variable d'instance de l'objet dbconnect qui contientra l'identifiant de session
Donc ca ressemblerait à :

Class dbquery
-----------------
->constructeur (appel dbconnect)
->destructeur (ferme dbconnect)

->objet dbconnect
->objet aquery
->objet query_error

donc fusionner les 2 classes que j'ai fait pour faire ca :

// Classe de connection a la base de donnée
// fonctions de connection et deconnection
// Classe des requetes sql
class dbquery  {

 protected $config = array(
 'host' => 'localhost',
 'user' => 'root',
 'pass' => 'enimatek',
 'dbname' => 'test_admin'
 );

 // Fonction : constructeur 
 function __construct() {
 
		mysql_connect($this->config['host'],
									$this->config['user'],
									$this->config['pass']);
									
		mysql_select_db($this->config['dbname']);							
									
 }

 // Fonction : destructeur
 function __destruct() {
	
		mysql_close();
 }


 // Fonction requete select sur la bdd
 public function aquery($select,$table,$join,$where) {

	$req = "SELECT $select FROM $table $join $where";

	if(!mysql_query($req)){ 
		
		throw new Exception($this->query_error($req));
	
	}else{
	
		$new_req = @mysql_query ($req);
	
		return mysql_fetch_array($new_req);
 	}
 }
 
 // Retourner l'erreur sql
 public function query_error($req) {
 
 return "Erreur sql n°".mysql_errno()." : ".mysql_error()." <br /><br /> ".$req ;
 
 }

}

par caroube » 22 mai 2008, 10:32

Il y a un problème de conception dans tes classes. Ta classe dbquery ne peut pas hériter de ta classe dbconnect. La notion d'héritage est une notion de caractérisation "est une sorte de".
Exemple : tu pars d'une classe véhicule, puis tu dis qu'un aéronef est une sorte de véhicule, puis qu'un avion est une sorte d'aéronef, tout comme un hélicoptère est une sorte d'aéronef.

Là, dbquery n'est pas une sorte de dbconnect.

Par contre, tu peux ajouter des variables dans une classe : un avion va comporter des variables de type "objet aile", "objet moteur", "objet roue", ...

Donc, ta classe dbquery va comporter une variable de type dbconnect que tu pourras initialiser lors du constructeur de dbquery. Par la suite, tes requêtes pourront se faire par rapport à cette variable d'instance de l'objet dbconnect qui contientra l'identifiant de session

par agité » 22 mai 2008, 09:58

Ok je comprenais pas pourquoi il me retournais seulement le premier enregistrement, maintenant ce que j'aimerais faire c'est ta 2ème solution :
- modifier ta classe de manière à ce que la ressource soit affectée à un attribut de celle-ci de manière à pouvoir le lire enregistrement par enregistrement

HTH :)
Car ca m'évite de retaper a chaque fois un mysql_fetch_array() dans chaque appel de la classe, mais je ne vois pas comment lui dire de faire enregistrement par enregistrement...

et HTH ca veux dire quoi ? ^^

par Ryle » 21 mai 2008, 20:14

Y a un loupé dans ta méthode aquery() (ou dans la façon dont tu l'utilises).

A chaque appel, ta méthode va :
- exécuter une requête SQL
- retourner la première ligne de résultat (via le mysql_fetch_array)

Donc forcément, appellée dans un while, tu vas à chaque fois exécuter la requête et à chaque fois retourner le premier enregistrement retourné. Le résultat est effectivement une boucle infinie.

Il te faut soit :
- retourner la ressource ($new_req) et boucler sur un mysql_fetch_array() en dehors de la méthode
- modifier ta classe de manière à ce que la ressource soit affectée à un attribut de celle-ci de manière à pouvoir le lire enregistrement par enregistrement

HTH :)

[POO] Debut avec des classes SQL

par agité » 21 mai 2008, 15:27

Bonjour,

avant tout je cherche a reprendre une class sql existante j'ai envie d'en faire une qui sera bien adaptée a mes besoin, pour l'instant je démarre doucement et tente de comprendre les principes de la POO.

Pour ca j'ai d'abord creer une classe sql simple :
// Classe de connection a la base de donnée
// fonctions de connection et deconnection 
 
class dbconnect {

 protected $config = array(
 'host' => 'localhost',
 'user' => 'root',
 'pass' => 'enimatek',
 'dbname' => 'test_admin'
 );

 // Fonction : constructeur 
 function __construct() {
 
		mysql_connect($this->config['host'],
									$this->config['user'],
									$this->config['pass']);
									
		mysql_select_db($this->config['dbname']);							
									
 }

 // Fonction : destructeur
 function __destruct() {
	
		mysql_close();
 }

} 


// Classe des requetes sql
class dbquery extends dbconnect {

 // Fonction requete select sur la bdd
 public function aquery($select,$table,$join,$where) {

	$req = "SELECT $select FROM $table $join $where";

	if(!mysql_query($req)){ 
		
		$this->query_error($req);
	
	}else{
	
		$new_req = mysql_query($req);
	
		return mysql_fetch_array($new_req);
 	}
 }
 
 // Retourner l'erreur sql
 public function query_error($req) {
 
 die( "Erreur sql n°".mysql_errno().", ".mysql_error()." <br /><br /> ".$req) ;
 
 }

}
ensuite j'appel cette class dans un tableau HTML pour ajouter toute les entrées de ma table :


		<?
	include("../_includes/php/classes/dbclass.php");
	
	$connect = new dbquery();
	
	while($arrayMenu = $connect->aquery('*','menu_titre','',''))
	{
	?>
	<tr>			
	<td valign="top" class="menutitre"><? echo $arrayMenu['Titre']; ?><br>
		<?
		while($arraySmenu = $connect->aquery('*','menu_element','',"WHERE Id_titre = '".$arrayMenu['Id']."' "))
		{
		?>
		<a href="<? echo $arraySmenu['Url']; ?>" target="principal" class="menu"><? echo $arraySmenu['Nom']; ?></a><br />
		<?
		}
		?>
	</td>
	</tr>
	<?
	}	
	?>
mais j'ai l'impression qu'il aime pas beaucoup la boucle while avec l'utilisation de la classe il me fait une boucle infinie du premier resultat de la requete.

en mettant tout sans poo il me retourne bien le bon résultat et je bloque un peu.

une idée ?