Page 1 sur 1

débutant en POO Php besoin de vos aides

Posté : 08 oct. 2012, 19:27
par miiidooo19
Bonjour, voila je suis sur le point de passer au POO sur PHP, j'ai lu la doc, cours de site de zero... mais j'ai toujours du mal a comprendre comment ça marche :s

disent que je souhaite faire une petite application web qui permet d'enregistrer un client et une photo dans la bdd, donc j'aurai un petit formulaire avec 5 champs + un champ pour uploider la photo.

pour celà j'ai donc deux table :

client(id, nom, prenom, sexe, tel, adresse)
photo(id, legende, description, path, id_client)

si j'ai bien compris dans cette application j'aurai besoin de 3 objets :

1 sql (pour se connecter et déconnecté de la bdd)
2 client
et photo

c'est bien ça?

Re: débutant en POO Php besoin de vos aides

Posté : 09 oct. 2012, 14:53
par miiidooo19
me revoila, prenant un autre exemple :

deux table : joueurs et images_joueurs
-- Base de données: `poo`
--------------------------------------------------------
 Structure de la table `images_joueurs`

CREATE TABLE IF NOT EXISTS `images_joueurs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `id_joueur` int(3) NOT NULL,
  `path` varchar(100) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

-- --------------------------------------------------------
-- Structure de la table `joueurs`

CREATE TABLE IF NOT EXISTS `joueurs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `nom` varchar(50) NOT NULL,
  `prenom` varchar(50) NOT NULL,
  `nationalite` varchar(50) NOT NULL,
  `club` varchar(50) NOT NULL,
  `age` int(2) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
mon fichier index.php
$cnx = mysql_connect("localhost", "root", "");
	$db = mysql_select_db( "poo" );
	
	
	$nom = "";
	$prenom = "";
	$age = "";
	$nationalite = "";
	$club = "";

