Bonjour,

J'ai suivi le tutoriel MVC qui fonctionne très bien, sauf que lorsqu'on crée un nouvel enregistrement il utilise lastinsertId() pour le prochain id, du coup si je supprime 10 enregistrements, le prochain ajout sera le N°11.

Du coup dans mes devis, commandes, factures etc je veux que le prochain numéro soit égal à findCount() + 1

J'ai changé le core/Model.php de cette manière sauf que les ajouts ont toujours le numéro lastInsertId()

class Model{

    static $connections = array(); 
    public $conf = 'default';
    public $table = false; 
    public $db; 
    public $primaryKey = 'id';
    public $id;
        public $countRow;

public function __construct(){
        // Nom de la table
        if($this->table === false){
                    $lastChar = strtolower(get_class($this));
                    if (substr($lastChar,-1) != 's'){
                        $this->table = strtolower(get_class($this)).'s';
                    }else{
                        $this->table = strtolower(get_class($this));
                        }
        }

        // Connection à la base ou récupération de la précédente connection
        $conf = Conf::$databases$this->conf];
        if(isset(Model::$connections$this->conf])){
            $this->db = Model::$connections$this->conf];
            return true; 
        }
        try{
            $pdo = new PDO(
                'mysql:host='.$conf'host'].';dbname='.$conf'database'].';',
                $conf'login'],
                $conf'password'],
                array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8')
            );
            $pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING);
            Model::$connections$this->conf] = $pdo; 
            $this->db = $pdo; 
        }catch(PDOException $e){
            if(Conf::$debug >= 1){
                die($e->getMessage()); 
            }else{
                die('Impossible de se connecter à la base de données'); 
            }
        }
                $this->countRow = $this->findCount() + 1;       
    }

public function save($data){
        $key = $this->primaryKey;
        $fields = array();
        $d = array(); 
        foreach($data as $k=>$v){
            if($k!=$this->primaryKey){
                $fields] = "$k=:$k";
                $d":$k"] = $v; 
            }elseif(!empty($v)){
                $d":$k"] = $v; 
            }
        }
        if(isset($data->$key) && !empty($data->$key)){
            $sql = 'UPDATE '.$this->table.' SET '.implode(',',$fields).' WHERE '.$key.'=:'.$key;
            $this->id = $data->$key;
            $action = 'update';
        }else{
                        $fields] = "id=:id";
            $d":id"] = $this->countRow;
            $sql = 'INSERT INTO '.$this->table.' SET '.implode(',',$fields);
            $action = 'insert'; 
        }
        $pre = $this->db->prepare($sql); 
        $pre->execute($d);
        if($action == 'insert'){
            $this->id = $this->countRow; 
        }
    }

si dans save($data) je remplace $d":id"] = $this->countRow; par $d":id"] = 1000;

L'ajout est bien numéroté 1000, et si je fais un count dans l'onglet sql de mon phpmyadmin, ça me retourne le bon numéro, je comprends pas.

Quelqu'un ?

4 réponses


Badoche
Auteur
Réponse acceptée

Merci pour ta réponse !

Pour les identifiants c'est une bonne idée mais malheureusement j'ai déjà 1600 factures éditées sur le principe facture N°xxxx

Pour la requête énoncée en effet cela simule le findCount() mais il était censé fonctionner.

Mon problème venait du fait que le $countRow était initialisé avec findCount() dans le constructeur de la classe mère, sauf que la classe mère n'est associée à aucune table (false), du coup le count retournait rien et le insert into se basait sur l'autoincrement

Il fallait que je passe par la classe fille (class Devis extends Model) pour que le count pointe bien sur la table devis.

Voici le code :

Attributs du modèle :

class Model{

