Afficher la liste des personnages : Apprentissage POO

Eléphant du PHP | 386 Messages

06 oct. 2014, 16:55

Bonjour,

Je suis en plein cours sur http://fr.openclassrooms.com/informatiq ... s-stockees
Et je n'arrive pas à afficher la liste de tous les personnages.
L'insertion d'un personnage ne se fait pas non plus.

Étant débutant, des explications (pour apprentis) seraient bien :wink:
Merci pour votre aide

index.php :
<?php
function chargerClasse($classe)
{
	require $classe . '.class.php'; // On inclut la classe correspondante au paramètre passé.
}

spl_autoload_register('chargerClasse'); // On enregistre la fonction en autoload pour qu'elle soit appelée dès qu'on instanciera une classe non déclarée.
?>
<!DOCTYPE html>
<html>
<head>
	<meta name="robots" content="noindex,nofollow" />
</head>
<body>
	<?php
		$perso = new Personnage(array(
		  'nom' => 'Victor',
		  'forcePerso' => 5,
		  'degats' => 0,
		  'niveau' => 1,
		  'experience' => 0
		));
		    
		$db = new PDO('mysql:host=***;dbname=***', '***', '***');
		$manager = new PersonnagesManager($db);
		$manager->add($perso);

		echo $manager->getList(); //Affiche la liste des personnages
	?>
</body>
</html>
Personnage.class.php :
<?php
require_once('PersonnagesManager.class.php');

class Personnage
{
	private $_id;
	private $_nom;
	private $_forcePerso;
	private $_degats;
	private $_niveau;
	private $_experience;

	public function hydrate(array $donnees)
	{
		foreach ($donnees as $key => $value)
		{
			$method = 'set'.ucfirst($key);

			if(method_exists($this, $method))
			{
				$this->$method($value);
			}
		}
	}

	public function id() { return $this->id; }
	public function nom() {	return $this->nom; }
	public function forcePerso() { return $this->forcePerso; }
	public function degats() { return $this->degats; }
	public function niveau() { return $this->niveau; }
	public function experience() { return $this->experience; }

	public function setId($id)
	{
		$id = (int) $id;
		if($id > 0)
		{
			$this->_id = $id;
		}
	}
	public function setNom($nom)
	{
		if(is_string($nom))
		{
			$this->_nom = $nom;
		}
	}
	public function setForcePerso($forcePerso)
	{
		$forcePerso = (int) $forcePerso;
		if($forcePerso >= 1 && $forcePerso <= 100)
		{
			$this->_forcePerso = $forcePerso;
		}
	}
	public function setDegats($degats)
	{
		$degats = (int) $degats;
		if($degats >= 0 && $degats <= 100)
		{
			$this->_degats = $degats;
		}
	}
	public function setNiveau($niveau)
	{
		$niveau = (int) $niveau;
		if($niveau >= 1 && $niveau <= 100)
		{
			$this->_niveau = $niveau;
		}
	}
	public function setExperience($exp)
	{
		$exp = (int) $exp;
		if($exp >= 1 && $exp <= 100)
		{
			$this->_experience = $exp;
		}
	}
}
PersonnagesManager.class.php :
<?php
require_once('Personnage.class.php');

class PersonnagesManager
{
	private $_db;

	public function __construct($db)
	{
		$this->setDb($db);
	}

	public function add(Personnage $perso)
	{
		$req = $this->_db->prepare('INSERT INTO personnages SET nom = :nom, forcePerso = :forcePerso, degats = :degats, niveau = :niveau, experience = :experience');

		$req->bindValue(':nom', $perso->nom());
		$req->bindValue(':forcePerso', $perso->forcePerso(), PDO::PARAM_INT);
		$req->bindValue(':degats', $perso->degats(), PDO::PARAM_INT);
		$req->bindValue(':niveau', $perso->niveau(), PDO::PARAM_INT);
		$req->bindValue(':experience', $perso->experience(), PDO::PARAM_INT);

		$req->execute();
	}