if (isset($_POST['envoyer']))
	{
		$erreur = "";
		$nom = $_POST['nom'];
		$prenom = $_POST['prenom'];
		$age = $_POST['age'];
		$nationalite = $_POST['nationalite'];
		$club = $_POST['club'];
		
		if ((isset($_FILES["photo"])) and ($_FILES["photo"]['name'] <> '') and ($_POST['nom'] != "") and ($_POST['prenom'] != ''))
		{ // on insert tous
		 // on commencer par les informations
		
			$extensions_ok = array('png', 'PNG', 'gif', 'GIF', 'jpg', 'JPG', 'jpeg', 'JPEG');
			$taille_max = 2097152;
			$dossier = 'images/';
			
			$taille= getimagesize($_FILES['photo']['tmp_name']);
			$largeur=$taille[0];
			$hauteur=$taille[1];
			
			$erreur = '';
			if( !in_array( substr(strrchr($_FILES["photo"]['name'], '.'), 1), $extensions_ok ) )
			{
				$erreur = "* Erreur dans dimensions, format ou la taille de l'image 1"; 				
			}
			elseif ( ($largeur > 728) or ($hauteur > 725) ) // les dimensions maximum
			{
				$erreur = $erreur ." <br />* Erreur dans dimensions, format ou la taille de l'image 2"; 
			}
			elseif( file_exists($_FILES["photo"]['tmp_name']) and filesize($_FILES["photo"]['tmp_name']) > $taille_max)
			{
				$erreur = $erreur ." <br />* Erreur dans dimensions, format ou la taille de l'image 3"; 
			}
			
			if ( $erreur == '' )
			{
				// exetension de l'image
				$extension = substr(strrchr($_FILES["photo"]['name'], '.'), 1);
				// nom de l'image = nom_prenom de joueur
				$joueur = $nom.' '.$prenom;
				$joueur=str_replace(' ','_',$joueur); // j'enleve les espace dans le nom de l'entreprise
				$nameImg = $joueur.".".$extension;
				// Uploader L'image
				
				
				
				
				
				
				if ($req =mysql_query('Insert into joueurs VALUES ("", "'.$nom.'", "'.$prenom.'", "'.$nationalite.'", "'.$club.'", "'.$age.'" )') or die (mysql_error())) 
				{
					
					$idJoueur = mysql_insert_id();
					$nameImg = $idJoueur.'_'.$joueur.".".$extension;
					$path = $dossier.$nameImg;
					if ($req2 = mysql_query('Insert into images_joueurs VALUES ("", "'.$idJoueur.'", "'.$path.'")') or die (mysql_error()))
					{
						
						move_uploaded_file($_FILES["photo"]['tmp_name'], $dossier . $nameImg); // Upoade la nouvelle image
						$nom = "";
						$prenom = "";
						$age = "";
						$nationalite = "";
						$club = "";
						$erreur = 'votre joueur est bien enregistre';
					}
					else
						$erreur = 'erreur de la 2eme requête';
				}
				else
					$erreur = 'erreur de la 1ere requête';
					
			
			}
			
				
		}	
		else
		{
			$erreur = 'le formulaire est incomplet';
		}
	}

		echo '<form action="#" method="post" enctype="multipart/form-data" />
		<input type="hidden" name="MAX_FILE_SIZE" value="2097152" />
		'.$erreur.' <br />
		<table>
			<tr>
				<td>Nom  </td><td><input type="text" value="'.$nom.'" name="nom" /></td>
			</tr>
			<tr>
				<td>prenom </td><td><input type="text" name="prenom" value="'.$prenom.'"/></td>
			</tr>
			<tr>
				<td>Age  </td><td><input type="text" value="'.$age.'" name="age" /></td>
			</tr>
			<tr>
				<td>Nationalité </td><td><input type="text" name="nationalite" value="'.$nationalite.'"/></td>
			</tr>
			<tr>
				<td>Club </td><td><input type="text" name="club" value="'.$club.'"/></td>
			</tr>
			<tr>
				<td>photo </td><td><input type="file" name="photo" /></td>
			</tr>
			<tr>
				<td><input type="submit" name="envoyer" value="Envoyer" /><td></td>
			</tr>
		</table>';
		
		echo '<br/><br/><a href="listeJoueur.php" >Voir la liste des joueurs</a>';
fichier listeJoueur.php
$cnx = mysql_connect("localhost", "root", "");
	$db = mysql_select_db( "poo" );
$query = mysql_query ('Select * FROM joueurs order by nom') or die (mysql_error());
	
	
	echo '<table><tr>';
	while ($res = mysql_fetch_object($query))
	{
		$query2 = mysql_query ('SELECT path from images_joueurs where id_joueur = '.$res->id.' ') or die (mysql_error());
		$res2 = mysql_fetch_object($query2);
		
		echo '<td> <center><img src="'.$res2->path.'" title="'.$res->nom.' '.$res->prenom.'" height="250px" width="200px" /><br />
				'.$res->nom.' '.$res->prenom.' <br />
				  Age : '.$res->age.' ans <br/>
				  Nationalité : '.$res->nationalite.' <br />
				  Club : '.$res->club.' </center></td>';
	}
	echo '</tr></table>';
n'oubliez pas de créer un dossier "images" dans la même racine que les deux fichiers pour le transfert des images

si vous essayer l'application ça marche bien maintenant je veux le transmettre a des objets POO

quels sont les classes a crée ? et quels sont les méthode a créer pour chaque une ? je demande pas de me créer les classes mais juste une idée sur ce qu'il faut faire

merci

Re: débutant en POO Php besoin de vos aides

Posté : 09 oct. 2012, 15:22
par moogli
salut,


as tu lu des cours sur la méthodologie objet ?

Lire les cours sur comment on "fait de l'objet" en php n'est pas suffisant.

tu peux regarder du coté des démarche UML pour la modélisation de l'application.

Dans ce que tu montre il y a déjà un problème : tu n'as de contrainte d'intégrité sur l'id_joueur => foreign key.
C'est déjà une chose à faire au niveau de la base de donnée.