    static $connections = array(); 
    public $conf = 'default';
    public $table = false; 
    public $db; 
    public $primaryKey = 'id';
    public $id;
        public $countRow = null;
    public $errors = array();
    public $form; 
    public $validate = array();

Ajoutez cette ligne dans le constructeur du modèle

$this->countRow = null;

fonction save du Model (parent)

public function save($data){
        $key = $this->primaryKey;
        $fields = array();
        $d = array(); 
        foreach($data as $k=>$v){
            if($k!=$this->primaryKey){
                $fields] = "$k=:$k";
                $d":$k"] = $v; 
            }elseif(!empty($v)){
                $d":$k"] = $v; 
            }
        }

        if(isset($data->$key) && !empty($data->$key)){
            $sql = 'UPDATE '.$this->table.' SET '.implode(',',$fields).' WHERE '.$key.'=:'.$key;
            $this->id = $data->$key;
            $action = 'update';
        }else{  
                        if(!empty($this->countRow)){
                            $fields] = "id=:id";
                            $d":id"] = $this->countRow;
                        }

            $sql = 'INSERT INTO '.$this->table.' SET '.implode(',',$fields);
            $action = 'insert'; 
        }
        $pre = $this->db->prepare($sql); 
        $pre->execute($d);
        if($action == 'insert'){
            $this->id = $this->countRow; 
        }
    }

Classe fille (devis, commande, facture)

<?php
class Devis extends Model{
    var $validate = array();

    public function __construct() {
        parent::__construct();

        $this->countRow = $this->findCount() + 1;
    }
}

En gros je remplis countRow que si je suis dans la classe fille et donc bien associé à la table voulue, et dans save() je n'exploite le champ id (dans mon insert into) que si celui-ci n'est pas vide (en gros que si la classe fille l'a initialisé à une valeur)

Voilà j'espère que c'est assez clair :) merci pour vos réponses !

Peut être que je dis une bêtise mais imaginons que tu insères 10 enregistrements puis que tu supprimes le deuxième uniquement.
Si tu fais un findCount(), le résultat sera 9. D'où findCount()+1 vaudrait 10. Or, l'ID 10 est déjà pris. Ca ne marchera donc pas.

Badoche
Auteur

Le truc c'est que sur les 3 tables en question j'ai enlevé la possibilité de supprimer un enregistrement, vu qu'en enregistrement comptable les factures par exemple doivent se suivre séquentiellement.

Une fois que j'aurai réussi à faire ça je mettrai countRow à count+1 dans les classes filles concernées (class Devis extends Model), et je mettrai countRow à lastinsertId() dans class Model afin d'éviter le problème dont tu parles ;)

EDIT : dans mon premier message je dis "si je supprime 10 enregistrements", sauf qu'en réalité je suis le seul a pouvoir supprimer les enregistrements de ces tables, et je m'en sers que pour les tests que je fais actuellement, en production je ne supprimerai pas ces enregistrements.

Ne pas supprimer est une bonne pratique à mon gout. Ensuite, je te conseillerai d'utiliser une notation particulière qui te permette d'avoir des informations sur le contenu de ta facture rien qu'en lisant l'identifiant, exemple : Mon client est badoche et il fait sa 2e commande aujourd'hui, son numéro de facture pourrait être : **BD02131112** BD pour Badoche 02 : sa 2e commande du jour 131112 : la date du jour** ainsi tu sais déjà a peu près qui est le client, son numéro de commande du jour et la date de sa commande. Mais bon, là n'est pas la question. Revenons sur les id : Sais-tu que les identifiants servent de référence dans la plupart des objets et c'est ce dernier qui sert de lien. Le modifier comporte des risques d'incohérences si tu ne modifies pas TOUTES les références à ton id. Ce genre de manipulation n'est donc pas conseillé mais là n'est encore pas la question. Pour répondre, il faut que ta colonne id ne soit pas en auto-increment dans ta base de donnée et tu peux utiliser cette requête pour trouver le premier id manquant (disponible) : [code]SELECT facture.id +1 FROM facture WHERE ( facture.id +1 ) NOT IN ( SELECT facture.id FROM facture ) ORDER BY facture.id LIMIT 1[/code]