	public function delete(Personnage $perso)
	{
		$this->_db->exec('DELETE FROM personnages WHERE id = '.$perso->id());
	}

	public function get($id)
	{
		$id = (int) $id;
		$req = $this->_db->query('SELECT id, nom, forcePerso, degats, niveau, experience FROM personnages WHERE id = '.$id);
		$donnees = $req->fetch(PDO::FETCH_ASSOC);

		return new Personnage($donnees);
	}

	public function getList()
	{
		$persos = array();
		$req = $this->_db->query('SELECT id, nom, forcePerso, degats, niveau, experience FROM personnages ORDER BY nom');

		while ($donnees = $req->fetch(PDO::FETCH_ASSOC))
		{
			$persos[] = new Personnage($donnees);
		}

		return $persos;
	}

	public function update(Personnage $perso)
	{
		$req = $this->_db->prepare('UPDATE personnages SET forcePerso = :forcePerso, degats = :degats, niveau = :niveau, experience = :experience WHERE id = :id');

		$req->bindValue(':forcePerso', $perso->forcePerso(), PDO::PARAM_INT);
		$req->bindValue(':degats', $perso->degats(), PDO::PARAM_INT);
		$req->bindValue(':niveau', $perso->niveau(), PDO::PARAM_INT);
		$req->bindValue(':experience', $perso->experience(), PDO::PARAM_INT);
		$req->bindValue(':id', $perso->id(), PDO::PARAM_INT);

		$req->execute();
	}

	public function setDb(PDO $db)
	{
		$this->_db = $db;
	}
}

Eléphant du PHP | 151 Messages

07 oct. 2014, 09:42

Il semblerait que $manager->getList(); retourne un tableau.
Fais plutôt un var_dump pour t'en assurer.
Développeur d'applications pour intranets industriels (IHM), DBA Oracle, auto entrepreneur. Je fuis les frameworks car je pense comme Rasmus Lerdorf : "all PHP frameworks suck"...
Je me suis lancé dans la reprise du projet PhpMyNewsletter (GNU GPL), que je vous invite à essayer.

