Bonjour à tous et à toutes,

Voila je rencontre un petit problème avec mon code.

Je développe actuellement une partie forums via la base du tuto MVC. L'architecture des forums est la suivante :

Model
ForumTable.php (Liste les forums)
TopicTable.php (Liste les sujets)
PostTable.php (Liste les messages)

Les requètes comportent bien évidément des jointures, mais là n'est pas le problème.

Un seul controller est utilisé pour le front, il se nomme bêtement ForumController.php

Ci dessous la partie pour ajouter un nouveau post dans un forum

        /**
         * Ajouter un nouveau post Topic
         */

        public function add(){
                $date = date('Y-m-d H:i:s'); // Initialisation de la date
                $auth = new DBAuth(app::getInstance()->getDB()); // Chargement de DBAuth
                $dbLasId = new MysqlDatabase(App::getInstance()->getDb()); // Chargement de MysqlDatabase
                $session = Session::getSessionInstance(); // Instance de session (erreur par ex)
                $getUser = $auth->getUserUid(); // Récupération de l'ID utilisateur en cours
                $getIDforum = (int) $_GET['forum_id']; // Sécurisation de la variable _GET "topic_ID"
                $forumId = $this->Forum->forumid($getIDforum, 'forum_id'); // Récupère l'ID du forum

                // On entre le topic dans la base de donnée en laissant le champ topic_last_post à 0
                if(!empty($_POST)){
        $resultTopic = $this->Topic->create([
        'forum_id' => $forumId->forum_id,
        'topic_title' => $_POST['title'],
        'topic_time' => $date,
        'uid' => $getUser,
        'topic_view' => 1,
                'topic_style' => $_POST['topic_genre']   
        ]);

                // On récupère le dernier ID entré dans la data
                $lastInsertId = $dbLasId->lastInsertId();

                // Puis on ajoute le message

        $resultPost = $this->Post->create([
        'post_forum_id' => $forumId->forum_id,
        'post_content' => $_POST['message'],
        'post_time' => $date,
        'uid' => $getUser,
                'topic_id' => $lastInsertId   
        ]);

                // On récupère le dernier ID entré dans la data
                $lastInsertId2 = $dbLasId->lastInsertId();

                // On update comme prévu la valeur de topic_last_post et de topic_first_post  

        $resultTopicLpFp = $this->Topic->update(
        'topic_id', $lastInsertId2,
        [
        'topic_last_post' => $lastInsertId2,
        'topic_first_post' => $lastInsertId2
        ]);

                // Pour terminer, mise à jour de la table forum_forum

                } // Fin if:$_post

                // Chargement des variables et de la vue
                $this->render('forums.add', compact('getIDforum', 'getUser','topicId','topic','forumId'));

        }

La function lastInsertId() se trouve dans la classe MysqlDatabase (comme le tuto MVC)

    /**
    * Récupère le dernier ID
    */

    public function lastInsertId(){

        return $this->getPDO()->lastInsertId();

    }

Ce que je veux

Je souhaite récupérer le dernier ID entré en data

Ce que j'obtiens

Malheureusement et après plusieurs tentative (même bourrine, hein), la function me retourne toujours 0 mais toutes les autres données sont bien ajoutées.

Merci :)

13 réponses


Kenor
Réponse acceptée

Vu comme c'est organiser, il faudrait ajouter une méthode "lastInsertId" dans ta classe Table, qui se contenterai de faire return $this->db->lastInsertId(); (ou une méthode getDb() avec return $this->db;)

Et donc ensuite, pouvoir faire, $this->Topic->lastInsertId();

Après, tu devrais revoir un peu l'organisation de ton code et de tes héritages je pense.

Bonjour.
Pour rappel, la méthode lastinsertId, est à utiliser juste après avoir inséré un enregistrement dans la table dans laquelle on veut récupérer l'id de cet enregistrement.
Par conséquent, il te faut faire quelque chose comme :