Après, si tu veux un modèle objet complet va falloir parler de design pattern, savoir ce que tu a prévu etc etc;

faire des classes DAO c'est les classes d'accès au SGBD ok, mais il te faut aussi des classes "images" de la base de données (donc ici une classe joueur qui va contenir une collection de classe images).
donc la tu as au moins 3 classes.

ensuite il te faut surement un contrôleur pour gérer tous ça.
peux être quelque chose qui va gérer les vues ?

sur le principe tu devrais avoir un controleur qui fait appel à la DAO qui va te retourner des objets joueurs (qui vont contenir, au besoin, des objet images) ;)

@+

Re: débutant en POO Php besoin de vos aides

Posté : 10 oct. 2012, 09:55
par guitoup
Hello,

Pour ce qui est MVC je suis d'accord, mais il faut commencer à marcher avant de courir ! L'objet d'abord les pattern après ou l'inverse, mais tout d'un coup ça fait beaucoup.

Pour l'objet un petit exemple tout simple pour représenter un joueur (j'écris de tête y'aura surement des erreurs mais le gros est là).

class Player {

   // tu déclares tes attributs
   protected $_listImg = array();

  // tu peux alimenter des attributs directement avec le constructeur, ou pas
   public function __construct($listImg)  {
       $this->addImg($listImg);
   }
   
  // tu fais un setter pour tes attributs avec les traitements qui vont bien (cast, calcul, etc...)
  // Ici on suppose que tu as créer une classe Image
   public function addImg($listImg) {

       // si on a pas un tableau d'image on le transforme en tableau, c'est plus simple... je suis fainéant
        if (false === is_array($listImg)) {
             listImg = array($listImg);
        } 

        foreach($listImg as $img) {
             $this->_listImg[] = $img;
         }
   }

  // tu fais un getter pour récupérer tes attributs en dehors de ta classe
   public function listImg() {
      $this->_listImg;
  }
}


// Pour utiliser tes classes

// on créer une liste d'image
$images[] = new Image();
$images[] = new Image();
$images[] = new Image();

// et le joueur
$player = new Player($images);

// Ensuite pour faire simple dans un premier temps, tu peux imaginer de créer une fonction save dans une classe dédié à la BD.

Re: débutant en POO Php besoin de vos aides

Posté : 10 oct. 2012, 10:19
par moogli
hum
<?php
public function addImg($listImg) {
       // si on a pas un tableau d'image on le transforme en tableau, c'est plus simple... je suis fainéant
        if (false === is_array($listImg)) {
             listImg = array($listImg);
        } 
        foreach($listImg as $img) {
             $this->_listImg[] = $img;
         }
   }
?>
je suis fainéant
ben franchement y'a moyen de faire plus simple et plus "optimisé"

quel est l’intérêt de parcourir un tableau pour l'ajouter à un tableau ?
la fonction array_merge est faite pour cela

donc
<?php
public function addImg($listImg) {
       // si on a pas un tableau d'image on le transforme en tableau, c'est plus simple... je suis fainéant
        if (false === is_array($listImg)) {
            $this->_listImg[] = $listImg;
        } 
        else {
                $this->_listImg = array_merge($this->_listImg[] ,$listImg);
         }
   }
?>
c'est simple et plus rapide

Y'a une raison pour le protected ?

sur le principe ton player est une classe qui représente un objet (en java on dirais un pojo, Plain Old Java Object, mais en php un heu popo ça fait moyen :mrgreen: ).
Donc généralement pas d'intelligence on utilise de simple accesseur, donc on passe un tableau pour la liste des images. ceci dit c'est vrai que c'est plis simple ainsi.

On est d'accord sur un truc : d'abord des cours sur l'objet, les exemples de code après parce que la c'est un peu à la louche, les objets découle d'une modélisation à laquelle on ne peux échapper sauf si on souhaite finir sur un truc bancale :).