echo ($user=='enregistré?"je t'aide":"je t'aide pas !");

Eléphant du PHP | 386 Messages

09 oct. 2014, 02:43

Le var_dump renvois bien les 3 résultats de ma base de données.
Mais comment on fait pour afficher la liste du tableau ?

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

09 oct. 2014, 15:43

<?php

foreach($manager->getList() as $user) {
echo $user->getNom(),'<br />'; // etc .
}
pour le reste, il faut que je regarde plus attentivement.
je peux déjà te dire qu'il y a mieux que d'utiliser une boucle sur le jeux de résultat dans getList
PDOStatement::fetchAll + flag PDO::FETCH_CLASS (voir exemple 4).?
c'est fait en natif et en une ligne :)


@+
Il en faut peu pour être heureux ......

Eléphant du PHP | 386 Messages

09 oct. 2014, 20:08

Je sais qu'il y a peut être mieux, mais c'est pour le cours :wink:
Ça affiche que 3 balises BR
Et rien d'autre, donc y'a déjà un début, ça m'affiche bien 3 entrées, mais pas de nom qui s'affiche

J'ai fais un var_dump, et ça affiche NULL NULL NULL

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

11 oct. 2014, 01:09

salut,

je risque d'être direct / cru désolé :

Il est impératif de coder avec l'error_reporting à E_ALL.
cela t'aurais permis d'avancer, car le code de ce tuto est un torchon :/

en clair
private $_id;

suivis de
public function id()
{
return $this->id;
}

=> Notice id n'existe pas, he oui c'est _id ....

=> en passant respect de la moitié des standards des setter (setNom) mais pas de getter (nom() plutot que getNom().
une classe comme personnages ne doit pas contenir de logique métier or la vérification d'une valeur c'est de la logique métier (vérifier si c'est un entier ou pas ok mais pas s'il est entre 4 et 100 ^^).

ce problème est la source du fait que n'as pas de valeur dans tes objets.

utilisons donc la version suivante dans le code => ah ba non y a plus de constructeur la classe "manager ne peux plus fonctionner".
il parle d'une méthode "hydrate" cette méthode n'est pas codée, et pis bon c'est pas trop complexe d'utiliser 6 setter.

Donc le code peux ce résumer à cela :
Personnages
<?php

namespace moogli\test;


class Personnages {
    private $id;
    private $nom;
    private $forcePerso;
    private $degats;
    private $niveau;
    private $experience;

    function __construct() {
    }

    /**
     * @return mixed
     */
    public function getDegats() {
        return $this->degats;
    }

    /**
     * @param mixed $degats
     */
    public function setDegats($degats) {
        $this->degats = $degats;
    }

    /**
     * @return mixed
     */
    public function getExperience() {
        return $this->experience;
    }

    /**
     * @param mixed $experience
     */
    public function setExperience($experience) {
        $this->experience = $experience;
    }

    /**
     * @return mixed
     */
    public function getForcePerso() {
        return $this->forcePerso;
    }

    /**
     * @param mixed $forcePerso
     */
    public function setForcePerso($forcePerso) {
        $this->forcePerso = $forcePerso;
    }

    /**
     * @return mixed
     */
    public function getId() {
        return $this->id;
    }

    /**
     * @param mixed $id
     */
    public function setId($id) {
        $this->id = $id;
    }

    /**
     * @return mixed
     */
    public function getNiveau() {
        return $this->niveau;
    }

    /**
     * @param mixed $niveau
     */
    public function setNiveau($niveau) {
        $this->niveau = $niveau;
    }

    /**
     * @return mixed
     */
    public function getNom() {
        return $this->nom;
    }

    /**
     * @param mixed $nom
     */
    public function setNom($nom) {
        $this->nom = $nom;
    }



} 
La DAO (ce qu'il appel le manager)
<?php

namespace moogli\test;

include_once 'Personnages.php';

class PersonnageDAO {
    /**
     * Connexion SGDB
     * @var \PDO
     */
    private $db;

    function __construct(\PDO $db) {
        $this->db = $db;
    }

    /**
     * Ajoute un personnage
     * @param Personnages $perso
     */
    public function add(Personnages $perso) {
        $req = $this->db->prepare('INSERT INTO personnages SET nom = :nom, forcePerso = :forcePerso, degats = :degats, niveau = :niveau, experience = :experience');

        $req->bindValue(':nom', $perso->getNom());
        $req->bindValue(':forcePerso', $perso->getForcePerso(), \PDO::PARAM_INT);
        $req->bindValue(':degats', $perso->getDegats(), \PDO::PARAM_INT);
        $req->bindValue(':niveau', $perso->getNiveau(), \PDO::PARAM_INT);
        $req->bindValue(':experience', $perso->getExperience(), \PDO::PARAM_INT);

        $req->execute();

        $perso->setId($this->db->lastInsertId());
    }

    /**
     * supprime un personnage
     * @param Personnages $perso
     */
    public function delete(Personnages $perso) {
        $this->db->exec('DELETE FROM personnages WHERE id = ' . $perso->getId());
    }

    /**
     * retourne un personnage a partir de son id
     * @param $id
     * @return mixed
     */
    public function get($id) {
        $req = $this->db->query('SELECT id, nom, forcePerso, degats, niveau, experience FROM personnages WHERE id = ' . $this->db->quote($id, \PDO::PARAM_INT));
        $donnees = $req->fetchAll(\PDO::FETCH_CLASS, '\moogli\test\Personnages')[0];
        $req->closeCursor();
        return $donnees;
    }

    /**
     * Liste des personnages
     * @return array
     */
    public function getList() {
        $req = $this->db->query('SELECT id, nom, forcePerso, degats, niveau, experience FROM personnages ORDER BY nom');

        $persos = $req->fetchAll(\PDO::FETCH_CLASS, '\moogli\test\Personnages');
        $req->closeCursor();
        return $persos;
    }

    /**
     * Mise à jour d'un personnage
     * @param Personnages $perso
     */
    public function update(Personnages $perso) {
        $req = $this->db->prepare('UPDATE personnages SET forcePerso = :forcePerso, degats = :degats, niveau = :niveau, experience = :experience WHERE id = :id');

        $req->bindValue(':forcePerso', $perso->getForcePerso(), \PDO::PARAM_INT);
        $req->bindValue(':degats', $perso->getDegats(), \PDO::PARAM_INT);
        $req->bindValue(':niveau', $perso->getNiveau(), \PDO::PARAM_INT);
        $req->bindValue(':experience', $perso->getExperience(), \PDO::PARAM_INT);
        $req->bindValue(':id', $perso->getId(), \PDO::PARAM_INT);

        $req->execute();
    }
} 
un code de test simple
<?php
include 'Personnages.php';
include 'PersonnageDAO.php';

$db = new PDO('mysql:host=localhost;dbname=test;port=3307', 'phpjunglev2', 'phpjunglev2');
$manager = new \moogli\test\PersonnageDAO($db);
$perso = new \moogli\test\Personnages();
$perso->setNom('Test');
$perso->setForcePerso(5);
$perso->setDegats(666);
$perso->setNiveau(1000);
$perso->setExperience(100);
$manager->add($perso);

$perso-> setForcePerso(400);
$manager->update($perso);

$manager->delete($perso);
echo '<table><thead><tr>
<th>id</th>
<th>nom</th>
<th>forcePerso</th>
<th>dégâts</th>
<th>niveau</th>
<th>XP</th>
</tr></thead><tbody>';
$x = $manager->getList();
var_dump($x);
foreach ($manager->getList() as $p) {
    echo '<tr>';
    echo '<td>', $p->getId(), '</td>';
    echo '<td>', $p->getNom(), '</td>';
    echo '<td>', $p->getForcePerso(), '</td>';
    echo '<td>', $p->getDegats(), '</td>';
    echo '<td>', $p->getNiveau(), '</td>';
    echo '<td>', $p->getExperience(), '</td>';
    echo '</tr>';
}
echo '</tbody></table>';

$y= $manager->get(3);
var_dump($y);
pour bien voir ce qui ce passe utilise un IDe avec un point de débug ligne 15 et 18 pour te laisser le temps de voir ce qui ce passe dans la base (un select sur la table pour voir ce qui change).

Attention code pour php 5+

il est important de comprendre ce que l'on copie du net (même pour test) et pour t'y aider la bonne configuration de php est obligatoire :
- Error_reporting = E_ALL
- display_error = on
- extension xdebug utilisable et correctement configurée

utilise aussi un IDE correct (ou s'insiste) Eclipse, netbeans et plein d'autre sont très bien et te permette de debugguer ton code en temps réelle (suivre l'évolution dans le code, voir la valeur des variables à un instant T etc. ).
c'est un outils inspensable qui facilite tellement la vie que l'on fini par ne plus s'en passer ;)


désolé pour la réponse tardive.

@+
Il en faut peu pour être heureux ......

Eléphant du PHP | 386 Messages

11 oct. 2014, 19:47

Tu devrais faire des cours :mrgreen: lol.
Je comprend mieux comment faire pour la suite, mais si tu me dit que ce cours est pourris...
Tu connais des bons cours ou tutoriels sur la POO, pour la comprendre de A à Z ?

Merci d'avance :wink:
Même si maintenant je connais une petite partie de la POO : Je suis rendu à l'opérateur de résolution de portée, j'en suis encore loin de pouvoir faire un espace membre en POO

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

12 oct. 2014, 13:45

Pour ce qui est du tuto le fond est la bien que je ne sois d'accord avec la forme et que je trouve dommage, d'autant plus sur ce site, de fournir des exemple pourris sachant que de toute façon les gens tests le code que l'on fournit.

Ce qu'il te faut pour comprend l'objet c'est un cours sur la modélisation objet d'une application et cela indépendamment du langage. Car la philosophie objet est implémentée de façon différente suivant les langages mais au final le principe est la et une fois que tu le connais tu transpose sur le langage ;) (sachant que php n'est pas forcément le mieux pour cela, un langage fortement typé est plus conseillé pour bien comprendre).

la résolution de portée c'est "relativement simple".

la base c'est la même chose que pour une fonction. Ce qui est déclaré dans une méthode / fonction n'est accessible que dans la méthode.
<?php
class test {

function mamethode(){
$mavariable = 'xxx'; // n'est utilisable que dans la méthode mamethode
}

function autremethode()'
echo $mavariable; // oups erreur la variable n'existe pas
}
}
ensuite il y a les propriétés d'une classe (tu entendras aussi parler de variable membre ou variables de classe.
c'est les variables que tu définis en dehors d'une méthode, par convention en début de la déclaration de la classe.
<?php
class test {
    $var_1; 
}
Sur un objet les méthodes et propriétés on une porté. Elle est indiquée par les mots clefs private, protected et public.
Chaque mot clef te permet d'indiquer comment le reste du monde va pouvoir utiliser la propriété ou méthode :
- private : il n'y a que la classe elle même qui peux utiliser la propriété ou méthode (attention les mots sont tous important ;) ).
- protected : souvent appelé "visibilité package". en clair l'objet ou les objets du même package (ou espace de nom en php mais c'ets la même chose) peuvent utiliser la propriété ou méthode. Attention subtilité il est possible d'utiliser une propriété ou méthode d'une objet parent qui est "protected" alors que ce n'est pas le cas si la propriété ou méthode est private (d'où mon aparté pour le private).
- public : bon ben la c'est open bar tous le monde peu accéder (lire / modifier) à la propriété ou méthode.

bon la tu va me ok c'est bien jolie tous ça mais c’est quoi l'opérateur de résolution de porté ?
c'est une notion propre à php et marqué par le symbole ::
la base c'est la doc de php ;) => http://fr2.php.net/manual/fr/language.o ... otayim.php
et comme elle dit pas trop de connerie :
L'opérateur de résolution de portée (aussi appelé Paamayim Nekudotayim) ou, en termes plus simples, le symbole "double deux-points" (::), fournit un moyen d'accéder aux membres static ou constant, ainsi qu'aux propriétés ou méthodes surchargées d'une classe.
Donc tu va l'utiliser quand tu va voir besoin d'accéder à une propriété / méthode d'un objet parent ou que tu aura déclaré comme statique (static) ou constante (const).
avec l'exemple de la doc
<?php
class MyClass {
    const CONST_VALUE = 'Une valeur constante';
}

// utilisation
echo MyClass::CONST_VALUE;
Après il est possible de mixer tous cela et déclarée des propriétés statique / contatante privée ou protégé et la c'est le drame ;)

et comme un exemple c'est mieux que les mots :
<?php

class MyClass {
    const CONST_VALUE = 'Une valeur constante';
    static $staticValue = 'valeur statique';
    private static $staticPrivate = 'valeur statique privée';
    protected  static $staticProtected = 'valeur statique protégée';

    private $private = 'une propriété privée';

    /**
     * @return string
     */
    public function getPrivate() {
        return $this->private;
    }
}

echo MyClass::$staticValue . PHP_EOL;
echo MyClass::CONST_VALUE . PHP_EOL;
echo '-------------------------------------' . PHP_EOL;

class OtherClass extends MyClass {
    public static $my_static = 'variable statique';

    public static function mamethode() {
        echo parent::CONST_VALUE . PHP_EOL;
        echo parent::$staticValue . PHP_EOL;
        echo parent::$staticProtected . PHP_EOL;
        echo self::$my_static . PHP_EOL;

//        echo parent::$staticPrivate . PHP_EOL; // erreur la méthode est privée
//        echo parent::$private; // idem
//        echo $this->getPrivate();// erreur la méthode n'est pas déclarée statique !
//        echo parent::getPrivate().PHP_EOL; // idem

    }

    public function methode(){
        echo $this->getPrivate();// erreur la méthode est déclarée statique !
    }
}

OtherClass::mamethode();
//OtherClass::$staticProtected(); // erreur $staticProtected est "protected" donc nom accessible de l'extérieur
$x = new OtherClass();
echo '-------------------------------------' . PHP_EOL;
$x->methode();
résultat

Code : Tout sélectionner

valeur statique Une valeur constante ------------------------------------- Une valeur constante valeur statique valeur statique protégée variable statique ------------------------------------- une propriété privée
Voilà tu sais tout ou presque ;)

quand a faire des tutos, l'expérience m'a prouvé que je ne suis pas trop fait pour cela (cf mon site ^^). Même si l'idée m'a déjà traversée l'esprit.
Et pi bon les autres ont déjà tout fait :mrgreen:

coté littérature j'ai trouvé ceci qui peux t'aider http://georges.gardarin.free.fr/Livre_B ... -Objet.pdf.
bon par contre c'est bien généraliste et donc pas trop de code et comme toujours dans ces cas barbant, mais il y a plus d'infos que je ne peux t'en donner ;)

La prochaine fois, héritage et interface,ou comment pousser un peu sont modèle ;)


