Précédent   Forum des professionnels en informatique > PHP > PHP & SGBD
PHP & SGBD Forum d'entraide sur les SGBD avec PHP. Avant de poster : FAQ BDD, toutes les FAQ PHP, cours BDD et sources BDD
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 20/07/2006, 13h28   #1
Invité de passage
 
Inscription : juin 2006
Messages : 6
Détails du profil
Informations personnelles :
Localisation : France, Meurthe et Moselle (Lorraine)

Informations forums :
Inscription : juin 2006
Messages : 6
Points : 2
Points : 2
Par défaut [Conception] class au dessus d'une base de donnée

Bonjour,
J'ai créé un site avec consultation d'une base de données. Je decouvre actuellement php et mysql aussi mon travail n'est il pas pertinent. J'ai décidé de revoir mon travail et c'est durant cette revision que l'envie d'utiliser des classes m'est venue.
Je tiens, a ce niveau, a preciser que mon site n'a aucune finalité si ce n'est me faire decouvrir php.
Mon probleme, quant a lui concerne la conception même des classes que je souhaiterai utiliser : mon manque d'experience ou mes difficultés a cerner mon probleme font que je ne trouve pas de doc donnant une methode complete de la marche que j'aimerai suivre. Même si certaines m'ont donné des pistes de reflexions interessantes je me trouve actuellement a critiquer l'utilité de telles classes (car je ne comprends pas tout ^^)

Mon post est assez long j'en suis desolé, je vais presenter une page que je possede. l'utilisation d'une classe pour cette page et m'arreterai la pour ne pas devenir trop illisible :

une de mes pages consulte une table de ma base et affiche et mets en page tous ses champs :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
ob_start("ob_gzhandler");
require("connection.php");
require("head.html");
?>
 
<div id="contenu">
 
<h2>Nos partenaires</h2>
 
<p>Un merci a tous ceux qui contribuent a la santé de notre club.</p>
 
<?php 
 
require("script/fonction.php");//fonction contient la class abstraite utilitaire
 
//affiche les partenaires
 
$REQUET="select * from partenaire";
 
if($RESULT=mysql_query($REQUET)){
 
  while($LIGNE=mysql_fetch_object($RESULT)){
 
    $NOM=$LIGNE->par_nom;
    $DESCR=$LIGNE->par_descr;		
    $IMG=$LIGNE->par_img_id;
    $URL=$LIGNE->par_url;
 
    if(!empty($IMG)){
      $IMG=utilitaire::chemin_Img($IMG);//chemin_Img crée le chemin de l'image voulue
      $IMGECHO="<img src=\"$IMG\" alt=\"logo de $NOM\" >";				
    }
    else{
      $IMGECHO= "photo pas encore en ligne";
    }
    $AFFICHAGE="<h3>$NOM</h3>";
    $AFFICHAGE.= "<div class=\"partenaire\">$IMGECHO  <i>$DESCR</i>";
    if(!empty($URL)){
      $AFFICHAGE.=" <br/>lien direct : <i><a href=\"$URL\">$NOM</a></i>";
    }
    $AFFICHAGE.= "</div>";
    echo $AFFICHAGE;
  }
}
else{
  echo"echec requete";
}
require("footer.html");
?>
ps: il est fort probable que sous cette forme mon travail ne soit pas structuré ou pro n'hesitez pas a critiquer les faiblesses de mon travail