$resultTopic = $this->Topic->create([
    'forum_id' => $forumId->forum_id,
    'topic_title' => $_POST['title'],
    'topic_time' => $date,
    'uid' => $getUser,
    'topic_view' => 1,
    'topic_style' => $_POST['topic_genre']
]);
$lastTopicId = $resultTopic->lastInsertId();

Bonjour,

Juste comme ça en passant, ton champ id de la table topic est-il autoincrémental ? Dès fois on y pense, mais ne le met pas.

SelMaK_
Auteur

Merci pour vos réponses :)

Afin de facilité le debug, j'ai supprimé les deux autres requêtes et fait un var_dump de $lastTopicId.

@Ze Nerzhul : "topic_id" est bien en AI oui.

@Lartak : j'ai testé ta solution, mais ça me retourne Call to a member function lastInsertId() on boolean mais malgré cette fatal error, les données sont tout de même postées excepté les entrées avec lastInsertId(). Donc à priori, la requête est bonne.

Tu peux nous donner ta classe MysqlDatabase ( au moins les variables, le constructeur et la méthode "query"). Merci

SelMaK_
Auteur

Bonjour Carouge.

C'est celle du tuto MVC (ici-même), je ne l'ai pas touchée depuis sa création.

namespace Core\Database;

use \PDO;

class MysqlDatabase extends Database{
    private $db_name;
    private $db_user;
    private $db_pass;
    private $db_host;
    private $pdo;

    /**
    * Connexion à la base de données via PDO
    */

    public function __construct($db_name, $db_user = '', $db_pass = '', $db_host = ''){

        $this->db_name = $db_name;
        $this->db_user = $db_user;
        $this->db_pass = $db_pass;
        $this->db_host = $db_host;

    }

 /*********/

    public function query($statement, $class_name = null, $one = false){
        $req = $this->getPDO()->query($statement);
        if(
            strrpos($statement, 'UPDATE') === 0 ||
            strrpos($statement, 'INSERT') === 0 ||
            strrpos($statement, 'DELETE') === 0 
        ){
            return $req;
        }
        if($class_name === null){
            $req->setFetchMode(PDO::FETCH_OBJ);
        } else {
            $req->setFetchMode(PDO::FETCH_CLASS, $class_name);
        }
        if($one){
        $data = $req->fetch();       
    }   else {
        $data = $req->fetchAll();
    }
        return $data;
    }

    /**
    *
    * true = 1 seul résultat
    */

        public function prepare($statement, $attribute, $class_name = null, $one = false){
        $req = $this->getPDO()->prepare($statement);
        $res = $req->execute($attribute);
        if(
            strrpos($statement, 'UPDATE') === 0 ||
            strrpos($statement, 'INSERT') === 0 ||
            strrpos($statement, 'DELETE') === 0 
        ){
            return $res;
        }
        if($class_name === null){
            $req->setFetchMode(PDO::FETCH_OBJ);
        } else {
            $req->setFetchMode(PDO::FETCH_CLASS, $class_name);
        }
        if($one){
        $data = $req->fetch();       
    }   else {

        $data = $req->fetchAll();  
    }
        return $data;
    }

    /**
    * Récupère le dernier ID
    */
    public function lastInsertId(){
        return $this->getPDO()->lastInsertId();

    }

}

J'ai pas tout mis car elle est quand même assez longue.

il serait intéressant de voir l'objet Databse, parce que, c'est dans cette objet que ça se passe ;)
@plus
Pierre

SelMaK_
Auteur

Bonjour Pierre,

namespace Core\Database;

/**
*
*
*/

use Core\Session;

class Database extends Session{

  /**
    *
    */

    public function queryscan($statement, $class_name = null, $one = false){

        $req = $this->getPDO()->query($statement);
        return $req;

        if($class_name === null){

            $req->setFetchMode(PDO::FETCH_OBJ);

        } else {

            $req->setFetchMode(PDO::FETCH_CLASS, $class_name);

        }

        if($one){

        $data = $req->fetch();    

    }   else {

        $data = $req->fetchAll();

    }

        return $data;

    }

    /**
    *Requete groupée (lecture uniquement)
    */

