Partage
  • Partager sur Facebook
  • Partager sur Twitter

delete() POO class PersonnageManager

    20 novembre 2019 à 4:55:28

    Bonjour, 
    Je travaille sur le cours Manipulation de données stockées (PHP en POO) : https://openclassrooms.com/fr/courses/1665806-programmez-en-oriente-objet-en-php/1666289-manipulation-de-donnees-stockees
    J'ai mes trois fichiers : class Personnage, class PersonnagesManager, index.
    J'ai ajouté des personnages, cela fonctionne. Même s'il me reste à comprendre pourquoi je peux les ajouter plusieurs fois si je rafraichie la page... 
    Par contre, si j'essaie d'effacer un personnage, je reçois une jolie erreur "Warning: PDO::exec(): SQLSTATE[42000]: Syntax error or access violation: 1064 Erreur de syntaxe près de '' à la ligne 1 in C:\wamp64\www\revisions_oops\envoi\PersonnagesManager.php on line 40"
    Pourtant, je ne vois pas d'erreur dans ma fonction delete... Je ne comrpends pas ce qui cloche.
    Est-ce que quelqu'un pourrait me dire où est mon erreur car je n'en vois aucune... donc je ne comprends pas du tout comment la régler.  
    index.php :
    <?php 
    
    // Auto chargement des classes
    spl_autoload_register(function($class)
    	{
    		require_once($class. '.php');
    	}
    );
    
    $perso = new Personnage([
      'nom' => 'Victor',
      'forcePerso' => 5,
      'degats' => 0,
      'niveau' => 1,
      'experience' => 1
    ]);
        
    //connection à la base
    
        try
        {
            $db = new PDO('mysql:host=localhost;dbname=cours_oops;charset=utf8', 'root', '');
            $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
        }
        catch (Exception $e)
        {
                die('Erreur : ' . $e->getMessage());
        }
    
    
    $manager = new PersonnagesManager($db);
        
    $manager->add($perso);
    
    
    
    $superman = new Personnage([
      'nom' => 'Superman',
      'forcePerso' => 5,
      'degats' => 0,
      'niveau' => 1,
      'experience' => 1
    ]);
    
    $manager->add($superman);
    
    
    $flash = new Personnage([
    'nom' => 'Flash',
    'forcePerso'=>6,
    'degats' => 3,
    'niveau' => 7,
    'experience' => 96
    ]);
    
    $manager->add($flash);
    
    
    $manager->delete($superman);
    ?>
     

    PersonnagesManager: 
    <?php
    
    class PersonnagesManager
    {
      //Création de l'attribut db pour la connection à la database
      private $_db; 
    
      // Le constructeur appelle setDb à la création d'un objet 
      public function __construct($db)
      {
        $this->setDb($db);
      }
    
      public function setDb(PDO $db)
      {
        $this->_db = $db;
      }
    
      // getter d'id
      public function id()
      {
        return $this->_id;
      }
    
      public function add(Personnage $perso) 
      {    
        $q = $this->_db->prepare('INSERT INTO personnages(nom, forcePerso, degats, niveau, experience) VALUES(:nom, :forcePerso, :degats, :niveau, :experience)');
        $q->bindValue(':nom', $perso->nom());
        $q->bindValue(':forcePerso', $perso->forcePerso(), PDO::PARAM_INT);
        $q->bindValue(':degats', $perso->degats(), PDO::PARAM_INT);
        $q->bindValue(':niveau', $perso->niveau(), PDO::PARAM_INT);
        $q->bindValue(':experience', $perso->experience(), PDO::PARAM_INT);
        $q->execute();
      }
    
    
      public function delete(Personnage $perso) 
      {
        
         $this->_db->exec('DELETE FROM personnages WHERE id = '.$perso->id());
      }
    
    
      public function get($id) 
      {
        $id = (int) $id;
    
        $q = $this->_db->query('SELECT id, nom, forcePerso, degats, niveau, experience FROM personnages WHERE id = '.$id);
        $donnees = $q->fetch(PDO::FETCH_ASSOC);
    
        return new Personnage($donnees);
      }
    
    
      public function getList() 
      {
        // Retourne la liste de tous les personnages.
        $persos = [];
    
        $q = $this->_db->query('SELECT id, nom, forcePerso, degats, niveau, experience FROM personnages ORDER BY nom');
    
        while ($donnees = $q->fetch(PDO::FETCH_ASSOC))
        {
          $persos[] = new Personnage($donnees);
        }
    
        return $persos;
      }
    
      public function update(Personnage $perso) 
      {
        $q = $this->_db->prepare('UPDATE personnages SET forcePerso = :forcePerso, degats = :degats, niveau = :niveau, experience = :experience WHERE id = :id');
        $q->bindValue(':forcePerso', $perso->forcePerso(), PDO::PARAM_INT);
        $q->bindValue(':degats', $perso->degats(), PDO::PARAM_INT);
        $q->bindValue(':niveau', $perso->niveau(), PDO::PARAM_INT);
        $q->bindValue(':experience', $perso->experience(), PDO::PARAM_INT);
        $q->bindValue(':id', $perso->id(), PDO::PARAM_INT);
        $q->execute();
      }
    }
    
    ?>
     
    Personnages :
    <?php
    
    class Personnage
    {
    	private $_id;
    	private $_nom;
    	private $_forcePerso;
    	private $_degats;
    	private $_niveau;
    	private $_experience;
    
    
    	public function __construct(array $donnees)
    	{
       		$this->hydrate($donnees);
    	}
    
    	public function hydrate(array $donnees)
    	{
    		// on doit récupérer tous les setters sans préciser lesquels et combien il y en a donc on fait une boucle foreach()
      		foreach ($donnees as $key => $value)
      		{
        	// On récupère le nom du setter correspondant à l'attribut.
      			// on récupère dans une variable $method (car on récupère une methode setSomething())
      			// les setters sont setForce par exemple, ici $key correspond à force et ucfirst vise à mettre la première lettre suivant le set en majuscule comme setForce
        		$method = 'set'.ucfirst($key);
            
        		// Si le setter correspondant existe.
        		// method_exists(nom de l'objet, nom de la methode)
        			if (method_exists($this, $method))
        			{
        			  // On appelle le setter.
        				// l'objet appelle alors la methode avec pour paramètres les valeurs
          				$this->$method($value);
      				}
      		}
    	}
    
    
    	// GETTERS
    	public function id()
    	{
    		//attention ici : ne pas oublier l'underscore
    		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;
    	}
    
    	// SETTERS
    
    	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)
    	{
    		// Attention : pour vérifier que l'id est un nombre entier, il faut d'abord demander à ce que ce soit un nombre puis mettre une condition pour dire que le nombre doit être supérieur à 0
    		$forcePerso= (int) $forcePerso;
    
    		if($forcePerso >= 0 && $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($experience)
    	{
    		$experience= (int) $experience;
    
    		if($experience >= 1 && $experience <=100)
    		{
    			$this->_experience=$experience;
    		}
    	}
    }
    
    ?>
    Merci beaucoup.

    -
    Edité par laure79 20 novembre 2019 à 4:56:27

    • Partager sur Facebook
    • Partager sur Twitter
      20 novembre 2019 à 8:13:10

      slt,

      si tu attend une reponse revois la mise en page de ton post, sinon tu vas pouvoir attendre longtemps

      • Partager sur Facebook
      • Partager sur Twitter
        20 novembre 2019 à 8:23:43

        Bonjour,

        en effet revois la mise en forme, c'est tout simplement horrible a lire.

        Ensuite, tu peux ajouter une infinité de personnage avec ton code de l'index.php, des que tu arrives la page, tu en créés 3 sans conditions.

        Pour le delete qui ne fonctionne pas, que contient ta variable $perso en entrée de la ta fonction ?

        • Partager sur Facebook
        • Partager sur Twitter
          20 novembre 2019 à 11:43:46

          Ta méthode PersonnagesManager::add ne met pas à jour l'attribut _id avec la valeur générée par l'auto-incrément (cf PDO::lastInsertId) or PersonnagesManager::delete repose dessus.

          Et comme cet attribut _id vaut/reste à NULL, ça donne '' (chaîne vide) après cast en string et donne cette erreur SQL (il manque l'entier qu'attend le SGBD)

          => il faut juste ajouter $perso->setId($this->_db->lastInsertId()); après l'execute dans PersonnagesManager::add

          -
          Edité par julp 20 novembre 2019 à 13:57:27

          • Partager sur Facebook
          • Partager sur Twitter
            20 novembre 2019 à 16:54:38

            Merci a tous, je regarde ca. Desolee pour le rendu du post. Bonne soiree.
            • Partager sur Facebook
            • Partager sur Twitter
              20 novembre 2019 à 21:29:35

              L'idéal pour moi c'est d'utiliser au maximum les fonctions prepare et bindValue de PDO pour détecter plus facilement ce genre d'erreur.

              // fonction actuelle
              public function delete(Personnage $perso)
              {
                $this->_db->exec('DELETE FROM personnages WHERE id = '.$perso->id());
              }
              
              /**
              * DELETE :  ma version avec prepare et bindValue
              *
              * @param integer $id
              * @return boolean
              */ 
              public function delete(Personnage $perso): bool
              {
                $sql = "DELETE FROM personnages WHERE id = :id";
                $query = $this->_db->prepare($sql);
                $query->bindValue(':id', $perso->getId(), PDO::PARAM_INT);
                return $query->execute();
              }

              Ce code ne permet pas de résoudre le problème (id à null) mais au moins ça marquera comme erreur "PDO can not convert null to int" ou quelque chose de proche qui permet de mieux déterminer l'origine du problème et le corriger plus facilement. 

              Je sais que c'est très tentant d'utiliser le raccourcis exec mais vérifier ce qu'on fait (surtout sur une requête de type DELETE) ça reste préférable. 

              -
              Edité par Benevolar 20 novembre 2019 à 21:30:34

              • Partager sur Facebook
              • Partager sur Twitter
                20 novembre 2019 à 21:46:41

                Je dirais plutôt que ça "générerait" WHERE id = NULL, ce qui ne matcherait aucune ligne et le DELETE donnerait l'impression d'avoir "fonctionné" (pas d'erreur mais aucune MàJ)

                J'ai presque envie de dire que PDO::exec est mieux. Fonctionnellement, PDO::exec l'est. Niveau sécurité, pas idéal par rapport à du préparé mais sur un AI, à moins de faire n'importe quoi, pas de raison de se manger une faille. A la rigueur avec de la cast et/ou du typehinting sur le getter, c'est blindé.

                -
                Edité par julp 21 novembre 2019 à 0:25:45

                • Partager sur Facebook
                • Partager sur Twitter

                delete() POO class PersonnageManager

                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                • Editeur
                • Markdown