Donc un cours sur UML me semble être une bonne approche.
Ce n'est pas du temps perdu "l'esprit" objet est réutilisable dans tous les langages objets, mêmes coté code cela change un poil mais c'est secondaire ;)

@+

Re: débutant en POO Php besoin de vos aides

Posté : 10 oct. 2012, 10:30
par guitoup
Je suis aller au plus simple de tête :mrgreen: oui le array_merge c'est mieux
Pour le protected ? C'est un exemple donc non y'a pas vraiment de raison mise à part que je voulais pas qu'il soit public pour forcé à faire un getter.
Pour le UML c'est la 1ère approche à avoir, conceptualiser les différents objets pour les représenter, mais on va pas tout lui faire non plus ? Faut qu'il réfléchisse à comment l'implémenter, nous on donne un p'tit coup de pouce pour l'aiguiller.

Sinon on peut lui balancer pleins de trucs à la figure :
Design pattern (Service, Adapter, Observer...)
Test Unitaire, Mock, Intégration continue
les principes S.O.L.I.D

et tout un tas de choses, faut bien commencer quelque part !

Re: débutant en POO Php besoin de vos aides

Posté : 10 oct. 2012, 10:36
par guitoup
En me relisant, j'en conclu que :

miiidooo19 décrit d'abord tes objets et le fonctionnement que tu cherche et modélise le en UML par exemple.

On t'aidera plus proprement par la suite, en attendant, je botte en touche... :oops:

Re: débutant en POO Php besoin de vos aides

Posté : 10 oct. 2012, 23:12
par miiidooo19
:shock: je crois que ça va me prendre plus de temps pour comprendre de la POO :s dans l'exemple de la classe que vous m'avez donné ils sont ou les requête insert, select....?

moi j'ai pensé a un truc de ce genre

Re: débutant en POO Php besoin de vos aides

Posté : 11 oct. 2012, 09:53
par moogli
salut,

oui mais non :)

lorsque tu modélise ton application, tu va avoir toutes tes méthodes d'ajout modification ou suppression. Mais elle ne doivent pas être dans l'objet qui représente une entité.

tes classes player ou photo ne sont que dess "sacs" de données.

En clair aucune intelligence dans ces classes (ce sont les "pojo" en java et "popo" en php, pour Plain Old Php Object :mrgreen: ).

Effectivement ta modélisation peux te ressortir ces méthodes.
Mais c'est la qu'interviennent les patrons de conception (ou design pattern). L'un d'entre heu s'appel le pattern DAO (pour data access object). Ce sont les classes qui auront accès au SGBD (MySQL, Oracle etc etc).

Donc toutes les méthodes ajout modification suppression seront dans des objet DAO.
une méthode d'ajout de joueur sera, par exemple, newPlayer(player). le paramètre sera un objet "player" idem pour le reste.
Il y aura aussi des méthodes qui te fournissent la liste complète des joueurs, qui te retourne un joueur par sont indentifiant etc
Ces méthodes retourne un objet player ou une liste (tableau) d'objet player.
par exemple, pour la liste des player tu peux faire un select * from player et avec PDO, sur le retour tu query : $retour->fetchAll(PDO::FETCH_CLASS, 'player'); pour avoir un tableu d'objet player ;)

de même tu peux applique le pattern singleton (très classique) qui te permettra de n'avoir qu'une seule connexion au SGBD d'ouverte (bon la pour le coup si tu veux un vrai singleton, il faut par exemple étendre PDO pour passer le constructeur en private et n'utiliser que la classe étendue).

donc au final tu aura
- des classes type "pojo" player, photo etc
- des classes dites "dao" playerDao, photoDao etc
- une classe singleton pour leSGBD qui sera utiliser par les classes DAO.
- une classe "controleur" pour gérer le tout. Le controleur fait appel aux DAO en lui passant des pojo.

Je te conseil de passer du temps sur le concept, les design pattern, ce n'est pas forcément naturel (voir même l'inverse) et demande un certain habitude).