    public function querygroup($statement, $class_name = null, $one = false){

        $req = $this->getPDO()->query($statement);

        if($class_name === null){

            $req->setFetchMode(PDO::FETCH_OBJ | PDO::FETCH_GROUP);

        } else {

            $req->setFetchMode(PDO::FETCH_CLASS, $class_name);

        }

        if($one){

        $data = $req->fetch();    

    }   else {

        $data = $req->fetchAll();

    }

        return $data;

    }

}

getPDO , ça vient d'ou ?
@plus
Pierre

la variable $this->Topic est initié comment ? Pourrais-tu nous fournir la class où se trouve la méthode "create()" ?

Pour moi, il y a un soucis d'instance, comme elle n'est pas identique, il n'arrive pas à récupérer la dernière insertion. Et par conséquent, la logique voudrait qu'il faille récupérer l'instance de "MysqlDatabase" utilisait par la méthode "create" dont je parle au dessus. Et à partir de là, faire ton lastInsertId().

Autre bizarrie new MysqlDatabase(App::getInstance()->getDb());Tu envois une instance à MysqlDatabase, là ou le constructeur semble demander un nom de base "$db_name".

Sans connaitre tout, un truc du genre App::getInstance()->getDb()->lastInsertId(); a une chance de fonctionner si l'instance est bien la même (et en considérant que getDb() renvoi une instance PDO).

SelMaK_
Auteur

Encore merci pour vos réponses :)

@Pierre : getPDO() est la connexion PDO dans MysqlDatabase (un oublie dans l'envoi du code).
@Kenor : $this->Topics renvoie vers le model/table forum_topics

L'instance était un test à l'arrache mais sans succés ^^

La classe "Table"

/**
* Class Table
*
*/

class Table{

    protected $table;
    protected $db;

    public function __construct(Database $db){

        $this->db = $db;
        if(is_null($this->table)){

        $parts = explode('\\', get_class($this));
        $class_name = end($parts);
        $this->table = strtolower(str_replace('Table', '', $class_name));

        }

    }

    /**
    * Met à jour des champs via l'ID passé en GET
    */

    public function update($idParent, $idget, $fields){

        $sql_parts = [];
        $attributes = [];
        foreach($fields as $k => $v){
            $sql_parts[] = "$k = ?";
            $attributes[] = $v;

        }
        $attributes[] = $idget;
        $sql_part = implode(', ', $sql_parts);
        return $this->query("UPDATE {$this->table} SET $sql_part WHERE $idParent = ?", $attributes, true);

    }

    /**
    * Met à jour des champs via l'ID passé en GET
    */

    public function create($fields){

        $sql_parts = [];
        $attributes = [];
        foreach($fields as $k => $v){
            $sql_parts[] = "$k = ?";
            $attributes[] = $v;

        }
        $sql_part = implode(', ', $sql_parts);
        return $this->query("INSERT INTO {$this->table} SET $sql_part", $attributes, true);

    }

    /**
    *
    */

    public function query($statement, $attributes = null, $one = false){

        if($attributes){

        return $this->db->prepare(
            $statement, 
            $attributes, 
            str_replace('Table', 'Entity', get_class($this)), 
            $one);

        } else {

        return $this->db->query(
            $statement, 
            str_replace('Table', 'Entity', get_class($this)), 
            $one);

        }

    }

    /**
    *
    */

    public function queryscan($statement, $attributes = null, $one = false){

        if($attributes){

        return $this->db->prepare(
            $statement, 
            $attributes, 
            str_replace('Table', 'Entity', get_class($this)), 
            $one);

        } else {

        return $this->db->query(
            $statement, 
            str_replace('Table', 'Entity', get_class($this)), 
            $one);

        }

    }

}

J'ai testé avec $lastTopicId = $this->db->lastInsertId(); mais ça me retourne Call to a member function lastInsertId() on null. Je comprend vraiment pas :(

SelMaK_
Auteur

Bonjour,

Un énorme merci Kenor, tu m'a sauvé sur ce coup. Je vais revisionner le cour sur les héritages est réorganiser tout ça :)