Admettons que je souhaite créer une classe partenaire, quelles sont les questions a se poser?
dois je créer une classe correspondant a tous les champs de la table que je stockerai ds un tableau parcouru par les methodes de la base? (ça me parait moche et je pense mal formuler l'idée.)
A l'heure actuelle je pense a quelque chose ressemblant a ceci :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
class partenaire{
     private $OBJET
    //je ne crée pas de constructeur
 
    function get_id($ID){//on sort les infos d'un seul partenaire
              $REQUET="select * from partenaire where $ID=part_id";
              $RESULT=mysql_query($REQUET);
              $OBJET=mysql_fetch_object($RESULT);
    }
 
     function nom(){
              return $OBJET->part_nom;
      }
 
     //etc pour le reste
}
La premiere version sort tout seul tous les partenaires qu'il met en page (une seule requete). La je ne sors qu'un seul partenaire a la fois. Ce qui pose plusieurs problemes selon moi :
Comment savoir que tous mes partenaires ont été bien affiché ?
Code :
1
2
3
4
5
6
7
8
9
10
 
$PARTENAIRE=1;//pour entrer dans la boucle
$I=1;
while($PARTENAIRE){
  $PARTENAIRE=new partenaire;
  $PARTENAIRE->get_id($I);//soit 20 partenaires alors j'ai 20 requetes :'(
   affichage($PARTENAIRE);//s'occupe de la mise en page peut mm etre 
//une methode de la classe donc plutot $PARTENAIRE->affichage()
$I+=1;
}
Voici en l'etat actuel de mes connaissances l'equivalent avec classe de mon probleme. Evidement l'avantage est que je peux maintenant utiliser cette classe sur d'autres pages ou je n'ai besoin que d'un partenaire particulier , l'inconvenient ici est le nombres élevé de consultation de la base.

Je m'arrete la en remerciant ceux qui ont lu jusqu'au bout (en esperant etre interessant) N'hesitez pas a critiquer ou commenter ce que je viens d'ecrire cela m'aiderai beaucoup.
Merci d'avance.
le_chainon_manquant est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/07/2006, 14h51   #2
Membre Expert
 
Avatar de Djakisback
 
Inscription : février 2005
Messages : 1 791
Détails du profil
Informations forums :
Inscription : février 2005
Messages : 1 791
Points : 1 681
Points : 1 681
Salut,
si tu veux vraiment programmer objet je pense qu'il faut que tu partes encore de plus générique.
Perso j'ai développé des classes dont je me sers partout :

SqlRecord (enregistrement SQL)
SqlRecordsSet (ensemble d'enregistrements SQL)

L'intérêt et qu'ensuite tu les étends et tu te retrouves à juste modifier des affichages ou des formulaires, toutes les opérations SQL existent déjà dans les classes mères (enfin dans l'idéal ^^).

Voici leurs structures simplifiées :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class SqlRecord() {
	var $table; 	// Nom de la table dans la BDD
	var $key; 	// Clé
	var $fields;    // Tableau des champs de l'enregistrement
 
	function SqlRecord($table = null, $key = null)	{}
	function sqlSelect($where = NULL)	{}
	function sqlInsert()	{}
	function sqlDelete()	{}
	function sqlUpdate()	{}
	function getField($name)	{
		if(isset($this->fields[$name]))
			return $this->fields[$name];
		return NULL;
	}
}
 
class SqlRecordsSet {
 
	var $table = null; 	// Nom de la table dans la BDD
	var $records = null;  	// Tableau des objets SqlRecord
	var $fields;    // Tableau des champs des enregistrements à traiter
 
	function SqlRecordsSet($table = NULL, $ids = NULL)	{}
	function sqlInsert()	{}
	function sqlDelete()	{}
	function sqlUpdate()	{}
	function sqlSelect()	{// c'est là que tu fais ton unique requête pour tous tes enregistrements plutôt que d'en faire 20}
}
Ensuite tu as plus qu'à étendre.
class Partenaire extends SqlRecord
class PartenairesEnsemble extends SqlRecordsSet
class Client extends SqlRecord
etc.

En plus de la réutilisabilité du code cela facilite également la maintenance. Mettons que t'aies oublié de traiter les injections sql, tu as juste à modifier ta fonction sqlSelect() et c'est bon.
Djakisback est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/07/2006, 11h24   #3
Invité de passage
 
Inscription : juin 2006
Messages : 6
Détails du profil
Informations personnelles :
Localisation : France, Meurthe et Moselle (Lorraine)

Informations forums :
Inscription : juin 2006
Messages : 6
Points : 2
Points : 2
Merci pour ta reponse mais je m'interroge encore :

chaque classe enfant heritera donc du tableau $field et aura la methode getfield et affichage (voir plus bas, c'est une methode que j'ai ajouté) c'est bien ça ?
De plus cela ne pose t'il pas probleme le fait qu'elles soient autant generaliste? Elles semblent permettre les insertions, modification...

Partons du principe que les insertions ne sont permises que dans un module admin ne vaudrait il pas mieux créer une autre classe gerant ces details de maintenance?
Idealement je permettrai a ces classes de consulter ma base (select) et eventuellement de formater un certain affichage (avec la methode affichage dont je parlais) et celles du module admin a faire le reste.

Je me permets de reprendre et adapter mon exemple sur SqlRecord :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
class SqlRecord() {
	var $table; 	// Nom de la table dans la BDD
	var $key; 	// Clé
	var $fields;    // Tableau des champs de l'enregistrement
 
	function SqlRecord($table = null, $key = null)	{}
	function sqlSelect($where = NULL)	{}
	function getField($name)	{
		if(isset($this->fields[$name]))
			return $this->fields[$name];
		return NULL;
	}
        function affichage(){
             //ici on permet la mise en page des données sorties par la classe
             //je ne l'ecris pas, ce n'est pas le but de mon post :P
        }
}
A ce stade je me pose une question sur la difference entre le constructeur SqlRecord et la methode SqlSelect :

Code :
function SqlRecord($table = null, $key = null)	{}
Va me permettre de sortir un champ de ma base si la cle existe. (Si la cle n'existe pas il va falloir le signaler ou l'objet gere seul?)

Code :
function sqlSelect($where = NULL)	{}
C'est une methode de l'objet. Mais que consulte t'elle? elle refait une connexion a la base en utilisant le contenu de $table et $key et en ajoutant un where?
Donc par exemple je peux instancier un objet correspondant au partenaire 1. Et avec cette methode verifier (en resortant le champ de la base) si son nom est COFADAS par exemple (where nom_part=COFADAS). Si c'est bien cela, alors je ne comprends pas trop l'interet. Je possede getField et je peux l'utiliser pour prendre les clefs de $field comme critere.

la methode SqlSelect n'est elle pas plus pertinente dans la classe SqlRecordSet et inutile ici?

Mon post va devenir indigeste si je continue. Je posterai plus tard ce que j'ai compris de ta solution adapté a mon exemple.
le_chainon_manquant est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/07/2006, 11h58   #4
Membre Expert
 
Avatar de Djakisback
 
Inscription : février 2005
Messages : 1 791
Détails du profil
Informations forums :
Inscription : février 2005
Messages : 1 791
Points : 1 681
Points : 1 681
Au niveau du découpage, tu peux effectivement faire plus propre en créant une classe d'enregistrement en lecture seule et une en lecture/écriture qui l'étend (tu auras un petit gain de mémoire de quelques octets pour les pointeurs de fonctions, par contre niveau de la sécurité ca changera rien) :

Code :
1
2
3
4
5
6
7
8
9
10
SqlRRecord() {
  sqlSelect()
  sqlGetField()
}
 
SqlRWRecord extends SqlRRecord() {
  sqlInsert()
  sqlUpdate()
  sqlDelete()
}
Au sujet de la fonction affichage() le but c'est justement de la mettre dans Partenaire et non dans SqlRecord ou bien dans mettre très générique dans SqlRecord du style affichage() {echo implode(',', $this->fields)}.

Le constructueur ne fait aucune opération SQL, il sert juste à définir la table et/ou la clé. C'est sqlSelect() qui s'occupe de remplir le tableau $fields. En fait sqlSelect() sert à "charger" les champs de l'objet en mémoire en faisant la requête "SELECT". getField() sert juste à récupérer un champ dans le tableau, il n'effectue aucune requête.

Citation:
Donc par exemple je peux instancier un objet correspondant au partenaire 1. Et avec cette methode verifier (en resortant le champ de la base) si son nom est COFADAS par exemple (where nom_part=COFADAS).
En effet mais si tu n'as pas la clé, ca te permet de récupérer un enregistrement en fonction d'une condition différente de "clé = truc".

Comme je te le disais c'est juste un exemple, j'ai pas le code de la dernière version que j'ai faite sous les yeux mais ensuite cela devient un peu plus ardus de gérer les jointures, etc.
Djakisback est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/07/2006, 12h14   #5
Invité de passage
 
Inscription : juin 2006
Messages : 6
Détails du profil
Informations personnelles :
Localisation : France, Meurthe et Moselle (Lorraine)

Informations forums :
Inscription : juin 2006
Messages : 6
Points : 2
Points : 2
Voici donc (avec plein de commentaire) ce que j'ai compris :
Comme dit plus haut le php est nouveau pour moi donc tous mes posts ne sont pas la pour critiquer la methode de djakisback juste que je suis un joyeux neophyte.

Je reprends ce que j'ai dit avoir compris plus haut moins mon histoire d'affichage (qu'une telle methode existe ou non n'a pas d'insidence sur la classe selon moi). Ma vision va faire subir des modifications aux exemples precedents mais c'est parce que je ne comprends pas leur fonctionnement exact.

Soit :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
class SqlRecord {
	var $table; 	// Nom de la table dans la BDD
	var $key; 	// Clé
	var $fields;    // Tableau des champs de l'enregistrement
 
/* le constructeurs est necessaire pour les classes heritiaires
et la fonction sqlSelect pretend a etre virtuelle?*/
	function SqlRecord($table = null, $key = null)	{}
	function sqlSelect($where = NULL)	{}
	function getField($name)	{
		if(isset($this->fields[$name]))
			return $this->fields[$name];
		return NULL;
	}
}
Je reprends donc l'idée de partenaire pour obtenir :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
class Partenaire extends SqlRecord{
 
       //on herite des variables de SqlRecord 
       //j'ajoute une variable verifiant si la requete a fonctionnée
       //cette variable devrait etre ajoutée ds la classe ancetre
       var $ok;
 
       function Partenaire($key=1){//valeur par defaut
           //je ne passe pas $table en parametre car $table est ici partenaire
           $table="partenaire";
           $requet="select * from $table where part_id=$key";
           $result=mysql_query($requet);
            if($ligne=mysql_fetch_object($result)){
                   $field[id]=$ligne->part_id;
                   $field[nom]=$ligne->part_nom;
                   //...
                   ok=true;
             }else {ok=false; }
        }
 
        //comme dit plus haut SqlSelect m'est hermetique :( 
        // et inutile de reprendre getfield (vive l'heritage)
 }
Au final je n'ai pas compris grand chose apres une journée de reflexion tout de même. Mais ces utilisations de classes avec heritages sont nettement plus agreables que mon jet lors de ma premiere question.
Si certaines choses sont ameliorable ou s'il manque certains principes ou idées dans mon approche n'hesitez pas a repondre ou a m'envoyer un mp.
Merci d'avance

edit: je viens de voir ta reponse apres mon post, j'ai ecrit cela pour rien :'(
le_chainon_manquant est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 11h19.


 
 
 
 
Partenaires

Hébergement Web