Le fait de découpler la DAO des "pojo" te permet :
- D'avoir des objet réutilisable. A l'affichage tu manipule des "player" (par exemple)
- Tu ne passe pas 3h a recherche une méthode dans un objet
- L'objet est réutilisable, tu peux reprendre playerDao dans d'autre script, voir même d'autre projet qui respect la même structure :)


@+

Re: débutant en POO Php besoin de vos aides

Posté : 11 oct. 2012, 10:08
par miiidooo19
ah ok :s et cette class du pattern DAO c'est moi qui va l'écrire ou il existe déjà ? et dans ce cas comment je peux m'en servir ?

supposent tt simplement je veux récupérer la liste de mes joueurs tu as dit : (par exemple, pour la liste des player tu peux faire un select * from player et avec PDO, sur le retour tu query : $retour->fetchAll(PDO::FETCH_CLASS, 'player'); pour avoir un tableu d'objet player )

le select je le met ou alors? :x

désolé j'ai un peu voir bcp même du mal a comprendre la POO

Re: débutant en POO Php besoin de vos aides

Posté : 11 oct. 2012, 10:54
par guitoup
Un petit exemple de ce qu'il est possible de faire pour découpler les différentes "responsabilités" des classes.
// Un service technique PDO
// dans cette classe tu auras la partie "branchement" technique avec la base, et uniquement cette partie
// on peut imaginer une fonction générique pour des requêtes, select, insert, etc.
namespace \Tech\Pdo;

class PdoService 
{
   public function getInstance() {}
   public function prepareQuery() {}
   public function update() {}
   public function listItem() {}
   public function totoTataQuiVaBien() {}
  //etc...
}

// Dans un second temps tu peux imaginer un service joueur
// dans cette classe tu aura tout ce qui a attrait au joueur et uniquement au joueur
namespace \Player;

class PlayerService
{
  protected $_adapter;

 // j'explique l'adapter plus bas, ici on imagine que par défaut ce sera \Tech\PdoService
  public function __construct($adapter) {
     $this->_adapter = $adapter;
  }

  // ici un exemple de  comment tu va utiliser ta classe pdo
  public function getPlayerById($id) {
     $this->getAdapter()->getPlayerById($id);

    public function getInstance() {}
 }

// Dans un troisième temps tu mets en place un Adapter, ce qui va faire le lien entre ton PlayerService et ton PdoService.
// Voit l'adapter comme un passe plat, qui ne fera que transmettre les demande de requêtes vers le PdoService.
// fonctionner de cette manière te permet d'avoir le moins possible de dépendance en tes objets. 
// Si par exemple tu travail en TDD tu peux facilement "transformer" ton adapter en Mock (un bouchon pour faire simple)

namespace \Player\Adapter;

class PlayerAdapter
{
 public function getPlayerById($id) {
    // ici je fais appel a une fonction générique getItem() de mon service PDO.
    // je lui passe en paramètre $id qui est la valeur sur laquelle je veux filtrer
    // 'table_player' pour lui dire dans quelle table executer la requête (il y a mieux que mettre en dur mais c'est pour l'exemple)
   // et le champs sur lequel je veux effectuer le filtre
    // je te conseil aussi fortement de bien nommer tes fonctions de manière générique
   // par exemple getItem() ne retournera que 1 seul résultat, pour liste une collection tu peux imaginer une fonction listItem() etc.
    return \Tech\Pdo\PdoService()::getInstance()->getItem($id, 'table_player', 'id');
 }

// concrètement dans ton contrôleur tu auras quelque chose comme ceci
$player = \Player()::getInstance()-> getPlayerById($id);
}
Pour ce qui est gestion des adapter, singleton, tu peux passer par une classe mère qui te permettra de gérer tout ça de manière automatique.
Je ne sais pas si je suis clair, j’essaie le plus complet possible, que quelqu'un n'hésite pas à compléter ou corriger, dans cet exemple tu as entre autre comme pattern /autres que je te conseil de bien potasser ça sera un bon début en plus de UML :
- Service
- Adapter
- Singleton
- Interface
- Test unitaire
- Mock

Edit : point très important dans cette archi, tout le code métier dois se trouver dans les Services, les adapter ne sont QUE des passe plat, ils ne doivent servir que de transmetteur, il ne doit y avoir AUCUNE logique. Normalement dans un Adapter tu as une ligne par fonction qui fait un appel à un Service externe.

Re: débutant en POO Php besoin de vos aides

Posté : 11 oct. 2012, 11:27
par guitoup
J'ai oublié de te montrer un exemple pour utiliser un Mock.
Un mock c'est un objet qui va simuler un comportement, ceci te permettant de faire des tests unitaires, vraiment unitaire, en contrôlant l'environnement qui englobe ta fonction au maximum. Un test qui test une fonction qui tape dans une base de données n'est PAS unitaire, c'est un test "fonctionnel" mais pas unitaire. L'unité est bien la fonction et uniquement la fonction, d'ou l'importance de pouvoir simuler des fonctionnement de base de données, de système de fichier, de webservice, etc.
namespace \Player\Mock;

class Mock {
 // ici on va moquer la fonction getPlayerById, on suppose pour notre exemple qu'elle renvoi un tableau array(id, name)
 public function getPlayerById($id) {
   return arrya('id' => 1, name => 'guitoup');
} 

// et c'est tout ! en gros tu mets tes infos en dur... point.
// l'exemple n'est pas très parlant car la fonction n'a que peu de code "métier".

// Côté test unitaire tu auras quelque chose comme ceci :
class ServiceTest extends PHPUnit_Framework_TestCase
{
  // tu créer ton player comme d'habitude, à la différence que tu lui passe l'adapter que tu veux ! dans le post précédent on avait supposer que par défaut on 
 // prenais \Player, cette fois on utilise \Player\Mock

 $player = \Player()::getInstance(new \Player\Mock)-> getPlayerById($id);
 $this->assertEquals($player['id'], 1);
 $this->assertEquals($player['name'], 'guitoup');
}
Voili voilou

Re: débutant en POO Php besoin de vos aides

Posté : 11 oct. 2012, 11:59
par Mazarini
Est ce que vous avez des liens vers des design pattern pas trop théorique et fumeux ? En francais ?

J'aimerai essayer de rattacher mes habitudes très pratique à des choses un peu plus théorique. J'ai appris l'objet en utilisant un cadre mis en place par un collègue à priori compétant et je voudrais un peu recadrer mes habitudes qui me semblent correspondre à ce qui est décrit dans ce post.

Re: débutant en POO Php besoin de vos aides

Posté : 11 oct. 2012, 15:10
par guitoup
Tout ceci n'est ni théorique ni fumeux ;)
Ce sont des bonnes pratiques développement quelque soit la technologie, j'essai de te trouver des liens en français.
tu trouveras beaucoup plus facilement de la doc en anglais...

Les exemples ne sont pas forcément en PHP, mais les principes sont les même et tu les retrouveras dans quasiment tous les langages objet
Le plus important étant la logique et non pas la syntaxe (à mon avis)

Quelques sources diverses trouvées rapidement sur google :


Sur les principes S.O.L.I.D http://philippe.developpez.com/articles/SOLIDdotNet/

Adapter
http://badger.developpez.com/tutoriels/ ... daptateur/
http://blog.phppro.fr/?post/2008/10/20/ ... -l-exemple
Une section adapter en java : http://abrillant.developpez.com/tutorie ... roduction/
En php mais en anglais http://www.fluffycat.com/PHP-Design-Patterns/Adapter/

Mocks :
http://www.phpunit.de/manual/3.0/en/mock-objects.html
http://www.clochix.net/post/2009/09/27/ ... ec-PHPUnit

Les singletons en php 5.3 :
http://blog.mageekbox.net/?post/2010/10 ... en-PHP-5.3

Interface
http://alain-sahli.developpez.com/tutor ... nterfaces/

Edit : ne vous fiez jamais à une seule source ! lisez en plusieurs !