bon courage.

@+
Il en faut peu pour être heureux ......

Eléphant du PHP | 386 Messages

12 oct. 2014, 16:57

Merci pour ton "petit tuto" ^^
Et pour l'héritage c'est avec "extends", lié une classe fille à une classe mère pour un système de rang d'administrateurs par exemple.
J'ai lu un peu la dessus.

Je cherche à pratiquer, donc je vais commencer à faire mon espace membre, avec tout ce que j'ai appris et retenus.
Je vais commencer par la classe de connexion des membres, ça sera déjà bien :wink:

En parallèle sur phpFrance, parce que je pense pas réussir du premier coup ^^
J'ai organisé mes fichiers en MVC, donc dans le fichier :

- ../modele/login : Il y aura la fonction dont le rôle sera de récupérer le membre qui se connecte, ses données dans une classe login
- ../vue/login : Pour la connexion il n'y a pas d'affichage à faire, juste une redirection qui se fera dans le modele
- ../controleur/login : Pareil pour le controleur

C'est bien ça ?

EDIT : Ou plutôt une classe "members" qui s'occupe d'ajouter un membre, de supprimer, de modifier les infos etc... ?
Mais où la placer dans l'architecture MVC ?

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

12 oct. 2014, 20:14

Même avec les espaces de noms c'est une mauvaise idée d'avoir le mêle nom ;)
Par exemple loginView, loginControler etc.
Oui une classe Membre et cette classe contient juste les infos du membre rien d'autre.

Le modèle va faire les ajouts, suppression, mise a jour, ou sélection (sa colle sur l'acronyme SCRUD).

Attention le modèle ne fait pas d'affichage.
Le contrôleur va utiliser le modèle pour l'accès à la base et va fournir l'info (objet membre, erreur etc.) à la vue.
Mais la vue n'accède que rarement au modèle (ou DAO ).

@+
Il en faut peu pour être heureux ......

Eléphant du PHP | 386 Messages

12 oct. 2014, 20:27

Donc je fais des getters et setters dans la classe membre, je place le fichier Membre.class.php dans le dossier "class", dossier situé à la racine de mon site.
Ensuite à la racine de mon site, je fais 3 autres dossiers, par ex :

- model
- vue
- controleur

Et dans chaque dossier, je fais des sous-dossiers de "modules" pour mon espace membre (news, commentaires, amis etc...)
La vue affiche uniquement avec des boucles ou directement un champ précis par ex :

Member::name();

Mais ce que je veux savoir, c'est si je dois faire une autre classe MembreControl et MembreVue et MembreModel, en plus de la classe Membre ?
Ça fais beaucoup de classe pour un module ?

"Ce que j'appelle module, c'est les différentes parties de mon site réparties dans des classes."